Files
Agent-System-Dev/scripts/workspace/transport.py
T
weichen b450e51c40 Add safe component editing and explicit legacy workspace transition
Why: Preserve a single Dev entry and independent repository ownership while allowing active feature branches to migrate without losing source or Git state.

Evidence: SELF 29 real Git/Go workspace tests and ordinary component evidence/lock tests passed; detailed RED/GREEN runs are recorded by make evidence in the task card.

Impact: Add fixed cloning, selected-version baselines, development overlays, npm source resolution, and independently preserved legacy snapshots. No other active worktree is modified.

Refs: Versioned dependencies U2/U5; R15; feature/dependency-workspace
2026-10-13 15:58:23 +00:00

72 lines
3.7 KiB
Python

"""Process-local module transport; configuration contains no credentials."""
import json
import os
from pathlib import Path
from urllib.parse import urlsplit, unquote
def _url(value):
if not isinstance(value, str) or any(c.isspace() for c in value):
raise ValueError('invalid module transport URL')
parsed = urlsplit(value)
if parsed.scheme not in {'https', 'ssh', 'git+ssh', 'file'} or parsed.password:
raise ValueError('unsupported transport or credentials in URL')
if parsed.scheme == 'https' and parsed.username:
raise ValueError('transport URL must not contain credentials')
if parsed.scheme == 'file' and parsed.netloc not in {'', 'localhost'}:
raise ValueError('file transport must be local')
if parsed.query or parsed.fragment or not parsed.path:
raise ValueError('transport URL must identify a repository path')
return value
def environment(root=None):
root = Path(root) if root is not None else Path(__file__).resolve().parents[2]
path = root / 'components.json'
config = json.loads(path.read_text()).get('transport', {}) if path.exists() else {}
env = os.environ.copy()
env.update(GOWORK='off', GOTOOLCHAIN='local')
private = config.get('go_private', [])
if not isinstance(private, list) or any(not isinstance(p, str) or not p or any(c.isspace() for c in p) for p in private):
raise ValueError('invalid private module prefixes')
if private:
env.update(GOPRIVATE=','.join(private), GONOPROXY=','.join(private), GONOSUMDB=','.join(private))
rewrites = config.get('git_rewrites', [])
if not isinstance(rewrites, list):
raise ValueError('invalid Git transport mappings')
if rewrites:
inherited = []
marker = env.get('CI_DEPENDENCY_MIRRORS')
if marker:
mirrors = Path(marker)
if not mirrors.is_absolute() or not mirrors.is_dir() or mirrors.is_symlink():
raise ValueError('invalid CI dependency mirror identity')
mirrors = mirrors.resolve()
try:
count = int(env.get('GIT_CONFIG_COUNT', '0'))
except ValueError as error:
raise ValueError('invalid process Git configuration') from error
for i in range(count):
key, value = env.get(f'GIT_CONFIG_KEY_{i}', ''), env.get(f'GIT_CONFIG_VALUE_{i}', '')
if (key, value) in {('protocol.file.allow', 'always'), ('core.hooksPath', '/dev/null'), ('credential.helper', '')}:
inherited.append((key, value))
elif key.startswith('url.file://') and key.endswith('.insteadOf'):
target = Path(unquote(urlsplit(key[4:-10]).path)).resolve()
if mirrors not in target.parents or not target.is_dir():
raise ValueError('CI mirror source escapes its registered directory')
inherited.append((key, _url(value)))
# Do not inherit temporary authentication configuration into candidate code.
for key in list(env):
if key == 'GIT_CONFIG_COUNT' or key.startswith(('GIT_CONFIG_KEY_', 'GIT_CONFIG_VALUE_')):
del env[key]
entries = list(inherited)
for rewrite in rewrites:
if not isinstance(rewrite, dict) or set(rewrite) != {'from', 'to'}:
raise ValueError('invalid Git transport mapping')
source, target = _url(rewrite['from']), _url(rewrite['to'])
entries.append((f'url.{target}.insteadOf', source))
for i, (key, value) in enumerate(entries):
env[f'GIT_CONFIG_KEY_{i}'], env[f'GIT_CONFIG_VALUE_{i}'] = key, value
env['GIT_CONFIG_COUNT'] = str(len(entries))
return env