Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ help-full: help
@echo " make validate-packaging Packaging contract suite"
@echo " make validate-release-contract Release/package matrix contract checks"
@echo " make validate-release-assets Exact 21 GitHub Release asset gate"
@echo " make validate-official-evidence-drift"
@echo " make validate-version-consistency"
@echo " make validate-runtime-imports"
@echo " make validate-pypi-contract"
Expand Down Expand Up @@ -1166,6 +1167,11 @@ validate-runtime-imports:
@$(PYTHON) scripts/check_runtime_imports.py
@echo "--> OK: production runtime imports"

.PHONY: validate-official-evidence-drift
validate-official-evidence-drift:
@$(UV) run python scripts/f4_linter_linux_provisioning.py --check-official-evidence-drift
@echo "--> OK: Linux official distro evidence drift gate"

.PHONY: validate-pypi-contract
validate-pypi-contract:
@test -f "$(PYPI_WHEEL_FILE)" || (echo "Missing $(PYPI_WHEEL_FILE)"; exit 2)
Expand Down Expand Up @@ -1209,7 +1215,7 @@ validate-windows-contract: package-windows-assert
@echo "--> OK: Windows contract"

.PHONY: validate-gate2
validate-gate2: validate-version-consistency validate-runtime-imports
validate-gate2: validate-version-consistency validate-runtime-imports validate-official-evidence-drift
@if [ -f "$(PYPI_WHEEL_FILE)" ] || [ -f "$(PYPI_WHEEL_FILE).sha256" ] || [ -f "$(PYPI_SDIST_FILE)" ] || [ -f "$(PYPI_SDIST_FILE).sha256" ]; then \
$(MAKE) validate-pypi-contract; \
else \
Expand Down
1 change: 1 addition & 0 deletions docs/release/artifact-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@ scripts and release contract tests.
| `scripts/check_log_invariant.py` | Read-only `git ls-files` log-location invariant |
| `scripts/verify_artifact.py` | Structural SHA256 sidecar verifier; exit-code contract `0`-`5` preserved |
| `scripts/verify_release_assets.py` | Read-only exact 21 ECLI-owned GitHub Release asset verifier; ignores `.checksums/` only when it is a directory |
| `scripts/f4_linter_linux_provisioning.py` | Read-only Linux F4 provisioning manifest verifier and official distro evidence drift audit gate; `--check-official-evidence-drift` exits `2` on release-blocking drift |
| `scripts/verify_runtime.py` | Cross-artifact launcher validation; exit codes (`0`/`2`/`3`/`4`/`5`/`6`) preserved |
| `scripts/provision_f4_linters.py` | Provider-neutral F4 linter provisioning planner/evidence writer; dry-run by default, no network/upstream downloads unless explicitly allowed |
| `scripts/verify_f4_linter_provisioning.py` | Read-only F4 linter provisioning evidence verifier for one artifact or all 21 canonical artifact entries |
Expand Down
7 changes: 7 additions & 0 deletions docs/release/packaging-flows.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ package-manager or bundle installation remains the responsibility of each
artifact-specific flow and must stay non-interactive for CI and unattended
package-manager installs.

Linux official distro evidence is release-gated by
`make validate-official-evidence-drift`, which calls
`uv run python scripts/f4_linter_linux_provisioning.py --check-official-evidence-drift`.
The command is read-only: it does not write evidence files, download tools, or
invoke package managers. Exit `0` means the official evidence registry matches
generated distro evidence; exit `2` is release-blocking drift.

## Mandatory GitHub Release Assets

