@windyroad/risk-scorer 0.13.2 → 0.13.3
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.
|
@@ -318,6 +318,28 @@ if [ "$EXTERNAL_COMMS_LEAK_PREFILTER" = "yes" ]; then
|
|
|
318
318
|
fi
|
|
319
319
|
fi
|
|
320
320
|
|
|
321
|
+
# ---------- Repo-visibility precondition: git-commit-message surface (P365) ----------
|
|
322
|
+
# A commit message only becomes external-facing prose when it lands in a PUBLIC
|
|
323
|
+
# GitHub repo (git log / PR commits tab / release-page auto-notes / CHANGELOG).
|
|
324
|
+
# In private or internal repos the marker-review delegation deny below is a pure
|
|
325
|
+
# false-positive (P365 — user direction 2026-06-11: "this MUST NOT fire for
|
|
326
|
+
# private repos"). Confirm visibility authoritatively via gh and silent-pass the
|
|
327
|
+
# marker gate on any non-PUBLIC result. Any INDETERMINATE result (gh absent,
|
|
328
|
+
# unauthenticated, no remote, API error → empty $REPO_VISIBILITY) is treated as
|
|
329
|
+
# non-public: a commit message is only demonstrably external when the repo is
|
|
330
|
+
# confirmably PUBLIC, so the conservative direction for THIS surface is to not
|
|
331
|
+
# fire. This is a fail-open on the voice/tone-and-prose review ONLY — the
|
|
332
|
+
# leak-pattern pre-filter above (credentials / prod-URLs) has already run for
|
|
333
|
+
# every surface in every repo, so the high-stakes secrecy net is unaffected.
|
|
334
|
+
# Scoped to git-commit-message only; the gh-issue/pr/api, npm-publish, and
|
|
335
|
+
# changeset-author surfaces are inherently external and stay gated regardless.
|
|
336
|
+
if [ "$SURFACE" = "git-commit-message" ]; then
|
|
337
|
+
REPO_VISIBILITY=$(gh repo view --json visibility -q .visibility 2>/dev/null || echo "")
|
|
338
|
+
if [ "$REPO_VISIBILITY" != "PUBLIC" ]; then
|
|
339
|
+
exit 0
|
|
340
|
+
fi
|
|
341
|
+
fi
|
|
342
|
+
|
|
321
343
|
# ---------- Marker-based gate (per-evaluator marker per ADR-028 amended 2026-05-14) ----------
|
|
322
344
|
SESSION_DIR="${TMPDIR:-/tmp}/claude-risk-${SESSION_ID}"
|
|
323
345
|
mkdir -p "$SESSION_DIR"
|
|
@@ -65,10 +65,28 @@ print(json.dumps({
|
|
|
65
65
|
" "$file_path" "$content"
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
# Mock `gh repo view --json visibility` for the git-commit-message surface
|
|
69
|
+
# repo-visibility precondition (P365). vis ∈ {PUBLIC,PRIVATE,INTERNAL}; pass the
|
|
70
|
+
# literal "FAIL" to simulate gh absent / unauthenticated (non-zero exit). The
|
|
71
|
+
# mock ignores args and prints the chosen visibility so the hook's
|
|
72
|
+
# `gh repo view --json visibility -q .visibility` resolves deterministically.
|
|
73
|
+
mock_gh_visibility() {
|
|
74
|
+
local vis="$1"
|
|
75
|
+
mkdir -p "$TEST_PROJECT_DIR/mockbin"
|
|
76
|
+
if [ "$vis" = "FAIL" ]; then
|
|
77
|
+
printf '#!/usr/bin/env bash\nexit 1\n' > "$TEST_PROJECT_DIR/mockbin/gh"
|
|
78
|
+
else
|
|
79
|
+
printf '#!/usr/bin/env bash\necho %s\n' "$vis" > "$TEST_PROJECT_DIR/mockbin/gh"
|
|
80
|
+
fi
|
|
81
|
+
chmod +x "$TEST_PROJECT_DIR/mockbin/gh"
|
|
82
|
+
}
|
|
83
|
+
|
|
68
84
|
# Run the hook in a project dir with RISK-POLICY.md present, piping JSON via stdin.
|
|
85
|
+
# mockbin (if populated by mock_gh_visibility) is prepended to PATH so the
|
|
86
|
+
# git-commit-message visibility precondition resolves against the mock.
|
|
69
87
|
run_hook() {
|
|
70
88
|
local input="$1"
|
|
71
|
-
run bash -c "cd '$TEST_PROJECT_DIR' && printf '%s' \"\$1\" | '$HOOK'" _ "$input"
|
|
89
|
+
run bash -c "cd '$TEST_PROJECT_DIR' && export PATH='$TEST_PROJECT_DIR/mockbin':\$PATH && printf '%s' \"\$1\" | '$HOOK'" _ "$input"
|
|
72
90
|
}
|
|
73
91
|
|
|
74
92
|
# ---------- Tests ----------
|
|
@@ -244,6 +262,7 @@ run_hook() {
|
|
|
244
262
|
}
|
|
245
263
|
|
|
246
264
|
@test "P082: git commit -m with leak-free body denies and delegates to risk evaluator" {
|
|
265
|
+
mock_gh_visibility PUBLIC
|
|
247
266
|
INPUT=$(build_bash_input "git commit -m \"fix(foo): handle null input\"")
|
|
248
267
|
run_hook "$INPUT"
|
|
249
268
|
[ "$status" -eq 0 ]
|
|
@@ -253,6 +272,7 @@ run_hook() {
|
|
|
253
272
|
}
|
|
254
273
|
|
|
255
274
|
@test "P082: git commit --amend -m is intercepted (P082 SC2)" {
|
|
275
|
+
mock_gh_visibility PUBLIC
|
|
256
276
|
INPUT=$(build_bash_input "git commit --amend -m \"rewritten subject\"")
|
|
257
277
|
run_hook "$INPUT"
|
|
258
278
|
[ "$status" -eq 0 ]
|
|
@@ -264,6 +284,7 @@ run_hook() {
|
|
|
264
284
|
# Build a HEREDOC-shaped command. The hook regex pulls the body BETWEEN
|
|
265
285
|
# the <<'EOF' opener and the closing EOF marker — the extracted DRAFT is
|
|
266
286
|
# the inner text, NOT the literal `$(cat <<'EOF' ... EOF)` wrapper.
|
|
287
|
+
mock_gh_visibility PUBLIC
|
|
267
288
|
BODY=$'feat(foo): add bar\n\nWe observed a build failure on Node 20.'
|
|
268
289
|
CMD=$'git commit -m "$(cat <<\'EOF\'\n'"$BODY"$'\nEOF\n)"'
|
|
269
290
|
INPUT=$(build_bash_input "$CMD")
|
|
@@ -306,6 +327,7 @@ run_hook() {
|
|
|
306
327
|
}
|
|
307
328
|
|
|
308
329
|
@test "P082: per-evaluator marker keyed on (body, git-commit-message) permits the call" {
|
|
330
|
+
mock_gh_visibility PUBLIC
|
|
309
331
|
BODY="docs(retro): close iter 3 ask-hygiene trail"
|
|
310
332
|
SURFACE="git-commit-message"
|
|
311
333
|
KEY=$(printf '%s\n%s' "$BODY" "$SURFACE" | shasum -a 256 | cut -d' ' -f1)
|
|
@@ -317,6 +339,70 @@ run_hook() {
|
|
|
317
339
|
[ -z "$output" ]
|
|
318
340
|
}
|
|
319
341
|
|
|
342
|
+
# ---------------------------------------------------------------------------
|
|
343
|
+
# P365 — repo-visibility precondition on the git-commit-message surface.
|
|
344
|
+
# A commit message is external-facing prose ONLY when it lands in a PUBLIC
|
|
345
|
+
# GitHub repo (git log / PR commits tab / release notes / CHANGELOG). In
|
|
346
|
+
# private/internal repos — or any repo whose visibility cannot be confirmed
|
|
347
|
+
# PUBLIC — the marker-review delegation deny is a pure false-positive
|
|
348
|
+
# (user direction 2026-06-11: "this MUST NOT fire for private repos"). The
|
|
349
|
+
# precondition silent-passes the marker gate for the git-commit-message
|
|
350
|
+
# surface on any non-PUBLIC / indeterminate gh result. It is scoped to that
|
|
351
|
+
# surface only and runs AFTER the leak pre-filter, so the credential/prod-URL
|
|
352
|
+
# security net survives the short-circuit.
|
|
353
|
+
# ---------------------------------------------------------------------------
|
|
354
|
+
|
|
355
|
+
@test "P365: git commit -m in a PRIVATE repo silent-passes (no external-comms deny)" {
|
|
356
|
+
mock_gh_visibility PRIVATE
|
|
357
|
+
INPUT=$(build_bash_input "git commit -m \"fix(foo): handle null input\"")
|
|
358
|
+
run_hook "$INPUT"
|
|
359
|
+
[ "$status" -eq 0 ]
|
|
360
|
+
[ -z "$output" ]
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
@test "P365: git commit -m in an INTERNAL repo silent-passes" {
|
|
364
|
+
mock_gh_visibility INTERNAL
|
|
365
|
+
INPUT=$(build_bash_input "git commit -m \"fix(foo): handle null input\"")
|
|
366
|
+
run_hook "$INPUT"
|
|
367
|
+
[ "$status" -eq 0 ]
|
|
368
|
+
[ -z "$output" ]
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
@test "P365: git commit -m when gh is unavailable/indeterminate silent-passes (fail-non-public)" {
|
|
372
|
+
mock_gh_visibility FAIL
|
|
373
|
+
INPUT=$(build_bash_input "git commit -m \"fix(foo): handle null input\"")
|
|
374
|
+
run_hook "$INPUT"
|
|
375
|
+
[ "$status" -eq 0 ]
|
|
376
|
+
[ -z "$output" ]
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
@test "P365: git commit -m in a PUBLIC repo still denies+delegates (gate intact, precondition surface-scoped)" {
|
|
380
|
+
mock_gh_visibility PUBLIC
|
|
381
|
+
INPUT=$(build_bash_input "git commit -m \"fix(foo): handle null input\"")
|
|
382
|
+
run_hook "$INPUT"
|
|
383
|
+
[ "$status" -eq 0 ]
|
|
384
|
+
[[ "$output" == *"deny"* ]]
|
|
385
|
+
[[ "$output" == *"git-commit-message"* ]]
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
@test "P365: leak-shaped credential in a PRIVATE-repo commit body still hard-fails (security net survives)" {
|
|
389
|
+
mock_gh_visibility PRIVATE
|
|
390
|
+
INPUT=$(build_bash_input "git commit -m \"docs: token=${GH_TOKEN_LIKE}\"")
|
|
391
|
+
run_hook "$INPUT"
|
|
392
|
+
[ "$status" -eq 0 ]
|
|
393
|
+
[[ "$output" == *"deny"* ]]
|
|
394
|
+
[[ "$output" == *"git-commit-message"* ]]
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
@test "P365: PRIVATE visibility does NOT short-circuit the gh-issue surface (still denies+delegates)" {
|
|
398
|
+
mock_gh_visibility PRIVATE
|
|
399
|
+
INPUT=$(build_bash_input "gh issue create --title x --body 'a clean issue body'")
|
|
400
|
+
run_hook "$INPUT"
|
|
401
|
+
[ "$status" -eq 0 ]
|
|
402
|
+
[[ "$output" == *"deny"* ]]
|
|
403
|
+
[[ "$output" == *"gh-issue-create"* ]]
|
|
404
|
+
}
|
|
405
|
+
|
|
320
406
|
# ---------------------------------------------------------------------------
|
|
321
407
|
# P364 — backtick-bearing double-quoted --body marker-key mismatch.
|
|
322
408
|
# When an outbound body contains markdown backticks (a code span), the
|