@windyroad/itil 0.35.5 → 0.35.6-preview.363
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -13,10 +13,19 @@
|
|
|
13
13
|
# shape (no skill wrapper required — authoring a changeset is a
|
|
14
14
|
# single command).
|
|
15
15
|
#
|
|
16
|
+
# Command-shape detection delegates to
|
|
17
|
+
# `lib/command-detect.sh::command_invokes_git_commit`, which strips
|
|
18
|
+
# common prefix shapes (leading whitespace, env-var assignments,
|
|
19
|
+
# `cd <path> &&`) and checks whether the residual leading token pair
|
|
20
|
+
# is literally `git commit`. P272: replaced the prior substring match
|
|
21
|
+
# `*"git commit"*` that misfired on non-commit Bash whose argument
|
|
22
|
+
# vectors merely mentioned the phrase (grep / sed / cat-heredoc /
|
|
23
|
+
# echo / `git log --grep`).
|
|
24
|
+
#
|
|
16
25
|
# Allow paths (exit 0 silently per ADR-045 Pattern 1):
|
|
17
26
|
# - tool_name != "Bash" (only Bash invocations are gated)
|
|
18
|
-
# - command
|
|
19
|
-
#
|
|
27
|
+
# - command is not a `git commit` invocation by leading-executable
|
|
28
|
+
# semantics (helper returns 1)
|
|
20
29
|
# - staged set is changeset-clean (helper returns 0)
|
|
21
30
|
# - BYPASS_CHANGESET_GATE=1 env (helper returns 0 first)
|
|
22
31
|
# - outside a git work tree (helper fails-open)
|
|
@@ -41,10 +50,15 @@
|
|
|
41
50
|
# `.changeset/*.md`); composes-with as defence-in-depth.
|
|
42
51
|
# P125 — sibling staging-trap hook (same enforcement-layer shape).
|
|
43
52
|
# P141 — this hook.
|
|
53
|
+
# P268 — shared `command_invokes_git_commit` helper landed for
|
|
54
|
+
# `itil-readme-refresh-discipline.sh`; consumed here.
|
|
55
|
+
# P272 — sibling-hook refactor: substring-match → helper here.
|
|
44
56
|
|
|
45
57
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
46
58
|
# shellcheck source=lib/changeset-detect.sh
|
|
47
59
|
source "$SCRIPT_DIR/lib/changeset-detect.sh"
|
|
60
|
+
# shellcheck source=lib/command-detect.sh
|
|
61
|
+
source "$SCRIPT_DIR/lib/command-detect.sh"
|
|
48
62
|
|
|
49
63
|
INPUT=$(cat)
|
|
50
64
|
|
|
@@ -71,13 +85,15 @@ except:
|
|
|
71
85
|
print('')
|
|
72
86
|
" 2>/dev/null || echo "")
|
|
73
87
|
|
|
74
|
-
# Only fire on `git commit` invocations.
|
|
75
|
-
#
|
|
76
|
-
#
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
88
|
+
# Only fire on actual `git commit` invocations. Delegates to
|
|
89
|
+
# `lib/command-detect.sh::command_invokes_git_commit`, which strips
|
|
90
|
+
# common prefix shapes (leading whitespace, env-var assignments,
|
|
91
|
+
# `cd <path> &&`) and checks whether the residual leading token pair
|
|
92
|
+
# is literally `git commit`. P272: replaced the prior substring match
|
|
93
|
+
# `*"git commit"*` that misfired on non-commit Bash whose argument
|
|
94
|
+
# vectors merely mentioned the phrase (grep / sed / cat-heredoc /
|
|
95
|
+
# echo / `git log --grep`).
|
|
96
|
+
command_invokes_git_commit "$COMMAND" || exit 0
|
|
81
97
|
|
|
82
98
|
# Run detection. Helper echoes offending plugin slug on stdout when
|
|
83
99
|
# detected; returns 1 in that case. Returns 0 (allow) on no-trap,
|
|
@@ -245,3 +245,112 @@ run_bash_hook() {
|
|
|
245
245
|
[ "$status" -eq 0 ]
|
|
246
246
|
[[ "$output" != *"\"permissionDecision\": \"deny\""* ]]
|
|
247
247
|
}
|
|
248
|
+
|
|
249
|
+
# --- P272: substring-vs-invocation regression coverage ---
|
|
250
|
+
#
|
|
251
|
+
# Prior to P272, the hook used `case "$COMMAND" in *"git commit"*) ;;`
|
|
252
|
+
# which fired on ANY Bash command whose text contained the literal
|
|
253
|
+
# phrase "git commit" — including grep patterns, sed substitutions,
|
|
254
|
+
# cat heredoc bodies, echo strings, and `git log --grep` queries.
|
|
255
|
+
# Workaround was stage-changeset-first-or-different-shell, observed
|
|
256
|
+
# ≥3 events per session in the P268 sibling-hook class.
|
|
257
|
+
# P272 replaces that match with a leading-executable-token check via
|
|
258
|
+
# `lib/command-detect.sh::command_invokes_git_commit` (the shared
|
|
259
|
+
# helper landed by P268). The tests below stage `@windyroad/itil/`
|
|
260
|
+
# source (which would trigger deny if the gate fired) and run various
|
|
261
|
+
# non-commit Bash commands whose argument vectors mention `git commit`.
|
|
262
|
+
# The hook MUST pass silently.
|
|
263
|
+
|
|
264
|
+
@test "P272 allow: grep with 'git commit' pattern does NOT trigger gate" {
|
|
265
|
+
echo "skill body" > packages/itil/skills/foo/SKILL.md
|
|
266
|
+
git add packages/itil/skills/foo/SKILL.md
|
|
267
|
+
run run_bash_hook "grep -n 'git commit' file.md"
|
|
268
|
+
[ "$status" -eq 0 ]
|
|
269
|
+
[[ "$output" != *"\"permissionDecision\": \"deny\""* ]]
|
|
270
|
+
# Silent pass per ADR-045 Pattern 1.
|
|
271
|
+
[ "${#output}" -eq 0 ]
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
@test "P272 allow: grep -rn 'git commit' packages/ (the recurring orchestrator surface)" {
|
|
275
|
+
echo "skill body" > packages/itil/skills/foo/SKILL.md
|
|
276
|
+
git add packages/itil/skills/foo/SKILL.md
|
|
277
|
+
run run_bash_hook "grep -rn 'git commit' packages/"
|
|
278
|
+
[ "$status" -eq 0 ]
|
|
279
|
+
[[ "$output" != *"\"permissionDecision\": \"deny\""* ]]
|
|
280
|
+
[ "${#output}" -eq 0 ]
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
@test "P272 allow: sed -i 's/git commit/.../' substitution does NOT trigger gate" {
|
|
284
|
+
echo "skill body" > packages/itil/skills/foo/SKILL.md
|
|
285
|
+
git add packages/itil/skills/foo/SKILL.md
|
|
286
|
+
run run_bash_hook "sed -i 's/git commit/git push/' file.md"
|
|
287
|
+
[ "$status" -eq 0 ]
|
|
288
|
+
[[ "$output" != *"\"permissionDecision\": \"deny\""* ]]
|
|
289
|
+
[ "${#output}" -eq 0 ]
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
@test "P272 allow: echo with 'git commit' inside string does NOT trigger gate" {
|
|
293
|
+
echo "skill body" > packages/itil/skills/foo/SKILL.md
|
|
294
|
+
git add packages/itil/skills/foo/SKILL.md
|
|
295
|
+
run run_bash_hook "echo 'the git commit gate fires here'"
|
|
296
|
+
[ "$status" -eq 0 ]
|
|
297
|
+
[[ "$output" != *"\"permissionDecision\": \"deny\""* ]]
|
|
298
|
+
[ "${#output}" -eq 0 ]
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
@test "P272 allow: git log --grep 'git commit' does NOT trigger gate (git log is leading)" {
|
|
302
|
+
echo "skill body" > packages/itil/skills/foo/SKILL.md
|
|
303
|
+
git add packages/itil/skills/foo/SKILL.md
|
|
304
|
+
run run_bash_hook "git log --grep 'git commit'"
|
|
305
|
+
[ "$status" -eq 0 ]
|
|
306
|
+
[[ "$output" != *"\"permissionDecision\": \"deny\""* ]]
|
|
307
|
+
[ "${#output}" -eq 0 ]
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
@test "P272 allow: cat heredoc whose body contains 'git commit' does NOT trigger gate (retro-write surface)" {
|
|
311
|
+
echo "skill body" > packages/itil/skills/foo/SKILL.md
|
|
312
|
+
git add packages/itil/skills/foo/SKILL.md
|
|
313
|
+
# Inline-build JSON with embedded newlines via python3 to mimic the
|
|
314
|
+
# Bash tool's multi-line command payload (the canonical retro-write
|
|
315
|
+
# surface that misfired in the P268 sibling).
|
|
316
|
+
local payload
|
|
317
|
+
payload=$(python3 -c "import json,sys; print(json.dumps({'tool_name':'Bash','tool_input':{'command':'cat >> docs/problems/README-history.md <<EOF\nFlow note: the git commit gate fires here.\nEOF'}}))")
|
|
318
|
+
run bash -c "echo '$payload' | bash $HOOK"
|
|
319
|
+
[ "$status" -eq 0 ]
|
|
320
|
+
[[ "$output" != *"\"permissionDecision\": \"deny\""* ]]
|
|
321
|
+
[ "${#output}" -eq 0 ]
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
@test "P272 allow: git commit-tree (boundary check — commit-tree is a different plumbing command)" {
|
|
325
|
+
echo "skill body" > packages/itil/skills/foo/SKILL.md
|
|
326
|
+
git add packages/itil/skills/foo/SKILL.md
|
|
327
|
+
run run_bash_hook "git commit-tree HEAD^{tree}"
|
|
328
|
+
[ "$status" -eq 0 ]
|
|
329
|
+
[[ "$output" != *"\"permissionDecision\": \"deny\""* ]]
|
|
330
|
+
[ "${#output}" -eq 0 ]
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
@test "P272 deny: actual git commit invocation with staged packages/<plugin>/ source still triggers gate (positive regression)" {
|
|
334
|
+
echo "skill body" > packages/itil/skills/foo/SKILL.md
|
|
335
|
+
git add packages/itil/skills/foo/SKILL.md
|
|
336
|
+
run run_bash_hook "git commit -m 'feat'"
|
|
337
|
+
[ "$status" -eq 0 ]
|
|
338
|
+
[[ "$output" == *"\"permissionDecision\": \"deny\""* ]]
|
|
339
|
+
[[ "$output" == *"P141"* ]]
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
@test "P272 deny: cd <path> && git commit (prefix-strip path) still triggers gate" {
|
|
343
|
+
echo "skill body" > packages/itil/skills/foo/SKILL.md
|
|
344
|
+
git add packages/itil/skills/foo/SKILL.md
|
|
345
|
+
run run_bash_hook "cd . && git commit -m 'feat'"
|
|
346
|
+
[ "$status" -eq 0 ]
|
|
347
|
+
[[ "$output" == *"\"permissionDecision\": \"deny\""* ]]
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
@test "P272 deny: GIT_AUTHOR_NAME=Test git commit (env-prefix path) still triggers gate" {
|
|
351
|
+
echo "skill body" > packages/itil/skills/foo/SKILL.md
|
|
352
|
+
git add packages/itil/skills/foo/SKILL.md
|
|
353
|
+
run run_bash_hook "GIT_AUTHOR_NAME=Test git commit -m 'feat'"
|
|
354
|
+
[ "$status" -eq 0 ]
|
|
355
|
+
[[ "$output" == *"\"permissionDecision\": \"deny\""* ]]
|
|
356
|
+
}
|
package/package.json
CHANGED