Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions host-setup/agent-safety/claude/install.py
Original file line number Diff line number Diff line change
Expand Up @@ -771,9 +771,14 @@ def report(claude_home):
if unset and not capable:
print(f"Note: agent commands on this host run uncontained ({reason}).")
if foreign is not None:
remedy = (
"Remove that value and re-run the installer for this kit to contain them."
if capable
else f"This kit cannot contain them here now ({reason})."
)
print(
f"Note: {PREFIX_VAR} is {foreign!r}, which this kit does not own, so agent commands run "
"uncontained. Remove it and re-run the installer to contain them."
f"Note: {PREFIX_VAR} is {foreign!r}, which this kit does not own, so this kit does not "
f"contain agent commands. {remedy}"
)
# Read from the file rather than compared against the stamp.
# An install onto a corrupted file writes the corruption into the stamp, and the two then agree.
Expand Down Expand Up @@ -1001,7 +1006,7 @@ def reject(where, held, want):
ours = held is not None and kit_prefix(held)
if held is not None and not ours:
done.append(
f"{PREFIX_VAR} left as {held!r}, which this kit does not own, so no containment"
f"{PREFIX_VAR} left as {held!r}, which this kit does not own, so this kit does not contain agent commands"
)
elif capable:
env[PREFIX_VAR] = prefix_value(contain_dst)
Expand Down
13 changes: 13 additions & 0 deletions host-setup/agent-safety/claude/test_install.py
Original file line number Diff line number Diff line change
Expand Up @@ -801,6 +801,19 @@ def test_a_prefix_naming_another_copy_reports_stale(self):
self.assertEqual(r.returncode, 1, r.stdout + r.stderr)
self.assertIn("does not run the deployed prefix", r.stdout)

def test_the_foreign_note_claims_only_what_this_kit_does(self):
"""Another wrapper may contain commands, and a host that cannot contain gets no remedy it cannot use."""
self.home.mkdir(parents=True)
self._write({"env": {install.PREFIX_VAR: "/usr/local/bin/audit-log"}})
self.install()
capable = run(self.home, "--report")
self.assertIn("this kit does not contain agent commands", capable.stdout)
self.assertIn("re-run the installer for this kit to contain them", capable.stdout)
self.assertNotIn("run uncontained", capable.stdout)
incapable = run(self.home, "--report", contain=False)
self.assertIn("This kit cannot contain them here now", incapable.stdout)
self.assertNotIn("re-run the installer for this kit", incapable.stdout)

def test_a_wrapper_merely_containing_the_prefix_name_is_foreign(self):
"""Someone else's wrapper is neither overwritten nor reported as a stale copy of ours."""
self.home.mkdir(parents=True)
Expand Down
Loading