feat(dashboard): pipelock edit TUI verb (PRD 0015)
Phase 3 of PRD 0015. Adds the proactive `pipelock edit` path, mirroring routes edit from PRD 0014: - discover_pipelock_slugs() lists running pipelock sidecars. - operator_edit_allowlist(slug, new) wraps apply_allowlist_change and writes an audit entry tagged ACTION_OPERATOR_EDIT. - New 'p' keybinding in the main TUI: discover slugs, prompt if multiple, fetch current allowlist, open in $EDITOR, apply on save. - Extracts shared scaffolding into _operator_edit_flow used by both routes-edit and pipelock-edit — DRY without sacrificing the per-verb status-line copy. - Footer updated. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -378,10 +378,41 @@ class TestDiscoverCredProxySlugs(unittest.TestCase):
|
||||
os.environ["PATH"] = "/nonexistent-no-docker-here"
|
||||
try:
|
||||
self.assertEqual([], dashboard.discover_cred_proxy_slugs())
|
||||
self.assertEqual([], dashboard.discover_pipelock_slugs())
|
||||
finally:
|
||||
os.environ["PATH"] = original
|
||||
|
||||
|
||||
class TestOperatorEditAllowlist(_FakeHomeMixin, unittest.TestCase):
|
||||
"""PRD 0015 Phase 3: operator-initiated pipelock allowlist edit."""
|
||||
|
||||
def setUp(self):
|
||||
self._setup_fake_home()
|
||||
self._original = dashboard.apply_allowlist_change
|
||||
|
||||
def tearDown(self):
|
||||
dashboard.apply_allowlist_change = self._original
|
||||
self._teardown_fake_home()
|
||||
|
||||
def test_writes_audit_with_operator_edit_action(self):
|
||||
dashboard.apply_allowlist_change = lambda slug, content: (
|
||||
"old.example\n", content,
|
||||
)
|
||||
dashboard.operator_edit_allowlist("dev", "old.example\nnew.example\n")
|
||||
entries = read_audit_entries("pipelock", "dev")
|
||||
self.assertEqual(1, len(entries))
|
||||
self.assertEqual(supervise.ACTION_OPERATOR_EDIT, entries[0].operator_action)
|
||||
self.assertIn("+new.example", entries[0].diff)
|
||||
|
||||
def test_failure_does_not_write_audit(self):
|
||||
dashboard.apply_allowlist_change = lambda slug, content: (_ for _ in ()).throw(
|
||||
PipelockApplyError("nope")
|
||||
)
|
||||
with self.assertRaises(PipelockApplyError):
|
||||
dashboard.operator_edit_allowlist("dev", "x.example\n")
|
||||
self.assertEqual([], read_audit_entries("pipelock", "dev"))
|
||||
|
||||
|
||||
class TestEditInEditor(unittest.TestCase):
|
||||
def test_runs_editor_returns_edited_content(self):
|
||||
# Fake "editor" is /bin/sh -c 'cat <<EOF > $1 ... EOF'
|
||||
|
||||
Reference in New Issue
Block a user