Phase B: mTLS as the primary trust-level path#10
Draft
hyperpolymath wants to merge 2 commits into
Draft
Conversation
Closes the Phase B security gap from the http-capability-gateway audit: header-derived trust is forgeable without transport-level client-cert verification. - B1: add a fail-closed Cowboy HTTPS listener (verify: :verify_peer, fail_if_no_peer_cert: true). When TRUST_LEVEL_SOURCE=mtls the TLS material is mandatory; the app refuses to start rather than silently downgrading to the header path. - B2: is_cert_verified/1 now reads real TLS transport state (https scheme + Cowboy adapter + non-empty peer cert) instead of mere cert presence. - B3: docs/mtls-rotation-runbook.md — CA-selection decision and no-downtime cert/CA rotation procedure. - B4: src/abi/MTLSPolicy.idr records the "unverified cert is never privileged" proof obligation (status pending Phase C/D; excluded from gateway.ipkg so it does not gate the build). - Real test-CA fixture (test/fixtures/mtls) + test/mtls_test.exs driving the cert->trust pipeline and proving the CA trust invariant via :public_key.pkix_path_validation/3. Closes the audit's "Real-CA mTLS integration test" gap. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 16 issues detected
View findings[
{
"reason": "Issue in quality.yml",
"type": "missing_workflow",
"file": "quality.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Issue in security-policy.yml",
"type": "missing_workflow",
"file": "security-policy.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "codeql.yml lists `language: javascript-typescript` but the repo has no source files in any CodeQL-scannable language. The analyze job will exit 'no source files' on every run. Switch the matrix to `actions` (which scans workflow files — every repo has those).",
"type": "codeql_language_matrix_mismatch",
"file": "codeql.yml",
"action": "switch_codeql_matrix_to_actions",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "believe_me undermines formal verification (1 occurrences, CWE-704)",
"type": "believe_me",
"file": "/home/runner/work/http-capability-gateway/http-capability-gateway/src/abi/MTLSPolicy.idr",
"action": "flag",
"rule_module": "code_safety",
"severity": "critical"
},
{
"reason": "Nickel file missing SPDX-License-Identifier header (1 occurrences, CWE-1104)",
"type": "ncl_missing_spdx",
"file": "/home/runner/work/http-capability-gateway/http-capability-gateway/configs/config.ncl",
"action": "flag",
"rule_module": "code_safety",
"severity": "medium"
},
{
"reason": "Download-and-execute pattern (curl|wget pipe to shell) -- verify integrity before execution (1 occurrences, CWE-494)",
"type": "shell_download_then_run",
"file": "/home/runner/work/http-capability-gateway/http-capability-gateway/setup.sh",
"action": "flag",
"rule_module": "code_safety",
"severity": "high"
},
{
"reason": "Nominal-only SAST in http-capability-gateway: codeql.yml language matrix contains no language present in the repo and lacks `actions`, so CodeQL records zero results on every commit. Remediation: set the CodeQL matrix to `language: actions`.",
"type": "StaticAnalysis",
"file": "/home/runner/work/http-capability-gateway/http-capability-gateway",
"action": "auto_fix",
"rule_module": "scorecard",
"severity": "medium",
"remediation": "Add CodeQL or equivalent SAST workflow.",
"scorecard_check": "SAST"
},
{
"reason": "Repository has 2 non-main remote branch(es). Policy: single main branch only.",
"type": "GS007",
"file": ".",
"action": "delete_remote_branches",
"rule_module": "git_state",
"severity": "medium"
},
{
"reason": "6a2ml file outside canonical location -- must be in .machine_readable/6a2/",
"type": "SD004",
"file": ".machine_readable/STATE.a2ml",
"action": "move",
"rule_module": "structural_drift",
"severity": "critical"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
Hypatia code_safety greps the literal token; the comment asserted the absence of the primitive but tripped the scanner (CWE-704, 1 occurrence). Rephrased -- no behaviour change, the module uses no bypass primitive. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 15 issues detected
View findings[
{
"reason": "Issue in quality.yml",
"type": "missing_workflow",
"file": "quality.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Issue in security-policy.yml",
"type": "missing_workflow",
"file": "security-policy.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "codeql.yml lists `language: javascript-typescript` but the repo has no source files in any CodeQL-scannable language. The analyze job will exit 'no source files' on every run. Switch the matrix to `actions` (which scans workflow files — every repo has those).",
"type": "codeql_language_matrix_mismatch",
"file": "codeql.yml",
"action": "switch_codeql_matrix_to_actions",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Nickel file missing SPDX-License-Identifier header (1 occurrences, CWE-1104)",
"type": "ncl_missing_spdx",
"file": "/home/runner/work/http-capability-gateway/http-capability-gateway/configs/config.ncl",
"action": "flag",
"rule_module": "code_safety",
"severity": "medium"
},
{
"reason": "Download-and-execute pattern (curl|wget pipe to shell) -- verify integrity before execution (1 occurrences, CWE-494)",
"type": "shell_download_then_run",
"file": "/home/runner/work/http-capability-gateway/http-capability-gateway/setup.sh",
"action": "flag",
"rule_module": "code_safety",
"severity": "high"
},
{
"reason": "Nominal-only SAST in http-capability-gateway: codeql.yml language matrix contains no language present in the repo and lacks `actions`, so CodeQL records zero results on every commit. Remediation: set the CodeQL matrix to `language: actions`.",
"type": "StaticAnalysis",
"file": "/home/runner/work/http-capability-gateway/http-capability-gateway",
"action": "auto_fix",
"rule_module": "scorecard",
"severity": "medium",
"remediation": "Add CodeQL or equivalent SAST workflow.",
"scorecard_check": "SAST"
},
{
"reason": "Repository has 2 non-main remote branch(es). Policy: single main branch only.",
"type": "GS007",
"file": ".",
"action": "delete_remote_branches",
"rule_module": "git_state",
"severity": "medium"
},
{
"reason": "6a2ml file outside canonical location -- must be in .machine_readable/6a2/",
"type": "SD004",
"file": ".machine_readable/STATE.a2ml",
"action": "move",
"rule_module": "structural_drift",
"severity": "critical"
},
{
"reason": "6a2ml file outside canonical location -- must be in .machine_readable/6a2/",
"type": "SD004",
"file": ".machine_readable/META.a2ml",
"action": "move",
"rule_module": "structural_drift",
"severity": "critical"
}
]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.
Phase B — mTLS as the primary X-Trust-Level path
Closes the core security gap identified in the BoJ integration audit
(
boj-serverdocs/integration/http-capability-gateway-audit.md§4): themTLS trust-extraction path was coded but not the primary proved path, and
header-derived trust is forgeable without transport-level client-certificate
verification.
Scope follows the Phase B deliverables in
boj-serverdocs/integration/http-capability-gateway-plan.md.What landed
HttpCapabilityGateway.Applicationnow buildsa fail-closed HTTPS listener with
verify: :verify_peer+fail_if_no_peer_cert: true, driven byMTLS_CA_CERT_PATH,GATEWAY_CERT_PATH,GATEWAY_KEY_PATH,GATEWAY_TLS_PORT. WhenTRUST_LEVEL_SOURCE=mtlsthe TLS material is mandatory — the apprefuses to start rather than silently downgrading to the header path.
Config wired in
config/runtime.exs.Gateway.is_cert_verified/1no longer treats merecert presence as verified; it requires the request to have arrived over
the verify_peer HTTPS listener (https scheme + Cowboy adapter + non-empty
peer cert) and fails closed otherwise.
docs/mtls-rotation-runbook.md:CA-selection decision (BoJ-own root initially; SDP-CA / Cloudflare-AOP
parity noted) and a no-downtime cert/CA dual-trust rotation procedure.
src/abi/MTLSPolicy.idrstates the"an unverified client cert is never mapped to a privileged trust class"
obligation in Idris2 terms; status pending Phase C/D, registered in
PROOFS_NEEDED.md, excluded fromgateway.ipkg modulesso it does notgate the build before discharge.
test/fixtures/mtls/(regen viagen-test-ca.sh) +test/mtls_test.exsdrive the cert→trust pipelinewith real certs and prove the CA trust invariant via
:public_key.pkix_path_validation/3. Closes the audit's"Real-CA mTLS integration test" gap (
TEST-NEEDS.mdupdated). Privatekeys are intentionally not committed (repo
.gitignoresecrethygiene); the suite only consumes the
.crtfixtures.Notes / scope boundaries
Elixir 1.19 / OTP 28 toolchain (apt only offers 1.14). Repo CI
(
boj-build,dogfood-gate) must confirmmix compile+mix test.Changes were kept review-grade and pattern-consistent with existing code.
gateway↔BoJ seam is Phase C (#98) scope per the integration plan; Phase B
proves the cert→trust logic and the CA trust invariant at the crypto
layer plus the fail-closed listener contract.
Refs hyperpolymath/standards#91
Closes hyperpolymath/standards#97
🤖 Generated with Claude Code
Generated by Claude Code