#!/usr/bin/env python3 """Audit workspace dependencies, licensing, and source inventory.""" from __future__ import annotations import hashlib import sys import tomllib from pathlib import Path ROOT = Path(__file__).resolve().parents[1] EXPECTED_LICENSE_SHA256 = "0d96a4ff68ad6d4b6f1f30f713b18d5184912ba8dd389f86aa7710db079abcb0" def fail(message: str) -> None: print(f"FAIL: {message}", file=sys.stderr) raise SystemExit(1) def load(path: Path) -> dict: with path.open("rb") as stream: return tomllib.load(stream) def main() -> None: workspace = load(ROOT / "Cargo.toml") package_defaults = workspace["workspace"]["package"] if package_defaults.get("license") != "AGPL-3.0-or-later": fail("workspace package license is not AGPL-3.0-or-later") if package_defaults.get("publish") is not False: fail("private workspace packages must set publish = false") if package_defaults.get("rust-version") != "1.97.1": fail("workspace minimum Rust version must match the reviewed local toolchain") if "repository" in package_defaults: fail("private scaffold must not advertise a placeholder repository URL") expected_members = { "crates/kiln-core", "crates/kiln-cli", "crates/kiln-adapter-native", "crates/kiln-adapter-steam", } if set(workspace["workspace"].get("members", [])) != expected_members: fail("workspace members do not match the reviewed private components") cli_manifest = load(ROOT / "crates" / "kiln-cli" / "Cargo.toml") core_dependency = cli_manifest.get("dependencies", {}).get("kiln-core", {}) if core_dependency.get("version") != "=0.0.1": fail("internal kiln-core dependency must use the exact workspace release version") if core_dependency.get("path") != "../kiln-core": fail("internal kiln-core dependency must resolve through the reviewed workspace path") if cli_manifest.get("dependencies", {}).get("serde_json") != "=1.0.150": fail("kiln-cli must use the reviewed serde_json contract version") if cli_manifest.get("dependencies", {}).get("kiln-adapter-steam") != { "version": "=0.0.1", "path": "../kiln-adapter-steam", }: fail("kiln-cli Steam adapter dependency must use the reviewed workspace path") native_manifest = load(ROOT / "crates" / "kiln-adapter-native" / "Cargo.toml") native_dependencies = native_manifest.get("dependencies", {}) expected_native = { "kiln-core": {"version": "=0.0.1", "path": "../kiln-core"}, "serde": {"version": "=1.0.228", "features": ["derive"]}, "toml": "=1.1.3", } if native_dependencies != expected_native: fail("native adapter dependencies differ from the reviewed exact set") if native_manifest.get("dev-dependencies", {}) != { "serde_json": "=1.0.150", "uuid": {"version": "=1.24.0", "features": ["v4"]}, }: fail("native adapter test dependencies differ from the reviewed exact set") steam_manifest = load(ROOT / "crates" / "kiln-adapter-steam" / "Cargo.toml") if steam_manifest.get("dependencies", {}) != { "kiln-core": {"version": "=0.0.1", "path": "../kiln-core"}, "uuid": "=1.24.0", }: fail("Steam adapter dependencies differ from the reviewed exact set") if steam_manifest.get("dev-dependencies", {}) != { "uuid": {"version": "=1.24.0", "features": ["v4"]} }: fail("Steam adapter test dependencies differ from the reviewed exact set") license_hash = hashlib.sha256((ROOT / "LICENSE").read_bytes()).hexdigest() if license_hash != EXPECTED_LICENSE_SHA256: fail(f"root LICENSE is not the canonical AGPL-3.0 text: {license_hash}") inventory = load(ROOT / "docs" / "phase-0" / "source-inventory.toml") components = {item["name"]: item for item in inventory["components"]} toolchain = load(ROOT / "rust-toolchain.toml")["toolchain"]["channel"] if components.get("rust", {}).get("version") != toolchain: fail("source inventory Rust version does not match rust-toolchain.toml") if components.get("cargo-deny", {}).get("version") != "0.20.2": fail("cargo-deny is absent or not pinned to the reviewed version") core_manifest = load(ROOT / "crates" / "kiln-core" / "Cargo.toml") expected_dependencies = { "serde": "=1.0.228", "serde_json": "=1.0.150", "toml": "=1.1.3", "uuid": "=1.24.0", } dependencies = core_manifest.get("dependencies", {}) for name, version in expected_dependencies.items(): configured = dependencies.get(name, {}) configured_version = configured if isinstance(configured, str) else configured.get("version") if configured_version != version: fail(f"{name} must remain pinned to reviewed version {version}") inventory_version = ( "1.1.3+spec-1.1.0" if name == "toml" else version.removeprefix("=") ) if components.get(name, {}).get("version") != inventory_version: fail(f"{name} source inventory does not match its manifest version") uuid_features = set(dependencies["uuid"].get("features", [])) if uuid_features != {"serde", "v4"}: fail("uuid must enable only the reviewed serde and v4 features") if set(components["uuid"].get("features", [])) != uuid_features: fail("uuid source inventory does not match its reviewed features") lock = load(ROOT / "Cargo.lock") external = [package for package in lock["package"] if "source" in package] unexpected_sources = [ f"{item['name']}@{item['version']}" for item in external if item["source"] != "registry+https://github.com/rust-lang/crates.io-index" ] if unexpected_sources: fail(f"unreviewed external Rust sources entered the workspace: {unexpected_sources}") load(ROOT / "deny.toml") print("PASS: workspace dependency, license, and source baseline") if __name__ == "__main__": main()