diff --git a/tests/test_ci_workflow.py b/tests/test_ci_workflow.py index de20d77..6d97b77 100644 --- a/tests/test_ci_workflow.py +++ b/tests/test_ci_workflow.py @@ -28,6 +28,12 @@ def test_ci_runs_sei_and_live_loomweave_conformance_targets(): def test_release_publish_requires_live_loomweave_conformance(): + # Skip-not-fail contract (owner decision 2026-06-25): Legis does not run + # live Loomweave conformance in remote CI. Publish stays chained through the + # conformance job, but the job no-ops with a notice when the oracle config + # is absent (never blocking publish); when the config IS present the oracle + # runs for real and a failure still blocks publish. The HMAC secret stays + # scoped to the steps that use it. jobs = _release_jobs() publish_needs = jobs["publish"]["needs"] @@ -36,35 +42,47 @@ def test_release_publish_requires_live_loomweave_conformance(): assert "live-loomweave-conformance" in publish_needs live_job = jobs["live-loomweave-conformance"] - assert "if" not in live_job + assert "if" not in live_job # gated per-step, never the whole job env = live_job["env"] assert env["LOOMWEAVE_URL"] == "${{ vars.LOOMWEAVE_URL }}" assert env["LOOMWEAVE_LIVE_ORACLE_LOCATOR"] == "${{ vars.LOOMWEAVE_LIVE_ORACLE_LOCATOR }}" + # The secret is never exposed to the whole job — only to the steps below. assert "LEGIS_LOOMWEAVE_HMAC_KEY" not in env - commands = "\n".join(str(step.get("run", "")) for step in live_job["steps"]) - assert "Missing required release conformance environment" in commands - assert "configured=false" not in commands - assert "configured=true" not in commands - assert "not blocking publish" not in commands + steps = live_job["steps"] + commands = "\n".join(str(step.get("run", "")) for step in steps) + # Skip-not-fail, not fail-closed: missing config no-ops, it does not error. + assert "configured=false" in commands + assert "configured=true" in commands + assert "not blocking publish" in commands + assert "Missing required release conformance environment" not in commands + + # When configured, the live oracle still runs for real, gated on detection. assert "tests/conformance/test_live_loomweave_oracle.py" in commands + gate_if = "steps.oracle_config.outputs.configured == 'true'" oracle_steps = [ step - for step in live_job["steps"] + for step in steps if "test_live_loomweave_oracle.py" in str(step.get("run", "")) ] assert oracle_steps - assert all("if" not in step for step in oracle_steps) + assert all(step.get("if") == gate_if for step in oracle_steps) oracle_step = oracle_steps[0] assert oracle_step["env"] == { "LEGIS_LOOMWEAVE_HMAC_KEY": "${{ secrets.LEGIS_LOOMWEAVE_HMAC_KEY }}" } - assert "LEGIS_LOOMWEAVE_HMAC_KEY" in oracle_step["run"] - non_oracle_steps = [step for step in live_job["steps"] if step is not oracle_step] - assert all( - "LEGIS_LOOMWEAVE_HMAC_KEY" not in step.get("env", {}) - for step in non_oracle_steps - ) + + # Secret scoping: the HMAC key appears only in the steps that need it (the + # presence check and the oracle run), never anywhere else in the job. + key_step_names = { + step.get("name") + for step in steps + if "LEGIS_LOOMWEAVE_HMAC_KEY" in step.get("env", {}) + } + assert key_step_names == { + "Detect live oracle configuration", + "Run live Loomweave oracle", + } def test_release_workflow_repeats_publication_quality_gates():