Files
mopac-pmo/archive/REPORT-20260828-2130-keyproxy-v0.md
T

5.0 KiB

REPORT — keyproxy v0 finish (commit + push of the self-killed turn)

Date: 2026-08-28 21:30 Repo: https://git.knownelement.com/ukrrs/mopac-keyproxy (branch main, pushed through 47343d5) Task: verify the keyproxy-v0 working tree left uncommitted by the previous turn (it self-SIGTERM'd via a broad pkill before committing), re-test in the Docker builder, commit in logical chunks, push, report.

What shipped (v0, per the TASK spec)

  • Two shapes, one resolver: keyproxy serve (localhost HTTP resolve hop) + keyproxy get REF (exec-style CLI, bare value, no newline).
  • Endpoints (internal/server/server.go):
    • POST /v1/resolve — bearer-token auth (constant-time compare, bootstrapped at startup from the file backend), body {"ref":"mpk-<name>"}{"value":"..."}.
    • GET /healthz — unauthenticated liveness.
    • Status codes: 200 / 401 / 400 (malformed body or non-mpk- ref, never echoed) / 404 / 405 / 413 (4 KiB cap) / 500 (recovered panic, detail suppressed) / 501 (stub backends) / 502. Failure bodies carry ref + backend + fixed reason enum only.
  • Backends (internal/backend/, one Backend interface):
    • file — 0600 KEY=VALUE env files, parsed in pure Go (never sourced), ~ expansion, permission mask enforced before read (default 0600, stricter passes, looser refused).
    • env — process-environment indirection (source IS the var name).
    • bitwarden, vaultexplicit not-implemented stubs returning 501 not_implemented behind the same interface; phase-3 drop-ins.
  • Config (internal/config/): strict stdlib-only TOML subset parser; unknown keys and backend-specific misconfigurations fail loudly at startup; keyproxy.toml.example tracked, real keyproxy.toml gitignored (holds the ref MAP — locations only, never material).
  • Redaction, no persistence, no admin UI: memory-only material; every log line naming a ref masks it <ref>=***; auth failures log remote address only; parse errors carry line numbers, never contents; panic values discarded. Enforced by tests + smoke log scan.
  • Build discipline: all dev in Docker via digest-pinned golang:1.26-bookworm (golang@sha256:e8c859f5...e5514); dev.sh build|vet|test|check|smoke, make is a thin front door. Host runs no Go toolchain.

Verification (re-run this turn, all in the Docker builder)

  • ./dev.sh check (= build + vet + test): PASS — ok internal/backend, ok internal/config, ok internal/server, go vet clean, binary built.
  • ./dev.sh smoke (end-to-end, containerized): 10/10 PASS — healthz; 401 no-token; 401 wrong-token; 200 file resolve; 200 env resolve; 404 unknown ref; 400 invalid ref without echo; 501 bitwarden stub; 501 vault stub; 405 GET resolve. Server log verified redacted: no material strings, refs masked ref=mpk-smoke=***. Smoke container torn down by exact name (docker rm -f keyproxy-smoke); no pkill used this turn.

Commits pushed to origin/main

Previous turn left everything uncommitted. Committed in 5 logical chunks (hashes post-rebase, see note below):

Commit Content
b43bc55 backend interface + file/env backends + bitwarden/vault stubs + env-file parser, with tests
7bec2a1 config loader + stdlib TOML subset parser, with tests
82861b6 HTTP resolve hop (auth, redaction, reason enums), with tests
24a57c1 CLI (serve, get, help; exit codes 0/1/2)
47343d5 dev.sh/Makefile Docker tooling, smoke/, keyproxy.toml.example, .gitignore, README

Note: first push was rejected — origin/main had been re-seeded (6c88e65 + 325a36c), an unrelated history whose README/LICENSE are byte-identical to our never-pushed local seed. Resolved by rebasing the 5 implementation commits onto 325a36c (dropping the redundant local seed; resulting tree verified identical to the pre-rebase tree). Push: 325a36c..47343d5 main -> main, working tree clean.

How to start it

See README "Quickstart" (repo root, verified verbatim on 2026-08-28): ./dev.sh check → create 0600 env files + cp keyproxy.toml.example keyproxy.toml./bin/keyproxy serve (binds 127.0.0.1:8082) → POST /v1/resolve with bearer token, or ./bin/keyproxy get mpk-example.

Left for phase 3

  • bitwarden backend: replace stub with Bitwarden Secrets Manager REST (machine accounts, stdlib-first — official SDK license is AGPL-incompatible).
  • vault backend: replace stub with HashiCorp Vault KV v2 + AppRole (official Go api pkg, MPL-2.0, vendored).
  • Optional: short-TTL memory cache (per README "Today vs planned").

Both stubs already fail loudly (501 not_implemented) naming ref + backend; connectors slot into the single backend.Backend interface and newRegistry() in cmd/keyproxy/main.go.

Hygiene

  • No broad pkill this turn; the only process handling was docker rm -f keyproxy-smoke (exact container name) in the smoke script's cleanup trap.
  • Nothing seeded beyond the repo; real keyproxy.toml, *.env, bin/, .smoke/ all gitignored; working tree clean after push.