Skip to content

Commit 01f9cf9

Browse files
committed
feat(rules): block inline redis-cli mutations
Adds Redis to the inline-db-mutation family. Even in a cache, manual one-liners create cross-env drift: the value you set is visible to your machine only until eviction, and other engineers cannot reproduce. Write verbs blocked: SET / DEL / FLUSHDB / FLUSHALL / HSET / HDEL / SADD / SREM / LPUSH / RPUSH / ZADD / ZREM / EXPIRE / RENAME / MSET / SETEX / SETNX / INCR / DECR / COPY / MOVE / UNLINK / RESTORE / EVAL (EVAL is included because Lua scripts can mutate). Read verbs (GET, MGET, HGET, KEYS, SCAN, INFO, PING, EXISTS, TYPE, TTL, LLEN, SCARD, ZRANGE, SMEMBERS, ...) remain allowed inline. Bypass via `# hook-bypass: db-mutation-rule` or the per-repo sentinel `.no-make-no-mistakes-db-mutation`. Tests: 10 (5 block + 4 allow + 1 bypass).
1 parent 14680ef commit 01f9cf9

2 files changed

Lines changed: 200 additions & 0 deletions

File tree

hooks/rules/rules.json

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3199,5 +3199,120 @@
31993199
"expected_exit": 0
32003200
}
32013201
]
3202+
},
3203+
{
3204+
"id": "inline-db-mutation-redis",
3205+
"description": "Block inline redis-cli mutations (use a versioned script in scripts/ or bin/ instead)",
3206+
"applies_to": [
3207+
"Bash"
3208+
],
3209+
"match": [
3210+
{
3211+
"field": "command",
3212+
"pattern": "\\bredis-cli\\b[^|]*[[:space:]]+(SET|DEL|FLUSHDB|FLUSHALL|HSET|HDEL|SADD|SREM|LPUSH|RPUSH|ZADD|ZREM|EXPIRE|RENAME|MSET|SETEX|SETNX|INCR|DECR|COPY|MOVE|UNLINK|RESTORE|EVAL)\\b",
3213+
"flags": "i"
3214+
},
3215+
{
3216+
"field": "command",
3217+
"not_pattern": "^[[:space:]]*(\\./scripts/|bash[[:space:]]+scripts/|\\./bin/|bash[[:space:]]+bin/|sh[[:space:]]+scripts/|sh[[:space:]]+bin/)"
3218+
}
3219+
],
3220+
"action": "block",
3221+
"bypass_marker": "db-mutation-rule",
3222+
"disable_if_repo_file": ".no-make-no-mistakes-db-mutation",
3223+
"memory_ref": "feedback_scripts_not_db.md",
3224+
"message": "BLOCKED: inline redis-cli mutation detected.\n\nEven in a cache, manual one-liners create cross-env drift: the value\nyou set is visible to your machine only until eviction, and other\nengineers cannot reproduce. Use a script under scripts/ or bin/.\n\nRead verbs (GET, MGET, HGET, KEYS, SCAN, INFO, PING, EXISTS, TYPE,\nTTL, LLEN, SCARD, ZRANGE, SMEMBERS, ...) remain allowed inline.\n\nBypass marker: `db-mutation-rule`. Per-repo opt-out:\n`touch .no-make-no-mistakes-db-mutation` at the root.\n",
3225+
"tests": [
3226+
{
3227+
"name": "blocks-redis-cli-set",
3228+
"input": {
3229+
"tool_input": {
3230+
"command": "redis-cli SET feature:enabled 1"
3231+
}
3232+
},
3233+
"expected_exit": 2
3234+
},
3235+
{
3236+
"name": "blocks-redis-cli-del",
3237+
"input": {
3238+
"tool_input": {
3239+
"command": "redis-cli DEL session:42"
3240+
}
3241+
},
3242+
"expected_exit": 2
3243+
},
3244+
{
3245+
"name": "blocks-redis-cli-flushall",
3246+
"input": {
3247+
"tool_input": {
3248+
"command": "redis-cli -h cache.example.com FLUSHALL"
3249+
}
3250+
},
3251+
"expected_exit": 2
3252+
},
3253+
{
3254+
"name": "blocks-redis-cli-flushdb",
3255+
"input": {
3256+
"tool_input": {
3257+
"command": "redis-cli -n 3 FLUSHDB"
3258+
}
3259+
},
3260+
"expected_exit": 2
3261+
},
3262+
{
3263+
"name": "blocks-redis-cli-hset",
3264+
"input": {
3265+
"tool_input": {
3266+
"command": "redis-cli HSET user:1 name alice"
3267+
}
3268+
},
3269+
"expected_exit": 2
3270+
},
3271+
{
3272+
"name": "allows-redis-cli-get",
3273+
"input": {
3274+
"tool_input": {
3275+
"command": "redis-cli GET feature:enabled"
3276+
}
3277+
},
3278+
"expected_exit": 0
3279+
},
3280+
{
3281+
"name": "allows-redis-cli-keys",
3282+
"input": {
3283+
"tool_input": {
3284+
"command": "redis-cli KEYS \"session:*\""
3285+
}
3286+
},
3287+
"expected_exit": 0
3288+
},
3289+
{
3290+
"name": "allows-redis-cli-info",
3291+
"input": {
3292+
"tool_input": {
3293+
"command": "redis-cli INFO memory"
3294+
}
3295+
},
3296+
"expected_exit": 0
3297+
},
3298+
{
3299+
"name": "allows-redis-via-versioned-script",
3300+
"input": {
3301+
"tool_input": {
3302+
"command": "./scripts/flush-cache.sh"
3303+
}
3304+
},
3305+
"expected_exit": 0
3306+
},
3307+
{
3308+
"name": "allows-bypass-marker",
3309+
"input": {
3310+
"tool_input": {
3311+
"command": "redis-cli FLUSHALL # hook-bypass: db-mutation-rule"
3312+
}
3313+
},
3314+
"expected_exit": 0
3315+
}
3316+
]
32023317
}
32033318
]

