mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
Restore trustworthy governance signals
This commit is contained in:
@@ -22,9 +22,11 @@ the generated shell program.
|
||||
Workflows triggered by `pull_request` cannot reference confidential repository
|
||||
secrets. Canonical governance therefore keeps its pull-request checks local to
|
||||
the public checkout. `canonical-private-governance.yml` performs cross-repo
|
||||
status, control-plane, subsystem-registry, mobile compatibility, and
|
||||
repo-governance checks only after a push to `main`, so unmerged pull-request
|
||||
code cannot replace the instructions that receive `WORKFLOW_PAT`.
|
||||
status, control-plane, subsystem-registry, subsystem-contract, mobile
|
||||
compatibility, and repo-governance checks only after a push to `main`, so
|
||||
unmerged pull-request code cannot replace the instructions that receive
|
||||
`WORKFLOW_PAT`. The public job still audits contract structure and every public
|
||||
path; only private path existence is deferred to that credential-isolated job.
|
||||
`PULSE_LICENSE_PUBLIC_KEY` is the sole explicit PR exception because that
|
||||
legacy secret value is intentionally non-confidential.
|
||||
|
||||
@@ -39,9 +41,10 @@ checksummed release asset and SSH signature, re-verify release and build
|
||||
attestations, and require the exact Docker Hub, GHCR, and OCI Helm identities
|
||||
to remain equal to the digests committed at activation. Stable Docker Hub and
|
||||
GHCR discovery aliases (`latest`, major, and major-minor) must also retain
|
||||
those identities. Every run retains a
|
||||
machine-readable evidence packet for 90 days, including partial outcomes when
|
||||
a check fails. Six-hour lock-watch evidence explicitly records its narrower
|
||||
those identities. Every run requests 90-day retention for a machine-readable
|
||||
evidence packet, including partial outcomes when a check fails; GitHub applies
|
||||
the repository's configured retention maximum and reports any clamp in the
|
||||
workflow warning. Six-hour lock-watch evidence explicitly records its narrower
|
||||
`release_lock` mode and skipped full-surface checks. The job is read-only and
|
||||
requires the public `PULSE_UPDATE_SIGNING_PUBLIC_KEY` repository variable.
|
||||
|
||||
|
||||
@@ -136,7 +136,9 @@ jobs:
|
||||
run: go test ./internal/mutationregistry ./internal/ai/tools -run 'Test(EveryRegisteredMutationHasDisposition|InfrastructureAPIRoutesResolveToRegistry|TransportCommandCatalogsResolveToRegistry|PatrolJobRegistrationResolvesToRegistry|RuntimeCandidateAuditNegativeFixtures|ActionRouteMethodAuthorityIsExactAndLookalikesFailClosed|NonAdmittingTransportMessagesCannotCarryDispatchAuthority|UnknownTransportLookalikeFailsClosed|RegisteredModelMutationSchemasResolveToClosedRegistry|RetiredMutationAliasesCannotShadowExtensions)' -count=1
|
||||
|
||||
- name: Run contract audit
|
||||
run: python3 scripts/release_control/contract_audit.py --check
|
||||
# Cross-repository path existence is checked with the credential-isolated
|
||||
# sibling checkouts after merge. Keep PR validation scoped to public truth.
|
||||
run: python3 scripts/release_control/contract_audit.py --check --repo-scope pulse
|
||||
|
||||
- name: Run canonical completion guard unit tests
|
||||
run: python3 scripts/release_control/canonical_completion_guard_test.py
|
||||
|
||||
@@ -109,6 +109,9 @@ jobs:
|
||||
- name: Run complete cross-repository registry audit
|
||||
run: python3 scripts/release_control/registry_audit.py --check
|
||||
|
||||
- name: Run complete cross-repository contract audit
|
||||
run: python3 scripts/release_control/contract_audit.py --check
|
||||
|
||||
- name: Run repo governance guardrail tests
|
||||
env:
|
||||
PULSE_REPO_ROOT_PULSE: ${{ github.workspace }}/repos/pulse
|
||||
|
||||
@@ -66,13 +66,16 @@ jobs:
|
||||
-H 'Accept: application/vnd.github+json' \
|
||||
-H 'X-GitHub-Api-Version: 2026-03-10' \
|
||||
"repos/${REPOSITORY}/releases/latest" > "${release_json}"
|
||||
jq -e '
|
||||
(.id | type == "number") and
|
||||
(.tag_name | type == "string" and test("^v[0-9]+\\.[0-9]+\\.[0-9]+$")) and
|
||||
(.target_commitish | type == "string" and test("^[0-9a-f]{40}$")) and
|
||||
.draft == false and .prerelease == false and .immutable == true and
|
||||
(.published_at | type == "string" and length > 0)
|
||||
' "${release_json}" >/dev/null
|
||||
if ! jq -e '
|
||||
(.id | type == "number") and
|
||||
(.tag_name | type == "string" and test("^v[0-9]+\\.[0-9]+\\.[0-9]+$")) and
|
||||
(.target_commitish | type == "string" and test("^[0-9a-f]{40}$")) and
|
||||
.draft == false and .prerelease == false and .immutable == true and
|
||||
(.published_at | type == "string" and length > 0)
|
||||
' "${release_json}" >/dev/null; then
|
||||
echo "::error::Advertised latest release failed the immutable stable identity contract. It must be a published, non-draft vX.Y.Z release locked immutable and bound to a 40-character source commit; inspect release.json in the continuity evidence."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
tag="$(jq -r '.tag_name' "${release_json}")"
|
||||
release_id="$(jq -r '.id' "${release_json}")"
|
||||
@@ -82,19 +85,22 @@ jobs:
|
||||
--pattern release-activation.json \
|
||||
--dir release-continuity-evidence
|
||||
|
||||
jq -e \
|
||||
--arg tag "${tag}" \
|
||||
--arg release_id "${release_id}" \
|
||||
--arg source_sha "${source_sha}" \
|
||||
'.schema_version == 1 and .tag == $tag and
|
||||
.release_id == $release_id and .target_commitish == $source_sha and
|
||||
(.source_release_run_id | test("^[0-9]+$")) and
|
||||
(.convergence_run_id | test("^[0-9]+$")) and
|
||||
(.r2_prefix | type == "string" and length > 0) and
|
||||
(.server_image_digest | test("^sha256:[0-9a-f]{64}$")) and
|
||||
(.control_plane_image_digest | test("^sha256:[0-9a-f]{64}$")) and
|
||||
(.helm_chart_digest | test("^sha256:[0-9a-f]{64}$"))' \
|
||||
"${marker}" >/dev/null
|
||||
if ! jq -e \
|
||||
--arg tag "${tag}" \
|
||||
--arg release_id "${release_id}" \
|
||||
--arg source_sha "${source_sha}" \
|
||||
'.schema_version == 1 and .tag == $tag and
|
||||
.release_id == $release_id and .target_commitish == $source_sha and
|
||||
(.source_release_run_id | test("^[0-9]+$")) and
|
||||
(.convergence_run_id | test("^[0-9]+$")) and
|
||||
(.r2_prefix | type == "string" and length > 0) and
|
||||
(.server_image_digest | test("^sha256:[0-9a-f]{64}$")) and
|
||||
(.control_plane_image_digest | test("^sha256:[0-9a-f]{64}$")) and
|
||||
(.helm_chart_digest | test("^sha256:[0-9a-f]{64}$"))' \
|
||||
"${marker}" >/dev/null; then
|
||||
echo "::error::release-activation.json does not bind the advertised stable tag, release, source commit, convergence runs, and published artifact digests."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "tag=${tag}" >> "${GITHUB_OUTPUT}"
|
||||
echo "release_id=${release_id}" >> "${GITHUB_OUTPUT}"
|
||||
|
||||
@@ -1826,6 +1826,7 @@ func TestCanonicalCompletionGuardIsWiredIntoPreCommit(t *testing.T) {
|
||||
"Contract Metadata",
|
||||
"audit_contract_payload",
|
||||
"contract metadata",
|
||||
"--repo-scope",
|
||||
"--check",
|
||||
})
|
||||
|
||||
@@ -1868,7 +1869,7 @@ func TestCanonicalGovernanceRunsInCI(t *testing.T) {
|
||||
"python3 scripts/release_control/canonical_completion_guard.py --files-from-stdin",
|
||||
"python3 scripts/release_control/browser_verification_guard.py",
|
||||
"python3 scripts/release_control/registry_audit.py --check --repo-scope pulse",
|
||||
"python3 scripts/release_control/contract_audit.py --check",
|
||||
"python3 scripts/release_control/contract_audit.py --check --repo-scope pulse",
|
||||
"python3 scripts/release_control/readiness_assertion_guard.py --active-target --proof-type automated",
|
||||
"python3 scripts/release_control/readiness_assertion_guard.py --active-target --proof-type hybrid",
|
||||
"go test ./internal/repoctl -count=1",
|
||||
@@ -1907,6 +1908,7 @@ func TestCanonicalGovernanceRunsInCI(t *testing.T) {
|
||||
"python3 scripts/release_control/status_audit.py --check",
|
||||
"python3 scripts/release_control/control_plane_audit.py --check",
|
||||
"python3 scripts/release_control/registry_audit.py --check",
|
||||
"python3 scripts/release_control/contract_audit.py --check",
|
||||
"go test ./internal/repoctl -count=1",
|
||||
})
|
||||
if strings.Contains(privateWorkflow, "pull_request:") || strings.Contains(privateWorkflow, "workflow_dispatch:") {
|
||||
|
||||
@@ -160,7 +160,9 @@ func TestSecurityScanRevalidatesLatestStableDelivery(t *testing.T) {
|
||||
"docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5",
|
||||
`"repos/${REPOSITORY}/releases/latest"`,
|
||||
`.draft == false and .prerelease == false and .immutable == true`,
|
||||
"Advertised latest release failed the immutable stable identity contract",
|
||||
`.release_id == $release_id and .target_commitish == $source_sha`,
|
||||
"release-activation.json does not bind the advertised stable tag",
|
||||
`./scripts/verify-github-release-integrity.sh`,
|
||||
`./scripts/validate-published-release.sh`,
|
||||
`PULSE_UPDATE_SIGNING_PUBLIC_KEY: ${{ vars.PULSE_UPDATE_SIGNING_PUBLIC_KEY }}`,
|
||||
|
||||
@@ -170,11 +170,15 @@ def validate_repo_path_token(
|
||||
errors: list[str],
|
||||
repo_roots: dict[str, Path],
|
||||
default_repo_id: str,
|
||||
audited_repo_ids: set[str] | None = None,
|
||||
) -> None:
|
||||
resolved = resolve_repo_path_token(token, repo_roots=repo_roots, default_repo_id=default_repo_id)
|
||||
if resolved is None:
|
||||
errors.append(f"{rel} {heading} contains non-clean repo-relative path {token!r}")
|
||||
return
|
||||
repo_id = token.split(":", 1)[0] if ":" in token else default_repo_id
|
||||
if audited_repo_ids is not None and repo_id not in audited_repo_ids:
|
||||
return
|
||||
if not resolved.exists():
|
||||
errors.append(f"{rel} {heading} references missing path {token!r}")
|
||||
return
|
||||
@@ -214,6 +218,7 @@ def audit_contract_text(
|
||||
*,
|
||||
repo_roots: dict[str, Path],
|
||||
default_repo_id: str,
|
||||
audited_repo_ids: set[str] | None = None,
|
||||
) -> tuple[dict[str, Any], list[str]]:
|
||||
errors: list[str] = []
|
||||
path_references: list[dict[str, str]] = []
|
||||
@@ -270,6 +275,7 @@ def audit_contract_text(
|
||||
errors=errors,
|
||||
repo_roots=repo_roots,
|
||||
default_repo_id=default_repo_id,
|
||||
audited_repo_ids=audited_repo_ids,
|
||||
)
|
||||
path_references.append({"heading": heading, "path": token})
|
||||
if heading == "## Extension Points":
|
||||
@@ -283,6 +289,7 @@ def audit_contract_text(
|
||||
errors=errors,
|
||||
repo_roots=repo_roots,
|
||||
default_repo_id=default_repo_id,
|
||||
audited_repo_ids=audited_repo_ids,
|
||||
)
|
||||
path_references.append({"heading": heading, "path": token})
|
||||
|
||||
@@ -339,6 +346,7 @@ def audit_contract_payload(
|
||||
status_payload: dict[str, Any],
|
||||
contract_texts: dict[str, str],
|
||||
repo_root: Path | None = None,
|
||||
audited_repo_ids: set[str] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
errors: list[str] = []
|
||||
warnings: list[str] = []
|
||||
@@ -388,6 +396,7 @@ def audit_contract_payload(
|
||||
contract_texts[rel],
|
||||
repo_roots=repo_roots,
|
||||
default_repo_id=default_repo_id,
|
||||
audited_repo_ids=audited_repo_ids,
|
||||
)
|
||||
errors.extend(parse_errors)
|
||||
metadata = parsed.get("metadata")
|
||||
@@ -513,6 +522,7 @@ def audit_contract_payload(
|
||||
errors=errors,
|
||||
repo_roots=repo_roots,
|
||||
default_repo_id=default_repo_id,
|
||||
audited_repo_ids=audited_repo_ids,
|
||||
)
|
||||
actual_shared_paths.append(shared_path)
|
||||
if shared_path in seen_shared_paths:
|
||||
@@ -590,6 +600,16 @@ def parse_args(argv: list[str]) -> argparse.Namespace:
|
||||
action="store_true",
|
||||
help="Read subsystem contracts from the git index instead of the working tree.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--repo-scope",
|
||||
action="append",
|
||||
default=[],
|
||||
metavar="REPO_ID",
|
||||
help=(
|
||||
"Audit paths for one available repository. Repeat to audit multiple "
|
||||
"repositories; the default audits the complete active profile."
|
||||
),
|
||||
)
|
||||
return parser.parse_args(argv)
|
||||
|
||||
|
||||
@@ -615,11 +635,33 @@ def render_pretty(report: dict[str, Any]) -> str:
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
args = parse_args(list(argv or []))
|
||||
status_payload = load_status_payload(staged=args.staged)
|
||||
active_repos = [
|
||||
repo_id
|
||||
for repo_id in status_payload.get("scope", {}).get("active_repos", [])
|
||||
if isinstance(repo_id, str) and repo_id.strip()
|
||||
] or [canonical_repo_id(REPO_ROOT)]
|
||||
local_repo = canonical_repo_id(REPO_ROOT)
|
||||
requested_repos = args.repo_scope or active_repos
|
||||
scope_errors: list[str] = []
|
||||
if len(requested_repos) != len(set(requested_repos)):
|
||||
scope_errors.append("--repo-scope must not contain duplicate repository ids")
|
||||
unknown_repos = sorted(set(requested_repos) - set(active_repos), key=str.casefold)
|
||||
if unknown_repos:
|
||||
scope_errors.append(
|
||||
"--repo-scope contains repositories outside the active profile: "
|
||||
+ ", ".join(unknown_repos)
|
||||
)
|
||||
if local_repo not in requested_repos:
|
||||
scope_errors.append(f"--repo-scope must include the local control-plane repository {local_repo!r}")
|
||||
|
||||
report = audit_contract_payload(
|
||||
registry_payload=load_registry_payload(staged=args.staged),
|
||||
status_payload=load_status_payload(staged=args.staged),
|
||||
status_payload=status_payload,
|
||||
contract_texts=tracked_contract_files(staged=args.staged),
|
||||
audited_repo_ids=set(requested_repos) if args.repo_scope else None,
|
||||
)
|
||||
report["errors"] = scope_errors + report["errors"]
|
||||
output = render_pretty(report) if args.pretty else json.dumps(report, indent=2, sort_keys=True)
|
||||
print(output)
|
||||
if args.check and report["errors"]:
|
||||
|
||||
@@ -20,10 +20,75 @@ class ContractAuditTest(unittest.TestCase):
|
||||
env=env,
|
||||
)
|
||||
|
||||
def cross_repo_contract_fixture(
|
||||
self,
|
||||
private_path: str = "pulse-mobile:src/relay/client.ts",
|
||||
) -> tuple[dict, dict, dict[str, str]]:
|
||||
registry_payload = {
|
||||
"subsystems": [
|
||||
{
|
||||
"id": "relay-runtime",
|
||||
"lane": "L7",
|
||||
"contract": "docs/release-control/v6/internal/subsystems/relay-runtime.md",
|
||||
}
|
||||
]
|
||||
}
|
||||
status_payload = {
|
||||
"scope": {"active_repos": ["pulse", "pulse-mobile"]},
|
||||
"lanes": [{"id": "L7"}],
|
||||
}
|
||||
contract_texts = {
|
||||
"docs/release-control/v6/internal/subsystems/relay-runtime.md": f"""# Relay Runtime Contract
|
||||
|
||||
## Contract Metadata
|
||||
|
||||
```json
|
||||
{{
|
||||
"subsystem_id": "relay-runtime",
|
||||
"lane": "L7",
|
||||
"contract_file": "docs/release-control/v6/internal/subsystems/relay-runtime.md",
|
||||
"status_file": "docs/release-control/v6/internal/status.json",
|
||||
"registry_file": "docs/release-control/v6/internal/subsystems/registry.json",
|
||||
"dependency_subsystem_ids": []
|
||||
}}
|
||||
```
|
||||
|
||||
## Purpose
|
||||
|
||||
Own relay runtime truth.
|
||||
|
||||
## Canonical Files
|
||||
|
||||
1. `{private_path}`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
1. None.
|
||||
|
||||
## Extension Points
|
||||
|
||||
1. Add mobile relay reconnect behavior through `pulse-mobile:src/relay/`
|
||||
|
||||
## Forbidden Paths
|
||||
|
||||
1. Ad hoc mobile relay reconnect state.
|
||||
|
||||
## Completion Obligations
|
||||
|
||||
1. Keep mobile relay runtime changes tied to tests.
|
||||
|
||||
## Current State
|
||||
|
||||
Cross-repo relay ownership is explicit.
|
||||
""",
|
||||
}
|
||||
return registry_payload, status_payload, contract_texts
|
||||
|
||||
def test_parse_args_accepts_staged_flag(self) -> None:
|
||||
args = parse_args(["--check", "--staged"])
|
||||
args = parse_args(["--check", "--staged", "--repo-scope", "pulse"])
|
||||
self.assertTrue(args.check)
|
||||
self.assertTrue(args.staged)
|
||||
self.assertEqual(args.repo_scope, ["pulse"])
|
||||
|
||||
def test_audit_contract_payload_accepts_valid_contracts(self) -> None:
|
||||
registry_payload = {
|
||||
@@ -314,66 +379,7 @@ Canonical alert identity is live runtime truth.
|
||||
)
|
||||
|
||||
def test_audit_contract_payload_accepts_cross_repo_contract_paths(self) -> None:
|
||||
registry_payload = {
|
||||
"subsystems": [
|
||||
{
|
||||
"id": "relay-runtime",
|
||||
"lane": "L7",
|
||||
"contract": "docs/release-control/v6/internal/subsystems/relay-runtime.md",
|
||||
}
|
||||
]
|
||||
}
|
||||
status_payload = {
|
||||
"scope": {
|
||||
"active_repos": ["pulse", "pulse-mobile"],
|
||||
},
|
||||
"lanes": [{"id": "L7"}],
|
||||
}
|
||||
contract_texts = {
|
||||
"docs/release-control/v6/internal/subsystems/relay-runtime.md": """# Relay Runtime Contract
|
||||
|
||||
## Contract Metadata
|
||||
|
||||
```json
|
||||
{
|
||||
"subsystem_id": "relay-runtime",
|
||||
"lane": "L7",
|
||||
"contract_file": "docs/release-control/v6/internal/subsystems/relay-runtime.md",
|
||||
"status_file": "docs/release-control/v6/internal/status.json",
|
||||
"registry_file": "docs/release-control/v6/internal/subsystems/registry.json",
|
||||
"dependency_subsystem_ids": []
|
||||
}
|
||||
```
|
||||
|
||||
## Purpose
|
||||
|
||||
Own relay runtime truth.
|
||||
|
||||
## Canonical Files
|
||||
|
||||
1. `pulse-mobile:src/relay/client.ts`
|
||||
|
||||
## Shared Boundaries
|
||||
|
||||
1. None.
|
||||
|
||||
## Extension Points
|
||||
|
||||
1. Add mobile relay reconnect behavior through `pulse-mobile:src/relay/`
|
||||
|
||||
## Forbidden Paths
|
||||
|
||||
1. Ad hoc mobile relay reconnect state.
|
||||
|
||||
## Completion Obligations
|
||||
|
||||
1. Keep mobile relay runtime changes tied to tests.
|
||||
|
||||
## Current State
|
||||
|
||||
Cross-repo relay ownership is explicit.
|
||||
""",
|
||||
}
|
||||
registry_payload, status_payload, contract_texts = self.cross_repo_contract_fixture()
|
||||
|
||||
report = audit_contract_payload(
|
||||
registry_payload=registry_payload,
|
||||
@@ -383,6 +389,38 @@ Cross-repo relay ownership is explicit.
|
||||
|
||||
self.assertEqual(report["errors"], [])
|
||||
|
||||
def test_scoped_audit_defers_missing_private_paths_to_private_governance(self) -> None:
|
||||
missing_path = "pulse-mobile:src/relay/definitely-missing.ts"
|
||||
registry_payload, status_payload, contract_texts = self.cross_repo_contract_fixture(missing_path)
|
||||
|
||||
full_report = audit_contract_payload(
|
||||
registry_payload=registry_payload,
|
||||
status_payload=status_payload,
|
||||
contract_texts=contract_texts,
|
||||
)
|
||||
scoped_report = audit_contract_payload(
|
||||
registry_payload=registry_payload,
|
||||
status_payload=status_payload,
|
||||
contract_texts=contract_texts,
|
||||
audited_repo_ids={"pulse"},
|
||||
)
|
||||
|
||||
self.assertIn(f"references missing path '{missing_path}'", "\n".join(full_report["errors"]))
|
||||
self.assertEqual(scoped_report["errors"], [])
|
||||
|
||||
def test_scoped_audit_still_rejects_unclean_private_path_tokens(self) -> None:
|
||||
unclean_path = "pulse-mobile:../client.ts"
|
||||
registry_payload, status_payload, contract_texts = self.cross_repo_contract_fixture(unclean_path)
|
||||
|
||||
report = audit_contract_payload(
|
||||
registry_payload=registry_payload,
|
||||
status_payload=status_payload,
|
||||
contract_texts=contract_texts,
|
||||
audited_repo_ids={"pulse"},
|
||||
)
|
||||
|
||||
self.assertIn(f"contains non-clean repo-relative path '{unclean_path}'", "\n".join(report["errors"]))
|
||||
|
||||
def test_audit_contract_payload_isolates_local_paths_and_resolves_siblings_from_linked_worktree(self) -> None:
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
workspace = Path(tmpdir) / "workspace"
|
||||
|
||||
Reference in New Issue
Block a user