forked from retoor/devplacepy
data/devplace.db is the live database and make dev, make prod and the Docker stack all share it, so an agent-initiated command that reaches it is a production incident waiting for a typo. The hazard is invisible in the command text: the script that prompted this named no path at all, it imported devplacepy and therefore resolved config.DATA_DIR to the real file. A path-pattern rule would have sailed straight past it. The PreToolUse hook reads the script and judges it on content, so one that points DEVPLACE_DATABASE_URL at a scratch file passes and an unguarded one does not. It also refuses commands naming the database or a production data directory, the management CLI, and python -m devplacepy. The suite, the server targets and the mandated import gate stay free. permissions.deny additionally refuses Write and Edit anywhere under data, which the Bash hook cannot see. The escape hatch is two-factor and cannot be self-served: without confirmation the command is denied outright rather than prompted, and the token that downgrades it to a prompt may only be added after the user has confirmed in their own words. Verified against thirty-five commands, and the heuristic is narrower than it looks because the repository path itself contains the package name, so it matches an import statement rather than the bare word. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
26 lines
554 B
JSON
26 lines
554 B
JSON
{
|
|
"$schema": "https://json.schemastore.org/claude-code-settings.json",
|
|
"permissions": {
|
|
"deny": [
|
|
"Bash(devplace *)",
|
|
"Write(data/**)",
|
|
"Edit(data/**)"
|
|
]
|
|
},
|
|
"hooks": {
|
|
"PreToolUse": [
|
|
{
|
|
"matcher": "Bash",
|
|
"hooks": [
|
|
{
|
|
"type": "command",
|
|
"command": "python3 \"$CLAUDE_PROJECT_DIR/.claude/hooks/guard_production_db.py\"",
|
|
"timeout": 10,
|
|
"statusMessage": "Checking for production database access"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
}
|