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
10 changes: 7 additions & 3 deletions packages/sie_server/bundle-locks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@ A saved inventory or CPU import check does not establish GPU namespace
isolation; a missing cu130 `nvidia` submodule may fall through to the base.
Live GPU qualification remains separate from lock validation.

Before installing, the verifier binds the lock to the root lock, resolved
bundle declarations, target, uv version, exact exception manifest, and the
compiler/verifier/declaration-resolver source hashes. After installation it
Before installing, the verifier binds the lock to the exact third-party versions
of the root lock, resolved bundle declarations, target, uv version, exact
exception manifest, and the compiler/verifier/declaration-resolver source
hashes. Workspace package versions and lock serialization are not part of that
binding, so a release version bump does not require recompilation; every check
still compares each locked artifact with the current root lock through the
exception policy. After installation it
checks the actual distribution set, versions, dependency metadata, requested
extras, and recorded direct-source identities without importing package code.
Missing, additional, duplicate, incompatible, or substituted distributions fail
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
],
"inputs": {
"requirements_sha256": "06013808500bdd0b62b916d46f4b7a308290f5c07567315faf967cfe9f7f5888",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "1f2350156ca95ae0ed398f20d94458135d6c9ac1fd4985419e1ea6873576e718",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
],
"inputs": {
"requirements_sha256": "06013808500bdd0b62b916d46f4b7a308290f5c07567315faf967cfe9f7f5888",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "1bc8a0f417323c67420e71cf16b71e562c7db5842b50d4c5cd60efea8106141b",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
],
"inputs": {
"requirements_sha256": "318d20931c1c977a77887959d8d99438c05406095022aa9a3a4ca4e8f4d30b52",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "27a63c27869eb36f251e586323e4d470ea739e7cf105bcc60c886d34df4a5fe4",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
],
"inputs": {
"requirements_sha256": "318d20931c1c977a77887959d8d99438c05406095022aa9a3a4ca4e8f4d30b52",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "7fbe48060336480af530b56634c04d4cb7968b84509d0e4da443b1e19a569ed9",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
],
"inputs": {
"requirements_sha256": "943a74a3f4565e0b7b3bab2f87080526604d1e3923a39ed287d444630d33b94c",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "11fd40b389103f700749005ecc1e10cee548a74e117e1177e91ca19870cd4cac",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
],
"inputs": {
"requirements_sha256": "943a74a3f4565e0b7b3bab2f87080526604d1e3923a39ed287d444630d33b94c",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "1315d6d8b3beac2917feab7728cc91a8bcae5f926c0dd1aa0f3f568770d1eefb",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
],
"inputs": {
"requirements_sha256": "f9e0f7979fcd2920254e6e9a62bdd767d87ceea7794d7df2d9af2ece4e02a324",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "85571638f5441da4e2633e383d1c61e6ba68bd18bf7e3f3a496c7ae3aafb612a",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@
],
"inputs": {
"requirements_sha256": "f9e0f7979fcd2920254e6e9a62bdd767d87ceea7794d7df2d9af2ece4e02a324",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "e371b5d89247efb1cfd7d4b1d100b8888c6a1acbbddb5a3482c29c48c8c9894e",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
],
"inputs": {
"requirements_sha256": "06013808500bdd0b62b916d46f4b7a308290f5c07567315faf967cfe9f7f5888",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "1f2350156ca95ae0ed398f20d94458135d6c9ac1fd4985419e1ea6873576e718",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
],
"inputs": {
"requirements_sha256": "1da4cc3c38305188df3a38287ca48a750637d2b316f6c7eb933e07e1ae665ee0",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "c4c48a529487092c6e3d7ac042d17a16709b68c1ae20046f97555d25baf5fa09",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
],
"inputs": {
"requirements_sha256": "943a74a3f4565e0b7b3bab2f87080526604d1e3923a39ed287d444630d33b94c",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "d70cdf482df2f4b25275b4ef20aaf274dfe432379cc2ed18b77c841399e652bd",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
],
"inputs": {
"requirements_sha256": "378dabe9b77bc2c593a05e1113534e8f50093ca205d3344a7ba2e20fe660e38a",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "e250fa531458fcdb9a3f2dff6fbb7e6b6e0144e114a835bbcd999b371ba0da60",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@
],
"inputs": {
"requirements_sha256": "378dabe9b77bc2c593a05e1113534e8f50093ca205d3344a7ba2e20fe660e38a",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "e250fa531458fcdb9a3f2dff6fbb7e6b6e0144e114a835bbcd999b371ba0da60",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
],
"inputs": {
"requirements_sha256": "5a97f31f45bddf41d827566173ad0200797fecd4a0037f70db40885e0ab5dbb3",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "95975ca37ffabefd6fcafca1d943379536a0b79a67e44f7df42ca07f25473b8a",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
],
"inputs": {
"requirements_sha256": "6d29b7815d5f5105dbc70e23f5c3c51a225c6b2e0127eca3834a327d94eeec4a",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "8b8f649c11f84b8f8e64a0dc7b2145d62cdcd0931610089a254d6f4a72e9914a",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "6808e668b2e2a0982ffa734b251936b07fab343a4b201d549e85333691f7ec85",
"target": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@
],
"inputs": {
"requirements_sha256": "16719ba49f177504ae160a1872b8d0c23e0a4b6d176ecad85c882977d27be9fe",
"uv_lock_sha256": "75848a1dc0e423ddb313eda2d12208568628efcae6d0eea7b6d99be5edc45d8f"
"root_versions_sha256": "3d69200d45fb5e395d3e4b707eac86b4b2a9ce22214bfacd85dd19f73c98a765"
},
"lock_sha256": "645a3f57ca3933838d1e9a1cc4098738219507102a99fef5301afe22de8eae5d",
"policy_sha256": "dbc9ef2b65ea54bebe46021a7813897c378207508e4d84caf45e93d31faf15d4",
"policy_sha256": "6c835f64b277b782d89eb5f2374924124cc3ddc058bb3232c7e0362ff907f377",
"schema_version": 1,
"source_pins_sha256": "44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a",
"target": {
Expand Down
17 changes: 16 additions & 1 deletion packages/sie_server/src/sie_server/bundle_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,18 @@ def root_packages(root_lock: Path) -> dict[str, list[dict[str, Any]]]:
return result


def root_versions_digest(root_lock: Path) -> str:
"""Bind the exact third-party root versions that constrain compilation.

Workspace members and lock serialization never reach ``bundle-libs``.
Root artifact sources are excluded here because every check revalidates
them against the current root lock through the exception policy.
"""
return canonical_digest(
{name: sorted({row["version"] for row in rows}) for name, rows in root_packages(root_lock).items()}
)


def root_constraints(root_lock: Path, exceptions: Mapping[str, Mapping[str, str]]) -> list[str]:
"""Pin every root package, except an explicitly recorded exact alternative.

Expand Down Expand Up @@ -348,7 +360,10 @@ def check_lock(
msg = "bundle compilation or verification policy changed; recompile and review"
raise ValueError(msg)
requirements = bundle_requirements(bundles, target)
expected_inputs = {"uv_lock_sha256": digest(root_lock), "requirements_sha256": canonical_digest(requirements)}
expected_inputs = {
"root_versions_sha256": root_versions_digest(root_lock),
"requirements_sha256": canonical_digest(requirements),
}
exceptions = exception_file["targets"].get(target.name, {})
source_pins = exception_file.get("source_pins", {}).get(target.name, {})
if manifest.get("inputs") != expected_inputs or manifest.get("exceptions_sha256") != canonical_digest(exceptions):
Expand Down
38 changes: 36 additions & 2 deletions packages/sie_server/tests/core/test_bundle_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
read_packages,
required_exceptions,
root_constraints,
root_versions_digest,
source_constraints,
validate_exceptions,
validate_source_pins,
Expand Down Expand Up @@ -64,7 +65,10 @@ def locked(tmp_path):
"uv_version": "0.9.28",
"policy_sha256": policy_digest(),
"target": TARGET.as_dict(),
"inputs": {"uv_lock_sha256": digest(root_lock), "requirements_sha256": canonical_digest(["demo>=1,<2"])},
"inputs": {
"root_versions_sha256": root_versions_digest(root_lock),
"requirements_sha256": canonical_digest(["demo>=1,<2"]),
},
"lock_sha256": digest(lock),
"exceptions_sha256": canonical_digest({}),
"source_pins_sha256": canonical_digest({}),
Expand All @@ -90,7 +94,10 @@ def test_stale_inputs_and_wrong_target_fail_before_install(locked, mutation):
manifest_path = locks / TARGET.name / "manifest.json"
manifest = json.loads(manifest_path.read_text())
if mutation == "root":
root_lock.write_text(root_lock.read_text() + "\n# different root lock\n")
root_lock.write_text(
root_lock.read_text()
+ '[[package]]\nname = "other"\nversion = "2.0"\nsource = { registry = "https://pypi.org/simple" }\n'
)
elif mutation == "requirements":
(bundles / "default.yaml").write_text('deps:\n demo: ">=1.1,<2"\n')
elif mutation == "target":
Expand All @@ -114,6 +121,33 @@ def test_stale_inputs_and_wrong_target_fail_before_install(locked, mutation):
check_lock(*locked, TARGET)


def test_workspace_versions_and_lock_serialization_do_not_invalidate_the_closure(locked):
_locks, _bundles, root_lock = locked
root_lock.write_text(
root_lock.read_text()
.replace("version = 1\n", "version = 1\nrevision = 3\n", 1)
.replace(f'hash = "sha256:{HASH}"', f'hash = "sha256:{HASH}", upload-time = "2026-10-01T00:00:00Z"')
+ '[[package]]\nname = "sie-server"\nversion = "0.11.0"\nsource = { editable = "packages/sie_server" }\n'
)
check_lock(*locked, TARGET)


def test_another_root_source_row_at_a_locked_version_does_not_invalidate_the_closure(locked):
_locks, _bundles, root_lock = locked
root_lock.write_text(
root_lock.read_text()
+ '[[package]]\nname = "demo"\nversion = "1.0"\nsource = { registry = "https://download.pytorch.org/whl/cpu" }\n'
)
check_lock(*locked, TARGET)


def test_root_artifact_substitution_at_the_same_version_still_fails(locked):
_locks, _bundles, root_lock = locked
root_lock.write_text(root_lock.read_text().replace(HASH, "b" * 64))
with pytest.raises(ValueError, match="bundle exceptions differ"):
check_lock(*locked, TARGET)


@pytest.mark.parametrize("mutation", ["missing", "extra", "version", "duplicate", "source", "dependency"])
def test_actual_inventory_drift_is_rejected(locked, tmp_path, mutation):
checked = check_lock(*locked, TARGET)
Expand Down
3 changes: 2 additions & 1 deletion tools/ci/bundle_lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
policy_digest,
read_packages,
root_constraints,
root_versions_digest,
source_constraints,
validate_exceptions,
validate_source_pins,
Expand Down Expand Up @@ -195,7 +196,7 @@ def compile_target(root: Path, target: Target, uv: str, cutoff: str, cache: Path
"indexes": index_arguments(target),
"completed_artifact_hashes": completed_hashes,
"inputs": {
"uv_lock_sha256": digest(root / "uv.lock"),
"root_versions_sha256": root_versions_digest(root / "uv.lock"),
"requirements_sha256": canonical_digest(requirements),
},
"exceptions_sha256": canonical_digest(exceptions),
Expand Down
Loading