security(secrets): remove committed credentials from the tree and read them from the vault/environment #112
@@ -16,8 +16,8 @@ litellm.exceptions.AuthenticationError: OpenrouterException -
|
|||||||
```
|
```
|
||||||
**Root Cause**: The OpenRouter API key in `/a0/usr/.env` belonged to a different OpenRouter user.
|
**Root Cause**: The OpenRouter API key in `/a0/usr/.env` belonged to a different OpenRouter user.
|
||||||
|
|
||||||
**Old Key**: `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`
|
**Old Key**: `«vault: agents/production OPENROUTER_API_KEY»`
|
||||||
**New Key**: `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`
|
**New Key**: `«vault: agents/production OPENROUTER_API_KEY»`
|
||||||
**New User**: `user_2rt9lCqcd5d7Vk1t18DHsvWdPTT`
|
**New User**: `user_2rt9lCqcd5d7Vk1t18DHsvWdPTT`
|
||||||
|
|
||||||
### 2. Telegram Bot Conflict (CRITICAL)
|
### 2. Telegram Bot Conflict (CRITICAL)
|
||||||
@@ -48,14 +48,14 @@ McpError: Timed out while waiting for response to ClientRequest. Waited 10.0 sec
|
|||||||
```bash
|
```bash
|
||||||
# Container .env update
|
# Container .env update
|
||||||
sudo docker exec agent-zero bash -c '
|
sudo docker exec agent-zero bash -c '
|
||||||
sed -i "s|^API_KEY_OPENROUTER=.*|API_KEY_OPENROUTER=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|" /a0/usr/.env
|
sed -i "s|^API_KEY_OPENROUTER=.*|API_KEY_OPENROUTER=«vault: agents/production OPENROUTER_API_KEY»|" /a0/usr/.env
|
||||||
'
|
'
|
||||||
```
|
```
|
||||||
|
|
||||||
**Verification**:
|
**Verification**:
|
||||||
```bash
|
```bash
|
||||||
curl -s https://openrouter.ai/api/v1/auth/key \
|
curl -s https://openrouter.ai/api/v1/auth/key \
|
||||||
-H "Authorization: Bearer sk-or-v1-0af3f3..." | python3 -m json.tool
|
-H "Authorization: Bearer «vault: agents/production OPENROUTER_API_KEY»" | python3 -m json.tool
|
||||||
```
|
```
|
||||||
Result: HTTP 200, user `user_2rt9lCqcd5d7Vk1t18DHsvWdPTT`, not free tier.
|
Result: HTTP 200, user `user_2rt9lCqcd5d7Vk1t18DHsvWdPTT`, not free tier.
|
||||||
|
|
||||||
@@ -140,7 +140,7 @@ Added section:
|
|||||||
|
|
||||||
| Component | Status | Details |
|
| Component | Status | Details |
|
||||||
|-----------|--------|---------|
|
|-----------|--------|---------|
|
||||||
| **OpenRouter Key** | ✅ Valid | `sk-or-v1-0af3f3…`, user verified |
|
| **OpenRouter Key** | ✅ Valid | `«vault: agents/production OPENROUTER_API_KEY»` user verified, |
|
||||||
| **Telegram Bot** | ✅ Resolved | Plugin disabled, conflicts cleared |
|
| **Telegram Bot** | ✅ Resolved | Plugin disabled, conflicts cleared |
|
||||||
| **MCP Services** | ✅ Working | No timeouts after key fix |
|
| **MCP Services** | ✅ Working | No timeouts after key fix |
|
||||||
| **Container** | ✅ Running | PID 3320, uptime 16+ hours |
|
| **Container** | ✅ Running | PID 3320, uptime 16+ hours |
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ description: >
|
|||||||
```
|
```
|
||||||
|
|
||||||
4. **Return status**
|
4. **Return status**
|
||||||
- If all checks pass: `{ key_status: "valid", key_prefix: "sk-or-v1-0af", user_id: "user_2rt9lCqcd5d7Vk1t18DHsvWdPTT" }`
|
- If all checks pass: `{ key_status: "valid", key_prefix: "sk-or-v1-synthetic...", user_id: "user_2rt9lCqcd5d7Vk1t18DHsvWdPTT" }`
|
||||||
- If OpenRouter returns 401: `{ key_status: "invalid", detail: "User not found" }`
|
- If OpenRouter returns 401: `{ key_status: "invalid", detail: "User not found" }`
|
||||||
- If vault secret is missing: `{ vault_synced: false }`
|
- If vault secret is missing: `{ vault_synced: false }`
|
||||||
|
|
||||||
@@ -89,8 +89,8 @@ description: >
|
|||||||
|
|
||||||
| Field | Value |
|
| Field | Value |
|
||||||
|-------|-------|
|
|-------|-------|
|
||||||
| **Key Prefix** | `sk-or-v1-0af3f3` |
|
| **Key Prefix** | `«vault: agents/production OPENROUTER_API_KEY»` |
|
||||||
| **Full Key** | `«redacted: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»` (in vault + /a0/usr/.env) |
|
| **Full Key** | `«vault: agents/production OPENROUTER_API_KEY»` (in vault + /a0/usr/.env) |
|
||||||
| **OpenRouter User** | `user_2rt9lCqcd5d7Vk1t18DHsvWdPTT` |
|
| **OpenRouter User** | `user_2rt9lCqcd5d7Vk1t18DHsvWdPTT` |
|
||||||
| **Free Tier** | No |
|
| **Free Tier** | No |
|
||||||
| **Monthly Usage** | 0 (as of 2026-09-01) |
|
| **Monthly Usage** | 0 (as of 2026-09-01) |
|
||||||
@@ -101,7 +101,7 @@ description: >
|
|||||||
|
|
||||||
| Date | Action | Notes |
|
| Date | Action | Notes |
|
||||||
|------|--------|-------|
|
|------|--------|-------|
|
||||||
| 2026-09-01 | fix-401 | Old key `sk-or-v1-036e5ca5…` returned 401 "User not found". Replaced with new key `sk-or-v1-0af3f3…` for user `user_2rt9lCqcd5d7Vk1t18DHsvWdPTT`. Verified OpenRouter 200. Container .env updated, run_ui restarted. |
|
| 2026-09-01 | fix-401 | Old key `«vault: agents/production OPENROUTER_API_KEY»…` returned 401 "User not found". Replaced with new key `«vault: agents/production OPENROUTER_API_KEY»…` for user `user_2rt9lCqcd5d7Vk1t18DHsvWdPTT`. Verified OpenRouter 200. Container .env updated, run_ui restarted. |
|
||||||
|
|
||||||
## Infrastructure References
|
## Infrastructure References
|
||||||
|
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ auxiliary:
|
|||||||
fallback_providers:
|
fallback_providers:
|
||||||
- provider: deepseek
|
- provider: deepseek
|
||||||
base_url: https://api.deepseek.com
|
base_url: https://api.deepseek.com
|
||||||
api_key: sk-b7d9... # ← hardcoded OK (external)
|
api_key: sk-synthetic-external-example # ← hardcoded OK (external, synthetic example)
|
||||||
api_key_env: DEEPSEEK_API_KEY # ← also OK if set in environment (vault or /etc/environment)
|
api_key_env: DEEPSEEK_API_KEY # ← also OK if set in environment (vault or /etc/environment)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -109,7 +109,7 @@ fallback_providers:
|
|||||||
# ❌ FORBIDDEN — hardcoded key (top) OR unauthenticated path (bottom)
|
# ❌ FORBIDDEN — hardcoded key (top) OR unauthenticated path (bottom)
|
||||||
model:
|
model:
|
||||||
provider: harness
|
provider: harness
|
||||||
api_key: sk-Flc62smlegyMEaSo1ka8JA # ← RULE VIOLATION: hardcoded key
|
api_key: sk-synthetic-example-12345 # ← RULE VIOLATION: hardcoded key (synthetic example)
|
||||||
|
|
||||||
model:
|
model:
|
||||||
provider: harness
|
provider: harness
|
||||||
@@ -182,7 +182,7 @@ grep -rn 'litellm/v1/responses' /root/.hermes/config.yaml
|
|||||||
|
|
||||||
# 2. Check systemd drop-ins for master key leaks (2026-07-05: Tanko had this)
|
# 2. Check systemd drop-ins for master key leaks (2026-07-05: Tanko had this)
|
||||||
grep -rn 'LITELLM_API_KEY' /root/.config/systemd/user/ 2>/dev/null
|
grep -rn 'LITELLM_API_KEY' /root/.config/systemd/user/ 2>/dev/null
|
||||||
grep -rn 'LITELLM_API_KEY=sk-litellm-7f96080d' /root/.config/systemd/ 2>/dev/null
|
grep -rn 'LITELLM_API_KEY=sk-synthetic-litellm-…' /root/.config/systemd/ 2>/dev/null
|
||||||
|
|
||||||
# 3. Verify running process env matches dedicated key
|
# 3. Verify running process env matches dedicated key
|
||||||
cat /proc/$(cat /home/jerome/.hermes/gateway.pid | python3 -c "import sys,json; print(json.load(sys.stdin)['pid'])")/environ \
|
cat /proc/$(cat /home/jerome/.hermes/gateway.pid | python3 -c "import sys,json; print(json.load(sys.stdin)['pid'])")/environ \
|
||||||
|
|||||||
@@ -181,8 +181,8 @@ description: >
|
|||||||
**Stirling-PDF** (deployed 2026-07-03, Authentik SSO 2026-07-03):
|
**Stirling-PDF** (deployed 2026-07-03, Authentik SSO 2026-07-03):
|
||||||
- URL: `https://pdf.sysloggh.net` (public) / `http://192.168.68.7:8989` (direct)
|
- URL: `https://pdf.sysloggh.net` (public) / `http://192.168.68.7:8989` (direct)
|
||||||
- Swagger: `http://192.168.68.7:8989/swagger-ui.html`
|
- Swagger: `http://192.168.68.7:8989/swagger-ui.html`
|
||||||
- Admin credentials: `admin` / `kakashi20stirling`
|
- Admin credentials: `«vault: infrastructure/production STIRLING_ADMIN_USER»` / `«vault: infrastructure/production STIRLING_ADMIN_PASSWORD»`
|
||||||
- API key: `adefaef837314afc37803747049c2e73f456da97699ff1b02b391347c4a3cb88`
|
- API key: `«vault: infrastructure/production STIRLING_API_KEY»`
|
||||||
- Authentik OAuth2: configured but disabled (requires paid Server license). Ready to enable: set `SECURITY_OAUTH2_ENABLED=true` + `SECURITY_LOGINMETHOD=all`
|
- Authentik OAuth2: configured but disabled (requires paid Server license). Ready to enable: set `SECURITY_OAUTH2_ENABLED=true` + `SECURITY_LOGINMETHOD=all`
|
||||||
- Compose: `/opt/home_stack/docker-compose.yml`
|
- Compose: `/opt/home_stack/docker-compose.yml`
|
||||||
- Control script: `/opt/home_stack/infra-control.sh`
|
- Control script: `/opt/home_stack/infra-control.sh`
|
||||||
@@ -636,7 +636,7 @@ monitor, or integration breaks.
|
|||||||
```bash
|
```bash
|
||||||
# Full cluster status
|
# Full cluster status
|
||||||
PVE="https://minipve.sysloggh.net"
|
PVE="https://minipve.sysloggh.net"
|
||||||
AUTH="Authorization: PVEAPIToken=monitoring@pve!mumuni=eafd56c5-93d4-4d40-a41d-e688be0987f3"
|
AUTH="Authorization: PVEAPIToken=«vault: infrastructure/production PVE_API_TOKEN»"
|
||||||
curl -sfk "$PVE/api2/json/cluster/resources" -H "$AUTH"
|
curl -sfk "$PVE/api2/json/cluster/resources" -H "$AUTH"
|
||||||
|
|
||||||
# Docker health from Abiba
|
# Docker health from Abiba
|
||||||
|
|||||||
@@ -144,8 +144,8 @@ through its agent wrapper.
|
|||||||
safety net for vault outage or token revocation. Must be kept in sync on rotation.
|
safety net for vault outage or token revocation. Must be kept in sync on rotation.
|
||||||
Example:
|
Example:
|
||||||
```bash
|
```bash
|
||||||
MUMUNI_LITELLM_API_KEY=sk-OzuWsoX22Hmb3Ps3JY01gw
|
MUMUNI_LITELLM_API_KEY=«vault: agents/production LITELLM_API_KEY»
|
||||||
MUMUNI_ZULIP_API_KEY=H8dY6V7aHmWNcfgNtJaDBPZ1dGWn0Ttt
|
MUMUNI_ZULIP_API_KEY=«vault: agents/production ZULIP_API_KEY»
|
||||||
```
|
```
|
||||||
6. **systemd drop-in** at `~/.config/systemd/user/hermes-gateway.service.d/50-vault-wrapper.conf`:
|
6. **systemd drop-in** at `~/.config/systemd/user/hermes-gateway.service.d/50-vault-wrapper.conf`:
|
||||||
```ini
|
```ini
|
||||||
@@ -191,7 +191,7 @@ through its agent wrapper.
|
|||||||
### Tanko migration (COMPLETED 2026-07-17)
|
### Tanko migration (COMPLETED 2026-07-17)
|
||||||
|
|
||||||
Tanko was the last agent migrated from hardcoded keys to vault wrapper.
|
Tanko was the last agent migrated from hardcoded keys to vault wrapper.
|
||||||
Previously: key hardcoded in `/home/jerome/.hermes/config.yaml` (`api_key: sk-CggiHWlamQy…`)
|
Previously: key hardcoded in `/home/jerome/.hermes/config.yaml` (`api_key: sk-synthetic-tanko-example…`)
|
||||||
and `zulip-env.conf` systemd drop-in. Now: user-scope systemd service with drop-in
|
and `zulip-env.conf` systemd drop-in. Now: user-scope systemd service with drop-in
|
||||||
`50-vault-wrapper.conf`, `infisical-gateway.sh` wrapper with while-true loop, token at
|
`50-vault-wrapper.conf`, `infisical-gateway.sh` wrapper with while-true loop, token at
|
||||||
`~/.infisical-token`, `.env` fallback at `~/.hermes/.env`. Keys injected live from vault.
|
`~/.infisical-token`, `.env` fallback at `~/.hermes/.env`. Keys injected live from vault.
|
||||||
@@ -271,13 +271,13 @@ not via the LiteLLM proxy. This is because Agent Zero's workflow (self-update ma
|
|||||||
UI bootstrap, model selection) is built around OpenRouter's native authentication.
|
UI bootstrap, model selection) is built around OpenRouter's native authentication.
|
||||||
|
|
||||||
**Key Storage:**
|
**Key Storage:**
|
||||||
- **Container**: `/a0/usr/.env` (line ~72: `API_KEY_OPENROUTER=sk-or-v1-…`)
|
- **Container**: `/a0/usr/.env` (line ~72: `API_KEY_OPENROUTER=«vault: agents/production OPENROUTER_API_KEY»…`)
|
||||||
- **Vault**: Infisical secret `OPENROUTER_API_KEY` (project=agents, env=production)
|
- **Vault**: Infisical secret `OPENROUTER_API_KEY` (project=agents, env=production)
|
||||||
- **Fallback**: The container's .env is the primary source; vault sync is optional
|
- **Fallback**: The container's .env is the primary source; vault sync is optional
|
||||||
(unlike fleet agents which require vault injection)
|
(unlike fleet agents which require vault injection)
|
||||||
|
|
||||||
**Current Key (2026-09-01):**
|
**Current Key (2026-09-01):**
|
||||||
- **Prefix**: `sk-or-v1-0af3f3…`
|
- **Prefix**: `«vault: agents/production OPENROUTER_API_KEY»`
|
||||||
- **User**: `user_2rt9lCqcd5d7Vk1t18DHsvWdPTT`
|
- **User**: `user_2rt9lCqcd5d7Vk1t18DHsvWdPTT`
|
||||||
- **Plan**: Paid (not free tier)
|
- **Plan**: Paid (not free tier)
|
||||||
- **Usage**: 0 (as of 2026-09-01)
|
- **Usage**: 0 (as of 2026-09-01)
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ contracts — read them there. Do not re-add retired names (`gemma-4-12b`, `gpu-
|
|||||||
- **Health-check script** (`/opt/inference-harness/scripts/litellm-health-check.sh` on CT 116): `gpu-fleet` check fails only on **critical** alerts (warnings are informational). Tests `strix-moe` (not `ornith-1.0-35b`).
|
- **Health-check script** (`/opt/inference-harness/scripts/litellm-health-check.sh` on CT 116): `gpu-fleet` check fails only on **critical** alerts (warnings are informational). Tests `strix-moe` (not `ornith-1.0-35b`).
|
||||||
- **GPU monitor** (`/root/scripts/gpu-monitor-server.py` on pi .24): runs as **systemd unit `gpu-monitor.service`** (was bare `&` process). `gpu_count` includes Strix Halo (was 2, now 3). VRAM alert thresholds: warning 93%, critical 97% (raised from 90/95 — 128K context steady-state is ~70% on RTX 3090, not a fault).
|
- **GPU monitor** (`/root/scripts/gpu-monitor-server.py` on pi .24): runs as **systemd unit `gpu-monitor.service`** (was bare `&` process). `gpu_count` includes Strix Halo (was 2, now 3). VRAM alert thresholds: warning 93%, critical 97% (raised from 90/95 — 128K context steady-state is ~70% on RTX 3090, not a fault).
|
||||||
- **Agent key monitor** (`/root/scripts/agent-health-check.py` on pi .24, cron `*/10`): v4 (2026-09-10) — vault-backed agents (tanko/koby/koonimo) read their **agent-specific** `{NAME}_LITELLM_API_KEY` from Infisical vault (not the shared master key); abiba (pi agent) reads `LITELLM_API_KEY` from its local `/root/.pi/agent/env.sh` (#735 — moved out of shared `/root/.bashrc`), not from the vault. Abiba is pi-only since the harness purge, so its Hermes config/wrapper/gateway legs are skipped rather than reported as faults; koby is **report-only** (captain's 2026-08-17 ruling) — its findings go to the `--json` `report_only` array and are never counted as fleet failures or repaired, and its CT 111 liveness is probed on storepve (.6). Covers: LiteLLM keys, GPU ports, agent gateways, CT liveness (pct status on PVE nodes), config.yaml YAML integrity, wrapper/CLI integrity, vault secret non-emptiness checks. Every run/report carries the absolute execution path (`script=` + `cwd=`). The current fleet roster is owned by the script changelog (`scripts/agent-health-check.py`); mumuni is no longer probed from this host. Legacy `tdunna`/`baggy` replaced with canonical agent hostnames.
|
- **Agent key monitor** (`/root/scripts/agent-health-check.py` on pi .24, cron `*/10`): v4 (2026-09-10) — vault-backed agents (tanko/koby/koonimo) read their **agent-specific** `{NAME}_LITELLM_API_KEY` from Infisical vault (not the shared master key); abiba (pi agent) reads `LITELLM_API_KEY` from its local `/root/.pi/agent/env.sh` (#735 — moved out of shared `/root/.bashrc`), not from the vault. Abiba is pi-only since the harness purge, so its Hermes config/wrapper/gateway legs are skipped rather than reported as faults; koby is **report-only** (captain's 2026-08-17 ruling) — its findings go to the `--json` `report_only` array and are never counted as fleet failures or repaired, and its CT 111 liveness is probed on storepve (.6). Covers: LiteLLM keys, GPU ports, agent gateways, CT liveness (pct status on PVE nodes), config.yaml YAML integrity, wrapper/CLI integrity, vault secret non-emptiness checks. Every run/report carries the absolute execution path (`script=` + `cwd=`). The current fleet roster is owned by the script changelog (`scripts/agent-health-check.py`); mumuni is no longer probed from this host. Legacy `tdunna`/`baggy` replaced with canonical agent hostnames.
|
||||||
- **Stale keys cleaned**: `daily-infra-report.py` SYNTHETIC_API_KEY was stale (`sk-U_ydi3B` → 401); now reads `LITELLM_MASTER_KEY` from env. Deprecated scripts (`router-original.py`, `router-phase0-backup.py`, `apply-fixes.py`) still reference `sk-syslog-local-master-key` but do not actively poll LiteLLM.
|
- **Stale keys cleaned**: `daily-infra-report.py` SYNTHETIC_API_KEY was stale (hardcoded key → 401); now reads `LITELLM_MASTER_KEY` from env. Deprecated scripts (`router-original.py`, `router-phase0-backup.py`, `apply-fixes.py`) still reference `sk-syslog-local-master-key` but do not actively poll LiteLLM (deprecated key, no live usage).
|
||||||
|
|
||||||
## Maintains
|
## Maintains
|
||||||
|
|
||||||
|
|||||||
@@ -122,10 +122,8 @@ def _fail(key, agent_name=None):
|
|||||||
|
|
||||||
|
|
||||||
INFISICAL_TOKEN = os.environ.get("INFISICAL_TOKEN")
|
INFISICAL_TOKEN = os.environ.get("INFISICAL_TOKEN")
|
||||||
INFISICAL_API_URL = os.environ.get("INFISICAL_API_URL", "https://vault.sysloggh.net")
|
|
||||||
|
|
||||||
# Fallback: if no env token, read the shared vault token file
|
|
||||||
if not INFISICAL_TOKEN:
|
if not INFISICAL_TOKEN:
|
||||||
|
# Fallback: read the shared vault token file
|
||||||
_token_path = os.path.expanduser("~/.infisical-token")
|
_token_path = os.path.expanduser("~/.infisical-token")
|
||||||
if os.path.isfile(_token_path):
|
if os.path.isfile(_token_path):
|
||||||
try:
|
try:
|
||||||
@@ -133,6 +131,7 @@ if not INFISICAL_TOKEN:
|
|||||||
INFISICAL_TOKEN = _f.read().strip()
|
INFISICAL_TOKEN = _f.read().strip()
|
||||||
except (OSError, UnicodeDecodeError):
|
except (OSError, UnicodeDecodeError):
|
||||||
pass
|
pass
|
||||||
|
INFISICAL_API_URL = os.environ.get("INFISICAL_API_URL", "https://vault.sysloggh.net")
|
||||||
|
|
||||||
# ── Helpers ──────────────────────────────────────────────────────────
|
# ── Helpers ──────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|||||||
@@ -16,14 +16,16 @@ from email.mime.text import MIMEText
|
|||||||
from email.mime.multipart import MIMEMultipart
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
|
||||||
PVE = "https://192.168.68.12:8006"
|
PVE = "https://192.168.68.12:8006"
|
||||||
AUTH = "Authorization: PVEAPIToken=monitoring@pve!mumuni=eafd56c5-93d4-4d40-a41d-e688be0987f3"
|
AUTH = "Authorization: PVEAPIToken=«vault: infrastructure/production PVE_API_TOKEN»"
|
||||||
|
|
||||||
# ── Shared credentials —─
|
# ── Shared credentials —─
|
||||||
|
|
||||||
ZULIP_SITE = "https://chat.sysloggh.net"
|
ZULIP_SITE = "https://chat.sysloggh.net"
|
||||||
ZULIP_EMAIL = "abiba-bot@chat.sysloggh.net"
|
ZULIP_EMAIL = "abiba-bot@chat.sysloggh.net"
|
||||||
ZULIP_KEY = "cKTDMZAPW08dk3zl05sStzO7HRztzyn8"
|
ZULIP_API_KEY = os.environ.get("ZULIP_API_KEY", "")
|
||||||
ZULIP_AUTH = f"{ZULIP_EMAIL}:{ZULIP_KEY}"
|
if not ZULIP_API_KEY:
|
||||||
|
raise SystemExit("ZULIP_API_KEY not set — refusing to run with no credential")
|
||||||
|
ZULIP_AUTH = f"{ZULIP_EMAIL}:{ZULIP_API_KEY}"
|
||||||
|
|
||||||
LITELLM_PUBLIC = "https://litellm.sysloggh.net"
|
LITELLM_PUBLIC = "https://litellm.sysloggh.net"
|
||||||
LITELLM_BACKEND = "192.168.68.116"
|
LITELLM_BACKEND = "192.168.68.116"
|
||||||
@@ -669,7 +671,10 @@ def send_email(html_content, subject_prefix=""):
|
|||||||
msg.attach(MIMEText(html_content, "html"))
|
msg.attach(MIMEText(html_content, "html"))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
EMAIL_PASSWORD = "rgbuomwcydxwbszd"
|
EMAIL_PASSWORD = os.environ.get("EMAIL_PASSWORD") or os.environ.get("SMTP_PASSWORD") or os.environ.get("MAIL_PASSWORD")
|
||||||
|
if not EMAIL_PASSWORD:
|
||||||
|
print("EMAIL_PASSWORD not set — refusing to send email", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
GMAIL_EMAIL = "jtabiri@gmail.com"
|
GMAIL_EMAIL = "jtabiri@gmail.com"
|
||||||
|
|
||||||
server = smtplib.SMTP("smtp.gmail.com", 587)
|
server = smtplib.SMTP("smtp.gmail.com", 587)
|
||||||
|
|||||||
@@ -7,9 +7,11 @@
|
|||||||
# agent leg is retired — see the note after the Tanko leg.
|
# agent leg is retired — see the note after the Tanko leg.
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Credentials sourced from environment variable ZULIP_API_KEY (set by vault-backed start script)
|
||||||
|
# Never fall back to a literal key
|
||||||
|
ZULIP_API_KEY="${ZULIP_API_KEY:?ZULIP_API_KEY not set — refusing to run with no credential}"
|
||||||
ZULIP_SITE="https://chat.sysloggh.net"
|
ZULIP_SITE="https://chat.sysloggh.net"
|
||||||
ZULIP_EMAIL="abiba-bot@chat.sysloggh.net"
|
ZULIP_EMAIL="abiba-bot@chat.sysloggh.net"
|
||||||
ZULIP_KEY="cKTDMZAPW08dk3zl05sStzO7HRztzyn8"
|
|
||||||
OWNER_ZULIP_ID="9"
|
OWNER_ZULIP_ID="9"
|
||||||
|
|
||||||
|
|
||||||
@@ -27,12 +29,12 @@ notify() {
|
|||||||
local form
|
local form
|
||||||
form="type=private&to=%5B${OWNER_ZULIP_ID}%5D&content=$(python3 -c "import urllib.parse; print(urllib.parse.quote('''${content}'''))")"
|
form="type=private&to=%5B${OWNER_ZULIP_ID}%5D&content=$(python3 -c "import urllib.parse; print(urllib.parse.quote('''${content}'''))")"
|
||||||
curl -sf -X POST "${ZULIP_SITE}/api/v1/messages" \
|
curl -sf -X POST "${ZULIP_SITE}/api/v1/messages" \
|
||||||
-u "${ZULIP_EMAIL}:${ZULIP_KEY}" \
|
-u "${ZULIP_EMAIL}:${ZULIP_API_KEY}" \
|
||||||
-d "${form}" > /dev/null 2>&1 || true
|
-d "${form}" > /dev/null 2>&1 || true
|
||||||
# Zulip stream post to #agent-hub on topic 'zulip-health'
|
# Zulip stream post to #agent-hub on topic 'zulip-health'
|
||||||
local stream_content="${severity} Zulip Monitor: ${msg}"
|
local stream_content="${severity} Zulip Monitor: ${msg}"
|
||||||
curl -sf -X POST "${ZULIP_SITE}/api/v1/messages" \
|
curl -sf -X POST "${ZULIP_SITE}/api/v1/messages" \
|
||||||
-u "${ZULIP_EMAIL}:${ZULIP_KEY}" \
|
-u "${ZULIP_EMAIL}:${ZULIP_API_KEY}" \
|
||||||
-d "type=stream&to=%5B7%5D&topic=zulip-health&content=$(printf '%s' "${stream_content}" | python3 -c "import sys,urllib.parse; print(urllib.parse.quote_from_bytes(sys.stdin.buffer.read()))")" \
|
-d "type=stream&to=%5B7%5D&topic=zulip-health&content=$(printf '%s' "${stream_content}" | python3 -c "import sys,urllib.parse; print(urllib.parse.quote_from_bytes(sys.stdin.buffer.read()))")" \
|
||||||
> /dev/null 2>&1 \
|
> /dev/null 2>&1 \
|
||||||
|| echo " WARN: stream alert to #agent-hub (zulip-health) delivery failed (curl exit $?)" >> "$LOG"
|
|| echo " WARN: stream alert to #agent-hub (zulip-health) delivery failed (curl exit $?)" >> "$LOG"
|
||||||
@@ -41,7 +43,7 @@ notify() {
|
|||||||
# ── Global: Zulip Server ──
|
# ── Global: Zulip Server ──
|
||||||
SERVER_CODE=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 10 \
|
SERVER_CODE=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 10 \
|
||||||
https://chat.sysloggh.net/api/v1/server_settings \
|
https://chat.sysloggh.net/api/v1/server_settings \
|
||||||
-u 'abiba-bot@chat.sysloggh.net:cKTDMZAPW08dk3zl05sStzO7HRztzyn8' 2>/dev/null) || SERVER_CODE="000"
|
-u "${ZULIP_EMAIL}:${ZULIP_API_KEY}" 2>/dev/null) || SERVER_CODE="000"
|
||||||
SERVER_CODE=$(printf '%s' "$SERVER_CODE" | tr -d '[:space:]')
|
SERVER_CODE=$(printf '%s' "$SERVER_CODE" | tr -d '[:space:]')
|
||||||
[ -n "$SERVER_CODE" ] || SERVER_CODE="000"
|
[ -n "$SERVER_CODE" ] || SERVER_CODE="000"
|
||||||
if [ "$SERVER_CODE" != "200" ]; then
|
if [ "$SERVER_CODE" != "200" ]; then
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ Agent (Hermes/pi) ──curl + X-API-Key──► Stirling-PDF (:8989) ──►
|
|||||||
| Base URL | `http://192.168.68.7:8989` |
|
| Base URL | `http://192.168.68.7:8989` |
|
||||||
| Auth Method | API Key (header) |
|
| Auth Method | API Key (header) |
|
||||||
| Header Name | `X-API-Key` |
|
| Header Name | `X-API-Key` |
|
||||||
| API Key | `adefaef837314afc37803747049c2e73f456da97699ff1b02b391347c4a3cb88` |
|
| API Key | `«vault: infrastructure/production STIRLING_API_KEY»` |
|
||||||
| Key Source | `SECURITY_CUSTOMGLOBALAPIKEY` in `/opt/home_stack/docker-compose.yml` |
|
| Key Source | `SECURITY_CUSTOMGLOBALAPIKEY` in `/opt/home_stack/docker-compose.yml` |
|
||||||
| Swagger | `http://192.168.68.7:8989/swagger-ui.html` |
|
| Swagger | `http://192.168.68.7:8989/swagger-ui.html` |
|
||||||
| Health | `http://192.168.68.7:8989/api/v1/info/status` |
|
| Health | `http://192.168.68.7:8989/api/v1/info/status` |
|
||||||
@@ -44,7 +44,7 @@ from the knowledge graph and use the documented curl patterns.
|
|||||||
Direct bash invocations:
|
Direct bash invocations:
|
||||||
```bash
|
```bash
|
||||||
curl -X POST "http://192.168.68.7:8989/api/v1/split-pdf" \
|
curl -X POST "http://192.168.68.7:8989/api/v1/split-pdf" \
|
||||||
-H "X-API-Key: adefaef837314afc37803747049c2e73f456da97699ff1b02b391347c4a3cb88" \
|
-H "X-API-Key: «vault: infrastructure/production STIRLING_API_KEY»" \
|
||||||
-F "fileInput=@/path/to/file.pdf" \
|
-F "fileInput=@/path/to/file.pdf" \
|
||||||
-F "pageNumbers=1,2,3" \
|
-F "pageNumbers=1,2,3" \
|
||||||
-o /tmp/output.zip
|
-o /tmp/output.zip
|
||||||
|
|||||||
Reference in New Issue
Block a user