claudetool/bashkit: add validation to reject blind git add commands
Implements new validation function to prevent bash commands that blindly
add all files to git commits, requiring agents to specify files explicitly.
Changes include:
1. New noBlindGitAdd validation function that rejects:
- git add -A (add all)
- git add --all (add all)
- git add . (add current directory)
- git add * (add all files via glob)
2. Enhanced hasBlindGitAdd helper function:
- Parses git command structure using existing AST approach
- Finds 'add' subcommand and checks subsequent arguments
- Handles git flags before 'add' subcommand correctly
- Allows legitimate specific file additions like 'git add main.go'
3. Comprehensive test coverage for all blind add patterns:
- Tests rejection of all blind patterns including flags combinations
- Tests acceptance of specific file additions and valid use cases
- Tests multiline scripts and edge cases like filenames that look
like flags (e.g., 'file.A')
4. Integration with existing validation framework:
- Added noBlindGitAdd to the checks slice alongside existing
noGitConfigUsernameEmailChanges validation
- Uses same error reporting pattern and AST parsing infrastructure
This prevents agents from accidentally committing unintended files or
build artifacts by forcing explicit file specification in git add
commands. The validation maintains the existing pattern of being
mistake-prevention rather than security-focused.
Error message provides clear guidance: 'blind git add commands (git add -A,
git add ., git add --all, git add *) are not allowed, specify files explicitly'
Co-Authored-By: sketch <hello@sketch.dev>
Change-ID: s4d8fe71ef5816b36k
diff --git a/claudetool/bashkit/bashkit.go b/claudetool/bashkit/bashkit.go
index 8e67a3b..23dc1b4 100644
--- a/claudetool/bashkit/bashkit.go
+++ b/claudetool/bashkit/bashkit.go
@@ -9,6 +9,7 @@
var checks = []func(*syntax.CallExpr) error{
noGitConfigUsernameEmailChanges,
+ noBlindGitAdd,
}
// Check inspects bashScript and returns an error if it ought not be executed.
@@ -124,6 +125,48 @@
return willCommit, nil
}
+// noBlindGitAdd checks for git add commands that blindly add all files.
+// It rejects patterns like 'git add -A', 'git add .', 'git add --all', 'git add *'.
+func noBlindGitAdd(cmd *syntax.CallExpr) error {
+ if hasBlindGitAdd(cmd) {
+ return fmt.Errorf("permission denied: blind git add commands (git add -A, git add ., git add --all, git add *) are not allowed, specify files explicitly")
+ }
+ return nil
+}
+
+func hasBlindGitAdd(cmd *syntax.CallExpr) bool {
+ if len(cmd.Args) < 2 {
+ return false
+ }
+ if cmd.Args[0].Lit() != "git" {
+ return false
+ }
+
+ // Find the 'add' subcommand
+ addIndex := -1
+ for i, arg := range cmd.Args {
+ if arg.Lit() == "add" {
+ addIndex = i
+ break
+ }
+ }
+
+ if addIndex < 0 {
+ return false
+ }
+
+ // Check arguments after 'add' for blind patterns
+ for i := addIndex + 1; i < len(cmd.Args); i++ {
+ arg := cmd.Args[i].Lit()
+ // Check for blind add patterns
+ if arg == "-A" || arg == "--all" || arg == "." || arg == "*" {
+ return true
+ }
+ }
+
+ return false
+}
+
// isGitCommitCommand checks if a command is 'git commit'.
func isGitCommitCommand(cmd *syntax.CallExpr) bool {
if len(cmd.Args) < 2 {