Skip to content

Commit 94fa041

Browse files
committed
feat(rules): block inline gcloud sql import / export
Adds gcloud Cloud SQL CLI to the inline-db-mutation family. Both directions are blocked: - `gcloud sql import sql|csv|bak ...` — the obvious mutation surface, overwrites target DB state from a GCS-hosted dump. - `gcloud sql export sql|csv|bak ...` — included because production exports cost IOPS and (when carrying PII) require data-handling approval; the discipline (versioned script with documented purpose) applies equally to both directions. Versioned-script wrappers under scripts/ or bin/ remain allowed. Bypass via `# hook-bypass: db-mutation-rule` or the per-repo sentinel `.no-make-no-mistakes-db-mutation`. Tests: 7 (4 block + 2 allow + 1 bypass). Brings the inline-db-mutation family to 6 rules (mysql, psql, sqlite, mongo, redis, gcloud-sql) and 38 rules total. 262 / 262 tests pass.
1 parent 01f9cf9 commit 94fa041

2 files changed

Lines changed: 160 additions & 0 deletions

File tree

hooks/rules/rules.json

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3314,5 +3314,96 @@
33143314
"expected_exit": 0
33153315
}
33163316
]
3317+
},
3318+
{
3319+
"id": "inline-db-mutation-gcloud-sql",
3320+
"description": "Block inline `gcloud sql import` / `gcloud sql export` (use a versioned script in scripts/ or bin/ that documents the source/destination)",
3321+
"applies_to": [
3322+
"Bash"
3323+
],
3324+
"match": [
3325+
{
3326+
"field": "command",
3327+
"pattern": "\\bgcloud[[:space:]]+sql[[:space:]]+(import|export)[[:space:]]+(sql|csv|bak)\\b",
3328+
"flags": "i"
3329+
},
3330+
{
3331+
"field": "command",
3332+
"not_pattern": "^[[:space:]]*(\\./scripts/|bash[[:space:]]+scripts/|\\./bin/|bash[[:space:]]+bin/|sh[[:space:]]+scripts/|sh[[:space:]]+bin/)"
3333+
}
3334+
],
3335+
"action": "block",
3336+
"bypass_marker": "db-mutation-rule",
3337+
"disable_if_repo_file": ".no-make-no-mistakes-db-mutation",
3338+
"memory_ref": "feedback_scripts_not_db.md",
3339+
"references": [
3340+
"feedback_never_touch_prod_without_approval.md (production guardrail)"
3341+
],
3342+
"message": "BLOCKED: inline `gcloud sql import` / `gcloud sql export` detected.\n\nImports overwrite target DB state. Exports against production cost\nIOPS and (when carrying PII) violate the data-handling guidelines.\nBoth belong in a versioned script that documents:\n - source / destination instance IDs (PROD vs STAGING)\n - dump version (timestamped GCS URI)\n - PII-handling approval if any\n - rollback procedure\n\nBypass marker: `db-mutation-rule`. Per-repo opt-out:\n`touch .no-make-no-mistakes-db-mutation` at the root.\n",
3343+
"tests": [
3344+
{
3345+
"name": "blocks-gcloud-sql-import-sql",
3346+
"input": {
3347+
"tool_input": {
3348+
"command": "gcloud sql import sql my-instance gs://backups/dump.sql --database=mydb"
3349+
}
3350+
},
3351+
"expected_exit": 2
3352+
},
3353+
{
3354+
"name": "blocks-gcloud-sql-export-sql",
3355+
"input": {
3356+
"tool_input": {
3357+
"command": "gcloud sql export sql my-instance gs://backups/dump.sql --database=mydb"
3358+
}
3359+
},
3360+
"expected_exit": 2
3361+
},
3362+
{
3363+
"name": "blocks-gcloud-sql-import-csv",
3364+
"input": {
3365+
"tool_input": {
3366+
"command": "gcloud sql import csv my-instance gs://backups/users.csv --database=mydb --table=users"
3367+
}
3368+
},
3369+
"expected_exit": 2
3370+
},
3371+
{
3372+
"name": "blocks-gcloud-sql-export-bak",
3373+
"input": {
3374+
"tool_input": {
3375+
"command": "gcloud sql export bak my-instance gs://backups/dump.bak --database=mydb"
3376+
}
3377+
},
3378+
"expected_exit": 2
3379+
},
3380+
{
3381+
"name": "allows-gcloud-sql-instances-list",
3382+
"input": {
3383+
"tool_input": {
3384+
"command": "gcloud sql instances list --project=myproject"
3385+
}
3386+
},
3387+
"expected_exit": 0
3388+
},
3389+
{
3390+
"name": "allows-gcloud-sql-via-versioned-script",
3391+
"input": {
3392+
"tool_input": {
3393+
"command": "./scripts/sql-import.sh my-instance gs://backups/dump.sql"
3394+
}
3395+
},
3396+
"expected_exit": 0
3397+
},
3398+
{
3399+
"name": "allows-bypass-marker",
3400+
"input": {
3401+
"tool_input": {
3402+
"command": "gcloud sql import sql my-instance gs://backups/dump.sql --database=mydb # hook-bypass: db-mutation-rule"
3403+
}
3404+
},
3405+
"expected_exit": 0
3406+
}
3407+
]
33173408
}
33183409
]

