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.
75 lines
2.2 KiB
YAML
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:
|