Configure immutable component sources and process scoped Go transport
Why: Prepare ordinary component workspaces and real module downloads without changing global Git configuration or other feature branches. Evidence: SELF clean-cache module consumption and real temporary-Git transport tests are recorded by make evidence in the task card, including expected RED and passing GREEN runs. Impact: Add component identities/source locks and non-secret transport configuration. Existing submodule layout remains supported during migration. Refs: Versioned dependencies U1/U2; R15; feature/dependency-workspace
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
"""Process-local module transport; configuration contains no credentials."""
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from urllib.parse import urlsplit
|
||||
|
||||
|
||||
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:
|
||||
# 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]
|
||||
for i, rewrite in enumerate(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'])
|
||||
env[f'GIT_CONFIG_KEY_{i}'] = f'url.{target}.insteadOf'
|
||||
env[f'GIT_CONFIG_VALUE_{i}'] = source
|
||||
env['GIT_CONFIG_COUNT'] = str(len(rewrites))
|
||||
return env
|
||||
Reference in New Issue
Block a user