@mc-and-his-agents/loom-installer 0.1.37 → 0.1.39
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 +52 -52
- package/payload/plugin/loom/skills/shared/scripts/fact_chain_support.py +2 -2
- package/payload/plugin/loom/skills/shared/scripts/governance_surface.py +2 -2
- package/payload/plugin/loom/skills/shared/scripts/loom_check.py +38 -0
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/fact_chain_support.py +2 -2
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/governance_surface.py +2 -2
- package/payload/skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py +38 -0
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/fact_chain_support.py +2 -2
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/governance_surface.py +2 -2
- package/payload/skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py +38 -0
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/fact_chain_support.py +2 -2
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/governance_surface.py +2 -2
- package/payload/skills/loom-init/.loom-runtime/shared/scripts/loom_check.py +38 -0
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/fact_chain_support.py +2 -2
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/governance_surface.py +2 -2
- package/payload/skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py +38 -0
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/fact_chain_support.py +2 -2
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/governance_surface.py +2 -2
- package/payload/skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py +38 -0
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/fact_chain_support.py +2 -2
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/governance_surface.py +2 -2
- package/payload/skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py +38 -0
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/fact_chain_support.py +2 -2
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/governance_surface.py +2 -2
- package/payload/skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py +38 -0
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/fact_chain_support.py +2 -2
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/governance_surface.py +2 -2
- package/payload/skills/loom-review/.loom-runtime/shared/scripts/loom_check.py +38 -0
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/fact_chain_support.py +2 -2
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/governance_surface.py +2 -2
- package/payload/skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py +38 -0
package/package.json
CHANGED
package/payload/manifest.json
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"schema_version": "loom-installer-payload/v1",
|
|
3
3
|
"loom_version": "0.4.0",
|
|
4
4
|
"source_repository": "https://github.com/MC-and-his-Agents/Loom",
|
|
5
|
-
"source_commit": "
|
|
5
|
+
"source_commit": "a0094e42a22f72429dccc3f437df2d86b084544d",
|
|
6
6
|
"source_ref": "main",
|
|
7
|
-
"built_at": "2026-04-
|
|
7
|
+
"built_at": "2026-04-27T16:28:18+08:00",
|
|
8
8
|
"runtime": {
|
|
9
9
|
"python_minimum": "3.10",
|
|
10
10
|
"python_recommended": "3.11+"
|
|
@@ -624,17 +624,17 @@
|
|
|
624
624
|
{
|
|
625
625
|
"path": "plugin/loom/skills/shared/scripts/fact_chain_support.py",
|
|
626
626
|
"bytes": 21748,
|
|
627
|
-
"sha256": "
|
|
627
|
+
"sha256": "e5c52cda01f1107cafcd00bf2d37feaa167f1acd5152fc8f41f28ee3255a7d52"
|
|
628
628
|
},
|
|
629
629
|
{
|
|
630
630
|
"path": "plugin/loom/skills/shared/scripts/governance_surface.py",
|
|
631
|
-
"bytes":
|
|
632
|
-
"sha256": "
|
|
631
|
+
"bytes": 57013,
|
|
632
|
+
"sha256": "902bba15e9da421b9a48a051940a67a2b019cd14b938d8acd2679c760734b2f5"
|
|
633
633
|
},
|
|
634
634
|
{
|
|
635
635
|
"path": "plugin/loom/skills/shared/scripts/loom_check.py",
|
|
636
|
-
"bytes":
|
|
637
|
-
"sha256": "
|
|
636
|
+
"bytes": 340603,
|
|
637
|
+
"sha256": "8affea751d682b3bcb0fd975652b7c09c9af2cebe5a7dd069d0e64a3e9ce6858"
|
|
638
638
|
},
|
|
639
639
|
{
|
|
640
640
|
"path": "plugin/loom/skills/shared/scripts/loom_flow.py",
|
|
@@ -1214,17 +1214,17 @@
|
|
|
1214
1214
|
{
|
|
1215
1215
|
"path": "skills/loom-adopt/.loom-runtime/shared/scripts/fact_chain_support.py",
|
|
1216
1216
|
"bytes": 21748,
|
|
1217
|
-
"sha256": "
|
|
1217
|
+
"sha256": "e5c52cda01f1107cafcd00bf2d37feaa167f1acd5152fc8f41f28ee3255a7d52"
|
|
1218
1218
|
},
|
|
1219
1219
|
{
|
|
1220
1220
|
"path": "skills/loom-adopt/.loom-runtime/shared/scripts/governance_surface.py",
|
|
1221
|
-
"bytes":
|
|
1222
|
-
"sha256": "
|
|
1221
|
+
"bytes": 57013,
|
|
1222
|
+
"sha256": "902bba15e9da421b9a48a051940a67a2b019cd14b938d8acd2679c760734b2f5"
|
|
1223
1223
|
},
|
|
1224
1224
|
{
|
|
1225
1225
|
"path": "skills/loom-adopt/.loom-runtime/shared/scripts/loom_check.py",
|
|
1226
|
-
"bytes":
|
|
1227
|
-
"sha256": "
|
|
1226
|
+
"bytes": 340603,
|
|
1227
|
+
"sha256": "8affea751d682b3bcb0fd975652b7c09c9af2cebe5a7dd069d0e64a3e9ce6858"
|
|
1228
1228
|
},
|
|
1229
1229
|
{
|
|
1230
1230
|
"path": "skills/loom-adopt/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -1834,17 +1834,17 @@
|
|
|
1834
1834
|
{
|
|
1835
1835
|
"path": "skills/loom-handoff/.loom-runtime/shared/scripts/fact_chain_support.py",
|
|
1836
1836
|
"bytes": 21748,
|
|
1837
|
-
"sha256": "
|
|
1837
|
+
"sha256": "e5c52cda01f1107cafcd00bf2d37feaa167f1acd5152fc8f41f28ee3255a7d52"
|
|
1838
1838
|
},
|
|
1839
1839
|
{
|
|
1840
1840
|
"path": "skills/loom-handoff/.loom-runtime/shared/scripts/governance_surface.py",
|
|
1841
|
-
"bytes":
|
|
1842
|
-
"sha256": "
|
|
1841
|
+
"bytes": 57013,
|
|
1842
|
+
"sha256": "902bba15e9da421b9a48a051940a67a2b019cd14b938d8acd2679c760734b2f5"
|
|
1843
1843
|
},
|
|
1844
1844
|
{
|
|
1845
1845
|
"path": "skills/loom-handoff/.loom-runtime/shared/scripts/loom_check.py",
|
|
1846
|
-
"bytes":
|
|
1847
|
-
"sha256": "
|
|
1846
|
+
"bytes": 340603,
|
|
1847
|
+
"sha256": "8affea751d682b3bcb0fd975652b7c09c9af2cebe5a7dd069d0e64a3e9ce6858"
|
|
1848
1848
|
},
|
|
1849
1849
|
{
|
|
1850
1850
|
"path": "skills/loom-handoff/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -2454,17 +2454,17 @@
|
|
|
2454
2454
|
{
|
|
2455
2455
|
"path": "skills/loom-init/.loom-runtime/shared/scripts/fact_chain_support.py",
|
|
2456
2456
|
"bytes": 21748,
|
|
2457
|
-
"sha256": "
|
|
2457
|
+
"sha256": "e5c52cda01f1107cafcd00bf2d37feaa167f1acd5152fc8f41f28ee3255a7d52"
|
|
2458
2458
|
},
|
|
2459
2459
|
{
|
|
2460
2460
|
"path": "skills/loom-init/.loom-runtime/shared/scripts/governance_surface.py",
|
|
2461
|
-
"bytes":
|
|
2462
|
-
"sha256": "
|
|
2461
|
+
"bytes": 57013,
|
|
2462
|
+
"sha256": "902bba15e9da421b9a48a051940a67a2b019cd14b938d8acd2679c760734b2f5"
|
|
2463
2463
|
},
|
|
2464
2464
|
{
|
|
2465
2465
|
"path": "skills/loom-init/.loom-runtime/shared/scripts/loom_check.py",
|
|
2466
|
-
"bytes":
|
|
2467
|
-
"sha256": "
|
|
2466
|
+
"bytes": 340603,
|
|
2467
|
+
"sha256": "8affea751d682b3bcb0fd975652b7c09c9af2cebe5a7dd069d0e64a3e9ce6858"
|
|
2468
2468
|
},
|
|
2469
2469
|
{
|
|
2470
2470
|
"path": "skills/loom-init/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -3079,17 +3079,17 @@
|
|
|
3079
3079
|
{
|
|
3080
3080
|
"path": "skills/loom-merge-ready/.loom-runtime/shared/scripts/fact_chain_support.py",
|
|
3081
3081
|
"bytes": 21748,
|
|
3082
|
-
"sha256": "
|
|
3082
|
+
"sha256": "e5c52cda01f1107cafcd00bf2d37feaa167f1acd5152fc8f41f28ee3255a7d52"
|
|
3083
3083
|
},
|
|
3084
3084
|
{
|
|
3085
3085
|
"path": "skills/loom-merge-ready/.loom-runtime/shared/scripts/governance_surface.py",
|
|
3086
|
-
"bytes":
|
|
3087
|
-
"sha256": "
|
|
3086
|
+
"bytes": 57013,
|
|
3087
|
+
"sha256": "902bba15e9da421b9a48a051940a67a2b019cd14b938d8acd2679c760734b2f5"
|
|
3088
3088
|
},
|
|
3089
3089
|
{
|
|
3090
3090
|
"path": "skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_check.py",
|
|
3091
|
-
"bytes":
|
|
3092
|
-
"sha256": "
|
|
3091
|
+
"bytes": 340603,
|
|
3092
|
+
"sha256": "8affea751d682b3bcb0fd975652b7c09c9af2cebe5a7dd069d0e64a3e9ce6858"
|
|
3093
3093
|
},
|
|
3094
3094
|
{
|
|
3095
3095
|
"path": "skills/loom-merge-ready/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -3699,17 +3699,17 @@
|
|
|
3699
3699
|
{
|
|
3700
3700
|
"path": "skills/loom-pre-review/.loom-runtime/shared/scripts/fact_chain_support.py",
|
|
3701
3701
|
"bytes": 21748,
|
|
3702
|
-
"sha256": "
|
|
3702
|
+
"sha256": "e5c52cda01f1107cafcd00bf2d37feaa167f1acd5152fc8f41f28ee3255a7d52"
|
|
3703
3703
|
},
|
|
3704
3704
|
{
|
|
3705
3705
|
"path": "skills/loom-pre-review/.loom-runtime/shared/scripts/governance_surface.py",
|
|
3706
|
-
"bytes":
|
|
3707
|
-
"sha256": "
|
|
3706
|
+
"bytes": 57013,
|
|
3707
|
+
"sha256": "902bba15e9da421b9a48a051940a67a2b019cd14b938d8acd2679c760734b2f5"
|
|
3708
3708
|
},
|
|
3709
3709
|
{
|
|
3710
3710
|
"path": "skills/loom-pre-review/.loom-runtime/shared/scripts/loom_check.py",
|
|
3711
|
-
"bytes":
|
|
3712
|
-
"sha256": "
|
|
3711
|
+
"bytes": 340603,
|
|
3712
|
+
"sha256": "8affea751d682b3bcb0fd975652b7c09c9af2cebe5a7dd069d0e64a3e9ce6858"
|
|
3713
3713
|
},
|
|
3714
3714
|
{
|
|
3715
3715
|
"path": "skills/loom-pre-review/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -4319,17 +4319,17 @@
|
|
|
4319
4319
|
{
|
|
4320
4320
|
"path": "skills/loom-resume/.loom-runtime/shared/scripts/fact_chain_support.py",
|
|
4321
4321
|
"bytes": 21748,
|
|
4322
|
-
"sha256": "
|
|
4322
|
+
"sha256": "e5c52cda01f1107cafcd00bf2d37feaa167f1acd5152fc8f41f28ee3255a7d52"
|
|
4323
4323
|
},
|
|
4324
4324
|
{
|
|
4325
4325
|
"path": "skills/loom-resume/.loom-runtime/shared/scripts/governance_surface.py",
|
|
4326
|
-
"bytes":
|
|
4327
|
-
"sha256": "
|
|
4326
|
+
"bytes": 57013,
|
|
4327
|
+
"sha256": "902bba15e9da421b9a48a051940a67a2b019cd14b938d8acd2679c760734b2f5"
|
|
4328
4328
|
},
|
|
4329
4329
|
{
|
|
4330
4330
|
"path": "skills/loom-resume/.loom-runtime/shared/scripts/loom_check.py",
|
|
4331
|
-
"bytes":
|
|
4332
|
-
"sha256": "
|
|
4331
|
+
"bytes": 340603,
|
|
4332
|
+
"sha256": "8affea751d682b3bcb0fd975652b7c09c9af2cebe5a7dd069d0e64a3e9ce6858"
|
|
4333
4333
|
},
|
|
4334
4334
|
{
|
|
4335
4335
|
"path": "skills/loom-resume/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -4939,17 +4939,17 @@
|
|
|
4939
4939
|
{
|
|
4940
4940
|
"path": "skills/loom-retire/.loom-runtime/shared/scripts/fact_chain_support.py",
|
|
4941
4941
|
"bytes": 21748,
|
|
4942
|
-
"sha256": "
|
|
4942
|
+
"sha256": "e5c52cda01f1107cafcd00bf2d37feaa167f1acd5152fc8f41f28ee3255a7d52"
|
|
4943
4943
|
},
|
|
4944
4944
|
{
|
|
4945
4945
|
"path": "skills/loom-retire/.loom-runtime/shared/scripts/governance_surface.py",
|
|
4946
|
-
"bytes":
|
|
4947
|
-
"sha256": "
|
|
4946
|
+
"bytes": 57013,
|
|
4947
|
+
"sha256": "902bba15e9da421b9a48a051940a67a2b019cd14b938d8acd2679c760734b2f5"
|
|
4948
4948
|
},
|
|
4949
4949
|
{
|
|
4950
4950
|
"path": "skills/loom-retire/.loom-runtime/shared/scripts/loom_check.py",
|
|
4951
|
-
"bytes":
|
|
4952
|
-
"sha256": "
|
|
4951
|
+
"bytes": 340603,
|
|
4952
|
+
"sha256": "8affea751d682b3bcb0fd975652b7c09c9af2cebe5a7dd069d0e64a3e9ce6858"
|
|
4953
4953
|
},
|
|
4954
4954
|
{
|
|
4955
4955
|
"path": "skills/loom-retire/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -5559,17 +5559,17 @@
|
|
|
5559
5559
|
{
|
|
5560
5560
|
"path": "skills/loom-review/.loom-runtime/shared/scripts/fact_chain_support.py",
|
|
5561
5561
|
"bytes": 21748,
|
|
5562
|
-
"sha256": "
|
|
5562
|
+
"sha256": "e5c52cda01f1107cafcd00bf2d37feaa167f1acd5152fc8f41f28ee3255a7d52"
|
|
5563
5563
|
},
|
|
5564
5564
|
{
|
|
5565
5565
|
"path": "skills/loom-review/.loom-runtime/shared/scripts/governance_surface.py",
|
|
5566
|
-
"bytes":
|
|
5567
|
-
"sha256": "
|
|
5566
|
+
"bytes": 57013,
|
|
5567
|
+
"sha256": "902bba15e9da421b9a48a051940a67a2b019cd14b938d8acd2679c760734b2f5"
|
|
5568
5568
|
},
|
|
5569
5569
|
{
|
|
5570
5570
|
"path": "skills/loom-review/.loom-runtime/shared/scripts/loom_check.py",
|
|
5571
|
-
"bytes":
|
|
5572
|
-
"sha256": "
|
|
5571
|
+
"bytes": 340603,
|
|
5572
|
+
"sha256": "8affea751d682b3bcb0fd975652b7c09c9af2cebe5a7dd069d0e64a3e9ce6858"
|
|
5573
5573
|
},
|
|
5574
5574
|
{
|
|
5575
5575
|
"path": "skills/loom-review/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -6179,17 +6179,17 @@
|
|
|
6179
6179
|
{
|
|
6180
6180
|
"path": "skills/loom-spec-review/.loom-runtime/shared/scripts/fact_chain_support.py",
|
|
6181
6181
|
"bytes": 21748,
|
|
6182
|
-
"sha256": "
|
|
6182
|
+
"sha256": "e5c52cda01f1107cafcd00bf2d37feaa167f1acd5152fc8f41f28ee3255a7d52"
|
|
6183
6183
|
},
|
|
6184
6184
|
{
|
|
6185
6185
|
"path": "skills/loom-spec-review/.loom-runtime/shared/scripts/governance_surface.py",
|
|
6186
|
-
"bytes":
|
|
6187
|
-
"sha256": "
|
|
6186
|
+
"bytes": 57013,
|
|
6187
|
+
"sha256": "902bba15e9da421b9a48a051940a67a2b019cd14b938d8acd2679c760734b2f5"
|
|
6188
6188
|
},
|
|
6189
6189
|
{
|
|
6190
6190
|
"path": "skills/loom-spec-review/.loom-runtime/shared/scripts/loom_check.py",
|
|
6191
|
-
"bytes":
|
|
6192
|
-
"sha256": "
|
|
6191
|
+
"bytes": 340603,
|
|
6192
|
+
"sha256": "8affea751d682b3bcb0fd975652b7c09c9af2cebe5a7dd069d0e64a3e9ce6858"
|
|
6193
6193
|
},
|
|
6194
6194
|
{
|
|
6195
6195
|
"path": "skills/loom-spec-review/.loom-runtime/shared/scripts/loom_flow.py",
|
|
@@ -195,12 +195,12 @@ def resolve_repo_relative_path(target_root: Path, relative: str, *, label: str)
|
|
|
195
195
|
if candidate_raw.is_absolute():
|
|
196
196
|
return None, [f"{label} must be repo-relative, got absolute path: {locator}"]
|
|
197
197
|
if ".." in candidate_raw.parts:
|
|
198
|
-
return None, [f"{label} must stay
|
|
198
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
199
199
|
candidate = (target_root / candidate_raw).resolve()
|
|
200
200
|
try:
|
|
201
201
|
candidate.relative_to(target_root.resolve())
|
|
202
202
|
except ValueError:
|
|
203
|
-
return None, [f"{label} must stay
|
|
203
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
204
204
|
return candidate, []
|
|
205
205
|
|
|
206
206
|
|
|
@@ -481,8 +481,8 @@ def locator_boundary_error(raw_locator: object, *, label: str) -> str:
|
|
|
481
481
|
locator = raw_locator.strip()
|
|
482
482
|
locator_path = Path(locator)
|
|
483
483
|
if locator_path.is_absolute() or ".." in locator_path.parts:
|
|
484
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
485
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
484
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
485
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
486
486
|
|
|
487
487
|
|
|
488
488
|
def resolve_locator(root: Path, raw_locator: object) -> tuple[str | None, Path | None]:
|
|
@@ -6422,6 +6422,44 @@ def check_adversarial_adoption_fixture(root: Path) -> list[Failure]:
|
|
|
6422
6422
|
if payload.get("status") != "block" or not any("must stay inside" in error for error in errors):
|
|
6423
6423
|
failures.append(Failure("adversarial-adoption", "registry executable and manifest paths must not escape the runtime root"))
|
|
6424
6424
|
|
|
6425
|
+
fact_chain_escape = base / "fact-chain-error-anchor"
|
|
6426
|
+
(fact_chain_escape / ".loom/bootstrap").mkdir(parents=True)
|
|
6427
|
+
write_json(
|
|
6428
|
+
fact_chain_escape / ".loom/bootstrap/init-result.json",
|
|
6429
|
+
{
|
|
6430
|
+
"schema_version": "loom-init-output/v1",
|
|
6431
|
+
"fact_chain": {
|
|
6432
|
+
"read_entry": "python3 .loom/bin/loom_init.py fact-chain --target .",
|
|
6433
|
+
"mode": "work-item + recovery-entry + derived status-surface",
|
|
6434
|
+
"entry_points": {
|
|
6435
|
+
"current_item_id": "INIT-0001",
|
|
6436
|
+
"work_item": "../outside.md",
|
|
6437
|
+
"recovery_entry": ".loom/progress/INIT-0001.md",
|
|
6438
|
+
"status_surface": ".loom/status/current.md",
|
|
6439
|
+
}
|
|
6440
|
+
},
|
|
6441
|
+
},
|
|
6442
|
+
)
|
|
6443
|
+
_, errors = inspect_fact_chain(fact_chain_escape)
|
|
6444
|
+
if not any("must stay within the target root" in error for error in errors):
|
|
6445
|
+
failures.append(Failure("adversarial-adoption", "fact-chain path-boundary errors must expose a stable target-root anchor"))
|
|
6446
|
+
|
|
6447
|
+
shadow_anchor_errors = governance_surface_module.validate_shadow_surface(
|
|
6448
|
+
root=base,
|
|
6449
|
+
surface="review",
|
|
6450
|
+
entry={
|
|
6451
|
+
"summary": "review parity",
|
|
6452
|
+
"loom_locator": ".loom/shadow/review-loom.json",
|
|
6453
|
+
"repo_locator": "../outside.json",
|
|
6454
|
+
},
|
|
6455
|
+
)
|
|
6456
|
+
if not any(
|
|
6457
|
+
"must stay inside the repository" in error
|
|
6458
|
+
and "must stay within the repository root" in error
|
|
6459
|
+
for error in shadow_anchor_errors
|
|
6460
|
+
):
|
|
6461
|
+
failures.append(Failure("adversarial-adoption", "shadow surface path-boundary errors must expose a stable repository anchor"))
|
|
6462
|
+
|
|
6425
6463
|
spec_contract_target = base / "spec-contract"
|
|
6426
6464
|
(spec_contract_target / ".loom/specs/INIT-0001").mkdir(parents=True)
|
|
6427
6465
|
(spec_contract_target / ".loom/specs/INIT-0001/spec.md").write_text("bootstrap spec\n", encoding="utf-8")
|
|
@@ -195,12 +195,12 @@ def resolve_repo_relative_path(target_root: Path, relative: str, *, label: str)
|
|
|
195
195
|
if candidate_raw.is_absolute():
|
|
196
196
|
return None, [f"{label} must be repo-relative, got absolute path: {locator}"]
|
|
197
197
|
if ".." in candidate_raw.parts:
|
|
198
|
-
return None, [f"{label} must stay
|
|
198
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
199
199
|
candidate = (target_root / candidate_raw).resolve()
|
|
200
200
|
try:
|
|
201
201
|
candidate.relative_to(target_root.resolve())
|
|
202
202
|
except ValueError:
|
|
203
|
-
return None, [f"{label} must stay
|
|
203
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
204
204
|
return candidate, []
|
|
205
205
|
|
|
206
206
|
|
|
@@ -481,8 +481,8 @@ def locator_boundary_error(raw_locator: object, *, label: str) -> str:
|
|
|
481
481
|
locator = raw_locator.strip()
|
|
482
482
|
locator_path = Path(locator)
|
|
483
483
|
if locator_path.is_absolute() or ".." in locator_path.parts:
|
|
484
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
485
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
484
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
485
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
486
486
|
|
|
487
487
|
|
|
488
488
|
def resolve_locator(root: Path, raw_locator: object) -> tuple[str | None, Path | None]:
|
|
@@ -6422,6 +6422,44 @@ def check_adversarial_adoption_fixture(root: Path) -> list[Failure]:
|
|
|
6422
6422
|
if payload.get("status") != "block" or not any("must stay inside" in error for error in errors):
|
|
6423
6423
|
failures.append(Failure("adversarial-adoption", "registry executable and manifest paths must not escape the runtime root"))
|
|
6424
6424
|
|
|
6425
|
+
fact_chain_escape = base / "fact-chain-error-anchor"
|
|
6426
|
+
(fact_chain_escape / ".loom/bootstrap").mkdir(parents=True)
|
|
6427
|
+
write_json(
|
|
6428
|
+
fact_chain_escape / ".loom/bootstrap/init-result.json",
|
|
6429
|
+
{
|
|
6430
|
+
"schema_version": "loom-init-output/v1",
|
|
6431
|
+
"fact_chain": {
|
|
6432
|
+
"read_entry": "python3 .loom/bin/loom_init.py fact-chain --target .",
|
|
6433
|
+
"mode": "work-item + recovery-entry + derived status-surface",
|
|
6434
|
+
"entry_points": {
|
|
6435
|
+
"current_item_id": "INIT-0001",
|
|
6436
|
+
"work_item": "../outside.md",
|
|
6437
|
+
"recovery_entry": ".loom/progress/INIT-0001.md",
|
|
6438
|
+
"status_surface": ".loom/status/current.md",
|
|
6439
|
+
}
|
|
6440
|
+
},
|
|
6441
|
+
},
|
|
6442
|
+
)
|
|
6443
|
+
_, errors = inspect_fact_chain(fact_chain_escape)
|
|
6444
|
+
if not any("must stay within the target root" in error for error in errors):
|
|
6445
|
+
failures.append(Failure("adversarial-adoption", "fact-chain path-boundary errors must expose a stable target-root anchor"))
|
|
6446
|
+
|
|
6447
|
+
shadow_anchor_errors = governance_surface_module.validate_shadow_surface(
|
|
6448
|
+
root=base,
|
|
6449
|
+
surface="review",
|
|
6450
|
+
entry={
|
|
6451
|
+
"summary": "review parity",
|
|
6452
|
+
"loom_locator": ".loom/shadow/review-loom.json",
|
|
6453
|
+
"repo_locator": "../outside.json",
|
|
6454
|
+
},
|
|
6455
|
+
)
|
|
6456
|
+
if not any(
|
|
6457
|
+
"must stay inside the repository" in error
|
|
6458
|
+
and "must stay within the repository root" in error
|
|
6459
|
+
for error in shadow_anchor_errors
|
|
6460
|
+
):
|
|
6461
|
+
failures.append(Failure("adversarial-adoption", "shadow surface path-boundary errors must expose a stable repository anchor"))
|
|
6462
|
+
|
|
6425
6463
|
spec_contract_target = base / "spec-contract"
|
|
6426
6464
|
(spec_contract_target / ".loom/specs/INIT-0001").mkdir(parents=True)
|
|
6427
6465
|
(spec_contract_target / ".loom/specs/INIT-0001/spec.md").write_text("bootstrap spec\n", encoding="utf-8")
|
|
@@ -195,12 +195,12 @@ def resolve_repo_relative_path(target_root: Path, relative: str, *, label: str)
|
|
|
195
195
|
if candidate_raw.is_absolute():
|
|
196
196
|
return None, [f"{label} must be repo-relative, got absolute path: {locator}"]
|
|
197
197
|
if ".." in candidate_raw.parts:
|
|
198
|
-
return None, [f"{label} must stay
|
|
198
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
199
199
|
candidate = (target_root / candidate_raw).resolve()
|
|
200
200
|
try:
|
|
201
201
|
candidate.relative_to(target_root.resolve())
|
|
202
202
|
except ValueError:
|
|
203
|
-
return None, [f"{label} must stay
|
|
203
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
204
204
|
return candidate, []
|
|
205
205
|
|
|
206
206
|
|
|
@@ -481,8 +481,8 @@ def locator_boundary_error(raw_locator: object, *, label: str) -> str:
|
|
|
481
481
|
locator = raw_locator.strip()
|
|
482
482
|
locator_path = Path(locator)
|
|
483
483
|
if locator_path.is_absolute() or ".." in locator_path.parts:
|
|
484
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
485
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
484
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
485
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
486
486
|
|
|
487
487
|
|
|
488
488
|
def resolve_locator(root: Path, raw_locator: object) -> tuple[str | None, Path | None]:
|
|
@@ -6422,6 +6422,44 @@ def check_adversarial_adoption_fixture(root: Path) -> list[Failure]:
|
|
|
6422
6422
|
if payload.get("status") != "block" or not any("must stay inside" in error for error in errors):
|
|
6423
6423
|
failures.append(Failure("adversarial-adoption", "registry executable and manifest paths must not escape the runtime root"))
|
|
6424
6424
|
|
|
6425
|
+
fact_chain_escape = base / "fact-chain-error-anchor"
|
|
6426
|
+
(fact_chain_escape / ".loom/bootstrap").mkdir(parents=True)
|
|
6427
|
+
write_json(
|
|
6428
|
+
fact_chain_escape / ".loom/bootstrap/init-result.json",
|
|
6429
|
+
{
|
|
6430
|
+
"schema_version": "loom-init-output/v1",
|
|
6431
|
+
"fact_chain": {
|
|
6432
|
+
"read_entry": "python3 .loom/bin/loom_init.py fact-chain --target .",
|
|
6433
|
+
"mode": "work-item + recovery-entry + derived status-surface",
|
|
6434
|
+
"entry_points": {
|
|
6435
|
+
"current_item_id": "INIT-0001",
|
|
6436
|
+
"work_item": "../outside.md",
|
|
6437
|
+
"recovery_entry": ".loom/progress/INIT-0001.md",
|
|
6438
|
+
"status_surface": ".loom/status/current.md",
|
|
6439
|
+
}
|
|
6440
|
+
},
|
|
6441
|
+
},
|
|
6442
|
+
)
|
|
6443
|
+
_, errors = inspect_fact_chain(fact_chain_escape)
|
|
6444
|
+
if not any("must stay within the target root" in error for error in errors):
|
|
6445
|
+
failures.append(Failure("adversarial-adoption", "fact-chain path-boundary errors must expose a stable target-root anchor"))
|
|
6446
|
+
|
|
6447
|
+
shadow_anchor_errors = governance_surface_module.validate_shadow_surface(
|
|
6448
|
+
root=base,
|
|
6449
|
+
surface="review",
|
|
6450
|
+
entry={
|
|
6451
|
+
"summary": "review parity",
|
|
6452
|
+
"loom_locator": ".loom/shadow/review-loom.json",
|
|
6453
|
+
"repo_locator": "../outside.json",
|
|
6454
|
+
},
|
|
6455
|
+
)
|
|
6456
|
+
if not any(
|
|
6457
|
+
"must stay inside the repository" in error
|
|
6458
|
+
and "must stay within the repository root" in error
|
|
6459
|
+
for error in shadow_anchor_errors
|
|
6460
|
+
):
|
|
6461
|
+
failures.append(Failure("adversarial-adoption", "shadow surface path-boundary errors must expose a stable repository anchor"))
|
|
6462
|
+
|
|
6425
6463
|
spec_contract_target = base / "spec-contract"
|
|
6426
6464
|
(spec_contract_target / ".loom/specs/INIT-0001").mkdir(parents=True)
|
|
6427
6465
|
(spec_contract_target / ".loom/specs/INIT-0001/spec.md").write_text("bootstrap spec\n", encoding="utf-8")
|
|
@@ -195,12 +195,12 @@ def resolve_repo_relative_path(target_root: Path, relative: str, *, label: str)
|
|
|
195
195
|
if candidate_raw.is_absolute():
|
|
196
196
|
return None, [f"{label} must be repo-relative, got absolute path: {locator}"]
|
|
197
197
|
if ".." in candidate_raw.parts:
|
|
198
|
-
return None, [f"{label} must stay
|
|
198
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
199
199
|
candidate = (target_root / candidate_raw).resolve()
|
|
200
200
|
try:
|
|
201
201
|
candidate.relative_to(target_root.resolve())
|
|
202
202
|
except ValueError:
|
|
203
|
-
return None, [f"{label} must stay
|
|
203
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
204
204
|
return candidate, []
|
|
205
205
|
|
|
206
206
|
|
|
@@ -481,8 +481,8 @@ def locator_boundary_error(raw_locator: object, *, label: str) -> str:
|
|
|
481
481
|
locator = raw_locator.strip()
|
|
482
482
|
locator_path = Path(locator)
|
|
483
483
|
if locator_path.is_absolute() or ".." in locator_path.parts:
|
|
484
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
485
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
484
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
485
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
486
486
|
|
|
487
487
|
|
|
488
488
|
def resolve_locator(root: Path, raw_locator: object) -> tuple[str | None, Path | None]:
|
|
@@ -6422,6 +6422,44 @@ def check_adversarial_adoption_fixture(root: Path) -> list[Failure]:
|
|
|
6422
6422
|
if payload.get("status") != "block" or not any("must stay inside" in error for error in errors):
|
|
6423
6423
|
failures.append(Failure("adversarial-adoption", "registry executable and manifest paths must not escape the runtime root"))
|
|
6424
6424
|
|
|
6425
|
+
fact_chain_escape = base / "fact-chain-error-anchor"
|
|
6426
|
+
(fact_chain_escape / ".loom/bootstrap").mkdir(parents=True)
|
|
6427
|
+
write_json(
|
|
6428
|
+
fact_chain_escape / ".loom/bootstrap/init-result.json",
|
|
6429
|
+
{
|
|
6430
|
+
"schema_version": "loom-init-output/v1",
|
|
6431
|
+
"fact_chain": {
|
|
6432
|
+
"read_entry": "python3 .loom/bin/loom_init.py fact-chain --target .",
|
|
6433
|
+
"mode": "work-item + recovery-entry + derived status-surface",
|
|
6434
|
+
"entry_points": {
|
|
6435
|
+
"current_item_id": "INIT-0001",
|
|
6436
|
+
"work_item": "../outside.md",
|
|
6437
|
+
"recovery_entry": ".loom/progress/INIT-0001.md",
|
|
6438
|
+
"status_surface": ".loom/status/current.md",
|
|
6439
|
+
}
|
|
6440
|
+
},
|
|
6441
|
+
},
|
|
6442
|
+
)
|
|
6443
|
+
_, errors = inspect_fact_chain(fact_chain_escape)
|
|
6444
|
+
if not any("must stay within the target root" in error for error in errors):
|
|
6445
|
+
failures.append(Failure("adversarial-adoption", "fact-chain path-boundary errors must expose a stable target-root anchor"))
|
|
6446
|
+
|
|
6447
|
+
shadow_anchor_errors = governance_surface_module.validate_shadow_surface(
|
|
6448
|
+
root=base,
|
|
6449
|
+
surface="review",
|
|
6450
|
+
entry={
|
|
6451
|
+
"summary": "review parity",
|
|
6452
|
+
"loom_locator": ".loom/shadow/review-loom.json",
|
|
6453
|
+
"repo_locator": "../outside.json",
|
|
6454
|
+
},
|
|
6455
|
+
)
|
|
6456
|
+
if not any(
|
|
6457
|
+
"must stay inside the repository" in error
|
|
6458
|
+
and "must stay within the repository root" in error
|
|
6459
|
+
for error in shadow_anchor_errors
|
|
6460
|
+
):
|
|
6461
|
+
failures.append(Failure("adversarial-adoption", "shadow surface path-boundary errors must expose a stable repository anchor"))
|
|
6462
|
+
|
|
6425
6463
|
spec_contract_target = base / "spec-contract"
|
|
6426
6464
|
(spec_contract_target / ".loom/specs/INIT-0001").mkdir(parents=True)
|
|
6427
6465
|
(spec_contract_target / ".loom/specs/INIT-0001/spec.md").write_text("bootstrap spec\n", encoding="utf-8")
|
|
@@ -195,12 +195,12 @@ def resolve_repo_relative_path(target_root: Path, relative: str, *, label: str)
|
|
|
195
195
|
if candidate_raw.is_absolute():
|
|
196
196
|
return None, [f"{label} must be repo-relative, got absolute path: {locator}"]
|
|
197
197
|
if ".." in candidate_raw.parts:
|
|
198
|
-
return None, [f"{label} must stay
|
|
198
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
199
199
|
candidate = (target_root / candidate_raw).resolve()
|
|
200
200
|
try:
|
|
201
201
|
candidate.relative_to(target_root.resolve())
|
|
202
202
|
except ValueError:
|
|
203
|
-
return None, [f"{label} must stay
|
|
203
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
204
204
|
return candidate, []
|
|
205
205
|
|
|
206
206
|
|
|
@@ -481,8 +481,8 @@ def locator_boundary_error(raw_locator: object, *, label: str) -> str:
|
|
|
481
481
|
locator = raw_locator.strip()
|
|
482
482
|
locator_path = Path(locator)
|
|
483
483
|
if locator_path.is_absolute() or ".." in locator_path.parts:
|
|
484
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
485
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
484
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
485
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
486
486
|
|
|
487
487
|
|
|
488
488
|
def resolve_locator(root: Path, raw_locator: object) -> tuple[str | None, Path | None]:
|
|
@@ -6422,6 +6422,44 @@ def check_adversarial_adoption_fixture(root: Path) -> list[Failure]:
|
|
|
6422
6422
|
if payload.get("status") != "block" or not any("must stay inside" in error for error in errors):
|
|
6423
6423
|
failures.append(Failure("adversarial-adoption", "registry executable and manifest paths must not escape the runtime root"))
|
|
6424
6424
|
|
|
6425
|
+
fact_chain_escape = base / "fact-chain-error-anchor"
|
|
6426
|
+
(fact_chain_escape / ".loom/bootstrap").mkdir(parents=True)
|
|
6427
|
+
write_json(
|
|
6428
|
+
fact_chain_escape / ".loom/bootstrap/init-result.json",
|
|
6429
|
+
{
|
|
6430
|
+
"schema_version": "loom-init-output/v1",
|
|
6431
|
+
"fact_chain": {
|
|
6432
|
+
"read_entry": "python3 .loom/bin/loom_init.py fact-chain --target .",
|
|
6433
|
+
"mode": "work-item + recovery-entry + derived status-surface",
|
|
6434
|
+
"entry_points": {
|
|
6435
|
+
"current_item_id": "INIT-0001",
|
|
6436
|
+
"work_item": "../outside.md",
|
|
6437
|
+
"recovery_entry": ".loom/progress/INIT-0001.md",
|
|
6438
|
+
"status_surface": ".loom/status/current.md",
|
|
6439
|
+
}
|
|
6440
|
+
},
|
|
6441
|
+
},
|
|
6442
|
+
)
|
|
6443
|
+
_, errors = inspect_fact_chain(fact_chain_escape)
|
|
6444
|
+
if not any("must stay within the target root" in error for error in errors):
|
|
6445
|
+
failures.append(Failure("adversarial-adoption", "fact-chain path-boundary errors must expose a stable target-root anchor"))
|
|
6446
|
+
|
|
6447
|
+
shadow_anchor_errors = governance_surface_module.validate_shadow_surface(
|
|
6448
|
+
root=base,
|
|
6449
|
+
surface="review",
|
|
6450
|
+
entry={
|
|
6451
|
+
"summary": "review parity",
|
|
6452
|
+
"loom_locator": ".loom/shadow/review-loom.json",
|
|
6453
|
+
"repo_locator": "../outside.json",
|
|
6454
|
+
},
|
|
6455
|
+
)
|
|
6456
|
+
if not any(
|
|
6457
|
+
"must stay inside the repository" in error
|
|
6458
|
+
and "must stay within the repository root" in error
|
|
6459
|
+
for error in shadow_anchor_errors
|
|
6460
|
+
):
|
|
6461
|
+
failures.append(Failure("adversarial-adoption", "shadow surface path-boundary errors must expose a stable repository anchor"))
|
|
6462
|
+
|
|
6425
6463
|
spec_contract_target = base / "spec-contract"
|
|
6426
6464
|
(spec_contract_target / ".loom/specs/INIT-0001").mkdir(parents=True)
|
|
6427
6465
|
(spec_contract_target / ".loom/specs/INIT-0001/spec.md").write_text("bootstrap spec\n", encoding="utf-8")
|
|
@@ -195,12 +195,12 @@ def resolve_repo_relative_path(target_root: Path, relative: str, *, label: str)
|
|
|
195
195
|
if candidate_raw.is_absolute():
|
|
196
196
|
return None, [f"{label} must be repo-relative, got absolute path: {locator}"]
|
|
197
197
|
if ".." in candidate_raw.parts:
|
|
198
|
-
return None, [f"{label} must stay
|
|
198
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
199
199
|
candidate = (target_root / candidate_raw).resolve()
|
|
200
200
|
try:
|
|
201
201
|
candidate.relative_to(target_root.resolve())
|
|
202
202
|
except ValueError:
|
|
203
|
-
return None, [f"{label} must stay
|
|
203
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
204
204
|
return candidate, []
|
|
205
205
|
|
|
206
206
|
|
|
@@ -481,8 +481,8 @@ def locator_boundary_error(raw_locator: object, *, label: str) -> str:
|
|
|
481
481
|
locator = raw_locator.strip()
|
|
482
482
|
locator_path = Path(locator)
|
|
483
483
|
if locator_path.is_absolute() or ".." in locator_path.parts:
|
|
484
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
485
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
484
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
485
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
486
486
|
|
|
487
487
|
|
|
488
488
|
def resolve_locator(root: Path, raw_locator: object) -> tuple[str | None, Path | None]:
|
|
@@ -6422,6 +6422,44 @@ def check_adversarial_adoption_fixture(root: Path) -> list[Failure]:
|
|
|
6422
6422
|
if payload.get("status") != "block" or not any("must stay inside" in error for error in errors):
|
|
6423
6423
|
failures.append(Failure("adversarial-adoption", "registry executable and manifest paths must not escape the runtime root"))
|
|
6424
6424
|
|
|
6425
|
+
fact_chain_escape = base / "fact-chain-error-anchor"
|
|
6426
|
+
(fact_chain_escape / ".loom/bootstrap").mkdir(parents=True)
|
|
6427
|
+
write_json(
|
|
6428
|
+
fact_chain_escape / ".loom/bootstrap/init-result.json",
|
|
6429
|
+
{
|
|
6430
|
+
"schema_version": "loom-init-output/v1",
|
|
6431
|
+
"fact_chain": {
|
|
6432
|
+
"read_entry": "python3 .loom/bin/loom_init.py fact-chain --target .",
|
|
6433
|
+
"mode": "work-item + recovery-entry + derived status-surface",
|
|
6434
|
+
"entry_points": {
|
|
6435
|
+
"current_item_id": "INIT-0001",
|
|
6436
|
+
"work_item": "../outside.md",
|
|
6437
|
+
"recovery_entry": ".loom/progress/INIT-0001.md",
|
|
6438
|
+
"status_surface": ".loom/status/current.md",
|
|
6439
|
+
}
|
|
6440
|
+
},
|
|
6441
|
+
},
|
|
6442
|
+
)
|
|
6443
|
+
_, errors = inspect_fact_chain(fact_chain_escape)
|
|
6444
|
+
if not any("must stay within the target root" in error for error in errors):
|
|
6445
|
+
failures.append(Failure("adversarial-adoption", "fact-chain path-boundary errors must expose a stable target-root anchor"))
|
|
6446
|
+
|
|
6447
|
+
shadow_anchor_errors = governance_surface_module.validate_shadow_surface(
|
|
6448
|
+
root=base,
|
|
6449
|
+
surface="review",
|
|
6450
|
+
entry={
|
|
6451
|
+
"summary": "review parity",
|
|
6452
|
+
"loom_locator": ".loom/shadow/review-loom.json",
|
|
6453
|
+
"repo_locator": "../outside.json",
|
|
6454
|
+
},
|
|
6455
|
+
)
|
|
6456
|
+
if not any(
|
|
6457
|
+
"must stay inside the repository" in error
|
|
6458
|
+
and "must stay within the repository root" in error
|
|
6459
|
+
for error in shadow_anchor_errors
|
|
6460
|
+
):
|
|
6461
|
+
failures.append(Failure("adversarial-adoption", "shadow surface path-boundary errors must expose a stable repository anchor"))
|
|
6462
|
+
|
|
6425
6463
|
spec_contract_target = base / "spec-contract"
|
|
6426
6464
|
(spec_contract_target / ".loom/specs/INIT-0001").mkdir(parents=True)
|
|
6427
6465
|
(spec_contract_target / ".loom/specs/INIT-0001/spec.md").write_text("bootstrap spec\n", encoding="utf-8")
|
|
@@ -195,12 +195,12 @@ def resolve_repo_relative_path(target_root: Path, relative: str, *, label: str)
|
|
|
195
195
|
if candidate_raw.is_absolute():
|
|
196
196
|
return None, [f"{label} must be repo-relative, got absolute path: {locator}"]
|
|
197
197
|
if ".." in candidate_raw.parts:
|
|
198
|
-
return None, [f"{label} must stay
|
|
198
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
199
199
|
candidate = (target_root / candidate_raw).resolve()
|
|
200
200
|
try:
|
|
201
201
|
candidate.relative_to(target_root.resolve())
|
|
202
202
|
except ValueError:
|
|
203
|
-
return None, [f"{label} must stay
|
|
203
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
204
204
|
return candidate, []
|
|
205
205
|
|
|
206
206
|
|
|
@@ -481,8 +481,8 @@ def locator_boundary_error(raw_locator: object, *, label: str) -> str:
|
|
|
481
481
|
locator = raw_locator.strip()
|
|
482
482
|
locator_path = Path(locator)
|
|
483
483
|
if locator_path.is_absolute() or ".." in locator_path.parts:
|
|
484
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
485
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
484
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
485
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
486
486
|
|
|
487
487
|
|
|
488
488
|
def resolve_locator(root: Path, raw_locator: object) -> tuple[str | None, Path | None]:
|
|
@@ -6422,6 +6422,44 @@ def check_adversarial_adoption_fixture(root: Path) -> list[Failure]:
|
|
|
6422
6422
|
if payload.get("status") != "block" or not any("must stay inside" in error for error in errors):
|
|
6423
6423
|
failures.append(Failure("adversarial-adoption", "registry executable and manifest paths must not escape the runtime root"))
|
|
6424
6424
|
|
|
6425
|
+
fact_chain_escape = base / "fact-chain-error-anchor"
|
|
6426
|
+
(fact_chain_escape / ".loom/bootstrap").mkdir(parents=True)
|
|
6427
|
+
write_json(
|
|
6428
|
+
fact_chain_escape / ".loom/bootstrap/init-result.json",
|
|
6429
|
+
{
|
|
6430
|
+
"schema_version": "loom-init-output/v1",
|
|
6431
|
+
"fact_chain": {
|
|
6432
|
+
"read_entry": "python3 .loom/bin/loom_init.py fact-chain --target .",
|
|
6433
|
+
"mode": "work-item + recovery-entry + derived status-surface",
|
|
6434
|
+
"entry_points": {
|
|
6435
|
+
"current_item_id": "INIT-0001",
|
|
6436
|
+
"work_item": "../outside.md",
|
|
6437
|
+
"recovery_entry": ".loom/progress/INIT-0001.md",
|
|
6438
|
+
"status_surface": ".loom/status/current.md",
|
|
6439
|
+
}
|
|
6440
|
+
},
|
|
6441
|
+
},
|
|
6442
|
+
)
|
|
6443
|
+
_, errors = inspect_fact_chain(fact_chain_escape)
|
|
6444
|
+
if not any("must stay within the target root" in error for error in errors):
|
|
6445
|
+
failures.append(Failure("adversarial-adoption", "fact-chain path-boundary errors must expose a stable target-root anchor"))
|
|
6446
|
+
|
|
6447
|
+
shadow_anchor_errors = governance_surface_module.validate_shadow_surface(
|
|
6448
|
+
root=base,
|
|
6449
|
+
surface="review",
|
|
6450
|
+
entry={
|
|
6451
|
+
"summary": "review parity",
|
|
6452
|
+
"loom_locator": ".loom/shadow/review-loom.json",
|
|
6453
|
+
"repo_locator": "../outside.json",
|
|
6454
|
+
},
|
|
6455
|
+
)
|
|
6456
|
+
if not any(
|
|
6457
|
+
"must stay inside the repository" in error
|
|
6458
|
+
and "must stay within the repository root" in error
|
|
6459
|
+
for error in shadow_anchor_errors
|
|
6460
|
+
):
|
|
6461
|
+
failures.append(Failure("adversarial-adoption", "shadow surface path-boundary errors must expose a stable repository anchor"))
|
|
6462
|
+
|
|
6425
6463
|
spec_contract_target = base / "spec-contract"
|
|
6426
6464
|
(spec_contract_target / ".loom/specs/INIT-0001").mkdir(parents=True)
|
|
6427
6465
|
(spec_contract_target / ".loom/specs/INIT-0001/spec.md").write_text("bootstrap spec\n", encoding="utf-8")
|
|
@@ -195,12 +195,12 @@ def resolve_repo_relative_path(target_root: Path, relative: str, *, label: str)
|
|
|
195
195
|
if candidate_raw.is_absolute():
|
|
196
196
|
return None, [f"{label} must be repo-relative, got absolute path: {locator}"]
|
|
197
197
|
if ".." in candidate_raw.parts:
|
|
198
|
-
return None, [f"{label} must stay
|
|
198
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
199
199
|
candidate = (target_root / candidate_raw).resolve()
|
|
200
200
|
try:
|
|
201
201
|
candidate.relative_to(target_root.resolve())
|
|
202
202
|
except ValueError:
|
|
203
|
-
return None, [f"{label} must stay
|
|
203
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
204
204
|
return candidate, []
|
|
205
205
|
|
|
206
206
|
|
|
@@ -481,8 +481,8 @@ def locator_boundary_error(raw_locator: object, *, label: str) -> str:
|
|
|
481
481
|
locator = raw_locator.strip()
|
|
482
482
|
locator_path = Path(locator)
|
|
483
483
|
if locator_path.is_absolute() or ".." in locator_path.parts:
|
|
484
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
485
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
484
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
485
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
486
486
|
|
|
487
487
|
|
|
488
488
|
def resolve_locator(root: Path, raw_locator: object) -> tuple[str | None, Path | None]:
|
|
@@ -6422,6 +6422,44 @@ def check_adversarial_adoption_fixture(root: Path) -> list[Failure]:
|
|
|
6422
6422
|
if payload.get("status") != "block" or not any("must stay inside" in error for error in errors):
|
|
6423
6423
|
failures.append(Failure("adversarial-adoption", "registry executable and manifest paths must not escape the runtime root"))
|
|
6424
6424
|
|
|
6425
|
+
fact_chain_escape = base / "fact-chain-error-anchor"
|
|
6426
|
+
(fact_chain_escape / ".loom/bootstrap").mkdir(parents=True)
|
|
6427
|
+
write_json(
|
|
6428
|
+
fact_chain_escape / ".loom/bootstrap/init-result.json",
|
|
6429
|
+
{
|
|
6430
|
+
"schema_version": "loom-init-output/v1",
|
|
6431
|
+
"fact_chain": {
|
|
6432
|
+
"read_entry": "python3 .loom/bin/loom_init.py fact-chain --target .",
|
|
6433
|
+
"mode": "work-item + recovery-entry + derived status-surface",
|
|
6434
|
+
"entry_points": {
|
|
6435
|
+
"current_item_id": "INIT-0001",
|
|
6436
|
+
"work_item": "../outside.md",
|
|
6437
|
+
"recovery_entry": ".loom/progress/INIT-0001.md",
|
|
6438
|
+
"status_surface": ".loom/status/current.md",
|
|
6439
|
+
}
|
|
6440
|
+
},
|
|
6441
|
+
},
|
|
6442
|
+
)
|
|
6443
|
+
_, errors = inspect_fact_chain(fact_chain_escape)
|
|
6444
|
+
if not any("must stay within the target root" in error for error in errors):
|
|
6445
|
+
failures.append(Failure("adversarial-adoption", "fact-chain path-boundary errors must expose a stable target-root anchor"))
|
|
6446
|
+
|
|
6447
|
+
shadow_anchor_errors = governance_surface_module.validate_shadow_surface(
|
|
6448
|
+
root=base,
|
|
6449
|
+
surface="review",
|
|
6450
|
+
entry={
|
|
6451
|
+
"summary": "review parity",
|
|
6452
|
+
"loom_locator": ".loom/shadow/review-loom.json",
|
|
6453
|
+
"repo_locator": "../outside.json",
|
|
6454
|
+
},
|
|
6455
|
+
)
|
|
6456
|
+
if not any(
|
|
6457
|
+
"must stay inside the repository" in error
|
|
6458
|
+
and "must stay within the repository root" in error
|
|
6459
|
+
for error in shadow_anchor_errors
|
|
6460
|
+
):
|
|
6461
|
+
failures.append(Failure("adversarial-adoption", "shadow surface path-boundary errors must expose a stable repository anchor"))
|
|
6462
|
+
|
|
6425
6463
|
spec_contract_target = base / "spec-contract"
|
|
6426
6464
|
(spec_contract_target / ".loom/specs/INIT-0001").mkdir(parents=True)
|
|
6427
6465
|
(spec_contract_target / ".loom/specs/INIT-0001/spec.md").write_text("bootstrap spec\n", encoding="utf-8")
|
|
@@ -195,12 +195,12 @@ def resolve_repo_relative_path(target_root: Path, relative: str, *, label: str)
|
|
|
195
195
|
if candidate_raw.is_absolute():
|
|
196
196
|
return None, [f"{label} must be repo-relative, got absolute path: {locator}"]
|
|
197
197
|
if ".." in candidate_raw.parts:
|
|
198
|
-
return None, [f"{label} must stay
|
|
198
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
199
199
|
candidate = (target_root / candidate_raw).resolve()
|
|
200
200
|
try:
|
|
201
201
|
candidate.relative_to(target_root.resolve())
|
|
202
202
|
except ValueError:
|
|
203
|
-
return None, [f"{label} must stay
|
|
203
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
204
204
|
return candidate, []
|
|
205
205
|
|
|
206
206
|
|
|
@@ -481,8 +481,8 @@ def locator_boundary_error(raw_locator: object, *, label: str) -> str:
|
|
|
481
481
|
locator = raw_locator.strip()
|
|
482
482
|
locator_path = Path(locator)
|
|
483
483
|
if locator_path.is_absolute() or ".." in locator_path.parts:
|
|
484
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
485
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
484
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
485
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
486
486
|
|
|
487
487
|
|
|
488
488
|
def resolve_locator(root: Path, raw_locator: object) -> tuple[str | None, Path | None]:
|
|
@@ -6422,6 +6422,44 @@ def check_adversarial_adoption_fixture(root: Path) -> list[Failure]:
|
|
|
6422
6422
|
if payload.get("status") != "block" or not any("must stay inside" in error for error in errors):
|
|
6423
6423
|
failures.append(Failure("adversarial-adoption", "registry executable and manifest paths must not escape the runtime root"))
|
|
6424
6424
|
|
|
6425
|
+
fact_chain_escape = base / "fact-chain-error-anchor"
|
|
6426
|
+
(fact_chain_escape / ".loom/bootstrap").mkdir(parents=True)
|
|
6427
|
+
write_json(
|
|
6428
|
+
fact_chain_escape / ".loom/bootstrap/init-result.json",
|
|
6429
|
+
{
|
|
6430
|
+
"schema_version": "loom-init-output/v1",
|
|
6431
|
+
"fact_chain": {
|
|
6432
|
+
"read_entry": "python3 .loom/bin/loom_init.py fact-chain --target .",
|
|
6433
|
+
"mode": "work-item + recovery-entry + derived status-surface",
|
|
6434
|
+
"entry_points": {
|
|
6435
|
+
"current_item_id": "INIT-0001",
|
|
6436
|
+
"work_item": "../outside.md",
|
|
6437
|
+
"recovery_entry": ".loom/progress/INIT-0001.md",
|
|
6438
|
+
"status_surface": ".loom/status/current.md",
|
|
6439
|
+
}
|
|
6440
|
+
},
|
|
6441
|
+
},
|
|
6442
|
+
)
|
|
6443
|
+
_, errors = inspect_fact_chain(fact_chain_escape)
|
|
6444
|
+
if not any("must stay within the target root" in error for error in errors):
|
|
6445
|
+
failures.append(Failure("adversarial-adoption", "fact-chain path-boundary errors must expose a stable target-root anchor"))
|
|
6446
|
+
|
|
6447
|
+
shadow_anchor_errors = governance_surface_module.validate_shadow_surface(
|
|
6448
|
+
root=base,
|
|
6449
|
+
surface="review",
|
|
6450
|
+
entry={
|
|
6451
|
+
"summary": "review parity",
|
|
6452
|
+
"loom_locator": ".loom/shadow/review-loom.json",
|
|
6453
|
+
"repo_locator": "../outside.json",
|
|
6454
|
+
},
|
|
6455
|
+
)
|
|
6456
|
+
if not any(
|
|
6457
|
+
"must stay inside the repository" in error
|
|
6458
|
+
and "must stay within the repository root" in error
|
|
6459
|
+
for error in shadow_anchor_errors
|
|
6460
|
+
):
|
|
6461
|
+
failures.append(Failure("adversarial-adoption", "shadow surface path-boundary errors must expose a stable repository anchor"))
|
|
6462
|
+
|
|
6425
6463
|
spec_contract_target = base / "spec-contract"
|
|
6426
6464
|
(spec_contract_target / ".loom/specs/INIT-0001").mkdir(parents=True)
|
|
6427
6465
|
(spec_contract_target / ".loom/specs/INIT-0001/spec.md").write_text("bootstrap spec\n", encoding="utf-8")
|
|
@@ -195,12 +195,12 @@ def resolve_repo_relative_path(target_root: Path, relative: str, *, label: str)
|
|
|
195
195
|
if candidate_raw.is_absolute():
|
|
196
196
|
return None, [f"{label} must be repo-relative, got absolute path: {locator}"]
|
|
197
197
|
if ".." in candidate_raw.parts:
|
|
198
|
-
return None, [f"{label} must stay
|
|
198
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
199
199
|
candidate = (target_root / candidate_raw).resolve()
|
|
200
200
|
try:
|
|
201
201
|
candidate.relative_to(target_root.resolve())
|
|
202
202
|
except ValueError:
|
|
203
|
-
return None, [f"{label} must stay
|
|
203
|
+
return None, [f"{label} must stay within the target root and inside the target repository: {locator}"]
|
|
204
204
|
return candidate, []
|
|
205
205
|
|
|
206
206
|
|
|
@@ -481,8 +481,8 @@ def locator_boundary_error(raw_locator: object, *, label: str) -> str:
|
|
|
481
481
|
locator = raw_locator.strip()
|
|
482
482
|
locator_path = Path(locator)
|
|
483
483
|
if locator_path.is_absolute() or ".." in locator_path.parts:
|
|
484
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
485
|
-
return f"{label} must stay within the repository root: {locator}"
|
|
484
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
485
|
+
return f"{label} must stay within the repository root and must stay inside the repository: {locator}"
|
|
486
486
|
|
|
487
487
|
|
|
488
488
|
def resolve_locator(root: Path, raw_locator: object) -> tuple[str | None, Path | None]:
|
|
@@ -6422,6 +6422,44 @@ def check_adversarial_adoption_fixture(root: Path) -> list[Failure]:
|
|
|
6422
6422
|
if payload.get("status") != "block" or not any("must stay inside" in error for error in errors):
|
|
6423
6423
|
failures.append(Failure("adversarial-adoption", "registry executable and manifest paths must not escape the runtime root"))
|
|
6424
6424
|
|
|
6425
|
+
fact_chain_escape = base / "fact-chain-error-anchor"
|
|
6426
|
+
(fact_chain_escape / ".loom/bootstrap").mkdir(parents=True)
|
|
6427
|
+
write_json(
|
|
6428
|
+
fact_chain_escape / ".loom/bootstrap/init-result.json",
|
|
6429
|
+
{
|
|
6430
|
+
"schema_version": "loom-init-output/v1",
|
|
6431
|
+
"fact_chain": {
|
|
6432
|
+
"read_entry": "python3 .loom/bin/loom_init.py fact-chain --target .",
|
|
6433
|
+
"mode": "work-item + recovery-entry + derived status-surface",
|
|
6434
|
+
"entry_points": {
|
|
6435
|
+
"current_item_id": "INIT-0001",
|
|
6436
|
+
"work_item": "../outside.md",
|
|
6437
|
+
"recovery_entry": ".loom/progress/INIT-0001.md",
|
|
6438
|
+
"status_surface": ".loom/status/current.md",
|
|
6439
|
+
}
|
|
6440
|
+
},
|
|
6441
|
+
},
|
|
6442
|
+
)
|
|
6443
|
+
_, errors = inspect_fact_chain(fact_chain_escape)
|
|
6444
|
+
if not any("must stay within the target root" in error for error in errors):
|
|
6445
|
+
failures.append(Failure("adversarial-adoption", "fact-chain path-boundary errors must expose a stable target-root anchor"))
|
|
6446
|
+
|
|
6447
|
+
shadow_anchor_errors = governance_surface_module.validate_shadow_surface(
|
|
6448
|
+
root=base,
|
|
6449
|
+
surface="review",
|
|
6450
|
+
entry={
|
|
6451
|
+
"summary": "review parity",
|
|
6452
|
+
"loom_locator": ".loom/shadow/review-loom.json",
|
|
6453
|
+
"repo_locator": "../outside.json",
|
|
6454
|
+
},
|
|
6455
|
+
)
|
|
6456
|
+
if not any(
|
|
6457
|
+
"must stay inside the repository" in error
|
|
6458
|
+
and "must stay within the repository root" in error
|
|
6459
|
+
for error in shadow_anchor_errors
|
|
6460
|
+
):
|
|
6461
|
+
failures.append(Failure("adversarial-adoption", "shadow surface path-boundary errors must expose a stable repository anchor"))
|
|
6462
|
+
|
|
6425
6463
|
spec_contract_target = base / "spec-contract"
|
|
6426
6464
|
(spec_contract_target / ".loom/specs/INIT-0001").mkdir(parents=True)
|
|
6427
6465
|
(spec_contract_target / ".loom/specs/INIT-0001/spec.md").write_text("bootstrap spec\n", encoding="utf-8")
|