4 Commits
Author SHA1 Message Date
Juan Denis 939c77b648 feat(connections): add provider SDK contract 2026-08-28 00:48:36 -04:00
Juan DenisandClaude Opus 5 3c24037b64 test(subprocess): one stub kit for subprocess seams
Plan 75 §G7. The suite's hand-rolled stubs were entrenching the very
duplication the plan removes: _FakeProc pasted byte-identical in four
modules, ~25 fake_run closures re-implementing argv dispatch, and zero
tests patching the wrappers — every stub targeted raw subprocess inside
one service module, so each new service test recreated the raw seam.

tests/subprocess_stub.py is that seam. Tests script argv → result; when
G1 moves services onto run_checked() the retarget happens here once
instead of in twelve files.

Two properties are deliberate:

- An unscripted command raises instead of inventing returncode=0. It is a
  BaseException for the same reason SbinPathError is — services wrap
  subprocess in `except Exception`, so an AssertionError would be eaten
  by exactly the handlers the kit exists to test.
- Stubbed execs are still sbin-guarded. Patching subprocess removes the
  §B2 runtime guard, so the kit re-applies it; popen_guard grows a public
  guard_argv() as the one door for that check.

Matching normalises away a sudo prefix and argv[0] absolutisation, so one
scripted rule matches on a root box, a sudo box and a dev box alike.

Mutation-checked: removing the guard call fails the guard test.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 11:24:20 -04:00
Juan DenisandClaude Fable 5 7b45504568 docs: adopt numbered filenames for docs/plans and update references
Plan docs in docs/plans/ (git-ignored) now carry a NN_ prefix in
creation order so new plans sort last. Updated the tracked references
(test docstrings, AGENTS.md, serverkit_installer, _utilities.scss) and
dropped two stale per-file .gitignore lines already covered by the
/docs/plans rule.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 20:49:41 -04:00
Juan DenisandClaude Opus 4.8 298c556ec7 feat(connections): authenticate private container registry pulls
Store per-registry credentials (Fernet-encrypted) and run `docker login`
before pulling a private image — GHCR, Docker Hub, GitLab, ECR, or any
generic registry. Public/anonymous pulls are unchanged.

- ContainerRegistry model (secret encrypted at rest; to_dict never returns it)
  + nullable applications.registry_id; migration 042.
- container_registry_service: CRUD + login/logout/test_connection (secret piped
  via stdin, never on argv) + lazy ECR token exchange.
- DockerService.pull_image gains a registry= arg (login -> pull -> logout in a
  try/finally). Wired into the deploy path (_deploy_docker) and the compose
  path (start_app / apply_image_update): a docker login authenticates both
  `docker pull` and `docker compose pull`.
- API under /api/v1/connections/registries (list=auth, writes=admin); registries
  join the unified /connections list.
- Frontend: Connections hub "Container registry" card (add/test/remove with a
  provider selector) + a per-app registry picker in Container Ops.
- Tests: encrypt/decrypt, stdin-not-argv, login->pull->logout ordering incl.
  finally-on-failure, deploy + compose auth-before-pull, API CRUD/masking/admin.

Deviation from the plan's "single injection point": docker apps run via compose,
so login was wired into both the compose and run_container paths; remote-agent
compose is a follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 01:35:44 -04:00