hooks/rules/rules.yaml

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2595,3 +2595,88 @@
25952595
command: 'mongo --eval "db.users.drop()" # hook-bypass: db-mutation-rule'
25962596
expected_exit: 0
25972597

2598+
- id: inline-db-mutation-redis
2599+
description: Block inline redis-cli mutations (use a versioned script in scripts/ or bin/ instead)
2600+
applies_to: [Bash]
2601+
match:
2602+
# Positive: `redis-cli ... <MUTATING_VERB> ...`. The Redis command
2603+
# surface is large — match the common write verbs that show up in
2604+
# incident-driven one-liners: SET, DEL, FLUSHDB, FLUSHALL, HSET,
2605+
# HDEL, SADD, SREM, LPUSH, RPUSH, ZADD, ZREM, EXPIRE, RENAME, MSET,
2606+
# SETEX, SETNX, INCR, DECR, COPY, MOVE, UNLINK, RESTORE, EVAL (EVAL
2607+
# can mutate via Lua even though it can also read).
2608+
# Verb must be at command-word boundaries to avoid mis-matching
2609+
# values that happen to contain those substrings.
2610+
- field: command
2611+
pattern: '\bredis-cli\b[^|]*[[:space:]]+(SET|DEL|FLUSHDB|FLUSHALL|HSET|HDEL|SADD|SREM|LPUSH|RPUSH|ZADD|ZREM|EXPIRE|RENAME|MSET|SETEX|SETNX|INCR|DECR|COPY|MOVE|UNLINK|RESTORE|EVAL)\b'
2612+
flags: i
2613+
- field: command
2614+
not_pattern: '^[[:space:]]*(\./scripts/|bash[[:space:]]+scripts/|\./bin/|bash[[:space:]]+bin/|sh[[:space:]]+scripts/|sh[[:space:]]+bin/)'
2615+
action: block
2616+
bypass_marker: db-mutation-rule
2617+
disable_if_repo_file: .no-make-no-mistakes-db-mutation
2618+
memory_ref: feedback_scripts_not_db.md
2619+
message: |
2620+
BLOCKED: inline redis-cli mutation detected.
2621+
2622+
Even in a cache, manual one-liners create cross-env drift: the value
2623+
you set is visible to your machine only until eviction, and other
2624+
engineers cannot reproduce. Use a script under scripts/ or bin/.
2625+
2626+
Read verbs (GET, MGET, HGET, KEYS, SCAN, INFO, PING, EXISTS, TYPE,
2627+
TTL, LLEN, SCARD, ZRANGE, SMEMBERS, ...) remain allowed inline.
2628+
2629+
Bypass marker: `db-mutation-rule`. Per-repo opt-out:
2630+
`touch .no-make-no-mistakes-db-mutation` at the root.
2631+
tests:
2632+
- name: blocks-redis-cli-set
2633+
input:
2634+
tool_input:
2635+
command: 'redis-cli SET feature:enabled 1'
2636+
expected_exit: 2
2637+
- name: blocks-redis-cli-del
2638+
input:
2639+
tool_input:
2640+
command: 'redis-cli DEL session:42'
2641+
expected_exit: 2
2642+
- name: blocks-redis-cli-flushall
2643+
input:
2644+
tool_input:
2645+
command: 'redis-cli -h cache.example.com FLUSHALL'
2646+
expected_exit: 2
2647+
- name: blocks-redis-cli-flushdb
2648+
input:
2649+
tool_input:
2650+
command: 'redis-cli -n 3 FLUSHDB'
2651+
expected_exit: 2
2652+
- name: blocks-redis-cli-hset
2653+
input:
2654+
tool_input:
2655+
command: 'redis-cli HSET user:1 name alice'
2656+
expected_exit: 2
2657+
- name: allows-redis-cli-get
2658+
input:
2659+
tool_input:
2660+
command: 'redis-cli GET feature:enabled'
2661+
expected_exit: 0
2662+
- name: allows-redis-cli-keys
2663+
input:
2664+
tool_input:
2665+
command: 'redis-cli KEYS "session:*"'
2666+
expected_exit: 0
2667+
- name: allows-redis-cli-info
2668+
input:
2669+
tool_input:
2670+
command: 'redis-cli INFO memory'
2671+
expected_exit: 0
2672+
- name: allows-redis-via-versioned-script
2673+
input:
2674+
tool_input:
2675+
command: './scripts/flush-cache.sh'
2676+
expected_exit: 0
2677+
- name: allows-bypass-marker
2678+
input:
2679+
tool_input:
2680+
command: 'redis-cli FLUSHALL # hook-bypass: db-mutation-rule'
2681+
expected_exit: 0
2682+

0 commit comments

Comments
 (0)