"""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