Files
Agent-System-Dev/tests/test_composition.py
T
weichen 01b7799663 Keep offline package verification reproducible with cold caches (U5)
Why:
An immutable npm lock caches tarballs but packed consumers also require resolver metadata before candidate execution.

Evidence:
SELF host replay passed 57 composition and CI credential cases; real npm 10 and 11 cold-cache consumers passed without lock changes.

Impact:
Acquire only installed exact-version npmjs metadata with clean config, preserve cache paths for offline execution, adopt the repaired Frontend source and record immutable CI fixtures.

Refs:
R6-R8, R14; dependency-workspace U4/U5; UI 63d289e and Frontend 5467517
2026-10-14 01:44:49 +00:00

701 lines
44 KiB
Python

"""Real Git/npm/Go fixtures for immutable product composition."""
import base64
import hashlib
import importlib.util
import io
import json
import os
from pathlib import Path
import shutil
import subprocess
import sys
import tarfile
import tempfile
import threading
import unittest
import zipfile
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
SCRIPT = Path(__file__).resolve().parents[1] / "scripts/build-composition.py"
RDM_SCRIPTS = Path(os.environ.get("COMPOSITION_RDM_SOURCE", str(SCRIPT.parent.parent / ".migration/Agent-System-RDM")))
LEGACY_PRODUCT = Path(__file__).resolve().parent / "fixtures/rdm-legacy-product.sh"
class LocalNpmRegistry:
"""Real npm cache/registry traffic with no public-network dependency."""
name = "composition-cold-fixture"
def __init__(self, base, env):
self.base, self.env = base, env
self.requests = []
self.tarballs = {}
self.integrities = {}
for version in ("1.0.0", "1.0.1"):
payload = json.dumps({"name": self.name, "version": version,
"scripts": {"install": "node -e 'process.exit(91)'"}}).encode()
stream = io.BytesIO()
with tarfile.open(fileobj=stream, mode="w:gz") as archive:
entry = tarfile.TarInfo("package/package.json")
entry.size = len(payload)
archive.addfile(entry, io.BytesIO(payload))
self.tarballs[version] = stream.getvalue()
self.integrities[version] = "sha512-" + base64.b64encode(hashlib.sha512(stream.getvalue()).digest()).decode()
registry = self
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
registry.requests.append((self.path, self.headers.get("Authorization")))
if self.path == "/" + registry.name:
versions = {v: {"name": registry.name, "version": v, "dist": {
"tarball": registry.url + "/" + registry.name + "/-/" + v + ".tgz",
"integrity": registry.integrities[v]}} for v in registry.tarballs}
body = json.dumps({"name": registry.name, "dist-tags": {"latest": "1.0.1"}, "versions": versions}).encode()
content_type = "application/json"
else:
version = self.path.rsplit("/", 1)[-1].removesuffix(".tgz")
if version not in registry.tarballs:
self.send_error(404)
return
body, content_type = registry.tarballs[version], "application/octet-stream"
self.send_response(200)
self.send_header("Content-Type", content_type)
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def log_message(self, *args):
pass
self.server = ThreadingHTTPServer(("127.0.0.1", 0), Handler)
self.url = "http://127.0.0.1:" + str(self.server.server_port)
self.thread = threading.Thread(target=self.server.serve_forever, daemon=True)
self.thread.start()
self.cache = base / "cold-npm-cache"
self.global_config = base / "empty-npm-globalrc"
self.global_config.write_text("")
self.home = base / "cold-home"
self.home.mkdir()
self.tools = base / "npm-tools"
self.tools.mkdir()
self.calls = base / "npm-calls.jsonl"
npm = shutil.which("npm")
wrapper = self.tools / "npm"
wrapper.write_text("#!" + sys.executable + "\n" +
"import json, os, sys\nfrom pathlib import Path\nargs = sys.argv[1:]\n" +
"with Path(" + repr(str(self.calls)) + ").open('a') as output:\n" +
" output.write(json.dumps({'args': args, 'credential_keys': [k for k in os.environ if any(w in k.upper() for w in ('TOKEN', 'SECRET', 'PASSWORD'))]}) + '\\n')\n" +
"if args[:2] == ['cache', 'add'] and args[2].startswith(" + repr(self.name + "@") + "):\n" +
" args = [a.replace('https://registry.npmjs.org', " + repr(self.url) + ") for a in args]\n" +
"if args[:1] == ['ci']: args.append('--offline')\n" +
"os.execv(" + repr(npm) + ", [" + repr(npm) + ", *args])\n")
wrapper.chmod(0o755)
self.env = env | {"HOME": str(self.home), "npm_config_cache": str(self.cache),
"PATH": str(self.tools) + os.pathsep + env["PATH"]}
# Seed only the locked tarball, exactly the state produced by npm ci.
tarball = base / "locked.tgz"
tarball.write_bytes(self.tarballs["1.0.0"])
subprocess.run([npm, "cache", "add", str(tarball), "--ignore-scripts", "--userconfig=/dev/null",
"--globalconfig=" + str(self.global_config)], env=self.env, check=True, capture_output=True)
def close(self):
self.server.shutdown()
self.server.server_close()
self.thread.join()
def manifests(self, source):
source.mkdir(exist_ok=True)
manifest = {"name": "fixture", "version": "1.0.0", "dependencies": {self.name: "1.0.0"}}
(source / "package.json").write_text(json.dumps(manifest))
lock = {"name": "fixture", "version": "1.0.0", "lockfileVersion": 3, "requires": True,
"packages": {"": manifest, "node_modules/" + self.name: {
"version": "1.0.0", "resolved": "https://registry.npmjs.org/" + self.name + "/-/1.0.0.tgz",
"integrity": self.integrities["1.0.0"]}}}
(source / "package-lock.json").write_text(json.dumps(lock))
return (source / "package-lock.json").read_bytes()
def consumer(self, directory, env=None):
directory.mkdir(exist_ok=True)
(directory / "package.json").write_text(json.dumps({"dependencies": {self.name: "1.0.0"}}))
return subprocess.run(["npm", "install", "--offline", "--ignore-scripts", "--no-audit", "--no-fund",
"--registry=" + self.url, "--userconfig=/dev/null", "--globalconfig=" + str(self.global_config)],
cwd=directory, env=env or self.env, capture_output=True, text=True)
@unittest.skipUnless(shutil.which("npm"), "npm required")
class NpmAcquisitionTests(unittest.TestCase):
def setUp(self):
self.temporary = tempfile.TemporaryDirectory(prefix="composition-cold-npm-")
self.addCleanup(self.temporary.cleanup)
self.base = Path(self.temporary.name)
self.registry = LocalNpmRegistry(self.base, os.environ.copy())
self.addCleanup(self.registry.close)
spec = importlib.util.spec_from_file_location("cold_npm_composer", SCRIPT)
self.composer = importlib.util.module_from_spec(spec)
spec.loader.exec_module(self.composer)
def test_locked_metadata_is_acquired_before_offline_consumer_without_credentials(self):
source = self.base / "source"
original = self.registry.manifests(source)
red = self.registry.consumer(self.base / "before")
self.assertNotEqual(red.returncode, 0)
self.assertIn("ENOTCACHED", red.stderr)
self.composer.npm_dependencies(source, {}, self.registry.env | {"GITEA_TOKEN": "synthetic-secret"})
self.assertEqual((source / "package-lock.json").read_bytes(), original)
green = self.registry.consumer(self.base / "after", self.composer.execution_environment(self.registry.env))
self.assertEqual(green.returncode, 0, green.stdout + green.stderr)
actual = json.loads((self.base / "after/node_modules" / self.registry.name / "package.json").read_text())
self.assertEqual(actual["version"], "1.0.0")
calls = [json.loads(line) for line in self.registry.calls.read_text().splitlines()]
metadata = [call for call in calls if call["args"][:2] == ["cache", "add"]]
self.assertTrue(metadata, "tarball acquisition alone does not populate offline resolver metadata")
self.assertEqual(metadata[0]["args"][2], self.registry.name + "@1.0.0")
self.assertFalse(metadata[0]["credential_keys"])
self.assertTrue(self.registry.requests)
self.assertTrue(all(auth is None for _, auth in self.registry.requests))
def test_unreviewed_tarball_source_is_refused_before_acquisition(self):
source = self.base / "source"
self.registry.manifests(source)
path = source / "package-lock.json"
lock = json.loads(path.read_text())
lock["packages"]["node_modules/" + self.registry.name]["resolved"] = self.registry.url + "/untrusted.tgz"
path.write_text(json.dumps(lock))
with self.assertRaisesRegex(self.composer.CompositionError, "reviewed public registry"):
self.composer.npm_dependencies(source, {}, self.registry.env | {"GITEA_TOKEN": "synthetic-secret"})
self.assertFalse(self.registry.requests)
self.assertFalse(self.registry.calls.exists())
@unittest.skipUnless(all(shutil.which(c) for c in ("git", "go", "node", "npm")), "Git/Go/Node/npm required")
class CompositionTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory(prefix="composition-test-")
self.addCleanup(self.temp.cleanup)
self.base = Path(self.temp.name)
self.root = self.base / "dev"
self.backend = self.base / "backend"
self.frontend = self.base / "frontend"
self.out = self.base / "output"
self.env = os.environ.copy()
self.env.update(GOWORK="off", GOPROXY="off", GOSUMDB="off", GOTOOLCHAIN="local")
self.env.pop("GOFLAGS", None)
for repo in (self.root, self.backend, self.frontend):
repo.mkdir()
self.run_command(["git", "init", "-q", "-b", "main"], repo)
self.run_command(["git", "config", "user.email", "fixture@example.invalid"], repo)
self.run_command(["git", "config", "user.name", "Composition Fixture"], repo)
self.write(self.backend, "go.mod", "module example.com/backend\n\ngo 1.23\n")
self.write(self.backend, "web/dist/.gitkeep", "")
self.write(self.backend, "web/embed.go", '''package web
import "embed"
//go:embed all:dist
var Files embed.FS
func Page() string { b, _ := Files.ReadFile("dist/index.html"); return string(b) }
''')
self.write(self.backend, "cmd/agent-system/main.go", '''package main
import ("fmt"; "os"; "example.com/backend/web")
var version = "fixture-dev"
func main() { if len(os.Args)>1 && os.Args[1]=="version" {fmt.Print(version)} else {fmt.Print(web.Page())} }
''')
self.write(self.backend, "cmd/storage-migrate/main.go", '''package main
import "fmt"
func main() { fmt.Print("migration-tool") }
''')
self.write(self.backend, "web/embed_test.go", '''package web
import "testing"
func TestProduct(t *testing.T) { if Page() != "immutable-page" { t.Fatalf("unexpected page: %q", Page()) } }
''')
self.backend_sha = self.commit(self.backend)
self.write(self.frontend, "package.json", json.dumps({
"name": "composition-fixture", "version": "1.0.0", "private": True,
"scripts": {"build": "node build.cjs", "test": "node test.cjs", "postinstall": "node -e \"process.exit(91)\""},
}))
self.write(self.frontend, "build.cjs", '''const fs = require('node:fs');
if (process.env.GITEA_TOKEN || process.env.SSH_AUTH_SOCK || process.env.GIT_CONFIG_COUNT) process.exit(90);
fs.mkdirSync('dist/assets', { recursive: true });
fs.writeFileSync('dist/index.html', 'immutable-page');
fs.writeFileSync('dist/assets/main.js', 'console.log("fixed")');
''')
self.write(self.frontend, "test.cjs", '''const fs = require('node:fs');
if (fs.readFileSync('dist/index.html', 'utf8') !== 'immutable-page') process.exit(92);
''')
self.run_command(["npm", "install", "--package-lock-only", "--ignore-scripts", "--no-audit", "--no-fund"], self.frontend)
self.frontend_sha = self.commit(self.frontend)
self.manifest = {"schema": 1, "components": [
{"id": "Agent-System-Backend", "repo": str(self.backend), "path": ".workspace/Agent-System-Backend", "role": "application", "modules": [{"path": "example.com/backend", "directory": "."}], "target": "main"},
{"id": "Agent-System-Frontend", "repo": str(self.frontend), "path": ".workspace/Agent-System-Frontend", "role": "application", "modules": [], "target": "main"},
]}
self.lock = {"schema": 1, "components": {
"Agent-System-Backend": {"commit": self.backend_sha},
"Agent-System-Frontend": {"commit": self.frontend_sha},
}}
self.save_inputs()
self.root_sha = self.commit(self.root)
def write(self, repo, path, value):
destination = repo / path
destination.parent.mkdir(parents=True, exist_ok=True)
destination.write_text(value)
def run_command(self, command, cwd=None, env=None, check=True):
result = subprocess.run(command, cwd=cwd, env=env or self.env, text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
if check:
self.assertEqual(result.returncode, 0, result.stdout)
return result
def commit(self, repo):
self.run_command(["git", "add", "."], repo)
self.run_command(["git", "commit", "-qm", "Fixture"], repo)
return self.run_command(["git", "rev-parse", "HEAD"], repo).stdout.strip()
def save_inputs(self):
self.write(self.root, "components.json", json.dumps(self.manifest))
self.write(self.root, "components.lock.json", json.dumps(self.lock))
def compose(self, target="build", extra=(), env=None):
return self.run_command([sys.executable, "-B", str(SCRIPT), "--root", str(self.root), "--target", target, "--output", str(self.out), *extra], env=env, check=False)
def acquisition_guard(self, env, *, mark_frontend=True):
"""Forward to real tools, refusing acquisition after candidate execution."""
marker = self.base / "candidate-executed"
tools = self.base / "guarded-tools"
tools.mkdir()
for name in ("git", "go", "npm"):
executable = shutil.which(name)
wrapper = tools / name
wrapper.write_text("#!" + sys.executable + "\n" + '''import os, pathlib, sys
args = sys.argv[1:]
name = pathlib.Path(sys.argv[0]).name
acquisition = (name == 'git' and args and args[0] in {'clone', 'fetch', 'archive'}
or name == 'go' and args and (args[0] == 'mod' or args[0] == 'list')
or name == 'npm' and args and (args[0] in {'ci', 'install'} or args[:2] == ['cache', 'add']))
if acquisition and pathlib.Path(os.environ['COMPOSITION_EXEC_MARKER']).exists():
print('acquisition-after-execution: ' + name + ' ' + ' '.join(args[:2]), file=sys.stderr)
sys.exit(86)
''' + "os.execv(" + repr(executable) + ", [" + repr(executable) + ", *args])\n")
wrapper.chmod(0o755)
if mark_frontend:
self.write(self.frontend, "build.cjs", (self.frontend / "build.cjs").read_text()
+ "\nrequire('node:fs').writeFileSync(process.env.COMPOSITION_EXEC_MARKER, 'frontend-executed')\n")
self.lock["components"]["Agent-System-Frontend"]["commit"] = self.commit(self.frontend)
self.save_inputs()
self.commit(self.root)
return env | {"PATH": str(tools) + os.pathsep + env["PATH"],
"COMPOSITION_EXEC_MARKER": str(marker), "GITEA_TOKEN": "synthetic-phase-token"}
def test_all_product_acquisition_precedes_candidate_execution(self):
self.test_rdm_vendored_remote_backend_embeds_assets_without_mutating_module_cache()
self.write(self.root, "plugins/example/plugin.json", '{"name":"fixed-plugin"}')
self.commit(self.root)
env = self.acquisition_guard(self.env | {"GOPROXY": (self.base / "proxy").as_uri(),
"GOMODCACHE": str(self.base / "module-cache")})
result = self.compose(extra=("--rdm-source", str(self.base / "rdm")), env=env)
self.assertEqual(result.returncode, 0, result.stdout)
self.assertEqual((self.base / "candidate-executed").read_text(), "frontend-executed")
self.assertEqual(self.run_command([str(self.out / "agent-system-rdm-product")]).stdout, "immutable-page")
self.assertEqual(self.run_command([str(self.out / "agent-system-admin")]).stdout, "immutable-page")
self.assertEqual((self.out / "plugins/example/plugin.json").read_text(), '{"name":"fixed-plugin"}')
def test_fixed_commits_embed_assets_without_touching_developer_checkout(self):
# Reading working trees or allowing go.work/npm overlays would produce DIRTY or fail.
self.write(self.backend, "web/dist/index.html", "DIRTY")
self.write(self.backend, "cmd/agent-system/main.go", "invalid local Go")
self.write(self.frontend, "build.cjs", "throw new Error('dirty local frontend')")
self.write(self.root, "go.work", "invalid developer workspace")
self.write(self.root, ".workspace/Agent-System-Frontend/package.json", '{"dependencies":{"bad":"file:/missing"}}')
env = self.env | {"GITEA_TOKEN": "fixture-secret", "SSH_AUTH_SOCK": "/missing-agent", "GIT_CONFIG_COUNT": "1", "GIT_CONFIG_KEY_0": "credential.helper", "GIT_CONFIG_VALUE_0": "bad-helper"}
result = self.compose(env=env)
self.assertEqual(result.returncode, 0, result.stdout)
self.assertEqual(self.run_command([str(self.out / "agent-system")]).stdout, "immutable-page")
self.assertEqual(self.run_command([str(self.out / "storage-migrate")]).stdout, "migration-tool")
self.assertEqual((self.backend / "web/dist/index.html").read_text(), "DIRTY")
resolved = json.loads((self.out / "resolved-manifest.json").read_text())
self.assertEqual(resolved["root"]["commit"], self.root_sha)
self.assertEqual(resolved["applications"]["Agent-System-Backend"]["commit"], self.backend_sha)
self.assertEqual(resolved["applications"]["Agent-System-Frontend"]["commit"], self.frontend_sha)
self.assertEqual(resolved["artifacts"]["agent-system"]["sha256"], hashlib.sha256((self.out / "agent-system").read_bytes()).hexdigest())
self.assertEqual(resolved["go"]["backend"]["modules"][0]["Path"], "example.com/backend")
self.assertTrue(resolved["npm"]["lock_sha256"])
self.assertTrue(resolved["frontend"]["sha256"])
self.assertNotIn("fixture-secret", (self.out / "resolved-manifest.json").read_text())
def test_test_target_runs_real_frontend_and_go_tests(self):
result = self.compose("test")
self.assertEqual(result.returncode, 0, result.stdout)
self.assertIn("example.com/backend/web", result.stdout)
self.assertEqual(json.loads((self.out / "resolved-manifest.json").read_text())["target"], "test")
def test_unused_transitive_zip_does_not_require_consumer_sum_rewrite(self):
proxy = self.base / "unused-proxy"
for name, mod, body in (
("unused", "module example.com/unused\n\ngo 1.16\n", "package unused\n"),
("used", "module example.com/used\n\ngo 1.16\nrequire example.com/unused v1.0.0\n", "package used\nfunc Value() int { return 7 }\n"),
):
directory = proxy / "example.com" / name / "@v"
directory.mkdir(parents=True)
(directory / "v1.0.0.mod").write_text(mod)
(directory / "v1.0.0.info").write_text('{"Version":"v1.0.0","Time":"2026-10-13T00:00:00Z"}')
(directory / "list").write_text("v1.0.0\n")
with zipfile.ZipFile(directory / "v1.0.0.zip", "w") as archive:
archive.writestr(f"example.com/{name}@v1.0.0/go.mod", mod)
archive.writestr(f"example.com/{name}@v1.0.0/value.go", body)
env = self.env | {"GOPROXY": proxy.as_uri(), "GOMODCACHE": str(self.base / "unused-cache")}
self.write(self.backend, "go.mod", "module example.com/backend\n\ngo 1.23\nrequire example.com/used v1.0.0\n")
self.write(self.backend, "web/value.go", 'package web\nimport "example.com/used"\nvar Value = used.Value()\n')
self.run_command(["go", "mod", "tidy"], self.backend, env=env)
sums = (self.backend / "go.sum").read_text()
self.assertNotIn("example.com/unused v1.0.0 h1:", sums)
self.lock["components"]["Agent-System-Backend"]["commit"] = self.commit(self.backend)
self.save_inputs()
self.commit(self.root)
result = self.compose(env=env)
self.assertEqual(result.returncode, 0, result.stdout)
self.assertEqual((self.backend / "go.sum").read_text(), sums)
graph = json.loads((self.out / "resolved-manifest.json").read_text())["go"]["backend"]["modules"]
self.assertIn("example.com/used", {module["Path"] for module in graph})
def test_developer_package_tarball_overrides_do_not_reach_formal_tests(self):
self.write(self.frontend, "test.cjs", "if (process.env.CONTRACTS_TARBALL || process.env.UI_TARBALL) process.exit(93)")
self.lock["components"]["Agent-System-Frontend"]["commit"] = self.commit(self.frontend)
self.save_inputs()
self.commit(self.root)
result = self.compose("test", env=self.env | {"CONTRACTS_TARBALL": "/tmp/dirty-contracts.tgz", "UI_TARBALL": "/tmp/dirty-ui.tgz"})
self.assertEqual(result.returncode, 0, result.stdout)
def test_test_target_checks_fixed_go_library_and_ui_sources(self):
library = self.base / "probe-library"
library.mkdir()
self.run_command(["git", "init", "-q", "-b", "main"], library)
self.run_command(["git", "config", "user.email", "fixture@example.invalid"], library)
self.run_command(["git", "config", "user.name", "Fixture"], library)
self.write(library, "go.mod", "module example.com/probe\n\ngo 1.23\n")
self.write(library, "probe.go", "package probe\nfunc Text() string { return \"\" }\n")
self.write(library, "probe_test.go", '''package probe
import ("testing"; "os")
func TestFixedLibrary(t *testing.T) {
if err:=os.WriteFile(os.Getenv("COMPOSITION_GO_MARKER"), []byte("fixed-go-test"), 0600); err!=nil {t.Fatal(err)}
if path:=os.Getenv("COMPOSITION_EXEC_MARKER"); path!="" { if err:=os.WriteFile(path, []byte("library-executed"), 0600); err!=nil {t.Fatal(err)} }
}
''')
library_sha = self.commit(library)
version = "v0.0.0-" + self.run_command(["git", "show", "-s", "--format=%cd", "--date=format-local:%Y%m%d%H%M%S", library_sha], library).stdout.strip() + "-" + library_sha[:12]
proxy = self.base / "probe-proxy/example.com/probe/@v"
proxy.mkdir(parents=True)
(proxy / (version + ".mod")).write_text((library / "go.mod").read_text())
(proxy / (version + ".info")).write_text(json.dumps({"Version": version, "Time": "2026-10-13T00:00:00Z", "Origin": {"VCS": "git", "URL": str(library), "Hash": library_sha}}))
(proxy / "list").write_text(version + "\n")
with zipfile.ZipFile(proxy / (version + ".zip"), "w") as archive:
for path in self.run_command(["git", "ls-files"], library).stdout.splitlines():
archive.write(library / path, "example.com/probe@" + version + "/" + path)
self.write(self.backend, "go.mod", f"module example.com/backend\n\ngo 1.23\nrequire example.com/probe {version}\n")
self.write(self.backend, "web/probe.go", 'package web\nimport "example.com/probe"\nvar _ = probe.Text()\n')
env = self.env | {"GOPROXY": (self.base / "probe-proxy").as_uri(), "GOMODCACHE": str(self.base / "probe-cache"),
"COMPOSITION_GO_MARKER": str(self.base / "go-tested"), "COMPOSITION_UI_MARKER": str(self.base / "ui-tested")}
self.run_command(["go", "mod", "download", "all"], self.backend, env=env)
self.lock["components"]["Agent-System-Backend"]["commit"] = self.commit(self.backend)
self.write(library, "probe_test.go", "invalid dirty library tests")
ui = self.base / "ui"
ui.mkdir()
self.run_command(["git", "init", "-q", "-b", "main"], ui)
self.run_command(["git", "config", "user.email", "fixture@example.invalid"], ui)
self.run_command(["git", "config", "user.name", "Fixture"], ui)
self.write(ui, "package.json", json.dumps({"name": "@agent-system/ui", "version": "1.0.0", "scripts": {"test": "node test.cjs", "typecheck": "node -e \"process.exit(0)\""}}))
self.write(ui, "test.cjs", "require('node:fs').writeFileSync(process.env.COMPOSITION_UI_MARKER, 'fixed-ui-test')")
self.run_command(["npm", "install", "--package-lock-only", "--ignore-scripts", "--no-audit", "--no-fund"], ui)
ui_sha = self.commit(ui)
package = json.loads((self.frontend / "package.json").read_text())
package["dependencies"] = {"@agent-system/ui": "git+" + ui.as_uri() + "#" + ui_sha}
self.write(self.frontend, "package.json", json.dumps(package))
self.run_command(["npm", "install", "--package-lock-only", "--ignore-scripts", "--no-audit", "--no-fund"], self.frontend)
self.lock["components"]["Agent-System-Frontend"]["commit"] = self.commit(self.frontend)
self.write(ui, "test.cjs", "throw Error('dirty ui tests')")
self.manifest["components"].extend([
{"id": "Probe", "repo": str(library), "path": ".workspace/Probe", "role": "go-library", "modules": [{"path": "example.com/probe", "directory": "."}], "target": "main"},
{"id": "Agent-System-UI", "repo": ui.as_uri(), "path": ".workspace/Agent-System-UI", "role": "npm-library", "modules": [], "target": "main"},
])
self.save_inputs()
self.commit(self.root)
env = self.acquisition_guard(env, mark_frontend=False)
result = self.compose("test", env=env)
self.assertEqual(result.returncode, 0, result.stdout)
self.assertTrue((self.base / "go-tested").is_file(), "resolved Go provider tests were not executed")
self.assertEqual((self.base / "go-tested").read_text(), "fixed-go-test")
self.assertTrue((self.base / "ui-tested").is_file(), "fixed npm UI provider tests were not executed")
self.assertEqual((self.base / "ui-tested").read_text(), "fixed-ui-test")
self.assertIn("go vet", result.stdout)
def test_version_and_plugin_assets_come_from_committed_root(self):
self.write(self.root, "plugins/example/plugin.json", '{"name":"immutable-plugin"}')
self.root_sha = self.commit(self.root)
self.write(self.root, "plugins/example/plugin.json", '{"name":"dirty-plugin"}')
result = self.compose()
self.assertEqual(result.returncode, 0, result.stdout)
resolved = json.loads((self.out / "resolved-manifest.json").read_text())
self.assertIn("version", resolved)
self.assertEqual(self.run_command([str(self.out / "agent-system"), "version"]).stdout, resolved["version"])
self.assertIn(self.root_sha[:12], resolved["version"])
self.assertIn(self.backend_sha[:12], resolved["version"])
self.assertIn(self.frontend_sha[:12], resolved["version"])
self.assertEqual((self.out / "plugins/example/plugin.json").read_text(), '{"name":"immutable-plugin"}')
self.assertTrue(resolved["assets"]["plugins"]["sha256"])
def test_npm_local_dependency_overlay_is_rejected(self):
lock = json.loads((self.frontend / "package-lock.json").read_text())
lock["packages"]["node_modules/local"] = {"resolved": "file:../dirty"}
self.write(self.frontend, "package-lock.json", json.dumps(lock))
self.lock["components"]["Agent-System-Frontend"]["commit"] = self.commit(self.frontend)
self.save_inputs()
self.commit(self.root)
result = self.compose()
self.assertNotEqual(result.returncode, 0, result.stdout)
self.assertIn("local", result.stdout)
self.assertFalse((self.out / "agent-system").exists())
def test_frontend_dist_symlink_cannot_import_assets_from_outside_source(self):
external = self.base / "external-assets"
self.write(external, "index.html", "escaped-page")
self.write(external, "assets/main.js", "escaped-code")
self.write(self.frontend, "build.cjs", "require('node:fs').symlinkSync(" + json.dumps(str(external)) + ", 'dist', 'dir')")
self.lock["components"]["Agent-System-Frontend"]["commit"] = self.commit(self.frontend)
self.save_inputs()
self.commit(self.root)
result = self.compose()
self.assertNotEqual(result.returncode, 0, result.stdout)
self.assertIn("symlink", result.stdout)
self.assertFalse((self.out / "agent-system").exists())
def test_project_test_mode_refuses_missing_boundary_gate(self):
self.write(self.root, "Makefile", "test-governance:\n\ttrue\n")
self.commit(self.root)
result = self.compose("test")
self.assertNotEqual(result.returncode, 0, result.stdout)
self.assertIn("lint-boundaries", result.stdout)
def test_fixed_root_governance_and_boundaries_receive_proven_source_map(self):
self.write(self.root, "Makefile", "test-governance:\n\tpython3 -B scripts/map-check.py governance\n")
self.write(self.root, "scripts/lint-boundaries.sh", "#!/bin/sh\npython3 -B scripts/map-check.py boundaries\n")
self.write(self.root, "scripts/check-pins.sh", "#!/bin/sh\npython3 -B scripts/map-check.py pins\n")
self.write(self.root, "scripts/map-check.py", '''import json, os, pathlib, sys
root = pathlib.Path.cwd()
assert not (root / '.git').exists(), 'gates must run from the immutable archive'
mapping = json.loads(pathlib.Path(os.environ['COMPOSITION_SOURCE_MAP']).read_text())
lock = json.loads((root / 'components.lock.json').read_text())
for name in ('Agent-System-Backend', 'Agent-System-Frontend'):
assert mapping['components'][name]['commit'] == lock['components'][name]['commit']
assert (pathlib.Path(mapping['components']['Agent-System-Backend']['path']) / 'web/dist/index.html').read_text() == 'immutable-page'
with pathlib.Path(os.environ['COMPOSITION_GATE_MARKER']).open('a') as output: output.write(sys.argv[1]+'\\n')
''')
self.commit(self.root)
# Dirty gate code is excluded, just like dirty application code.
self.write(self.root, "scripts/map-check.py", "raise Exception('dirty governance')")
marker = self.base / "gates-run"
result = self.compose("test", extra=("--source-map", str(self.base / "source-map.json")), env=self.env | {"COMPOSITION_GATE_MARKER": str(marker)})
self.assertEqual(result.returncode, 0, result.stdout)
self.assertEqual(marker.read_text(), "boundaries\npins\ngovernance\n")
self.assertEqual(json.loads((self.base / "source-map.json").read_text())["components"]["Agent-System-Backend"]["commit"], self.backend_sha)
def test_missing_frontend_assets_fails_before_publishing_binary(self):
self.write(self.frontend, "build.cjs", "require('node:fs').mkdirSync('dist', {recursive:true});")
self.lock["components"]["Agent-System-Frontend"]["commit"] = self.commit(self.frontend)
self.save_inputs()
self.commit(self.root)
result = self.compose()
self.assertNotEqual(result.returncode, 0, result.stdout)
self.assertIn("index.html", result.stdout)
self.assertFalse((self.out / "agent-system").exists())
def test_dirty_root_lock_is_rejected(self):
self.lock["components"]["Agent-System-Backend"]["commit"] = "a" * 40
self.save_inputs()
result = self.compose()
self.assertNotEqual(result.returncode, 0, result.stdout)
def test_dirty_root_composer_cannot_publish_under_committed_identity(self):
tools = self.root / "scripts"
(tools / "workspace").mkdir(parents=True)
shutil.copy2(SCRIPT, tools / "build-composition.py")
shutil.copy2(SCRIPT.parent / "workspace/transport.py", tools / "workspace/transport.py")
self.commit(self.root)
composer = tools / "build-composition.py"
composer.write_text(composer.read_text().replace(
'(destination / ".gitkeep").touch()',
'(destination / ".gitkeep").touch(); (destination / "index.html").write_text("dirty-tool-page")'))
result = self.run_command([sys.executable, str(composer), "--root", str(self.root),
"--target", "build", "--output", str(self.out)], check=False)
self.assertNotEqual(result.returncode, 0, result.stdout)
self.assertIn("tool", result.stdout)
self.assertFalse((self.out / "agent-system").exists())
def test_dirty_root_transport_is_refused_before_import(self):
tools = self.root / "scripts"
(tools / "workspace").mkdir(parents=True)
shutil.copy2(SCRIPT, tools / "build-composition.py")
shutil.copy2(SCRIPT.parent / "workspace/transport.py", tools / "workspace/transport.py")
self.commit(self.root)
marker = self.base / "transport-executed"
(tools / "workspace/transport.py").write_text(
"from pathlib import Path\nPath(" + repr(str(marker)) + ").write_text('executed')\n")
result = self.run_command([sys.executable, str(tools / "build-composition.py"), "--root", str(self.root),
"--target", "build", "--output", str(self.out)], check=False)
self.assertNotEqual(result.returncode, 0, result.stdout)
self.assertFalse(marker.exists(), "dirty transport executed before source identity validation")
self.assertIn("committed", result.stdout)
def test_locked_missing_revision_is_rejected(self):
self.lock["components"]["Agent-System-Backend"]["commit"] = "a" * 40
self.save_inputs()
self.commit(self.root)
result = self.compose()
self.assertNotEqual(result.returncode, 0, result.stdout)
self.assertFalse((self.out / "agent-system").exists())
def test_source_path_escape_is_rejected(self):
self.manifest["components"][0]["path"] = "../outside"
self.save_inputs()
self.commit(self.root)
result = self.compose()
self.assertNotEqual(result.returncode, 0, result.stdout)
self.assertIn("path", result.stdout)
def test_local_go_replace_is_rejected(self):
self.write(self.backend, "go.mod", "module example.com/backend\n\ngo 1.23\nreplace example.com/dirty => /missing/local\n")
self.lock["components"]["Agent-System-Backend"]["commit"] = self.commit(self.backend)
self.save_inputs()
self.commit(self.root)
result = self.compose()
self.assertNotEqual(result.returncode, 0, result.stdout)
self.assertIn("replace", result.stdout)
def test_rdm_vendored_remote_backend_embeds_assets_without_mutating_module_cache(self):
rdm = self.base / "rdm"
rdm.mkdir()
self.run_command(["git", "init", "-q", "-b", "main"], rdm)
self.run_command(["git", "config", "user.email", "fixture@example.invalid"], rdm)
self.run_command(["git", "config", "user.name", "Fixture"], rdm)
version = "v0.0.0-" + self.run_command(["git", "show", "-s", "--format=%cd", "--date=format-local:%Y%m%d%H%M%S", self.backend_sha], self.backend).stdout.strip() + "-" + self.backend_sha[:12]
proxy = self.base / "proxy/example.com/backend/@v"
proxy.mkdir(parents=True)
(proxy / (version + ".mod")).write_text((self.backend / "go.mod").read_text())
(proxy / (version + ".info")).write_text(json.dumps({"Version": version, "Time": "2026-10-13T00:00:00Z"}))
(proxy / "list").write_text(version + "\n")
with zipfile.ZipFile(proxy / (version + ".zip"), "w") as archive:
paths = self.run_command(["git", "ls-files"], self.backend).stdout.splitlines()
for path in paths:
archive.write(self.backend / path, "example.com/backend@" + version + "/" + path)
self.write(rdm, "go.mod", f"module example.com/rdm\n\ngo 1.23\nrequire example.com/backend {version}\n")
self.write(rdm, "main.go", 'package main\nimport ("fmt"; "example.com/backend/web")\nfunc main() { fmt.Print(web.Page()) }\n')
module_cache = self.base / "module-cache"
env = self.env | {"GOPROXY": (self.base / "proxy").as_uri(), "GOMODCACHE": str(module_cache)}
self.run_command(["go", "mod", "download", "all"], rdm, env=env)
rdm_sha = self.commit(rdm)
cached_asset = module_cache / ("example.com/backend@" + version) / "web/dist/.gitkeep"
self.assertTrue(cached_asset.exists())
result = self.compose(extra=("--rdm-source", str(rdm)), env=env)
self.assertEqual(result.returncode, 0, result.stdout)
self.assertEqual(self.run_command([str(self.out / "agent-system-rdm-product")]).stdout, "immutable-page")
self.assertFalse(cached_asset.with_name("index.html").exists())
resolved = json.loads((self.out / "resolved-manifest.json").read_text())
self.assertEqual(resolved["applications"]["Agent-System-RDM"]["commit"], rdm_sha)
self.assertTrue(resolved["go"]["rdm"]["vendor_modules_sha256"])
self.assertTrue(resolved["go"]["rdm"]["vendor_backend_source_sha256"])
self.assertEqual(resolved["go"]["rdm"]["modules"][1]["Version"], version)
@unittest.skipUnless((RDM_SCRIPTS / "scripts/build-product.sh").is_file(), "external RDM source was not supplied; host must replay the actual wrapper")
def test_versioned_rdm_product_entry_uses_fixed_composer(self):
# Reuse the real module fixture first; its independent embed test remains
# mandatory even when an external RDM wrapper is unavailable.
self.test_rdm_vendored_remote_backend_embeds_assets_without_mutating_module_cache()
rdm = self.base / "rdm"
version = self.run_command(["go", "list", "-m", "-f", "{{.Version}}", "example.com/backend"], rdm,
env=self.env | {"GOPROXY": (self.base / "proxy").as_uri(), "GOMODCACHE": str(self.base / "module-cache")}).stdout.strip()
env = self.env | {"GOPROXY": (self.base / "proxy").as_uri(), "GOMODCACHE": str(self.base / "module-cache")}
# The versioned RDM entry invokes the same fixed Dev composer, even when
# local RDM Go source is dirty. No API-only fallback is allowed.
self.write(rdm, "go.mod", f"module git-ssh.u1680832.nyat.app/weichen/Agent-System-RDM.git\n\ngo 1.23\nrequire example.com/backend {version}\n")
shutil.copy2(RDM_SCRIPTS / "Makefile", rdm / "Makefile")
(rdm / "scripts").mkdir()
shutil.copy2(RDM_SCRIPTS / "scripts/build-product.sh", rdm / "scripts/build-product.sh")
self.commit(rdm)
self.write(rdm, "main.go", "invalid local RDM")
(self.root / "scripts/workspace").mkdir(parents=True)
shutil.copy2(SCRIPT, self.root / "scripts/build-composition.py")
shutil.copy2(SCRIPT.parent / "workspace/transport.py", self.root / "scripts/workspace/transport.py")
self.commit(self.root)
result = self.run_command(["make", "product", "COMPOSITION_ROOT=" + str(self.root)], rdm, env=env, check=False)
self.assertEqual(result.returncode, 0, result.stdout)
self.assertEqual(self.run_command([str(rdm / "bin/agent-system-rdm-product")]).stdout, "immutable-page")
self.assertTrue((rdm / "bin/agent-system-admin").exists())
self.assertEqual(json.loads((rdm / "bin/PRODUCT_MANIFEST.json").read_text())["kind"], "agent-system-composition/1")
def test_modified_go_module_cache_is_rejected_before_product_publication(self):
self.test_rdm_vendored_remote_backend_embeds_assets_without_mutating_module_cache()
cached = next((self.base / "module-cache/example.com").glob("backend@*/web/embed.go"))
cached.chmod(0o644)
cached.write_text(cached.read_text() + "\n// unauthorized cache mutation\n")
result = self.compose(extra=("--rdm-source", str(self.base / "rdm")),
env=self.env | {"GOPROXY": (self.base / "proxy").as_uri(), "GOMODCACHE": str(self.base / "module-cache")})
self.assertNotEqual(result.returncode, 0, result.stdout)
self.assertIn("modified", result.stdout)
def test_rdm_product_and_admin_follow_its_selected_backend_not_dev_source_lock(self):
self.test_rdm_vendored_remote_backend_embeds_assets_without_mutating_module_cache()
selected_embed = (self.backend / "web/embed.go").read_text().replace("return string(b)", 'return "selected-rdm:" + string(b)')
self.write(self.backend, "web/embed.go", selected_embed)
selected_sha = self.commit(self.backend)
selected_version = "v0.0.0-" + self.run_command(["git", "show", "-s", "--format=%cd", "--date=format-local:%Y%m%d%H%M%S", selected_sha], self.backend).stdout.strip() + "-" + selected_sha[:12]
proxy = self.base / "proxy/example.com/backend/@v"
(proxy / (selected_version + ".mod")).write_text((self.backend / "go.mod").read_text())
(proxy / (selected_version + ".info")).write_text(json.dumps({"Version": selected_version, "Time": "2026-10-13T00:00:00Z", "Origin": {"VCS": "git", "URL": str(self.backend), "Hash": selected_sha}}))
with zipfile.ZipFile(proxy / (selected_version + ".zip"), "w") as archive:
for path in self.run_command(["git", "ls-files"], self.backend).stdout.splitlines():
archive.write(self.backend / path, "example.com/backend@" + selected_version + "/" + path)
rdm = self.base / "rdm"
self.write(rdm, "go.mod", f"module example.com/rdm\n\ngo 1.23\nrequire example.com/backend {selected_version}\n")
env = self.env | {"GOPROXY": (self.base / "proxy").as_uri(), "GOMODCACHE": str(self.base / "module-cache")}
self.run_command(["go", "mod", "download", "all"], rdm, env=env)
self.commit(rdm)
result = self.compose(extra=("--rdm-source", str(rdm)), env=env)
self.assertEqual(result.returncode, 0, result.stdout)
self.assertEqual(self.run_command([str(self.out / "agent-system")]).stdout, "immutable-page")
self.assertEqual(self.run_command([str(self.out / "agent-system-rdm-product")]).stdout, "selected-rdm:immutable-page")
self.assertEqual(self.run_command([str(self.out / "agent-system-admin")]).stdout, "selected-rdm:immutable-page")
resolved = json.loads((self.out / "resolved-manifest.json").read_text())
self.assertEqual(resolved["applications"]["Agent-System-Backend"]["commit"], self.backend_sha)
self.assertEqual(resolved["go"]["rdm"]["backend_source"]["commit"], selected_sha)
self.assertEqual(resolved["go"]["rdm"]["backend_source"]["version"], selected_version)
admin_version = self.run_command([str(self.out / "agent-system-admin"), "version"]).stdout
self.assertEqual(admin_version, resolved["go"]["rdm"]["admin_version"])
self.assertIn(selected_sha[:12], admin_version)
self.assertFalse((self.base / "module-cache/example.com" / ("backend@" + selected_version) / "web/dist/index.html").exists())
def test_historical_rdm_product_still_builds_from_legacy_pins(self):
rdm = self.base / "legacy-rdm"
rdm.mkdir()
self.run_command(["git", "init", "-q", "-b", "main"], rdm)
self.run_command(["git", "config", "user.email", "fixture@example.invalid"], rdm)
self.run_command(["git", "config", "user.name", "Fixture"], rdm)
self.write(rdm, "go.mod", "module legacy-rdm\n\ngo 1.23\nrequire example.com/backend v0.0.0\nreplace example.com/backend => ./pins/agent-system-backend\n")
self.write(rdm, "main.go", 'package main\nimport ("fmt"; "example.com/backend/web")\nfunc main() { fmt.Print(web.Page()) }\n')
(rdm / "scripts").mkdir()
shutil.copy2(LEGACY_PRODUCT, rdm / "scripts/build-product.sh")
self.commit(rdm)
pins = rdm / "pins"
pins.mkdir()
for name, source in (("agent-system-backend", self.backend), ("agent-system-frontend", self.frontend), ("agent-system-ui", self.frontend)):
self.run_command(["git", "clone", "-q", str(source), str(pins / name)])
for name in ("agent-system-frontend", "agent-system-ui"):
package = json.loads((pins / name / "package.json").read_text())
del package["scripts"]["postinstall"]
self.write(pins / name, "package.json", json.dumps(package))
self.run_command(["npm", "install", "--package-lock-only", "--ignore-scripts", "--no-audit", "--no-fund"], pins / name)
result = self.run_command(["bash", "scripts/build-product.sh"], rdm, check=False)
self.assertEqual(result.returncode, 0, result.stdout)
self.assertEqual(self.run_command([str(rdm / "bin/agent-system-rdm-product")]).stdout, "immutable-page")
self.assertEqual(json.loads((rdm / "bin/PRODUCT_MANIFEST.json").read_text())["kind"], "rdm-product/1")
if __name__ == "__main__":
unittest.main()