refactor(backend): remove _validate_git_entries host key-file check
test / unit (pull_request) Successful in 37s
test / integration (pull_request) Successful in 18s
lint / lint (push) Successful in 1m39s
test / unit (push) Successful in 37s
test / integration (push) Successful in 18s
Update Quality Badges / update-badges (push) Successful in 1m38s

The git-gate copies the identity file at start time and surfaces a
clear failure then; the pre-launch presence check was redundant.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit was merged in pull request #238.
This commit is contained in:
2026-06-22 14:44:46 -04:00
parent 9f97de115b
commit 65faa40b9a
2 changed files with 8 additions and 27 deletions
+5 -23
View File
@@ -45,7 +45,7 @@ from ..agent_provider import AgentProvisionPlan, get_provider, build_agent_provi
from ..egress import EgressPlan from ..egress import EgressPlan
from ..git_gate import GitGatePlan from ..git_gate import GitGatePlan
from ..log import die, info from ..log import die, info
from ..manifest import ManifestGitEntry, Manifest from ..manifest import Manifest
from ..supervise import SupervisePlan from ..supervise import SupervisePlan
from ..util import expand_tilde from ..util import expand_tilde
from ..env import resolve_env, ResolvedEnv from ..env import resolve_env, ResolvedEnv
@@ -356,16 +356,14 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]):
pass pass
def _validate(self, spec: BottleSpec) -> None: def _validate(self, spec: BottleSpec) -> None:
"""Cross-backend pre-launch checks. Confirms the agent exists, """Cross-backend pre-launch checks. Confirms the agent exists
the named skills are present on the host, and every git and the named skills are present on the host. Subclasses with
IdentityFile resolves. Subclasses with additional preconditions additional preconditions should override and call
should override and call `super()._validate(spec)` first.""" `super()._validate(spec)` first."""
manifest = spec.manifest manifest = spec.manifest
manifest.require_agent(spec.agent_name) manifest.require_agent(spec.agent_name)
agent = manifest.agents[spec.agent_name] agent = manifest.agents[spec.agent_name]
bottle = manifest.bottle_for(spec.agent_name)
self._validate_skills(agent.skills) self._validate_skills(agent.skills)
self._validate_git_entries(bottle.git)
self._validate_agent_provider_dockerfile(spec) self._validate_agent_provider_dockerfile(spec)
def _validate_skills(self, skills: Sequence[str]) -> None: def _validate_skills(self, skills: Sequence[str]) -> None:
@@ -380,22 +378,6 @@ class BottleBackend(ABC, Generic[PlanT, CleanupT]):
f"Create it under ~/.claude/skills/, then re-run." f"Create it under ~/.claude/skills/, then re-run."
) )
def _validate_git_entries(self, entries: Sequence[ManifestGitEntry]) -> None:
"""Each `static`-provider entry's IdentityFile must exist on the
host (after expanding leading ~) — the git-gate copies it in at
start time to authenticate the upstream push (PRD 0008). Shape is
already enforced by Manifest validation; this only checks presence.
`gitea`-provider entries (PRD 0047/0048) carry no host key:
IdentityFile is empty at parse time and the deploy key is created
at provision time, so there is nothing to check here."""
for entry in entries:
if entry.Key.provider != "static":
continue
key = expand_tilde(entry.IdentityFile)
if not os.path.isfile(key):
die(f"git upstream key file not found for '{entry.Name}': {key}")
def _validate_agent_provider_dockerfile(self, spec: BottleSpec) -> None: def _validate_agent_provider_dockerfile(self, spec: BottleSpec) -> None:
bottle = spec.manifest.bottle_for(spec.agent_name) bottle = spec.manifest.bottle_for(spec.agent_name)
dockerfile = bottle.agent_provider.dockerfile dockerfile = bottle.agent_provider.dockerfile
+3 -4
View File
@@ -92,10 +92,9 @@ class TestSandboxEscape(unittest.TestCase):
"on PATH: curl -sSL https://smolmachines.com/install.sh | sh" "on PATH: curl -sSL https://smolmachines.com/install.sh | sh"
) )
# Throwaway "identity file" so the manifest's _validate_git_entries # Throwaway "identity file" for the git-gate's `identity` field.
# passes (it only checks `os.path.isfile`, not that the content is # It need not be a real SSH key: test 5 reaches gitleaks before
# a real SSH key). Test 5 reaches gitleaks before any SSH attempt # any SSH attempt anyway.
# anyway.
fd, kp = tempfile.mkstemp(prefix="sandbox-test-key.") fd, kp = tempfile.mkstemp(prefix="sandbox-test-key.")
os.close(fd) os.close(fd)
cls._key_path = Path(kp) cls._key_path = Path(kp)