Why: Replace repeated submodule source pointers with consumer-owned language versions and fixed application sources, keeping independent repository edits and existing branches intact. Evidence: SELF task receipts contain startup/sync evidence, real Go and npm consumption, Native overlay/unlink, safe transition/ref preservation, credential boundary and historical build regressions. Exact committed full composition and RDM checks follow this checkpoint; formal acceptance and GATE CI remain pending. Impact: Add isolated build/test composition, source provenance and safe owner refresh, adapt governance and service build callers, remove replaced index links while retaining original Git metadata, and adopt reusable dependency standards. Refs: Documents approved dependency-workspace r1/R1-R15 and U1-U7 implementation plan; feature/dependency-workspace task card.
53 lines
2.6 KiB
Python
53 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Resolve governance inputs from a formal source map or the owner's checkout."""
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import re
|
|
import sys
|
|
|
|
LEGACY = {"Agent-System-Backend": "modules/backend", "Agent-System-Frontend": "modules/frontend",
|
|
"Agent-System-Core": "modules/core", "Agent-System-UI": "modules/ui",
|
|
"Agent-Native": "deps/agent-native", "Agent-Intent": "deps/agent-intent", "Agent-Squad": "deps/agent-squad"}
|
|
SHA = re.compile(r"[0-9a-f]{40}\Z")
|
|
|
|
|
|
def source_path(root, name):
|
|
if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_-]*", name):
|
|
raise ValueError("invalid component identifier")
|
|
marker = os.environ.get("COMPOSITION_SOURCE_MAP")
|
|
if not marker:
|
|
relative = ".workspace/" + name if (root / "components.json").exists() else LEGACY[name]
|
|
path = root / relative
|
|
else:
|
|
source_map = Path(marker)
|
|
if not source_map.is_absolute() or source_map.is_symlink() or not source_map.is_file():
|
|
raise ValueError("composition source map must be an absolute regular file")
|
|
document = json.loads(source_map.read_text())
|
|
if document.get("schema") != 1 or not SHA.fullmatch(str(document.get("root_commit", ""))):
|
|
raise ValueError("invalid composition source map identity")
|
|
manifest = json.loads((root / "components.json").read_text())
|
|
declared = [entry for entry in manifest["components"] if entry.get("id") == name]
|
|
item = document.get("components", {}).get(name)
|
|
if len(declared) != 1 or not isinstance(item, dict) or item.get("repo") != declared[0].get("repo") or not SHA.fullmatch(str(item.get("commit", ""))):
|
|
raise ValueError("invalid isolated component identity: " + name)
|
|
locked = json.loads((root / "components.lock.json").read_text())["components"].get(name)
|
|
if locked and item["commit"] != locked["commit"]:
|
|
raise ValueError("isolated component differs from locked source: " + name)
|
|
path = Path(item.get("path", ""))
|
|
if not path.is_absolute():
|
|
raise ValueError("isolated component path must be absolute: " + name)
|
|
if not path.is_dir() or path.resolve() != path.absolute():
|
|
raise ValueError("component source is missing or traverses a symbolic link: " + name)
|
|
return path
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
if len(sys.argv) != 2:
|
|
raise ValueError("usage: component-source.py <component-id>")
|
|
print(source_path(Path(__file__).resolve().parents[1], sys.argv[1]))
|
|
except (OSError, ValueError, KeyError, TypeError) as error:
|
|
print("component-source: " + str(error), file=sys.stderr)
|
|
raise SystemExit(1)
|