hooks/rules/rules.yaml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2680,3 +2680,72 @@
26802680
command: 'redis-cli FLUSHALL # hook-bypass: db-mutation-rule'
26812681
expected_exit: 0
26822682

2683+
- id: inline-db-mutation-gcloud-sql
2684+
description: Block inline `gcloud sql import` / `gcloud sql export` (use a versioned script in scripts/ or bin/ that documents the source/destination)
2685+
applies_to: [Bash]
2686+
match:
2687+
# Positive: import/export of SQL or CSV dumps via the gcloud SQL CLI.
2688+
# Both directions are blocked: import is the obvious mutation surface;
2689+
# export is included because exports against PRODUCTION leak PII and
2690+
# consume IOPS, so the discipline (versioned script with documented
2691+
# purpose) applies equally.
2692+
- field: command
2693+
pattern: '\bgcloud[[:space:]]+sql[[:space:]]+(import|export)[[:space:]]+(sql|csv|bak)\b'
2694+
flags: i
2695+
- field: command
2696+
not_pattern: '^[[:space:]]*(\./scripts/|bash[[:space:]]+scripts/|\./bin/|bash[[:space:]]+bin/|sh[[:space:]]+scripts/|sh[[:space:]]+bin/)'
2697+
action: block
2698+
bypass_marker: db-mutation-rule
2699+
disable_if_repo_file: .no-make-no-mistakes-db-mutation
2700+
memory_ref: feedback_scripts_not_db.md
2701+
references:
2702+
- "feedback_never_touch_prod_without_approval.md (production guardrail)"
2703+
message: |
2704+
BLOCKED: inline `gcloud sql import` / `gcloud sql export` detected.
2705+
2706+
Imports overwrite target DB state. Exports against production cost
2707+
IOPS and (when carrying PII) violate the data-handling guidelines.
2708+
Both belong in a versioned script that documents:
2709+
- source / destination instance IDs (PROD vs STAGING)
2710+
- dump version (timestamped GCS URI)
2711+
- PII-handling approval if any
2712+
- rollback procedure
2713+
2714+
Bypass marker: `db-mutation-rule`. Per-repo opt-out:
2715+
`touch .no-make-no-mistakes-db-mutation` at the root.
2716+
tests:
2717+
- name: blocks-gcloud-sql-import-sql
2718+
input:
2719+
tool_input:
2720+
command: 'gcloud sql import sql my-instance gs://backups/dump.sql --database=mydb'
2721+
expected_exit: 2
2722+
- name: blocks-gcloud-sql-export-sql
2723+
input:
2724+
tool_input:
2725+
command: 'gcloud sql export sql my-instance gs://backups/dump.sql --database=mydb'
2726+
expected_exit: 2
2727+
- name: blocks-gcloud-sql-import-csv
2728+
input:
2729+
tool_input:
2730+
command: 'gcloud sql import csv my-instance gs://backups/users.csv --database=mydb --table=users'
2731+
expected_exit: 2
2732+
- name: blocks-gcloud-sql-export-bak
2733+
input:
2734+
tool_input:
2735+
command: 'gcloud sql export bak my-instance gs://backups/dump.bak --database=mydb'
2736+
expected_exit: 2
2737+
- name: allows-gcloud-sql-instances-list
2738+
input:
2739+
tool_input:
2740+
command: 'gcloud sql instances list --project=myproject'
2741+
expected_exit: 0
2742+
- name: allows-gcloud-sql-via-versioned-script
2743+
input:
2744+
tool_input:
2745+
command: './scripts/sql-import.sh my-instance gs://backups/dump.sql'
2746+
expected_exit: 0
2747+
- name: allows-bypass-marker
2748+
input:
2749+
tool_input:
2750+
command: 'gcloud sql import sql my-instance gs://backups/dump.sql --database=mydb # hook-bypass: db-mutation-rule'
2751+
expected_exit: 0

0 commit comments

Comments
 (0)