feat(security-review): schedule the Plane-1 checker coordinator nightly + role-skip (#36)
- checker_coordinator.sh: add COORDINATOR_SKIP_ROLES env (comma-separated) to drop
roles whose credentials are not provisioned from the registry entirely (never
canaried/run/ALARMed). Fail-safe: empty/unset = run all.
- systemd: sea-haven-checkers.{service,timer} run the coordinator nightly at ~03:30
UTC (90 min after the secrev sweep so they don't contend on $MIRROR_DIR / the
Claude pool). The unit sets COORDINATOR_SKIP_ROLES=aws-posture,confluence-doc
(aws-posture needs IAM Roles Anywhere; confluence-doc needs the confluence-bot
token — both intentionally unprovisioned).
Deployed + enabled on the box (deploy-before-merge): canary 4/4 with the skip,
timer scheduled for 2026-06-23 03:35 UTC.
This commit is contained in:
parent
e875d97cbf
commit
17ef4de415
3 changed files with 83 additions and 0 deletions
|
|
@ -145,6 +145,23 @@ if [ "$SQUEEZE" -eq 1 ]; then
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Operator role-skip (COORDINATOR_SKIP_ROLES="aws-posture,confluence-doc"): remove
|
||||||
|
# roles whose backing credentials are not provisioned (aws-posture needs IAM Roles
|
||||||
|
# Anywhere; confluence-doc needs the confluence-bot token). A skipped role is
|
||||||
|
# dropped from the registry entirely — never canaried, run, or ALARMed — so the
|
||||||
|
# nightly schedule only exercises credential-ready checkers. Empty/unset = run all.
|
||||||
|
if [ -n "${COORDINATOR_SKIP_ROLES:-}" ]; then
|
||||||
|
declare -a _kept=()
|
||||||
|
for entry in "${ROLES[@]}"; do
|
||||||
|
_name="$(role_field "$entry" 1)"
|
||||||
|
case ",${COORDINATOR_SKIP_ROLES}," in
|
||||||
|
*",${_name},"*) log "SKIP role '$_name' (COORDINATOR_SKIP_ROLES)" ;;
|
||||||
|
*) _kept+=( "$entry" ) ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
ROLES=( ${_kept[@]+"${_kept[@]}"} )
|
||||||
|
fi
|
||||||
|
|
||||||
# ==============================================================================
|
# ==============================================================================
|
||||||
# DURABLE STATE (design §6.7): atomic write-temp-then-rename + integrity check.
|
# DURABLE STATE (design §6.7): atomic write-temp-then-rename + integrity check.
|
||||||
# Integrity = schema_version match + stored content_hash + logical-consistency.
|
# Integrity = schema_version match + stored content_hash + logical-consistency.
|
||||||
|
|
|
||||||
46
security-review/systemd/sea-haven-checkers.service
Normal file
46
security-review/systemd/sea-haven-checkers.service
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
# sea-haven-checkers.service — Plane-1 nightly checker coordinator (sh-secrev VM, user adam).
|
||||||
|
#
|
||||||
|
# Runs security-review/checker_coordinator.sh: the read-only Plane-1 checkers
|
||||||
|
# (compliance-drift, dependency-cve, doc-drift, plan-groomer) under ONE shared
|
||||||
|
# budget ledger + versioned rotation/coverage, ALARM-only to Slack. Reuses the
|
||||||
|
# secrev sweep's substrate ($MIRROR_DIR clones, budget discipline) — no re-clone.
|
||||||
|
#
|
||||||
|
# Install (on the VM, as root):
|
||||||
|
# sudo cp sea-haven-checkers.service /etc/systemd/system/
|
||||||
|
# sudo cp sea-haven-checkers.timer /etc/systemd/system/
|
||||||
|
# sudo systemctl daemon-reload
|
||||||
|
# sudo systemctl enable --now sea-haven-checkers.timer # the timer drives it
|
||||||
|
# systemctl list-timers sea-haven-checkers.timer
|
||||||
|
#
|
||||||
|
# Secrets/config come from the EnvironmentFiles (leading '-' = optional):
|
||||||
|
# ~/secrev.env -> CLAUDE_CODE_OAUTH_TOKEN, GH_TOKEN, SLACK_WEBHOOK_URL
|
||||||
|
# ~/orchestrator/.env -> OPENAI/etc. (only if a checker shells the cross-model run.py)
|
||||||
|
#
|
||||||
|
# COORDINATOR_SKIP_ROLES excludes roles whose creds are NOT provisioned:
|
||||||
|
# - aws-posture needs IAM Roles Anywhere / step-ca (not provisioned)
|
||||||
|
# - confluence-doc needs the confluence-bot Atlassian token (not provisioned)
|
||||||
|
# Remove a name here once its credential is provisioned to bring that checker online.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Sea Haven agent-team Plane-1 nightly checker coordinator
|
||||||
|
After=network-online.target
|
||||||
|
Wants=network-online.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
User=adam
|
||||||
|
WorkingDirectory=/home/adam/orchestrator/security-review
|
||||||
|
EnvironmentFile=-/home/adam/secrev.env
|
||||||
|
EnvironmentFile=-/home/adam/orchestrator/.env
|
||||||
|
Environment=GH_ORG=Sea-Haven-Industries
|
||||||
|
Environment=COORDINATOR_SKIP_ROLES=aws-posture,confluence-doc
|
||||||
|
# Tune the shared ceiling without editing the script (uncomment to override):
|
||||||
|
# Environment=TOTAL_BUDGET_USD=120
|
||||||
|
# Environment=MAX_CYCLE_NIGHTS=4
|
||||||
|
ExecStart=/home/adam/orchestrator/security-review/checker_coordinator.sh
|
||||||
|
# Bounded so a hung checker cannot run forever; spend is capped by TOTAL_BUDGET_USD.
|
||||||
|
TimeoutStartSec=10800
|
||||||
|
Nice=10
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
20
security-review/systemd/sea-haven-checkers.timer
Normal file
20
security-review/systemd/sea-haven-checkers.timer
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# sea-haven-checkers.timer — fires the Plane-1 checker coordinator nightly.
|
||||||
|
#
|
||||||
|
# 03:30 UTC — ~90 min after the sea-haven-secrev sweep (02:00) so the two do not
|
||||||
|
# contend on $MIRROR_DIR or the shared Claude subscription pool at the same instant.
|
||||||
|
# Persistent=true → if the VM was off, it runs at next boot. RandomizedDelaySec
|
||||||
|
# spreads load off an exact-minute spike.
|
||||||
|
#
|
||||||
|
# Install: see the header of sea-haven-checkers.service.
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=Run the Sea Haven Plane-1 checker coordinator nightly (~03:30 UTC)
|
||||||
|
|
||||||
|
[Timer]
|
||||||
|
OnCalendar=*-*-* 03:30:00
|
||||||
|
Persistent=true
|
||||||
|
RandomizedDelaySec=600
|
||||||
|
Unit=sea-haven-checkers.service
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=timers.target
|
||||||
Reference in a new issue