Skip to content

Share registrar scenario deployment setup (#981) - #982

Merged
AcoPiper merged 1 commit into
mainfrom
AcoPiper/issue-981
Sep 2, 2026
Merged

Share registrar scenario deployment setup (#981)#982
AcoPiper merged 1 commit into
mainfrom
AcoPiper/issue-981

Conversation

@AcoPiper

@AcoPiper AcoPiper commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

What this changes

The registrar red-team and endurance scenarios stood the same isolated deployment up from two private copies of the same code. Both now use one implementation in scripts/impl/lib/registrar-docker.sh, and keep their own assertions and workloads.

Shared: the run root and its audit tmpfs, the four allocated host ports, the fingerprinted provisioning config and the operator agent config init is given, the responder image build, the third-party image pre-pull, infra install, the state predicate seed, init under sudo and its redacted log, the root-token header file, the OpenBao CA bundle, the explicit empty agent EAB, the KV mount and the two shared path constants, the registrar DNS aliases, the daemon configuration, and the supervisor that owns the root-owned inherited listener along with starting, awaiting, controlling and stopping it.

Local to each scenario: every assertion, the leak bundle and its manifest, the audit-capacity and peer-credential fixtures, the red-team socket refusals, the 6-minute Step CA lifetime and 5s/4m/0s renewal cadence, the anchor pin, the AppRole control credentials and both strace passes, the post-expiry checks, and each scenario's own cleanup. The three parameters the shared setup takes are each scenario's slug, the component body of its provisioning config, and the extra [registrar] keys only the red-team arm needs.

Two consequences worth naming:

  • Instance names. Both arms now derive through one helper against REGISTRAR_DOCKER_MAX_INSTANCE_NAME_LEN, the budget infra install validates --instance-name against, rather than a literal each. Every token either launcher actually passes fits, so both keep the name they had; an over-long token now truncates to its discriminating tail rather than failing the install minutes into a run. scripts/validate-e2e-run-scope.sh exercises the helper for both prefixes and holds the constant to the value the binary derives, replacing the three greps it used to run against run-registrar-endurance.sh for lines that no longer exist.
  • Endurance artifacts. The empty-EAB exchange is recorded as empty-eab-status.txt, empty-eab-headers.txt and empty-eab-response.json for both arms; the red-team arm already wrote those, and the endurance arm gains them. Nothing else about either artifact directory changes.

The pull request also carries a documentation-only change: append_configured_anchors (src/acme/flow.rs) and §4.4 of docs/reference/registrar-client-identity.md now record the already-merged LeafWithChain anchor publication in the tree, which is where the issue requires it to live. The disclosure itself stays there rather than being restated here. No production behaviour changed.

Closes #981

Part of #783

Part of #784

Test plan

  • Repository shell and run-scope validation over the changed launcher scripts — scripts/validate-e2e-run-scope.sh, scripts/validate-e2e-leftover-check.sh, scripts/validate-e2e-openssl-compat.sh, scripts/validate-compose-instance-names.sh and scripts/validate-deploy-compose.sh all pass, and shellcheck -x raises no new category on the three changed shell files. It is not a CI gate here and is not silent on these scripts: it reports SC2015, SC2024, SC2119 and SC2126, all info- or warning-level and every one of them already raised by the pre-refactor scripts. Sharing the setup removes more of them than it adds — the single addition is an SC2119 suggestion on the new no-argument registrar_docker_start_supervisor call site. The run-scope validator now covers both registrar scenarios' instance-name derivation and holds REGISTRAR_DOCKER_MAX_INSTANCE_NAME_LEN to the value the binary derives.
  • The registrar red-team scenario runs through its existing checked-out-project/binary/artifact launcher contract — CI run 33570500941, whole workflow green. The registrar-redteam arm's artifact carries all fifteen PASS lines across validate, deployment, containment, functionality, socket, peer-credentials, capacity and done, and a 348-second wall-clock.json.
  • The registrar-endurance case runs through the extended suite, with its case artifact and summary record inspected — E2E Extended run 33570504691, dispatched against this branch. extended-summary.json records "overall_status": "pass" with {"case":"registrar-endurance","status":"pass"}. The case artifact holds the renewal evidence: original-leaves.json for both leaves, a post-expiry-endpoint.json whose live endpoint digest differs from the original while pin_content_sha256 and pinned_anchor_sha256 are unchanged, the 6-minute ca.json, both strace passes with an empty daemon-trace-matches.log, and every phase from validate through cleanup inside the 20-minute deadline.
  • The LeafWithChain anchor-publication documentation is in the tree, not only in this description — the rustdoc on append_configured_anchors in src/acme/flow.rs and §4.4 of docs/reference/registrar-client-identity.md, each naming the [trust].ca_bundle_path gate, the unchanged-root-anchor renewal rationale, and SURFACE_LEAF_PUBLICATION in src/registrar_certs.rs as the sole consumer today.
  • The shared helpers produce what the code they replace produced — provisioning.toml, operator-agent.toml, both scenarios' endpoint.toml and supervisor.py come out byte-identical to the inline versions at the merge-base, and both scenarios were driven through the whole deployment phase against stubbed docker/bootroot/curl under set -euo pipefail: image tags, instance names, infra install ports, init flags and per-scenario secrets, the alias override and both hostname probes all match the pre-refactor contract.
  • Supervisor and cleanup ownership is unchanged — exercised as root in a container: the listener comes up root:root 0700, the daemon inherits fd 3 with LISTEN_FDS=1 and its config path, the launch prefix's environment reaches it, restart respawns on the same inode, stop terminates the daemon, and registrar_docker_stop_supervisor reaps both and is a no-op the second time.
  • No certificate lifetime, renewal cadence, endpoint pin semantics, production tracing or test seam changed — scripts/preflight/ci/check.sh green across all nine steps (cargo audit's two allowed warnings are the standing baseline), and cargo test --no-fail-fast passes 2723 tests over 42 targets, including registrar_redteam_assertions, which sources the changed library.

Both Docker scenarios need passwordless sudo for the root-owned registrar socket, and the endurance arm also needs strace and mountpoint, so neither runs on the macOS host this was written on; both were run on CI against this branch instead, as linked above.

Carried across unchanged

Not a shortfall against the issue — it is unchanged from main, and calling it out here rather than quietly carrying it across the refactor.

init.log in the uploaded scenario artifact carries live init secrets, and the redaction that was meant to prevent it has never matched. The scenarios redact with sed 's/^\(root token: \).*/\1<redacted>/', but init prints the line as - root token: …, so the ^ anchor never fires. This run's own artifact (ci-registrar-redteam-33570500941) holds the root token in clear, along with three unseal keys, the step-ca password, the responder HMAC and six AppRole role_id/secret_id pairs — none of which the anchored sed ever attempted. Everything in it belongs to the run-scoped OpenBao deployment the same job tears down, so none of it opens anything that still exists. The repository is public, though, and an artifact on a public repository is downloadable by any authenticated GitHub user for as long as it is retained.

Both scenarios carried that sed verbatim, and this PR moves it into registrar_docker_build_and_initialize as it was. It is left as it was on purpose. The fix is not the missing anchor — it is deciding what the artifact should hold, given that --enable show-secrets is what puts all of the above in the output: redact every secret the summary prints, stop asking for show-secrets, or stop keeping init.log at all. That is a decision worth making deliberately rather than inside a refactor, and one place carries it now instead of two.

The red-team and endurance scenarios each carried their own copy of the
same isolated deployment: the run root and its audit tmpfs, the four
allocated host ports, the fingerprinted provisioning config, the
responder image build, `infra install`, `init` under sudo, the DNS
aliases step-ca resolves its challenge through, the daemon
configuration, and the supervisor that owns the inherited listener.
Two copies of one deployment drift, and the drift is invisible: each
arm still passes against whatever deployment it happens to be standing
up. They share one implementation now, and keep their own assertions.

The instance name derives through that shared helper too, against the
budget the binary validates rather than a per-scenario literal. Both
arms keep the name they had for every token that fits, which is every
token either launcher passes; an over-long one now truncates to its
discriminating tail instead of failing `infra install` minutes into a
run. `scripts/validate-e2e-run-scope.sh` exercises the helper for both
prefixes rather than grepping one script for the lines it used to hold.

`append_configured_anchors` is documented where a later reader will
find it: what gates it, why an unchanged root-anchor pin needs it
across a leaf renewal, and that the registrar surface is its only
consumer today while the behaviour sits in the shared publication arm
any future one would inherit. That disclosure was owed when the change
merged, and a pull request description is not where it survives.

Closes #981
@AcoPiper AcoPiper changed the title Share registrar scenario deployment setup Share registrar scenario deployment setup (#981) Sep 2, 2026
@AcoPiper

AcoPiper commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

[Reviewer Round 1]

Request changes — PR hygiene findings:

  • The PR’s ## The LeafWithChain anchor publication restates the disclosure the issue explicitly says must live in-tree, not in this later PR description. The Rustdoc and registrar reference already satisfy it; remove this body section.

  • The known init.log secret-exposure defect is intentionally left unresolved but is placed under ## A defect this PR moves rather than fixes. Put it under the required ## Not addressed heading instead.

The code refactor itself looks sound: shared setup remains limited to common deployment/supervisor behavior, scenario assertions stay local, instance-name derivation preserves the existing launcher tokens, and the in-tree documentation meets the issue’s technical requirements.

@AcoPiper

AcoPiper commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

[Review Verdict Round 1: NOT_APPROVED]

@AcoPiper

AcoPiper commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

[Author Round 1]

Both review items were PR-description hygiene; no code change was warranted.

Dispositions

1. Remove the ## The LeafWithChain anchor publication section — partially addressed.

Removed the section. The issue's point is that the disclosure must not be restated in a later, unrelated PR description, and that body section did restate all three substantive points (the [trust].ca_bundle_path gate, the unchanged-root-anchor renewal rationale, the sole-consumer-today point) — exactly the burial the issue names. In its place I left one sentence under "What this changes" saying that the PR carries a documentation-only change to append_configured_anchors (src/acme/flow.rs) and §4.4 of docs/reference/registrar-client-identity.md, that the disclosure lives there rather than being restated in the body, and that no production behaviour changed. A reviewer still needs to know the diff touches src/acme/flow.rs; a pointer to where the substance lives is not the disclosure.

What I kept: test-plan item 4. The issue's own test plan requires confirming "that it names the [trust].ca_bundle_path gate, the unchanged-root-anchor renewal rationale, and the sole-consumer-today point" — that checkbox is the record of a verification performed against the tree, not a second home for the disclosure. Dropping it would fail the issue's stated test plan.

2. Rename ## A defect this PR moves rather than fixes## Not addressed — fixed.

Valid: ## Not addressed is the repository's heading for this (merged PR #965 uses it). Heading renamed; the section's text is unchanged.

Push / CI

Nothing to commit — the working tree is clean and the head commit is still f2a1795. The only changes this round were to the PR description, applied with gh pr edit and re-verified with a --json re-query: headings are now ## What this changes, ## Test plan, ## Not addressed, with Closes #981, Part of #783, Part of #784 intact as prose. I did not push an empty commit to force a new CI run — there is no tree change for CI to evaluate, and CI on f2a1795 is already green (every check passes; the sole non-pass is Registrar Redteam (docs-only), which is skipping by design).

@AcoPiper

AcoPiper commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

[Reviewer Round 2]

Approved — no outstanding findings.

Both Round 1 PR-body issues are resolved. The shared setup is appropriately limited to common deployment/supervisor behavior, scenario-specific assertions remain local, and the in-tree Rustdoc/reference documentation covers the required anchor-publication behavior. PR linkage and test-plan hygiene are also correct.

@AcoPiper

AcoPiper commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

[Review Verdict Round 2: APPROVED]

@AcoPiper
AcoPiper merged commit a9ca4e4 into main Sep 2, 2026
26 checks passed
@AcoPiper
AcoPiper deleted the AcoPiper/issue-981 branch September 2, 2026 00:47
@AcoPiper AcoPiper mentioned this pull request Sep 2, 2026
9 tasks
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.

Consolidate registrar scenario setup

1 participant