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.
142 lines
10 KiB
Python
142 lines
10 KiB
Python
"""Local named checks prepare fixed sources and retain edits with real Go/Git."""
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import shutil
|
|
import subprocess
|
|
import tempfile
|
|
import unittest
|
|
|
|
SOURCE = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
@unittest.skipUnless(shutil.which("go"), "Go required")
|
|
class ComponentCheckTests(unittest.TestCase):
|
|
def setUp(self):
|
|
self.tmp = tempfile.TemporaryDirectory(prefix="component-check-")
|
|
self.addCleanup(self.tmp.cleanup)
|
|
self.base = Path(self.tmp.name)
|
|
self.root = self.base / "dev"
|
|
self.root.mkdir()
|
|
self.env = os.environ.copy()
|
|
for key in list(self.env):
|
|
if key.startswith("GIT_CONFIG_") or key in ("GIT_DIR", "GIT_WORK_TREE", "GIT_INDEX_FILE", "GOWORK", "COMPOSITION_SOURCE_MAP", "CI_DEPENDENCY_MIRRORS"):
|
|
self.env.pop(key, None)
|
|
self.env.update(GIT_CONFIG_NOSYSTEM="1", GIT_CONFIG_GLOBAL="/dev/null", GIT_ALLOW_PROTOCOL="file",
|
|
GIT_AUTHOR_NAME="Checks", GIT_AUTHOR_EMAIL="check@example.invalid",
|
|
GIT_COMMITTER_NAME="Checks", GIT_COMMITTER_EMAIL="check@example.invalid",
|
|
GOTOOLCHAIN="local", GOPROXY="off", GOSUMDB="off")
|
|
self.call(self.root, "git", "init", "--initial-branch=main")
|
|
shutil.copytree(SOURCE / "scripts", self.root / "scripts")
|
|
shutil.copyfile(SOURCE / "Makefile", self.root / "Makefile")
|
|
(self.root / ".gitignore").write_text(".workspace/\ngo.work\ngo.work.sum\ntests/integration/multi-instance/.build/\n")
|
|
app = self.base / "backend"
|
|
app.mkdir()
|
|
self.call(app, "git", "init", "--initial-branch=main")
|
|
(app / "go.mod").write_text("module example.com/backend\n\ngo 1.23\n")
|
|
(app / "source.go").write_text("package backend\nfunc Value() string {return \"fixed\"}\n")
|
|
(app / "source_test.go").write_text('package backend\nimport "testing"\nfunc TestValue(t *testing.T) {if Value() != "fixed" {t.Fatal(Value())}}\n')
|
|
(app / "cmd/agent-system").mkdir(parents=True)
|
|
(app / "cmd/agent-system/main.go").write_text('package main\nimport "fmt"\nfunc main(){fmt.Print("fixed-binary")}\n')
|
|
self.call(app, "git", "add", ".")
|
|
self.call(app, "git", "commit", "-m", "Fixed Backend")
|
|
sha = self.call(app, "git", "rev-parse", "HEAD").stdout.strip()
|
|
manifest = {"schema": 1, "components": [{"id": "Agent-System-Backend", "repo": str(app), "path": ".workspace/Agent-System-Backend", "legacy_path": "modules/backend", "role": "application", "modules": [{"path": "example.com/backend", "directory": "."}], "target": "main"}]}
|
|
(self.root / "components.json").write_text(json.dumps(manifest))
|
|
(self.root / "components.lock.json").write_text(json.dumps({"schema": 1, "components": {"Agent-System-Backend": {"commit": sha}}}))
|
|
self.call(self.root, "git", "add", ".")
|
|
self.call(self.root, "git", "commit", "-m", "Fixed Dev")
|
|
|
|
def call(self, cwd, *args, check=True, env=None):
|
|
result = subprocess.run(args, cwd=cwd, env=env or self.env, text=True,
|
|
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, timeout=90)
|
|
if check:
|
|
self.assertEqual(result.returncode, 0, result.stdout)
|
|
return result
|
|
|
|
def test_backend_check_prepares_fixed_source_and_replays_owner_edits(self):
|
|
result = self.call(self.root, "make", "test-backend")
|
|
self.assertIn("GOWORK=off", result.stdout)
|
|
child = self.root / ".workspace/Agent-System-Backend"
|
|
self.assertEqual((child / "source.go").read_text(), 'package backend\nfunc Value() string {return "fixed"}\n')
|
|
self.call(self.root, "python3", "scripts/workspace.py", "--root", str(self.root), "edit", "--name", "Agent-System-Backend", "--branch", "feature/owned")
|
|
(child / "source.go").write_text('package backend\nfunc Value() string {return "owner-edit"}\n')
|
|
result = self.call(self.root, "make", "test-backend", check=False)
|
|
self.assertNotEqual(result.returncode, 0, result.stdout)
|
|
self.assertIn("owner-edit", result.stdout)
|
|
self.assertEqual(self.call(child, "git", "branch", "--show-current").stdout.strip(), "feature/owned")
|
|
self.assertIn('"owner-edit"', (child / "source.go").read_text())
|
|
|
|
def test_pg_gate_requires_environment_and_forwards_it_to_real_go_tests(self):
|
|
result = self.call(self.root, "make", "test-backend-pg", check=False)
|
|
self.assertNotEqual(result.returncode, 0, result.stdout)
|
|
self.assertFalse((self.root / ".workspace").exists())
|
|
self.call(self.root, "python3", "scripts/workspace.py", "--root", str(self.root), "edit", "--name", "Agent-System-Backend", "--branch", "feature/pg-gate")
|
|
child = self.root / ".workspace/Agent-System-Backend"
|
|
(child / "pg_gate_test.go").write_text('package backend\nimport("os";"testing")\nfunc TestGateEnv(t *testing.T){if os.Getenv("AGENT_PG_TEST_DSN")!="fixture-dsn"||os.Getenv("AGENT_REDIS_TEST_ADDR")!="fixture-redis"{t.Fatal("gate environment missing")}}\n')
|
|
self.call(self.root, "make", "test-backend-pg", env=self.env | {"AGENT_PG_TEST_DSN": "fixture-dsn", "AGENT_REDIS_TEST_ADDR": "fixture-redis"})
|
|
|
|
def test_multi_instance_binary_is_built_inside_dev_root_and_reached_by_suite(self):
|
|
suite = self.root / "tests/integration/multi-instance"
|
|
suite.mkdir(parents=True)
|
|
(suite / "go.mod").write_text("module example.com/multi\n\ngo 1.23\n")
|
|
(suite / "binary_test.go").write_text('package multi\nimport("os";"os/exec";"testing")\nfunc TestBinary(t *testing.T){b,e:=exec.Command(os.Getenv("AGENT_BIN")).Output();if e!=nil||string(b)!="fixed-binary"{t.Fatalf("%s %v",b,e)}}\n')
|
|
self.call(self.root, "make", "test-multi-instance", env=self.env | {"AGENT_PG_TEST_DSN": "fixture-dsn"})
|
|
self.assertTrue((suite / ".build/agent-system").is_file())
|
|
self.assertFalse((self.root / ".workspace/tests").exists())
|
|
|
|
def test_new_pin_gate_validates_fixed_sources_and_rejects_local_replaces(self):
|
|
self.call(self.root, "python3", "scripts/workspace.py", "--root", str(self.root), "prepare")
|
|
self.call(self.root, "bash", "scripts/check-pins.sh")
|
|
child = self.root / ".workspace/Agent-System-Backend"
|
|
(child / "go.mod").write_text((child / "go.mod").read_text() + "\nreplace example.com/dependency => ../local\n")
|
|
result = self.call(self.root, "bash", "scripts/check-pins.sh", check=False)
|
|
self.assertNotEqual(result.returncode, 0, result.stdout)
|
|
self.assertIn("local replace", result.stdout)
|
|
|
|
def test_registered_private_transport_reaches_real_go_process_without_global_change(self):
|
|
manifest = json.loads((self.root / "components.json").read_text())
|
|
manifest["transport"] = {"go_private": ["private.example.test"], "git_rewrites": [{"from": "https://private.example.test/", "to": self.base.as_uri() + "/"}]}
|
|
(self.root / "components.json").write_text(json.dumps(manifest))
|
|
global_config = self.base / "global.gitconfig"
|
|
global_config.write_text("[user]\n name = existing-user\n")
|
|
env = self.env | {"GIT_CONFIG_GLOBAL": str(global_config)}
|
|
self.call(self.root, "python3", "scripts/workspace.py", "--root", str(self.root), "edit", "--name", "Agent-System-Backend", "--branch", "feature/transport", env=env)
|
|
child = self.root / ".workspace/Agent-System-Backend"
|
|
(child / "transport_test.go").write_text('package backend\nimport("os";"testing")\nfunc TestTransport(t *testing.T){if os.Getenv("GOPRIVATE")!="private.example.test"||os.Getenv("GOWORK")!="off"||os.Getenv("GIT_CONFIG_COUNT")==""{t.Fatal("process-scoped transport missing")}}\n')
|
|
before = global_config.read_bytes()
|
|
self.call(self.root, "make", "test-backend", env=env)
|
|
self.assertEqual(global_config.read_bytes(), before)
|
|
|
|
def test_explicit_overlay_uses_registered_workspace_and_preserves_default_version_mode(self):
|
|
self.call(self.root, "python3", "scripts/workspace.py", "--root", str(self.root), "edit", "--name", "Agent-System-Backend", "--branch", "feature/overlay")
|
|
child = self.root / ".workspace/Agent-System-Backend"
|
|
work = self.root / "go.work"
|
|
(child / "overlay_test.go").write_text('package backend\nimport("os";"testing")\nfunc TestOverlay(t *testing.T){if os.Getenv("GOWORK")!="' + str(work) + '"{t.Fatal("registered overlay missing")}}\n')
|
|
self.call(self.root, "make", "test-backend", "LOCAL_OVERLAY=1")
|
|
default = self.call(self.root, "make", "test-backend", check=False)
|
|
self.assertNotEqual(default.returncode, 0, default.stdout)
|
|
self.assertIn("registered overlay missing", default.stdout)
|
|
self.assertTrue(work.is_file())
|
|
|
|
def test_make_pin_gate_uses_map_in_gitless_formal_root_and_ignores_external_rdm_identity(self):
|
|
self.call(self.root, "python3", "scripts/workspace.py", "--root", str(self.root), "prepare")
|
|
formal = self.base / "formal"
|
|
formal.mkdir()
|
|
shutil.copytree(self.root / "scripts", formal / "scripts")
|
|
for name in ("Makefile", "components.json", "components.lock.json"):
|
|
shutil.copy2(self.root / name, formal / name)
|
|
entry = json.loads((self.root / "components.json").read_text())["components"][0]
|
|
locked = json.loads((self.root / "components.lock.json").read_text())["components"][entry["id"]]["commit"]
|
|
mapping = {"schema": 1, "root_commit": self.call(self.root, "git", "rev-parse", "HEAD").stdout.strip(),
|
|
"components": {entry["id"]: {"path": str(self.root / entry["path"]), "repo": entry["repo"], "commit": locked},
|
|
"Agent-System-RDM": {"path": str(self.base / "external-rdm"), "repo": "external registered by composer", "commit": locked}}}
|
|
source_map = self.base / "map.json"
|
|
source_map.write_text(json.dumps(mapping))
|
|
self.call(formal, "make", "test-pins", env=self.env | {"COMPOSITION_SOURCE_MAP": str(source_map)})
|
|
self.assertFalse((formal / ".workspace").exists())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|