```text
Expand Down
9 changes: 9 additions & 0 deletions docs/release/release-checklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ See the LICENSE file in the project root for full license text.
`make sysinfo` match current package surfaces and canonical Python
scripts.
- [ ] `make validate-gate2` passes before any publish step.
- [ ] `make validate-official-evidence-drift` passes; this invokes
`scripts/f4_linter_linux_provisioning.py --check-official-evidence-drift`
and blocks release readiness if the Linux official distro evidence
registry drifts from generated evidence.
- [ ] `make validate-release-assets` passes against `releases/<version>/`.
- [ ] Required packaging scripts exist and are executable.
- [ ] Active shell wrappers under `scripts/` are absent; Python entrypoints under
Expand Down Expand Up @@ -82,6 +86,11 @@ See the LICENSE file in the project root for full license text.
21 deterministic `f4-linter-provisioning-<artifact-entry-id>.json`
evidence files, and
`scripts/verify_f4_linter_provisioning.py --all-artifacts` verifies them.
- [ ] Linux official distro evidence drift audit remains clean:
`uv run python scripts/f4_linter_linux_provisioning.py --check-official-evidence-drift`
prints
`PASS: Linux official distro evidence drift audit clean` and exits `0`;
exit `2` is release-blocking drift.
- [ ] F4 linter package-manager dependencies: package metadata asserts the
dependency relationship and post-install executable availability for each
required linter/toolchain dependency it delegates to the OS package
Expand Down
95 changes: 95 additions & 0 deletions tests/packaging/test_f4_linter_linux_provisioning.py
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,101 @@ def test_official_distro_evidence_drift_check_cli_passes(
assert result.stdout == "PASS: Linux official distro evidence drift audit clean\n"


def test_validate_gate2_invokes_official_evidence_drift_gate(
read_repo_text: RepoReader,
) -> None:
makefile = read_repo_text("Makefile")
target_start = makefile.index(".PHONY: validate-official-evidence-drift")
target_end = makefile.index(".PHONY: validate-pypi-contract")
target = makefile[target_start:target_end]

assert "validate-official-evidence-drift:" in target
assert (
"$(UV) run python scripts/f4_linter_linux_provisioning.py --check-official-evidence-drift"
in target
)
assert "provision_f4_linters.py" not in target
assert "build/evidence" not in target
assert "releases/" not in target
assert (
"validate-gate2: validate-version-consistency validate-runtime-imports validate-official-evidence-drift"
in makefile
)


def test_make_official_evidence_drift_gate_passes_clean(
repo_root: Path,
) -> None:
result = subprocess.run(
["make", "validate-official-evidence-drift"],
cwd=repo_root,
capture_output=True,
text=True,
check=False,
)

assert result.returncode == 0
assert "PASS: Linux official distro evidence drift audit clean" in result.stdout
assert "--> OK: Linux official distro evidence drift gate" in result.stdout


def test_validate_gate2_propagates_official_evidence_drift_failure(
repo_root: Path,
tmp_path: Path,
) -> None:
fake_python = tmp_path / "python-ok"
fake_python.write_text(
"#!/usr/bin/env python3\nimport sys\nsys.exit(0)\n",
encoding="utf-8",
)
fake_python.chmod(0o755)
uv_log = tmp_path / "uv-args.txt"
fake_uv = tmp_path / "uv-fail"
fake_uv.write_text(
"#!/usr/bin/env python3\n"
"import pathlib\n"
"import sys\n"
f"pathlib.Path({str(uv_log)!r}).write_text(' '.join(sys.argv[1:]), encoding='utf-8')\n"
"print('FAIL: Linux official distro evidence drift detected')\n"
"sys.exit(2)\n",
encoding="utf-8",
)
fake_uv.chmod(0o755)

result = subprocess.run(
[
"make",
"validate-gate2",
f"PYTHON={fake_python}",
f"UV={fake_uv}",
],
cwd=repo_root,
capture_output=True,
text=True,
check=False,
)

assert result.returncode != 0
assert uv_log.read_text(encoding="utf-8") == (
"run python scripts/f4_linter_linux_provisioning.py "
"--check-official-evidence-drift"
)
assert "FAIL: Linux official distro evidence drift detected" in result.stdout


def test_release_docs_reference_official_evidence_drift_gate(
read_repo_text: RepoReader,
) -> None:
for path in (
"docs/release/release-checklist.md",
"docs/release/artifact-contract.md",
"docs/release/packaging-flows.md",
):
text = read_repo_text(path)
assert "--check-official-evidence-drift" in text
assert "release" in text.lower()


def test_official_distro_evidence_drift_comparison_rejects_mismatched_url(
linux_helper: ModuleType,
) -> None:
Expand Down
Loading