diff --git a/.github/workflows/strix-changed-path-quality-ci.yml b/.github/workflows/strix-changed-path-quality-ci.yml index 31924910a..3521836e8 100644 --- a/.github/workflows/strix-changed-path-quality-ci.yml +++ b/.github/workflows/strix-changed-path-quality-ci.yml @@ -10,6 +10,8 @@ on: - "docs/doctoring/strix-legal-git-paths.md" - "docs/doctoring/strix-model-behavior-error.md" - "docs/doctoring/strix-quality-timeout-fixtures.md" + - "docs/doctoring/strix-dependency-manifest-trigger.md" + - "requirements-strix-ci-hashes.txt" - "scripts/ci/strix_quick_gate.sh" - "scripts/ci/test_strix_quick_gate.sh" - "tests/test_strix_changed_path_policy.py" @@ -73,3 +75,21 @@ jobs: python -m compileall -q tests/test_strix_changed_path_policy.py tests/test_strix_model_behavior_error.py tests/test_strix_nvidia_nim_not_found_fallback.py tests/test_strix_workflow_dependency_hashes.py tests/test_strix_quality_timeout_fixture_budget.py bash -n scripts/ci/strix_quick_gate.sh git diff --exit-code + + - name: Set up production Strix lock Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.13" + + - name: Preflight exact hashed Strix dependency closure + env: + PIP_DISABLE_PIP_VERSION_CHECK: "1" + PIP_NO_INPUT: "1" + shell: bash --noprofile --norc -e -o pipefail {0} + run: | + python -m pip install \ + --dry-run \ + --ignore-installed \ + --no-deps \ + --require-hashes \ + -r requirements-strix-ci-hashes.txt diff --git a/CHANGELOG.md b/CHANGELOG.md index 453691d4f..93104bcb1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,9 @@ Semantic Versioning where the repository publishes a release. ### Fixed +- Bound the Strix changed-path quality gate to the complete production hash + lock and mirrored production's deliberate `--no-deps` security-override + boundary without rejecting source distributions that production accepts. - Restored the hourly organization commercial-readiness loop after five consecutive startup failures caused by its mandatory but unprovisioned `PR_REVIEW_MERGE_TOKEN`. Protected scheduled jobs now prefer that maintainer diff --git a/docs/doctoring/strix-dependency-manifest-trigger.md b/docs/doctoring/strix-dependency-manifest-trigger.md new file mode 100644 index 000000000..7d01041b8 --- /dev/null +++ b/docs/doctoring/strix-dependency-manifest-trigger.md @@ -0,0 +1,32 @@ +# Strix dependency-manifest quality trigger + +## Incident and buyer impact + +`requirements-strix-ci-hashes.txt` is executable supply-chain input for the +organization-required Strix gate. The permanent changed-path quality +workflow did not list that file. A Dependabot lock-only pull request could +therefore merge without running the Strix install, policy, shell-regression, +and full-suite contract. + +## Decision + +Add the exact repository-root manifest path to +`.github/workflows/strix-changed-path-quality-ci.yml` and bind it with +`test_strix_workflow_reruns_when_dependency_manifest_changes`. The same gate +uses production Python 3.13 to perform a hash-enforced dry-run of every pinned +lock entry. It mirrors production's deliberate `--no-deps` boundary because +the reviewed `cryptography==50.0.0` security override is newer than the range +declared by `strix-agent==1.5.3`; every installed entry is still version- and +hash-pinned. The preflight permits source distributions because production +does too, so it does not invent a stricter platform contract. Scanner models, +credentials, timeouts, and result semantics are unchanged. + +## References + +National Institute of Standards and Technology. (2024). *Cybersecurity +supply chain risk management practices for systems and organizations* +(NIST Special Publication 800-161 Rev. 1). +https://doi.org/10.6028/NIST.SP.800-161r1 + +Open Source Security Foundation. (2025). *SLSA specification version 1.2*. +https://slsa.dev/spec/v1.2/ diff --git a/tests/test_strix_workflow_dependency_hashes.py b/tests/test_strix_workflow_dependency_hashes.py index e2509c18b..dbdc74548 100644 --- a/tests/test_strix_workflow_dependency_hashes.py +++ b/tests/test_strix_workflow_dependency_hashes.py @@ -40,6 +40,33 @@ def test_strix_workflow_reruns_when_hash_contract_changes() -> None: assert ' - "tests/test_strix_workflow_dependency_hashes.py"' in workflow +def test_strix_workflow_reruns_when_dependency_manifest_changes() -> None: + """Changing the Strix dependency lock must trigger its install contract.""" + workflow = WORKFLOW.read_text(encoding="utf-8") + + assert (ROOT / "requirements-strix-ci-hashes.txt").is_file() + assert ' - "requirements-strix-ci-hashes.txt"' in workflow + assert ' - "docs/doctoring/strix-dependency-manifest-trigger.md"' in workflow + + +def test_strix_workflow_preflights_dependency_manifest_hashes() -> None: + """The specialized gate resolves the production lock with enforced hashes.""" + + workflow = WORKFLOW.read_text(encoding="utf-8") + preflight = workflow.split( + " - name: Preflight exact hashed Strix dependency closure\n", 1 + )[1].split("\n - name:", 1)[0] + + assert 'python-version: "3.13"' in workflow + assert "python -m pip install \\" in preflight + assert "--dry-run \\" in preflight + assert "--ignore-installed \\" in preflight + assert "--no-deps \\" in preflight + assert "--only-binary=:all:" not in preflight + assert "--require-hashes \\" in preflight + assert "-r requirements-strix-ci-hashes.txt" in preflight + + def test_strix_workflow_rejects_branch_selected_manual_dispatch() -> None: """Central executable workflows load no branch-selected manual source.""" workflow = WORKFLOW.read_text(encoding="utf-8")