feat(scripts): hcg-policy-smoke.sh — §1.5 operator pre-check (Phase E)#210
Draft
hyperpolymath wants to merge 1 commit into
Draft
feat(scripts): hcg-policy-smoke.sh — §1.5 operator pre-check (Phase E)#210hyperpolymath wants to merge 1 commit into
hyperpolymath wants to merge 1 commit into
Conversation
Lands `scripts/hcg-policy-smoke.sh`: a checked-in smoke that exercises the HCG tier-2 live Verb Governance Spec (`config/gateway-policy-boj.yaml`) from outside the gateway. Replaces the manual probe sequence the rollout runbook §1.5 last open item formerly described as "out of band — operator pre-check". What the script does, by default: * Sends one no-trust-header deny probe to every non-public route in the live policy (25 routes spanning the 19 authenticated and 6 internal+stealth entries — `cartridges`, `cartridge/:name(/invoke| /sse|/load|/unload|/reload)`, `umoja/*`, `coprocessor/*`, `sdp/status`, `graphql`, `sse`, `order(-ticket)`, `community/*`, etc.) and asserts a 4xx response, covering both bare 403 and stealth-profile codes regardless of the gateway's `:stealth_profiles` runtime config. * Sends a default-deny verb canary (DELETE /cartridges, PUT /health, PATCH /cartridges) to confirm `global_verbs: [GET, POST]` enforces the ADR-0004 verb-governance invariant for un-listed verbs. * Exits non-zero with a per-probe FAIL summary on any mismatch. This entire mode is gateway-internal — BoJ does not have to be reachable. It can run during §1.5 staging stand-up before BoJ is wired behind the gateway, and it'll catch a policy-not-loaded or policy-not-enforcing regression at the cheapest possible step. With `--with-backend`, the script additionally probes the allow path with `X-Trust-Level: authenticated` (and `internal` for internal+stealth routes), asserting the response is NOT a gateway-origin 4xx (2xx / 3xx / 5xx all pass — BoJ's own status is fine; only a gateway deny is a failure). This second mode requires BoJ reachable at the gateway's `BACKEND_URL` and the script to run from a trusted-proxy IP so the trust header is not stripped by the gateway's `strip_untrusted_headers` plug. Runbook diff: * §1.5 — last unchecked operator pre-check item flips from a free-form "stand the gateway up ... exercise one allow + one deny per route" sequence (which was deferred to boj-server#165's test plan and documented as out-of-band) to a single `scripts/hcg-policy-smoke.sh` invocation. The PASS/FAIL summary attaches to the cut-over ticket; a single FAIL is a stop-the-rollout condition with the three failure modes named (policy not enforcing, BoJ unreachable, non-trusted-proxy caller stripping the header). * Header — version 0.3 → 0.4; date 2026-06-09 → 2026-06-10; status line acknowledges the smoke script landing alongside the existing live policy promotion. * Appendix B — new cross-reference entry for `scripts/hcg-policy-smoke.sh`. What this PR deliberately does NOT do: * **Close `standards#100`.** Per runbook §6.5 the joint-close happens after the §6.4 Trustfile flip (`tier_2_gateway.status: PENDING → DEPLOYED`), which itself follows the §3.3 100% production-soak window. Using `Refs` to match the Phase E PR convention established by #208 / #38 / #168 and documented in §6.5 ("Do not self-close standards#100; joint-close is owner-only per the single-lane channel discipline"). * **Touch HCG.** This is a BoJ-side artefact: the script lives in `scripts/`, reads `config/gateway-policy-boj.yaml`, and probes the gateway over HTTP. No gateway-repo change required. * **Run during deployment.** The script is checked in but only the operator's explicit invocation against a live gateway URL exercises it. CI does not stand up a gateway to run it (would require an external service); the script is intentionally operator-driven. Verification: * `bash -n scripts/hcg-policy-smoke.sh` — syntax check passes. * `scripts/hcg-policy-smoke.sh` (no args) — exits 64 (usage error). * `scripts/hcg-policy-smoke.sh --help` — exits 64 with full help. * Against a synthetic always-403 mock on :18443 — `PASS=28 FAIL=0`, exits 0 (deny-only mode covers all 25 policy routes + 3 verb canaries). * Against a closed port (no gateway up) — every probe FAILs with "got=000 expected=deny"; exits 1 with the FAIL line summary. Refs hyperpolymath/standards#91 Refs hyperpolymath/standards#100 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 273 issues detected
View findings[
{
"reason": "Stale AI session file -- delete",
"type": "stale",
"file": "GEMINI.md",
"action": "delete",
"rule_module": "root_hygiene",
"severity": "medium"
},
{
"reason": "Action if: always()\n uses: actions/upload-artifact@ea165f8 needs attention",
"type": "unpinned_action",
"file": "e2e.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action perpolymath/standards/.github/workflows/governance-reusable.yml@main\n needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in abi-drift.yml",
"type": "missing_timeout_minutes",
"file": "abi-drift.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in codeql.yml",
"type": "missing_timeout_minutes",
"file": "codeql.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in container-publish.yml",
"type": "missing_timeout_minutes",
"file": "container-publish.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "missing_timeout_minutes",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "missing_timeout_minutes",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "missing_timeout_minutes",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "missing_timeout_minutes",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lands
scripts/hcg-policy-smoke.sh— a checked-in smoke that exercisesthe HCG tier-2 live Verb Governance Spec
(
config/gateway-policy-boj.yaml) from outside the gateway. Replacesthe manual probe sequence the rollout runbook §1.5 last open item
formerly described as "out of band — operator pre-check".
Single-lane HCG tier-2 channel (
standards#91). Phase A (#96), B (#97),C (#98), D (#99) are joint-closed; Phase E (
standards#100) is theactive phase. This PR lands one tractable artefact (§1.5 operator
pre-check now checked-in and reproducible); staging soak (§2),
production traffic split (§3), and the §6.4 Trustfile flip remain
owner-driven.
What this PR lands
scripts/hcg-policy-smoke.sh— POSIX-conformant bash + curl, nojq/yq dependency.
non-public route in the live policy (25 routes spanning the 19
authenticated and 6 internal+stealth entries) and asserts a 4xx
response. The 4xx assertion covers both bare 403 and stealth-profile
codes regardless of the gateway's
:stealth_profilesruntimeconfig. Plus a default-deny verb canary (DELETE /cartridges, PUT
/health, PATCH /cartridges) confirming
global_verbs: [GET, POST]enforces the ADR-0004 verb-governance invariant for un-listed verbs.
Gateway-internal — BoJ does not have to be reachable.
--with-backendmode: additionally probes the allow path withX-Trust-Level: authenticated(andinternalfor internal+stealthroutes), asserting the response is NOT a gateway-origin 4xx (2xx /
3xx / 5xx all pass — BoJ's own status is fine; only a gateway deny
is a failure). Requires BoJ reachable at the gateway's
BACKEND_URLand the script to run from a trusted-proxy IP so the trust header is
not stripped by the gateway's
strip_untrusted_headersplug.usage error.
Runbook §1.5 — last unchecked operator pre-check item flips from
a free-form "stand the gateway up ... exercise one allow + one deny
per route" sequence (which was deferred to boj-server#165's test plan
and documented as out-of-band) to a single
scripts/hcg-policy-smoke.shinvocation. The PASS/FAIL summaryattaches to the cut-over ticket; a single FAIL is a stop-the-rollout
condition with the three failure modes named (policy not enforcing,
BoJ unreachable, non-trusted-proxy caller stripping the header).
Runbook header — version 0.3 → 0.4; date 2026-06-09 → 2026-06-10;
status line acknowledges the smoke script landing alongside the
existing live policy promotion.
Runbook Appendix B — new cross-reference entry for
scripts/hcg-policy-smoke.sh.What this PR deliberately does NOT do
standards#100. Per runbook §6.5 the joint-close happensafter the §6.4 Trustfile flip (
tier_2_gateway.status: PENDING → DEPLOYED), which itself follows the §3.3 100% production-soakwindow. Using
Refsto match the Phase E PR convention establishedby feat(config): promote gateway policy example → live (Phase E §1.5) #208 / chore(deps): bump nixpkgs from
01fbdeeto6368eda#38 / docs(hcg-load-profile): Phase D D1 — load profile declaration (standards#99) #168 and documented in §6.5 ("Do not self-closestandards#100; joint-close is owner-only per the single-lane channel
discipline"). The owner remains the sole closer of
standards#100.scripts/, readsconfig/gateway-policy-boj.yaml, and probes thegateway over HTTP. No companion PR on the gateway repo required.
operator's explicit invocation against a live gateway URL exercises
it. CI does not stand up a gateway to run it (would require an
external service); the script is intentionally operator-driven, with
the PASS/FAIL summary attached to the cut-over ticket as the
evidence-of-pre-check artefact.
route matrix mirrors the 25-route live policy. When the policy file
evolves (new BoJ surface routes wired in), the script must be updated
in lock-step — that is a benefit not a cost (the script doubles as a
policy-completeness checklist), but it must be observed.
Verification
bash -n scripts/hcg-policy-smoke.sh— syntax check passes.scripts/hcg-policy-smoke.sh(no args) — exits 64 (usage error).scripts/hcg-policy-smoke.sh --help— exits 64 with full help.PASS=28 FAIL=0,exits 0 (deny-only mode covers all 25 policy routes + 3 verb
canaries).
got=000 expected=deny; exits 1 with the FAIL line summary.MPL-2.0matches repo convention (scripts/, docs/).§1.5, Appendix B, siblingdocs).
Channel position
Refs hyperpolymath/standards#91
Refs hyperpolymath/standards#100
🤖 Generated with Claude Code
Generated by Claude Code