fix(orc): support trusted release shell workflow
This commit is contained in:
@@ -5,6 +5,7 @@ from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import ipaddress
|
||||
import json
|
||||
import os
|
||||
import pwd
|
||||
@@ -15,6 +16,7 @@ import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from urllib.parse import urlsplit
|
||||
|
||||
LEVELS = ("low", "mid", "high")
|
||||
STAGES = ("code", "release", "deb", "docker")
|
||||
@@ -35,6 +37,14 @@ PROFILE_KEYS = {
|
||||
"approvalPolicy",
|
||||
}
|
||||
MODEL_RE = re.compile(r"[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}\Z")
|
||||
REMOTE_HOST_RE = re.compile(
|
||||
r"(?=.{1,253}\Z)(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)*"
|
||||
r"[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\Z"
|
||||
)
|
||||
SCP_REMOTE_RE = re.compile(
|
||||
r"(?:(?P<username>[A-Za-z0-9._-]+)@)?"
|
||||
r"(?P<host>[A-Za-z0-9.-]+):(?P<path>[^\s]+)\Z"
|
||||
)
|
||||
MAX_CONFIG_SIZE = 64 * 1024
|
||||
MAX_CONTROL_OUTPUT = 64 * 1024
|
||||
CONTROL_TIMEOUT_SECONDS = 15
|
||||
@@ -302,10 +312,13 @@ def resolve_profile(
|
||||
else:
|
||||
level, source = config["defaultLevel"], "config.defaultLevel"
|
||||
|
||||
profile = config["profiles"][selected_cli].get(level)
|
||||
if profile is None:
|
||||
configured_profile = config["profiles"][selected_cli].get(level)
|
||||
if configured_profile is None:
|
||||
raise ConfigError(f"requested profile does not exist: {selected_cli}/{level}")
|
||||
profile = dict(configured_profile)
|
||||
if selected_cli == "codex":
|
||||
if stage == "release":
|
||||
profile["approvalPolicy"] = "on-request"
|
||||
worker_args = [
|
||||
"--model",
|
||||
profile["model"],
|
||||
@@ -317,6 +330,8 @@ def resolve_profile(
|
||||
profile["approvalPolicy"],
|
||||
"--strict-config",
|
||||
]
|
||||
if stage == "release":
|
||||
worker_args.extend(["-c", 'approvals_reviewer="auto_review"'])
|
||||
else:
|
||||
worker_args = [
|
||||
"--model",
|
||||
@@ -333,7 +348,7 @@ def resolve_profile(
|
||||
"selectionSource": source,
|
||||
"modelAuth": selected_auth,
|
||||
"remoteAuth": remote_auth,
|
||||
"profile": dict(profile),
|
||||
"profile": profile,
|
||||
"workerArgs": worker_args,
|
||||
}
|
||||
|
||||
@@ -549,6 +564,117 @@ def _run_control(argv: list[str], label: str) -> str:
|
||||
return output
|
||||
|
||||
|
||||
def _validated_remote_host(value: str, label: str) -> str:
|
||||
host = value.lower()
|
||||
if not REMOTE_HOST_RE.fullmatch(host):
|
||||
raise ConfigError(f"{label} has an unsupported host")
|
||||
if host == "localhost" or host.endswith(".localhost"):
|
||||
raise ConfigError(f"{label} must not target a local host")
|
||||
try:
|
||||
address = ipaddress.ip_address(host)
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
if not address.is_global:
|
||||
raise ConfigError(f"{label} must not target a private or local address")
|
||||
return host
|
||||
|
||||
|
||||
def _remote_url_facts(value: str, label: str) -> dict[str, Any]:
|
||||
if (
|
||||
not value
|
||||
or value != value.strip()
|
||||
or any(character.isspace() or character == "\x00" for character in value)
|
||||
):
|
||||
raise ConfigError(f"{label} is not a safe remote URL")
|
||||
|
||||
if "://" not in value:
|
||||
match = SCP_REMOTE_RE.fullmatch(value)
|
||||
if match is None:
|
||||
raise ConfigError(f"{label} is not a supported HTTPS or SSH URL")
|
||||
scheme = "ssh"
|
||||
username = match.group("username") or "git"
|
||||
host = _validated_remote_host(match.group("host"), label)
|
||||
port = 22
|
||||
path = "/" + match.group("path").lstrip("/")
|
||||
else:
|
||||
parsed = urlsplit(value)
|
||||
if (
|
||||
parsed.scheme not in {"https", "ssh"}
|
||||
or not parsed.hostname
|
||||
or parsed.password is not None
|
||||
or parsed.query
|
||||
or parsed.fragment
|
||||
or not parsed.path
|
||||
or parsed.path == "/"
|
||||
):
|
||||
raise ConfigError(f"{label} is not a supported HTTPS or SSH URL")
|
||||
scheme = parsed.scheme
|
||||
username = parsed.username
|
||||
if scheme == "https" and username is not None:
|
||||
raise ConfigError(f"{label} must not embed HTTPS credentials")
|
||||
host = _validated_remote_host(parsed.hostname, label)
|
||||
try:
|
||||
port = parsed.port or (443 if scheme == "https" else 22)
|
||||
except ValueError as exc:
|
||||
raise ConfigError(f"{label} is not a safe remote URL") from exc
|
||||
path = parsed.path
|
||||
|
||||
if not path.startswith("/") or _path_has_parent_reference(path):
|
||||
raise ConfigError(f"{label} has an unsafe repository path")
|
||||
user_prefix = f"{username}@" if username is not None else ""
|
||||
canonical = f"{scheme}://{user_prefix}{host}:{port}{path}"
|
||||
return {
|
||||
"url": value,
|
||||
"canonical": canonical,
|
||||
"scheme": scheme,
|
||||
"host": host,
|
||||
"port": port,
|
||||
"path": path,
|
||||
}
|
||||
|
||||
|
||||
def _origin_urls(git: Path, worktree: Path, *, push: bool) -> list[str]:
|
||||
argv = [str(git), "-C", str(worktree), "remote", "get-url"]
|
||||
if push:
|
||||
argv.append("--push")
|
||||
argv.extend(["--all", "origin"])
|
||||
output = _run_control(
|
||||
argv,
|
||||
f"Git origin {'push' if push else 'fetch'} URL check",
|
||||
)
|
||||
return output.splitlines()
|
||||
|
||||
|
||||
def resolve_release_remote(worktree: Path) -> dict[str, Any]:
|
||||
git = resolve_trusted_executable("git")
|
||||
fetch_urls = _origin_urls(git, worktree, push=False)
|
||||
push_urls = _origin_urls(git, worktree, push=True)
|
||||
if len(fetch_urls) != 1:
|
||||
raise ConfigError("release origin must have exactly one fetch URL")
|
||||
if len(push_urls) != 1:
|
||||
raise ConfigError("release origin must have exactly one push URL")
|
||||
|
||||
fetch = _remote_url_facts(fetch_urls[0], "Git origin fetch URL")
|
||||
push = _remote_url_facts(push_urls[0], "Git origin push URL")
|
||||
if fetch["canonical"] != push["canonical"]:
|
||||
raise ConfigError("release origin fetch and push URLs must match")
|
||||
network_hosts = [push["host"]]
|
||||
if push["host"] == "github.com":
|
||||
network_hosts.extend(["api.github.com", "uploads.github.com"])
|
||||
return {
|
||||
"name": "origin",
|
||||
"fetchUrl": fetch["url"],
|
||||
"pushUrl": push["url"],
|
||||
"canonical": push["canonical"],
|
||||
"scheme": push["scheme"],
|
||||
"host": push["host"],
|
||||
"port": push["port"],
|
||||
"path": push["path"],
|
||||
"networkHosts": network_hosts,
|
||||
}
|
||||
|
||||
|
||||
def _git_path(value: str, cwd: Path, label: str) -> Path:
|
||||
candidate = Path(value)
|
||||
if not candidate.is_absolute():
|
||||
@@ -721,6 +847,35 @@ def build_launch_plan(
|
||||
model_auth=profile["modelAuth"],
|
||||
remote_auth=remote_auth,
|
||||
)
|
||||
release_remote = None
|
||||
if stage == "release":
|
||||
release_remote = resolve_release_remote(Path(worktree_facts["worktree"]))
|
||||
if profile["cli"] == "codex":
|
||||
network_domains = ", ".join(
|
||||
f'"{host}" = "allow"' for host in release_remote["networkHosts"]
|
||||
)
|
||||
profile = {
|
||||
**profile,
|
||||
"workerArgs": [
|
||||
*profile["workerArgs"],
|
||||
"-c",
|
||||
"sandbox_workspace_write.network_access=true",
|
||||
"-c",
|
||||
"features.network_proxy.enabled=true",
|
||||
"-c",
|
||||
"features.network_proxy.allow_local_binding=false",
|
||||
"-c",
|
||||
"features.network_proxy.allow_upstream_proxy=false",
|
||||
"-c",
|
||||
"features.network_proxy.dangerously_allow_all_unix_sockets=false",
|
||||
"-c",
|
||||
"features.network_proxy.dangerously_allow_non_loopback_proxy=false",
|
||||
"-c",
|
||||
"features.network_proxy.unix_sockets={}",
|
||||
"-c",
|
||||
f"features.network_proxy.domains={{ {network_domains} }}",
|
||||
],
|
||||
}
|
||||
agent_cli = resolve_trusted_executable(profile["cli"])
|
||||
executable = _executable_facts(agent_cli)
|
||||
orca = resolve_trusted_executable("orca")
|
||||
@@ -749,6 +904,8 @@ def build_launch_plan(
|
||||
"sha256": script_sha256,
|
||||
},
|
||||
}
|
||||
if release_remote is not None:
|
||||
launch_facts["releaseRemote"] = release_remote
|
||||
fingerprint = _fingerprint(launch_facts)
|
||||
worker_argv = [str(agent_cli), *profile["workerArgs"]]
|
||||
if profile["cli"] == "cursor-agent":
|
||||
|
||||
Reference in New Issue
Block a user