4 Commits

Author SHA1 Message Date
Fredrik Johansson
58d5d787dd Implement announce/watch: a deploy signal that reverses CI's reach
All checks were successful
Docker / build-and-push (push) Successful in 1m58s
CI announces a new image tag to keep (any grant is enough, read-only
included); each deploy target polls for it locally instead of CI
holding standing SSH access to production. keep stays a pure relay —
the tag lives outside the encrypted vault payload in its own table,
and keep never executes anything itself.

Adds vault_announcements, POST/GET /vaults/:key/announce, and the
`keep announce`/`keep watch` CLI commands, per
PROPOSAL-announce-and-agent.md (now marked implemented). Verified live:
a read-only identity announcing successfully and being logged, watch
picking up the tag on its first poll, and watch exiting nonzero for an
unknown/ungranted vault.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 21:12:55 +02:00
Fredrik Johansson
674e408f09 Reject keep-executes-locally, switch to a .keep-vault marker file
Two changes based on further review:

- Explicitly considers and rejects letting keep's server execute the
  redeploy directly on announce, even though co-location removes the
  credential/network objection that sank the CI-SSHes-in alternative.
  The reason it's still wrong: a fully compromised keep server today
  can't do anything worse than leak ciphertext, since it never holds a
  decryption key. Giving it exec capability breaks that property — a
  routine web app bug becomes "triggers arbitrary redeploys," not
  "leaks encrypted blobs." Also notes the concrete cost: doing this
  from inside a container needs the Docker socket mounted in, which is
  broadly equivalent to root on the host.

- Replaces the "vault key = deploy directory name" assumption with an
  explicit .keep-vault marker file per project directory. Repo name,
  deploy directory name, and vault key are three independent strings
  in practice (confirmed by a real example already in this fleet) —
  no naming convention should assume any two of them match. Bootstrap
  is now: choose a vault key, keep push it, drop a one-line
  .keep-vault file. CI's announce step uses the same deliberately
  hardcoded key, never derived from the repo name automatically.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 21:07:08 +02:00
Fredrik Johansson
114f234cd3 Revise announce+agent proposal against the real deploy script
The original draft speced a hypothetical per-project agent.sh on a
per-project cron. Reality turned out different: there's already a
production bulk deploy script on the host (fixed project array,
docker compose up -d per project, no explicit pull — freshness comes
entirely from pull_policy: always) — so this patches that existing
loop in place instead of introducing a parallel per-project script
that would duplicate its array/failure-tracking logic.

Also folds in a real prerequisite gap found while reconciling the
proposal with the actual script: pull_policy: always isn't universal
across the fleet yet, independent of keep entirely — the bulk script
can't redeploy anything missing that line regardless of keep adoption.
One instance of this was already fixed this session (a sibling
project's docker-compose.yml missed the line when copying another
project's compose pattern).

Reframes §5's announce/watch benefit accordingly: since the real
script is one all-or-nothing sweep, not N independent watchers, the
natural fit is waking the whole sweep early (watch-any), not
per-project selective redeploy — still deliberately left unbuilt
until there's a real signal it's worth it over the already-scheduled
sweep.

Project names anonymized per policy — generic proj1..proj12
placeholders instead of the real fleet.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 20:50:15 +02:00
Fredrik Johansson
e505fbf9b4 Add proposal: announce + self-deploying agent, with a no-keep fallback
Design doc for closing the CI->deploy gap without reintroducing the
credential-concentration problem a naive "CI SSHes into the VPS"
approach would bring back. keep stays a pure relay — never executes
anything remotely. CI announces a new tag (a distinct verb from push/
pull, since a tag isn't a secret and doesn't belong in the encrypted
vault payload); each VPS polls and redeploys itself locally, using an
identity and grant it already holds.

Explicitly specs the not-yet-bootstrapped fallback: the agent script's
`keep pull` is allowed to fail for any reason, and on failure just runs
a plain `docker compose pull && up -d` against whatever's already on
disk — the same thing that would have happened before keep existed.
Ships the dumb-periodic-timer version of the agent first; the watch/
announce fast path is speced but deliberately left unbuilt until
there's a real signal that polling latency is worth the complexity.

Not implemented — design stage.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 20:43:51 +02:00