Skip to content

feat(rigging): service containers — closes #26 (increment 3 of 3) - #38

Merged
submtd merged 6 commits into
mainfrom
feature/issue-26-service-containers
Jul 23, 2026
Merged

feat(rigging): service containers — closes #26 (increment 3 of 3)#38
submtd merged 6 commits into
mainfrom
feature/issue-26-service-containers

Conversation

@submtd

@submtd submtd commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Closes #26 — the third and final increment. A repo whose tests need a live database can now use rigging end to end.

What

.rigging.json's per-stack config gains services:

"stacks": {"node": {"services": {"postgres": {"version": "16", "urlEnv": "TEST_DATABASE_URL"}}}}

Supported: postgres, mysql, redis. rigging renders a job-level services: block and sets the composed connection URL in a job-level env: var the repo names — so every step (including migrations) sees it.

The design in one line

A SERVICE_REGISTRY owns everything except the two things the repo picks — the image version (a tag) and the urlEnv name. It owns the image, port, credentials, the connection-URL template, and — crucially — the health check, so the job waits for the container to be ready instead of racing it and flaking. No user string ever reaches a Docker options: line.

Why it's safe, and why it runs

  • Injection: the only two user values are version (charset-constrained, lands in a quoted tag) and urlEnv (a strict ^[A-Za-z_][A-Za-z0-9_]*$ identifier, refused at load). Health options and URLs are registry constants.
  • Runtime correctness — the thing this suite has shipped wrong before. The health commands were verified against GitHub's own documented service-container examples, and the whole-branch review (most-capable model) independently re-confirmed them byte-for-byte against GitHub's docs and the mysqladmin man page. The URLs match the container credentials; the escaped-quote options: rendering (--health-cmd \"redis-cli ping\") round-trips through YAML correctly.
  • Tag, not digest — a deliberate, documented inconsistency with the Action SHA-pinning rule: an ephemeral test fixture on a private network that never sees the workflow token has a different threat model, and a tag keeps getting patches. This does not enlarge hull: the trufflehog pin has no automated bump path, and two scanner facts are hardcoded outside the registry #30.

Scope & tests

  • services is a hand-authored declaration, so it does not flow through propose_configscaffold.py/SIGNAL_KEYS untouched.
  • The nine pre-existing goldens stay byte-identical (structural: services:/env: emit only when non-empty). Three new goldens — postgres, redis, and mysql — pin the rendering; redis covers the empty-container-env path and mysql the env-block + quoted-health-command combination.
  • Full suite 1436 passing.

🤖 Generated with Claude Code

submtd and others added 6 commits July 22, 2026 18:02
Four tasks closing #26: a SERVICE_REGISTRY (postgres/mysql/redis) owning image,
port, credentials, health check, and URL template; config validation of
stacks.<id>.services into StackConfig; render of a job-level services: block and
env: with the composed connection URL; docs + changelog. Health commands are
externally verified against GitHub's docs (byte-identity tests can't catch a
wrong one), and two goldens (postgres, redis) pin the rendering including
redis's empty-env + escaped-quote health command. services is manual-only, so
it does not touch propose_config/SIGNAL_KEYS. Job-level env placement per the
user's choice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Externally verified against GitHub's own service-container docs
(postgres, redis) and the docker-library/healthcheck mysql script
(mysqladmin ping) -- health commands, env var names, and ports match
the documented canonical forms exactly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0119qj5F9NnGhQCxHehLy99E
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ers (#26)

Final whole-branch review (runtime correctness confirmed against GitHub's docs)
returned only Minors; applied:
- Add node-mysql.yml golden -- mysql was the one service with no render test, and
  it is the only one exercising a container env: block AND a quoted health-cmd
  together. Generated via sync_action_pins.py; the nine other goldens and the
  dogfooded workflows are unchanged.
- Note in services.py that `mysqladmin ping` is a liveness, not readiness, probe
  (the standard GHA idiom; --health-retries covers the gap).
- Drop an unused `import re` in test_services.py.
- Type _build_job's `services` parameter as tuple[config.ResolvedService, ...].

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@submtd submtd left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review (author) — satisfies keel's reviewPolicy: review gate.

Increment 3 of 3, closing #26. rigging now renders GitHub Actions service containers (postgres/mysql/redis) alongside the test job, with each service's connection URL exposed under its configured urlEnv.

Reviewed:

  • Correctness — the whole-branch opus review confirmed runtime correctness against GitHub's service-container docs; health commands were externally verified twice (implementer + reviewer), including the mysqladmin liveness-not-readiness caveat documented in services.py.
  • Teststest_services.py covers the registry (URL composed from registry constants not the version tag, every service carries a health check, no Actions expressions in health options). Four goldens exercise the render paths: postgres, redis (empty container env), mysql (env block + quoted health-cmd combined). Suite 1404 → 1436.
  • Scope — diff is confined to services.py (new), config/plan/render, goldens, sync script, and docs/changelog. Nothing extraneous.
  • Injection safety — service images tag-pinned by design (ephemeral fixture on a private network); health options are registry constants, never user input; urlEnv is a strict identifier. Does not enlarge #30.
  • Changelog — Unreleased Added entry is accurate and user-facing.

Ready to land.

@submtd
submtd merged commit 8eec074 into main Jul 23, 2026
4 checks passed
@submtd
submtd deleted the feature/issue-26-service-containers branch July 23, 2026 01:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

rigging: cannot express any JS toolchain but plain npm, a custom test command, or a service container

1 participant