Files
cayce-ops/docker-compose.yml
T
cayce 90e6cfcc19 fix: address external audit — criticals 1-5 + mediums
Critical 1 (approval forgery): audit_log is now hash-chained
(prev_hash/entry_hash, verify_audit_chain); executor approve REQUIRES a
BIP-340 signature over sha256(cayce-ops:approve:<id>) when
CAYCE_OPS_OPERATOR_PUBKEY is set; deploy/roles.sql ships least-privilege
per-daemon DB roles.

Critical 2 (threading dead): sends create real OUTBOUND rows (own
Message-ID, In-Reply-To -> inbound); inbound message_id never overwritten;
maild compose adds the first-contact path; _match_proposal falls back to
inbound chains.

Critical 3 (duplicate sends): per-message transactions in send path —
SMTP failure on message N no longer resurrects 1..N-1; failures audited
(send_failed) and the row stays queued.

Critical 4 (classifier): negated approvals (cannot accept / not approved /
not accepting) classify REJECTION at 0.95 before the bare-keyword rule;
LLM prompt braces escaped (.format no longer KeyError into silent fallback).

Critical 5 (systemd): every daemon has a run subcommand
(maild run = poll+send, publisher run = publish-due, monitor run = build);
deploy README documents the separate daily publisher plan timer.

Mediums: approved_hash binds drafts/captions to the approved text (edited
text refuses to send/publish until re-approved); risk_score renamed
match_score (migration 0002) and auto-approve orders HIGHEST relevance
first; compose binds postgres to 127.0.0.1; IMAP marks \\Seen only after
commit (fetch returns (num, raw), mark post-commit); disabled channels are
terminal (ContentStatus.SKIPPED) and publish failures burn a bounded
attempt budget before abandonment; make hooks installs the pre-push gate.

tests: 12 new — 56 total, all green; ruff 0 findings; gitleaks clean.
2026-10-19 23:06:29 +00:00

75 lines
2.2 KiB
YAML

services:
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: cayce
POSTGRES_PASSWORD: localdev-only-not-a-secret
POSTGRES_DB: cayce_ops
ports:
- "127.0.0.1:5432:5432" # loopback only — Docker bypasses host firewalls
volumes:
- pgdata:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U cayce -d cayce_ops"]
interval: 5s
timeout: 3s
retries: 10
# One container per daemon; all run the same image and differ only in command.
# Cron-style cadence via `sleep` loop; on a VPS prefer the systemd timers in
# deploy/systemd/ (they are the primary deployment path).
scanner:
build: .
command: sh -c "while true; do cayceops scanner run; sleep 3600; done"
env_file: .env
environment:
CAYCE_OPS_DATABASE_URL: postgresql+psycopg://cayce:localdev-only-not-a-secret@db:5432/cayce_ops
depends_on:
db:
condition: service_healthy
executor:
build: .
command: sh -c "while true; do cayceops executor run; sleep 600; done"
env_file: .env
environment:
CAYCE_OPS_DATABASE_URL: postgresql+psycopg://cayce:localdev-only-not-a-secret@db:5432/cayce_ops
depends_on:
db:
condition: service_healthy
maild:
build: .
command: sh -c "while true; do cayceops maild poll && cayceops maild send-approved; sleep 300; done"
env_file: .env
environment:
CAYCE_OPS_DATABASE_URL: postgresql+psycopg://cayce:localdev-only-not-a-secret@db:5432/cayce_ops
depends_on:
db:
condition: service_healthy
publisher:
build: .
command: sh -c "while true; do cayceops publisher publish-due; sleep 300; done"
env_file: .env
environment:
CAYCE_OPS_DATABASE_URL: postgresql+psycopg://cayce:localdev-only-not-a-secret@db:5432/cayce_ops
depends_on:
db:
condition: service_healthy
monitor:
build: .
command: sh -c "while true; do cayceops monitor build; sleep 60; done"
environment:
CAYCE_OPS_DATABASE_URL: postgresql+psycopg://cayce:localdev-only-not-a-secret@db:5432/cayce_ops
CAYCE_OPS_MONITOR_OUTPUT: /srv/status.html
volumes:
- ./status:/srv
depends_on:
db:
condition: service_healthy
volumes:
pgdata: