commit fecd0eea4075e718457251960df23dc6e241ac00
parent 17f95a70398f7cb85e423bb05cb6f94126ff7012
Author: triesap <tyson@radroots.org>
Date: Fri, 4 Sep 2026 22:19:07 +0000
fix: bind Step 289 platform probe source
Diffstat:
2 files changed, 72 insertions(+), 4 deletions(-)
diff --git a/contracts/rshr-201-step-gates.v1.json b/contracts/rshr-201-step-gates.v1.json
@@ -1 +1 @@
-{"gate_command_contract":[{"argv_template":["cargo","extbuild","run","--","uv","run","--offline","--no-project","python3","-B","tools/rshr_201_step_gate.py","--step={step}","--check-id={check_id}","--source-revision={source_revision}","--source-tree={source_tree}","--candidate-digest={candidate_digest}","--platform=macos_aarch64","--execution-request-sha256={execution_request_sha256}"],"assertion_id":["step_289_gate_01_ff71b7cb8259835dc66c6e65a6124e265dff667fa929e895c6556636f49c7e54"],"check_id":"gate-01-ff71b7cb8259835dc66c6e65a6124e265dff667fa929e895c6556636f49c7e54","environment_authority":{"cache_policy_id":"rshr-200-step-287-cache-policy.v1","cache_policy_sha256":"3e81d178bce97b6c349dfbb00c68fd6f620ac00b1a1c8d37b12e9998f3c9eaaa","cadence_policy_id":"rshr-200-step-287-cadence-policy.v1","cadence_policy_sha256":"d24903df8659ee3772297c84994911efe7d21cb8b988320ddc6ddce0431892a1","isolation":"extbuild_host_constrained","network":"disabled","network_policy_id":"none","network_policy_sha256":"none","resource_policy_id":"rshr-200-step-287-resource-policy.v1","resource_policy_sha256":"05d3c7a89185d3c55678d97955193fce2ed92b1eee5af99083d77ea64c98d14e"},"environment_names":["EXT_BUILD_CONFIG","EXT_BUILD_MACHINE_CONFIG","EXT_BUILD_ROOT","HOME","PATH","RUSTUP_TOOLCHAIN","TMPDIR"],"gate_definition_sha256":"ff71b7cb8259835dc66c6e65a6124e265dff667fa929e895c6556636f49c7e54","required_platforms":["macos_aarch64"],"required_tools":["uv","python3","git"],"result_schema":"radroots.services-hardening.rshr-200-step-check-result.v1","schema":"radroots.services-hardening.rshr-200-step-check-command.v1","step":289,"verifier_path":"tools/rshr_201_step_gate.py","verifier_sha256":"81d852d3f2a38339e7b273fd0315737712e4d69d90d4f163c013eb053777b416"}],"schema":"radroots.harvestcircle.rshr-201-step-gates.v1","step":[289]}
+{"gate_command_contract":[{"argv_template":["cargo","extbuild","run","--","uv","run","--offline","--no-project","python3","-B","tools/rshr_201_step_gate.py","--step={step}","--check-id={check_id}","--source-revision={source_revision}","--source-tree={source_tree}","--candidate-digest={candidate_digest}","--platform=macos_aarch64","--execution-request-sha256={execution_request_sha256}"],"assertion_id":["step_289_gate_01_ff71b7cb8259835dc66c6e65a6124e265dff667fa929e895c6556636f49c7e54"],"check_id":"gate-01-ff71b7cb8259835dc66c6e65a6124e265dff667fa929e895c6556636f49c7e54","environment_authority":{"cache_policy_id":"rshr-200-step-287-cache-policy.v1","cache_policy_sha256":"3e81d178bce97b6c349dfbb00c68fd6f620ac00b1a1c8d37b12e9998f3c9eaaa","cadence_policy_id":"rshr-200-step-287-cadence-policy.v1","cadence_policy_sha256":"d24903df8659ee3772297c84994911efe7d21cb8b988320ddc6ddce0431892a1","isolation":"extbuild_host_constrained","network":"disabled","network_policy_id":"none","network_policy_sha256":"none","resource_policy_id":"rshr-200-step-287-resource-policy.v1","resource_policy_sha256":"05d3c7a89185d3c55678d97955193fce2ed92b1eee5af99083d77ea64c98d14e"},"environment_names":["EXT_BUILD_CONFIG","EXT_BUILD_MACHINE_CONFIG","EXT_BUILD_ROOT","HOME","PATH","RUSTUP_TOOLCHAIN","TMPDIR"],"gate_definition_sha256":"ff71b7cb8259835dc66c6e65a6124e265dff667fa929e895c6556636f49c7e54","required_platforms":["macos_aarch64"],"required_tools":["uv","python3","git"],"result_schema":"radroots.services-hardening.rshr-200-step-check-result.v1","schema":"radroots.services-hardening.rshr-200-step-check-command.v1","step":289,"verifier_path":"tools/rshr_201_step_gate.py","verifier_sha256":"a148c7a260330af444701492b7105b1e5c31f2fd45258e924b621a86cca90f3e"}],"schema":"radroots.harvestcircle.rshr-201-step-gates.v1","step":[289]}
diff --git a/tools/rshr_201_step_gate.py b/tools/rshr_201_step_gate.py
@@ -264,22 +264,84 @@ def run_step(step: int, source_revision: str) -> None:
def parse_arguments() -> argparse.Namespace:
parser = argparse.ArgumentParser(allow_abbrev=False)
+ parser.add_argument("--emit-platform-result", action="store_true")
parser.add_argument("--step", type=int, required=True)
- parser.add_argument("--check-id", required=True)
+ parser.add_argument("--check-id")
parser.add_argument("--source-revision", required=True)
parser.add_argument("--source-tree", required=True)
- parser.add_argument("--candidate-digest", required=True)
+ parser.add_argument("--candidate-digest")
parser.add_argument("--platform", required=True)
parser.add_argument("--execution-request-sha256", required=True)
return parser.parse_args()
+def emit_platform_result(arguments: argparse.Namespace) -> int:
+ if arguments.check_id is not None or arguments.candidate_digest is not None:
+ raise GateError("platform probe received gate-only arguments")
+ require_source_state(arguments.source_revision, arguments.source_tree)
+ identity = os.uname()
+ if (
+ arguments.platform != "macos_aarch64"
+ or identity.sysname != "Darwin"
+ or identity.machine not in {"arm64", "aarch64"}
+ ):
+ raise GateError("platform probe is not running on macOS aarch64")
+ xcode_identity = {
+ "xcodebuild": run(["/usr/bin/xcodebuild", "-version"]).decode(
+ "utf-8", "strict"
+ ),
+ "sdk": {
+ sdk: run(
+ ["/usr/bin/xcrun", "--sdk", sdk, "--show-sdk-version"]
+ ).decode("utf-8", "strict")
+ for sdk in ("iphoneos", "iphonesimulator", "macosx")
+ },
+ }
+ verifier_path = Path(__file__).resolve()
+ result = {
+ "schema": "radroots.services-hardening.rshr-200-platform-result.v1",
+ "platform": "macos_aarch64",
+ "system": "aarch64-darwin",
+ "os_family": "macos",
+ "architecture": "aarch64",
+ "kernel_name": "Darwin",
+ "kernel_release": identity.release,
+ "os_build_sha256": sha256_bytes(
+ canonical(
+ {
+ "kernel_name": identity.sysname,
+ "kernel_release": identity.release,
+ "kernel_version": identity.version,
+ }
+ )
+ ),
+ "runner_kind": "host",
+ "runner_image_sha256": "none",
+ "apple_toolchain_identity_sha256": sha256_bytes(canonical(xcode_identity)),
+ "probe_source_path": verifier_path.relative_to(ROOT).as_posix(),
+ "probe_source_sha256": sha256_bytes(read_regular(verifier_path)),
+ "execution_request_sha256": arguments.execution_request_sha256,
+ "assertion": [
+ {"id": identifier, "result": "pass"}
+ for identifier in (
+ "os_family",
+ "architecture",
+ "kernel_identity",
+ "runner_identity",
+ "apple_identity",
+ )
+ ],
+ "result": "available",
+ }
+ sys.stdout.buffer.write(canonical(result))
+ return 0
+
+
def main() -> int:
arguments = parse_arguments()
if arguments.step not in GATE_DEFINITIONS:
raise GateError("step is outside the HarvestCircle gate authority")
for value, label in (
- (arguments.check_id.removeprefix("gate-01-"), "check digest"),
(arguments.source_revision, "source revision"),
(arguments.source_tree, "source tree"),
(arguments.execution_request_sha256, "execution request"),
@@ -287,6 +349,12 @@ def main() -> int:
expected_length = 40 if label in {"source revision", "source tree"} else 64
if re.fullmatch(rf"[0-9a-f]{{{expected_length}}}", value) is None:
raise GateError(f"{label} is not canonical")
+ if arguments.emit_platform_result:
+ return emit_platform_result(arguments)
+ if arguments.check_id is None or re.fullmatch(
+ r"gate-01-[0-9a-f]{64}", arguments.check_id
+ ) is None:
+ raise GateError("check digest is not canonical")
if arguments.candidate_digest != "none" or arguments.platform != "macos_aarch64":
raise GateError("candidate or platform scope differs")
authority_bytes = read_regular(AUTHORITY_PATH, 256 * 1024)