Skip to content

Commit f844a9a

Browse files
committed
fix(pi): tune command footgun policy
1 parent ce0d2c5 commit f844a9a

3 files changed

Lines changed: 52 additions & 1 deletion

File tree

config/pi/pi-permissions.jsonc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
"*deploy-rs*": "deny",
4646
"*nix run .#deploy-rs*": "deny",
4747

48+
// Dangerous commands are hard blocks: they bypass safety rails, mutate host
49+
// state, or weaken repo integrity in ways an agent should not choose.
50+
// Foot-guns are also hard blocks, but for a different reason: they are
51+
// likely to hang, open an interactive editor, or leave the session wedged.
52+
4853
// Keep hook/signing enforcement in the same command policy system.
4954
"*--no-verify*": "deny",
5055
"*--no-gpg-sign*": "deny",
@@ -60,6 +65,22 @@
6065
"*HUSKY=0*": "deny",
6166
"*PRE_COMMIT_ALLOW_NO_CONFIG=*": "deny",
6267

68+
// VCS foot-guns: these commonly open an editor or require an interactive
69+
// terminal. Agents should use non-interactive forms (`jj describe -m`,
70+
// `git commit -m`, explicit sequence-editor/editor env) or ask in chat.
71+
"*git rebase -i*": "deny",
72+
"*git rebase --interactive*": "deny",
73+
"*git -c sequence.editor=: rebase -i*": "allow",
74+
"*git -c sequence.editor=true rebase -i*": "allow",
75+
"*GIT_SEQUENCE_EDITOR=:*git rebase -i*": "allow",
76+
"*GIT_SEQUENCE_EDITOR=true*git rebase -i*": "allow",
77+
"*GIT_EDITOR=vim*git rebase*": "deny",
78+
"*GIT_EDITOR=nvim*git rebase*": "deny",
79+
"*GIT_SEQUENCE_EDITOR=vim*git rebase*": "deny",
80+
"*GIT_SEQUENCE_EDITOR=nvim*git rebase*": "deny",
81+
"git commit": "deny",
82+
"*&& git commit": "deny",
83+
6384
// Never let an agent reboot/power off a host directly. Require the human to do it
6485
// or use a guarded deployment workflow that owns rollback semantics.
6586
"*sudo reboot*": "deny",

packages/pi-packages/pi-command-policy-bridge/README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,9 @@ For supported tool calls, the extension extracts the embedded command and evalua
1717
- `allow` lets the tool call proceed
1818
- no matching rule allows the tool call
1919

20-
This package is intentionally a deny-list guardrail, not an approval system or LLM danger classifier.
20+
This package is intentionally a deny-list guardrail, not an approval system or LLM danger classifier. If a command is not explicitly denied, it runs without prompting.
21+
22+
The deny list can include both:
23+
24+
- dangerous commands: bypass safety rails, mutate host state, or weaken repo integrity
25+
- foot-guns: likely to hang, open an interactive editor, or wedge the agent session

packages/pi-packages/pi-command-policy-bridge/index.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,29 @@ describe("pi-command-policy-bridge", () => {
8989
rmSync(dir, { recursive: true, force: true });
9090
}
9191
});
92+
93+
it("treats foot-gun rules as explicit denies, not prompts", () => {
94+
const dir = mkdtempSync(join(tmpdir(), "pi-footgun-policy-test-"));
95+
const previous = process.env.PI_PERMISSION_SYSTEM_POLICY_AGENT_DIR;
96+
process.env.PI_PERMISSION_SYSTEM_POLICY_AGENT_DIR = dir;
97+
writeFileSync(
98+
join(dir, "pi-permissions.jsonc"),
99+
'{ "bash": { "*": "allow", "*git rebase -i*": "deny" } }'
100+
);
101+
102+
try {
103+
const decision = evaluateToolGuard({
104+
toolName: "bash",
105+
input: { command: "git rebase -i HEAD~3" },
106+
});
107+
expect(decision.kind).toBe("deny");
108+
} finally {
109+
if (previous === undefined) {
110+
delete process.env.PI_PERMISSION_SYSTEM_POLICY_AGENT_DIR;
111+
} else {
112+
process.env.PI_PERMISSION_SYSTEM_POLICY_AGENT_DIR = previous;
113+
}
114+
rmSync(dir, { recursive: true, force: true });
115+
}
116+
});
92117
});

0 commit comments

Comments
 (0)