Loading repository data…
Loading repository data…
pensados / repository
Give AI agents controlled access to your server — not unrestricted shell. Command allowlist, structured editing, service management, file upload. Pairs with sentinelx-core-mcp for Claude and ChatGPT via MCP/OAuth. MIT license.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
⚠️ This repository is archived and no longer maintained
SentinelX has evolved into a multi-host, hub-managed platform. Active development happens at pensados/sentinelx-cloud-core (Apache 2.0).
This repo is the original single-host SentinelX: HTTP API, token auth, no hub. It works, but receives no further updates. The license remains MIT — forks are welcome to continue independently.
Live product: sentinelx.pensa.ar
Controlled server agent over HTTP. Command allowlist. Structured editing. Upload. Script execution. Service management.
SentinelX Core runs as a dedicated service user on your server and exposes a token-authenticated local HTTP API. Any integration layer — an MCP bridge, a script, a CI job — can call it to perform controlled operations without giving that layer unrestricted shell access.
Your integration layer (MCP, script, CI...)
│
│ HTTP + Bearer token
▼
SentinelX Core (local, port 8091)
│
├─ /exec → runs allowed commands only
├─ /edit → structured file edits via sentinelx-safe-edit
├─ /script/run → executes temporary bash or python3 scripts
├─ /service → start / stop / restart / status for registered services
├─ /upload → file upload (simple and chunked)
├─ /capabilities → allowed commands, services, locations, playbooks
└─ /state → runtime state snapshot
The key constraint: /exec only runs commands that are explicitly in ALLOWED_COMMANDS. Everything else is rejected.
bin/sentinelx-safe-edit (no shell quoting, supports replace / regex / replace-block / append / prepend / write, with dry-run, diff and automatic backup)nginx, docker, sentinelx) with per-action commands and risk levels/capabilities endpoint exposing allowed commands, categories, PATH_INDEX, playbooks and embedded help — useful for AI agents and MCP integrations.
├── agent.py
├── bin/
│ └── sentinelx-safe-edit
├── config.py
├── context.py
├── logger.py
├── logger_exec.py
├── examples/
│ └── sentinelx.env.example
├── install.sh
├── run.sh
├── requirements.txt
└── systemd/
└── sentinelx.service
git clone https://github.com/pensados/sentinelx-core.git
cd sentinelx-core
sudo bash install.sh
The installer:
sentinelx system user/opt/sentinelx/etc/sentinelx/sentinelx.envsystemd service named sentinelxsudo nano /etc/sentinelx/sentinelx.env
Minimum required:
SENTINEL_TOKEN=your_strong_token_here
AGENT_PORT=8091
LOG_DIR=/var/log/sentinelx
LOG_FILE=/var/log/sentinelx/sentinelx.log
LOG_EXEC_FILE=/var/log/sentinelx/exec.log
SENTINEL_UPLOAD_DIR=/var/lib/sentinelx/uploads
SENTINEL_SAFE_EDIT_BIN=/opt/sentinelx/bin/sentinelx-safe-edit
Then restart:
sudo systemctl restart sentinelx
sudo systemctl status sentinelx
python3 -m venv venv
venv/bin/pip install -r requirements.txt
./run.sh
Default local port: 8092 (intentionally different from the installed default to avoid conflicts).
Replace YOUR_TOKEN and YOUR_PORT with your actual values.
curl -s -H "Authorization: Bearer YOUR_TOKEN" \
http://127.0.0.1:YOUR_PORT/state | jq
curl -s -H "Authorization: Bearer YOUR_TOKEN" \
http://127.0.0.1:YOUR_PORT/capabilities | jq
curl -s -X POST http://127.0.0.1:YOUR_PORT/exec \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"cmd": "df -h"}'
curl -s -X POST http://127.0.0.1:YOUR_PORT/edit \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"path": "/etc/nginx/sites-available/example.conf",
"sudo": true,
"mode": "replace",
"old": "server_name old.example.com;",
"new_text": "server_name new.example.com;",
"diff": true,
"validator_preset": "nginx"
}'
curl -s -X POST http://127.0.0.1:YOUR_PORT/script/run \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"interpreter": "bash",
"content": "#!/bin/bash\necho hello from sentinelx\nuptime",
"timeout": 30
}'
curl -s -X POST http://127.0.0.1:YOUR_PORT/service \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"service": "nginx", "action": "reload"}'
SentinelX Core runs as the sentinelx system user. This means:
sudo run with the permissions of that usersudo must be writable by sentinelx/etc) require explicit sudoers rulessentinelx/var/lib/sentinelx/uploadsroot or another usernginx -t that touch system pathsNever grant unrestricted sudo to the sentinelx user.
Use a narrow, explicit policy:
sudo visudo -f /etc/sudoers.d/sentinelx-core
Example minimal content:
Cmnd_Alias SENTINELX_SYSTEMD = \
/bin/systemctl status nginx, \
/bin/systemctl restart nginx, \
/bin/systemctl reload nginx
Cmnd_Alias SENTINELX_NGINX = /usr/sbin/nginx -t
Cmnd_Alias SENTINELX_EDIT = /opt/sentinelx/bin/sentinelx-safe-edit
sentinelx ALL=(root) NOPASSWD: SENTINELX_SYSTEMD, SENTINELX_NGINX, SENTINELX_EDIT
Verify binary paths first:
which systemctl
which nginx
Validate and fix permissions:
sudo visudo -cf /etc/sudoers.d/sentinelx-core
sudo chmod 440 /etc/sudoers.d/sentinelx-core
The command allowlist is defined in ALLOWED_COMMANDS in agent.py. Add only commands you intend to expose. Prefer broad base commands (docker, git) over redundant specific variants.
After any change to agent.py, restart the service:
sudo systemctl restart sentinelx
SERVICE_ACTIONS in agent.py defines which services can be controlled and which actions are allowed per service. Add an entry with:
unit: the systemd unit nameactions: list of allowed actions (status, start, stop, restart, reload, validate)action_commands: the exact command for each actionrisk: low, medium, or high (informational, passed through /capabilities)Installed log locations:
| File | Content |
|---|---|
/var/log/sentinelx/sentinelx.log | Main service log |
/var/log/sentinelx/exec.log | Structured exec audit log |
Useful checks:
sudo tail -f /var/log/sentinelx/exec.log
sudo journalctl -u sentinelx -n 100 --no-pager
After installation, verify in order:
sudo systemctl status sentinelx → service is running/state responds with a valid JSON object/capabilities lists the expected allowed commands/exec with {"cmd": "pwd"} returns a result/edit on a file owned by sentinelx succeeds without sudo/edit on a protected file succeeds with "sudo": true (if sudoers is configured)/service for nginx status worksService does not start
sudo journalctl -u sentinelx -n 50 --no-pager
/edit fails with permission error
The target file is not writable by sentinelx. Either change ownership, or use "sudo": true with the appropriate sudoers rule.
/exec is blocked
The command is not in ALLOWED_COMMANDS. Add it to agent.py and restart.
Logs are empty
Verify that /var/log/sentinelx exists and is owned by the sentinelx user, and that the env file points to the correct log paths.
127.0.0.1 unless you have a specific reason to expose itSENTINEL_TOKENALLOWED_COMMANDS and SERVICE_ACTIONS before deployingMIT