@mc-and-his-agents/loom-installer 0.1.21 → 0.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/manifest.json +62 -62
- package/payload/plugin/loom/skills/shared/scripts/loom_check.py +21 -0
- package/payload/plugin/loom/skills/shared/scripts/loom_init.py +48 -40
- package/payload/plugin/loom/skills/shared/scripts/runtime_state.py +17 -0
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py +21 -0
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_init.py +48 -40
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/runtime_state.py +17 -0
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py +21 -0
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_init.py +48 -40
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/runtime_state.py +17 -0
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_check.py +21 -0
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_init.py +48 -40
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/runtime_state.py +17 -0
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py +21 -0
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_init.py +48 -40
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/runtime_state.py +17 -0
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py +21 -0
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_init.py +48 -40
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/runtime_state.py +17 -0
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py +21 -0
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_init.py +48 -40
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/runtime_state.py +17 -0
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py +21 -0
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_init.py +48 -40
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/runtime_state.py +17 -0
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_check.py +21 -0
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_init.py +48 -40
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/runtime_state.py +17 -0
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py +21 -0
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_init.py +48 -40
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/runtime_state.py +17 -0
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
import argparse
|
|
7
|
+
import hashlib
|
|
7
8
|
import json
|
|
8
9
|
import os
|
|
9
10
|
import re
|
|
@@ -27,6 +28,17 @@ TOOL_VERSION = "1.3.0"
|
|
|
27
28
|
CONTRACT_VERSION = "1.3.0"
|
|
28
29
|
WORK_ITEM_ID = "INIT-0001"
|
|
29
30
|
|
|
31
|
+
RUNTIME_ARTIFACT_SOURCES = {
|
|
32
|
+
".loom/bin/loom_init.py": RUNTIME_SOURCE,
|
|
33
|
+
".loom/bin/fact_chain_support.py": FACT_CHAIN_RUNTIME_SOURCE,
|
|
34
|
+
".loom/bin/governance_surface.py": GOVERNANCE_RUNTIME_SOURCE,
|
|
35
|
+
".loom/bin/loom_flow.py": FLOW_RUNTIME_SOURCE,
|
|
36
|
+
".loom/bin/loom_status.py": STATUS_RUNTIME_SOURCE,
|
|
37
|
+
".loom/bin/runtime_paths.py": "skills/shared/scripts/runtime_paths.py",
|
|
38
|
+
".loom/bin/runtime_state.py": "skills/shared/scripts/runtime_state.py",
|
|
39
|
+
".loom/bin/loom_check.py": CHECK_RUNTIME_SOURCE,
|
|
40
|
+
}
|
|
41
|
+
|
|
30
42
|
ROOT_BOUNDARY_FILES = (
|
|
31
43
|
"AGENTS.md",
|
|
32
44
|
"WORKFLOW.md",
|
|
@@ -816,46 +828,14 @@ def initial_artifacts(target_root: Path, install_pr_template: bool, adoption_pat
|
|
|
816
828
|
"kind": "capability-map",
|
|
817
829
|
"source": "generated",
|
|
818
830
|
},
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
"source": FACT_CHAIN_RUNTIME_SOURCE,
|
|
828
|
-
},
|
|
829
|
-
{
|
|
830
|
-
"path": ".loom/bin/governance_surface.py",
|
|
831
|
-
"kind": "loom-tool-support",
|
|
832
|
-
"source": GOVERNANCE_RUNTIME_SOURCE,
|
|
833
|
-
},
|
|
834
|
-
{
|
|
835
|
-
"path": ".loom/bin/loom_flow.py",
|
|
836
|
-
"kind": "loom-tool",
|
|
837
|
-
"source": FLOW_RUNTIME_SOURCE,
|
|
838
|
-
},
|
|
839
|
-
{
|
|
840
|
-
"path": ".loom/bin/loom_status.py",
|
|
841
|
-
"kind": "loom-tool",
|
|
842
|
-
"source": STATUS_RUNTIME_SOURCE,
|
|
843
|
-
},
|
|
844
|
-
{
|
|
845
|
-
"path": ".loom/bin/runtime_paths.py",
|
|
846
|
-
"kind": "loom-tool-support",
|
|
847
|
-
"source": "skills/shared/scripts/runtime_paths.py",
|
|
848
|
-
},
|
|
849
|
-
{
|
|
850
|
-
"path": ".loom/bin/runtime_state.py",
|
|
851
|
-
"kind": "loom-tool-support",
|
|
852
|
-
"source": "skills/shared/scripts/runtime_state.py",
|
|
853
|
-
},
|
|
854
|
-
{
|
|
855
|
-
"path": ".loom/bin/loom_check.py",
|
|
856
|
-
"kind": "loom-tool",
|
|
857
|
-
"source": CHECK_RUNTIME_SOURCE,
|
|
858
|
-
},
|
|
831
|
+
runtime_artifact(".loom/bin/loom_init.py", "loom-tool", RUNTIME_SOURCE),
|
|
832
|
+
runtime_artifact(".loom/bin/fact_chain_support.py", "loom-tool-support", FACT_CHAIN_RUNTIME_SOURCE),
|
|
833
|
+
runtime_artifact(".loom/bin/governance_surface.py", "loom-tool-support", GOVERNANCE_RUNTIME_SOURCE),
|
|
834
|
+
runtime_artifact(".loom/bin/loom_flow.py", "loom-tool", FLOW_RUNTIME_SOURCE),
|
|
835
|
+
runtime_artifact(".loom/bin/loom_status.py", "loom-tool", STATUS_RUNTIME_SOURCE),
|
|
836
|
+
runtime_artifact(".loom/bin/runtime_paths.py", "loom-tool-support", "skills/shared/scripts/runtime_paths.py"),
|
|
837
|
+
runtime_artifact(".loom/bin/runtime_state.py", "loom-tool-support", "skills/shared/scripts/runtime_state.py"),
|
|
838
|
+
runtime_artifact(".loom/bin/loom_check.py", "loom-tool", CHECK_RUNTIME_SOURCE),
|
|
859
839
|
]
|
|
860
840
|
if uses_attach_only_path(adoption_path):
|
|
861
841
|
artifacts.extend(
|
|
@@ -1362,6 +1342,34 @@ def copy_file(source: Path, target: Path, force: bool) -> bool:
|
|
|
1362
1342
|
return write_text(target, content, force=force)
|
|
1363
1343
|
|
|
1364
1344
|
|
|
1345
|
+
def sha256_file(path: Path) -> str:
|
|
1346
|
+
digest = hashlib.sha256()
|
|
1347
|
+
with path.open("rb") as handle:
|
|
1348
|
+
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
|
1349
|
+
digest.update(chunk)
|
|
1350
|
+
return digest.hexdigest()
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
def runtime_artifact(path: str, kind: str, source: str) -> dict[str, str]:
|
|
1354
|
+
runtime_sources = {
|
|
1355
|
+
".loom/bin/loom_init.py": Path(__file__),
|
|
1356
|
+
".loom/bin/fact_chain_support.py": Path(__file__).with_name("fact_chain_support.py"),
|
|
1357
|
+
".loom/bin/governance_surface.py": Path(__file__).with_name("governance_surface.py"),
|
|
1358
|
+
".loom/bin/loom_flow.py": Path(__file__).with_name("loom_flow.py"),
|
|
1359
|
+
".loom/bin/loom_status.py": Path(__file__).with_name("loom_status.py"),
|
|
1360
|
+
".loom/bin/runtime_paths.py": Path(__file__).with_name("runtime_paths.py"),
|
|
1361
|
+
".loom/bin/runtime_state.py": Path(__file__).with_name("runtime_state.py"),
|
|
1362
|
+
".loom/bin/loom_check.py": Path(__file__).with_name("loom_check.py"),
|
|
1363
|
+
}
|
|
1364
|
+
source_path = runtime_sources[path]
|
|
1365
|
+
return {
|
|
1366
|
+
"path": path,
|
|
1367
|
+
"kind": kind,
|
|
1368
|
+
"source": source,
|
|
1369
|
+
"sha256": sha256_file(source_path),
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
|
|
1365
1373
|
def manifest_payload(result: dict[str, object]) -> dict[str, object]:
|
|
1366
1374
|
return {
|
|
1367
1375
|
"schema_version": "loom-bootstrap-manifest/v1",
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
import json
|
|
7
|
+
import hashlib
|
|
7
8
|
import os
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
from typing import Any
|
|
@@ -85,6 +86,14 @@ def detect_carrier(caller_file: str) -> str | None:
|
|
|
85
86
|
return None
|
|
86
87
|
|
|
87
88
|
|
|
89
|
+
def sha256_file(path: Path) -> str:
|
|
90
|
+
digest = hashlib.sha256()
|
|
91
|
+
with path.open("rb") as handle:
|
|
92
|
+
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
|
93
|
+
digest.update(chunk)
|
|
94
|
+
return digest.hexdigest()
|
|
95
|
+
|
|
96
|
+
|
|
88
97
|
def _default_scene_for_carrier(carrier: str) -> str:
|
|
89
98
|
if carrier == "repo-local-wrapper":
|
|
90
99
|
return "repo-local-demo"
|
|
@@ -284,6 +293,14 @@ def _validate_bootstrapped_runtime(caller_file: str) -> tuple[dict[str, Any], li
|
|
|
284
293
|
runtime_file = runtime_root / Path(relative).name
|
|
285
294
|
if not runtime_file.exists():
|
|
286
295
|
errors.append(f"bootstrapped runtime file is missing: `{relative}`")
|
|
296
|
+
continue
|
|
297
|
+
expected_hash = artifact.get("sha256")
|
|
298
|
+
if not isinstance(expected_hash, str) or not expected_hash.strip():
|
|
299
|
+
errors.append(f"bootstrap runtime artifact `{relative}` must declare sha256 provenance")
|
|
300
|
+
continue
|
|
301
|
+
actual_hash = sha256_file(runtime_file)
|
|
302
|
+
if actual_hash != expected_hash:
|
|
303
|
+
errors.append(f"bootstrap runtime artifact `{relative}` sha256 drifted")
|
|
287
304
|
|
|
288
305
|
status = "pass" if not errors else "block"
|
|
289
306
|
summary = (
|
|
@@ -3711,6 +3711,27 @@ def check_daily_execution_cli(root: Path) -> list[Failure]:
|
|
|
3711
3711
|
elif payload.get("result") != "block":
|
|
3712
3712
|
failures.append(Failure("daily-execution-cli", "`bootstrapped runtime-state` must block when the bootstrap manifest drifts"))
|
|
3713
3713
|
|
|
3714
|
+
hash_drift_bootstrap = tmp_root / "hash-drift-bootstrapped-target"
|
|
3715
|
+
shutil.copytree(example_target, hash_drift_bootstrap)
|
|
3716
|
+
manifest_path = hash_drift_bootstrap / ".loom" / "bootstrap" / "manifest.json"
|
|
3717
|
+
manifest = load_json_file(manifest_path)
|
|
3718
|
+
if isinstance(manifest, dict):
|
|
3719
|
+
artifacts = manifest.get("artifacts")
|
|
3720
|
+
if isinstance(artifacts, list):
|
|
3721
|
+
for artifact in artifacts:
|
|
3722
|
+
if isinstance(artifact, dict) and artifact.get("path") == ".loom/bin/runtime_state.py":
|
|
3723
|
+
artifact["sha256"] = "0" * 64
|
|
3724
|
+
manifest_path.write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
3725
|
+
payload, error = load_command_json(
|
|
3726
|
+
root,
|
|
3727
|
+
["python3", ".loom/bin/loom_init.py", "runtime-state", "--target", "."],
|
|
3728
|
+
cwd=hash_drift_bootstrap,
|
|
3729
|
+
)
|
|
3730
|
+
if error:
|
|
3731
|
+
failures.append(Failure("daily-execution-cli", f"`bootstrapped runtime-state` provenance hash drift failed unexpectedly: {error}"))
|
|
3732
|
+
elif payload.get("result") != "block":
|
|
3733
|
+
failures.append(Failure("daily-execution-cli", "`bootstrapped runtime-state` must block when runtime provenance hashes drift"))
|
|
3734
|
+
|
|
3714
3735
|
if shutil.which("git") is not None:
|
|
3715
3736
|
with tempfile.TemporaryDirectory(prefix="loom-check-installed-pre-merge-") as tmp:
|
|
3716
3737
|
tmp_root = Path(tmp)
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
import argparse
|
|
7
|
+
import hashlib
|
|
7
8
|
import json
|
|
8
9
|
import os
|
|
9
10
|
import re
|
|
@@ -27,6 +28,17 @@ TOOL_VERSION = "1.3.0"
|
|
|
27
28
|
CONTRACT_VERSION = "1.3.0"
|
|
28
29
|
WORK_ITEM_ID = "INIT-0001"
|
|
29
30
|
|
|
31
|
+
RUNTIME_ARTIFACT_SOURCES = {
|
|
32
|
+
".loom/bin/loom_init.py": RUNTIME_SOURCE,
|
|
33
|
+
".loom/bin/fact_chain_support.py": FACT_CHAIN_RUNTIME_SOURCE,
|
|
34
|
+
".loom/bin/governance_surface.py": GOVERNANCE_RUNTIME_SOURCE,
|
|
35
|
+
".loom/bin/loom_flow.py": FLOW_RUNTIME_SOURCE,
|
|
36
|
+
".loom/bin/loom_status.py": STATUS_RUNTIME_SOURCE,
|
|
37
|
+
".loom/bin/runtime_paths.py": "skills/shared/scripts/runtime_paths.py",
|
|
38
|
+
".loom/bin/runtime_state.py": "skills/shared/scripts/runtime_state.py",
|
|
39
|
+
".loom/bin/loom_check.py": CHECK_RUNTIME_SOURCE,
|
|
40
|
+
}
|
|
41
|
+
|
|
30
42
|
ROOT_BOUNDARY_FILES = (
|
|
31
43
|
"AGENTS.md",
|
|
32
44
|
"WORKFLOW.md",
|
|
@@ -816,46 +828,14 @@ def initial_artifacts(target_root: Path, install_pr_template: bool, adoption_pat
|
|
|
816
828
|
"kind": "capability-map",
|
|
817
829
|
"source": "generated",
|
|
818
830
|
},
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
"source": FACT_CHAIN_RUNTIME_SOURCE,
|
|
828
|
-
},
|
|
829
|
-
{
|
|
830
|
-
"path": ".loom/bin/governance_surface.py",
|
|
831
|
-
"kind": "loom-tool-support",
|
|
832
|
-
"source": GOVERNANCE_RUNTIME_SOURCE,
|
|
833
|
-
},
|
|
834
|
-
{
|
|
835
|
-
"path": ".loom/bin/loom_flow.py",
|
|
836
|
-
"kind": "loom-tool",
|
|
837
|
-
"source": FLOW_RUNTIME_SOURCE,
|
|
838
|
-
},
|
|
839
|
-
{
|
|
840
|
-
"path": ".loom/bin/loom_status.py",
|
|
841
|
-
"kind": "loom-tool",
|
|
842
|
-
"source": STATUS_RUNTIME_SOURCE,
|
|
843
|
-
},
|
|
844
|
-
{
|
|
845
|
-
"path": ".loom/bin/runtime_paths.py",
|
|
846
|
-
"kind": "loom-tool-support",
|
|
847
|
-
"source": "skills/shared/scripts/runtime_paths.py",
|
|
848
|
-
},
|
|
849
|
-
{
|
|
850
|
-
"path": ".loom/bin/runtime_state.py",
|
|
851
|
-
"kind": "loom-tool-support",
|
|
852
|
-
"source": "skills/shared/scripts/runtime_state.py",
|
|
853
|
-
},
|
|
854
|
-
{
|
|
855
|
-
"path": ".loom/bin/loom_check.py",
|
|
856
|
-
"kind": "loom-tool",
|
|
857
|
-
"source": CHECK_RUNTIME_SOURCE,
|
|
858
|
-
},
|
|
831
|
+
runtime_artifact(".loom/bin/loom_init.py", "loom-tool", RUNTIME_SOURCE),
|
|
832
|
+
runtime_artifact(".loom/bin/fact_chain_support.py", "loom-tool-support", FACT_CHAIN_RUNTIME_SOURCE),
|
|
833
|
+
runtime_artifact(".loom/bin/governance_surface.py", "loom-tool-support", GOVERNANCE_RUNTIME_SOURCE),
|
|
834
|
+
runtime_artifact(".loom/bin/loom_flow.py", "loom-tool", FLOW_RUNTIME_SOURCE),
|
|
835
|
+
runtime_artifact(".loom/bin/loom_status.py", "loom-tool", STATUS_RUNTIME_SOURCE),
|
|
836
|
+
runtime_artifact(".loom/bin/runtime_paths.py", "loom-tool-support", "skills/shared/scripts/runtime_paths.py"),
|
|
837
|
+
runtime_artifact(".loom/bin/runtime_state.py", "loom-tool-support", "skills/shared/scripts/runtime_state.py"),
|
|
838
|
+
runtime_artifact(".loom/bin/loom_check.py", "loom-tool", CHECK_RUNTIME_SOURCE),
|
|
859
839
|
]
|
|
860
840
|
if uses_attach_only_path(adoption_path):
|
|
861
841
|
artifacts.extend(
|
|
@@ -1362,6 +1342,34 @@ def copy_file(source: Path, target: Path, force: bool) -> bool:
|
|
|
1362
1342
|
return write_text(target, content, force=force)
|
|
1363
1343
|
|
|
1364
1344
|
|
|
1345
|
+
def sha256_file(path: Path) -> str:
|
|
1346
|
+
digest = hashlib.sha256()
|
|
1347
|
+
with path.open("rb") as handle:
|
|
1348
|
+
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
|
1349
|
+
digest.update(chunk)
|
|
1350
|
+
return digest.hexdigest()
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
def runtime_artifact(path: str, kind: str, source: str) -> dict[str, str]:
|
|
1354
|
+
runtime_sources = {
|
|
1355
|
+
".loom/bin/loom_init.py": Path(__file__),
|
|
1356
|
+
".loom/bin/fact_chain_support.py": Path(__file__).with_name("fact_chain_support.py"),
|
|
1357
|
+
".loom/bin/governance_surface.py": Path(__file__).with_name("governance_surface.py"),
|
|
1358
|
+
".loom/bin/loom_flow.py": Path(__file__).with_name("loom_flow.py"),
|
|
1359
|
+
".loom/bin/loom_status.py": Path(__file__).with_name("loom_status.py"),
|
|
1360
|
+
".loom/bin/runtime_paths.py": Path(__file__).with_name("runtime_paths.py"),
|
|
1361
|
+
".loom/bin/runtime_state.py": Path(__file__).with_name("runtime_state.py"),
|
|
1362
|
+
".loom/bin/loom_check.py": Path(__file__).with_name("loom_check.py"),
|
|
1363
|
+
}
|
|
1364
|
+
source_path = runtime_sources[path]
|
|
1365
|
+
return {
|
|
1366
|
+
"path": path,
|
|
1367
|
+
"kind": kind,
|
|
1368
|
+
"source": source,
|
|
1369
|
+
"sha256": sha256_file(source_path),
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
|
|
1365
1373
|
def manifest_payload(result: dict[str, object]) -> dict[str, object]:
|
|
1366
1374
|
return {
|
|
1367
1375
|
"schema_version": "loom-bootstrap-manifest/v1",
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
from __future__ import annotations
|
|
5
5
|
|
|
6
6
|
import json
|
|
7
|
+
import hashlib
|
|
7
8
|
import os
|
|
8
9
|
from pathlib import Path
|
|
9
10
|
from typing import Any
|
|
@@ -85,6 +86,14 @@ def detect_carrier(caller_file: str) -> str | None:
|
|
|
85
86
|
return None
|
|
86
87
|
|
|
87
88
|
|
|
89
|
+
def sha256_file(path: Path) -> str:
|
|
90
|
+
digest = hashlib.sha256()
|
|
91
|
+
with path.open("rb") as handle:
|
|
92
|
+
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
|
|
93
|
+
digest.update(chunk)
|
|
94
|
+
return digest.hexdigest()
|
|
95
|
+
|
|
96
|
+
|
|
88
97
|
def _default_scene_for_carrier(carrier: str) -> str:
|
|
89
98
|
if carrier == "repo-local-wrapper":
|
|
90
99
|
return "repo-local-demo"
|
|
@@ -284,6 +293,14 @@ def _validate_bootstrapped_runtime(caller_file: str) -> tuple[dict[str, Any], li
|
|
|
284
293
|
runtime_file = runtime_root / Path(relative).name
|
|
285
294
|
if not runtime_file.exists():
|
|
286
295
|
errors.append(f"bootstrapped runtime file is missing: `{relative}`")
|
|
296
|
+
continue
|
|
297
|
+
expected_hash = artifact.get("sha256")
|
|
298
|
+
if not isinstance(expected_hash, str) or not expected_hash.strip():
|
|
299
|
+
errors.append(f"bootstrap runtime artifact `{relative}` must declare sha256 provenance")
|
|
300
|
+
continue
|
|
301
|
+
actual_hash = sha256_file(runtime_file)
|
|
302
|
+
if actual_hash != expected_hash:
|
|
303
|
+
errors.append(f"bootstrap runtime artifact `{relative}` sha256 drifted")
|
|
287
304
|
|
|
288
305
|
status = "pass" if not errors else "block"
|
|
289
306
|
summary = (
|