Skip to content

Commit 8d3bc0a

Browse files
nciminoclaude
andcommitted
fix(ansible): blank OPS_AUTHORIZED_KEYS must not wipe team SSH keys
The SSH-key sync task guarded only against an unset/empty value ([ -z ]), but a whitespace-only OPS_AUTHORIZED_KEYS passed that check and then had all lines stripped by the blank-line filter, yielding an empty temp file that `install` would write over authorized_keys.weown-ops — revoking every team key and locking ops out (the separately-managed DO break-glass key survives). Reorder to filter first, then treat "no non-blank lines" the same as unset: warn and exit 0 without touching the destination. Applied to the template (ansible/deploy.yml.jinja) and the s004.ccc.bot site. Verified with a harness: unset/empty/whitespace-only all preserve the existing file; real keys still sync. Template re-renders byte-identical to the site. Caught by Copilot review on PR #39. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent b98a824 commit 8d3bc0a

3 files changed

Lines changed: 19 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ Changes in this section will be promoted to a dated release entry on merge to `m
6060

6161
### Fixed
6262

63+
- **`OPS_AUTHORIZED_KEYS` sync could revoke all team SSH access on a blank value (2026-06-02)** — the ansible SSH-key sync task guarded only against an unset/empty `OPS_AUTHORIZED_KEYS` (`[ -z ]`), but a whitespace-only value passed that check and then had every line stripped by the blank-line filter, producing an empty temp file that `install` would write over `authorized_keys.weown-ops` — wiping all team keys and locking ops out (the DO break-glass key, managed separately, would survive). Reordered to filter first and treat "no non-blank lines" the same as unset (warn + exit without touching the destination). Fixed in the template (`ansible/deploy.yml.jinja`) and the `s004.ccc.bot` site; verified with a harness (unset/empty/whitespace-only all preserve the existing file; real keys still sync). Caught by Copilot review on PR #39.
6364
- **`TF_VAR_alert_email` missing from the `weown-tofu` setup caused a `tofu apply` failure (2026-06-02)** — the `s004.ccc.bot` runbook's `weown-tofu` `TF_VAR_*` table omitted `alert_email`, so `var.alert_email` fell back to its placeholder default `alerts@example.com` and DigitalOcean rejected the CPU/mem/disk monitor-alert creation with `400 … email is not verified` (the rest of the apply — droplet, reserved IP, firewall — succeeded). Added `TF_VAR_alert_email` to the runbook table with a note that it must be a DO-**verified** email (plus a `TF_VAR_enable_monitoring=false` opt-out), and added the same ⚠️ warning to `terraform.tfvars.example` in both the `s004.ccc.bot` site and the template `.jinja`.
6465
- **`OPENROUTER_API_KEY` never injected into the AnythingLLM container across `anythingllm-docker` (2026-06-02)** — the compose files documented `OPENROUTER_API_KEY` as a required Infisical secret, but the `environment:` block only injected `JWT_SECRET` and `ADMIN_EMAIL` (the original Helm chart mounted all three). A redeploy/restore therefore came up with no OpenRouter credential in the container env — and for the INT-S004 restore specifically, AnythingLLM would fall back to the **expired** key persisted in the restored `storage/.env`, breaking inference with an opaque OpenRouter 401. Added a fail-loud `${OPENROUTER_API_KEY:?...}` injection (same pattern as the `JWT_SECRET` guard) to the template (`compose.prod.yaml.jinja`) and both live sites (`s004.ccc.bot`, `ai.weown.agency`); a value injected via `infisical run` now correctly overrides the stale persisted key. Also gave `OPENROUTER_MODEL_PREF` a default (`${OPENROUTER_MODEL_PREF:-anthropic/claude-opus-4.5}` in the sites, `{{ openrouter_model_pref }}` in the template) to silence the Compose "variable is not set" warning. Caught by Copilot review on PR #39.
6566
- **`otel-agent/deploy.yml` broken Jinja escaping (2026-05-23)** — the file is a plain Ansible playbook (not a copier template), but it had been written with `{{ '{{' }} otel_agent_dir {{ '}}' }}` patterns that would render as the literal string `{{ otel_agent_dir }}` and prevent Ansible variable substitution. Replaced with plain `{{ otel_agent_dir }}` throughout.

anythingllm-docker/sites/s004.ccc.bot/ansible/deploy.yml

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,17 @@
186186
infisical run --projectId={{ infisical_project_id }} --env={{ infisical_env }} -- bash -c '
187187
keys="${OPS_AUTHORIZED_KEYS:-}"
188188
dest=/root/.ssh/authorized_keys.weown-ops
189-
if [ -z "$keys" ]; then
190-
echo "WARN: OPS_AUTHORIZED_KEYS not set in Infisical; leaving team keys unchanged."
189+
umask 077; tmp=$(mktemp)
190+
# Keep only non-blank lines. An unset, empty, or all-whitespace value
191+
# yields an empty file here; treat that the same as "unset" and leave
192+
# the destination untouched, so a blank OPS_AUTHORIZED_KEYS can never
193+
# wipe authorized_keys.weown-ops and revoke all team SSH access.
194+
printf "%s\n" "$keys" | grep -vE "^[[:space:]]*$" > "$tmp" || true
195+
if [ ! -s "$tmp" ]; then
196+
rm -f "$tmp"
197+
echo "WARN: OPS_AUTHORIZED_KEYS is unset or has no non-blank lines; leaving team keys unchanged."
191198
exit 0
192199
fi
193-
umask 077; tmp=$(mktemp)
194-
printf "%s\n" "$keys" | grep -vE "^[[:space:]]*$" > "$tmp"
195200
if cmp -s "$tmp" "$dest" 2>/dev/null; then
196201
rm -f "$tmp"; echo "unchanged"
197202
else

anythingllm-docker/template/ansible/deploy.yml.jinja

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -186,12 +186,17 @@
186186
infisical run --projectId={{ '{{' }} infisical_project_id {{ '}}' }} --env={{ '{{' }} infisical_env {{ '}}' }} -- bash -c '
187187
keys="${OPS_AUTHORIZED_KEYS:-}"
188188
dest=/root/.ssh/authorized_keys.weown-ops
189-
if [ -z "$keys" ]; then
190-
echo "WARN: OPS_AUTHORIZED_KEYS not set in Infisical; leaving team keys unchanged."
189+
umask 077; tmp=$(mktemp)
190+
# Keep only non-blank lines. An unset, empty, or all-whitespace value
191+
# yields an empty file here; treat that the same as "unset" and leave
192+
# the destination untouched, so a blank OPS_AUTHORIZED_KEYS can never
193+
# wipe authorized_keys.weown-ops and revoke all team SSH access.
194+
printf "%s\n" "$keys" | grep -vE "^[[:space:]]*$" > "$tmp" || true
195+
if [ ! -s "$tmp" ]; then
196+
rm -f "$tmp"
197+
echo "WARN: OPS_AUTHORIZED_KEYS is unset or has no non-blank lines; leaving team keys unchanged."
191198
exit 0
192199
fi
193-
umask 077; tmp=$(mktemp)
194-
printf "%s\n" "$keys" | grep -vE "^[[:space:]]*$" > "$tmp"
195200
if cmp -s "$tmp" "$dest" 2>/dev/null; then
196201
rm -f "$tmp"; echo "unchanged"
197202
else

0 commit comments

Comments
 (0)