@windyroad/risk-scorer 0.15.1 → 0.16.0-preview.885

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.
@@ -310,5 +310,5 @@
310
310
  }
311
311
  },
312
312
  "name": "wr-risk-scorer",
313
- "version": "0.15.1"
313
+ "version": "0.16.0"
314
314
  }
@@ -125,6 +125,19 @@ except Exception:
125
125
  # Permit silently when session_id is absent; the gate cannot key a marker.
126
126
  [ -n "$SESSION_ID" ] || exit 0
127
127
 
128
+ # P405: `gh api` defaults to a read (GET). It only carries an outbound prose
129
+ # body — the thing this gate reviews — when a request-body flag is supplied
130
+ # (-f/--field, -F/--raw-field, --input; any of these flips gh api's default to
131
+ # POST). Read-only polls carry none — e.g. `/wr-itil:review-problems` Step 4.5c's
132
+ # security-advisories discovery poll `gh api repos/O/R/security-advisories --jq ...`
133
+ # — and must NOT trip the gate. Used to narrow the two `gh api` surfaces
134
+ # (security-advisories + comments) to writes only; every other surface
135
+ # (gh issue/pr create|comment|edit, npm publish, changeset, git commit) is
136
+ # inherently a write and stays gated unconditionally.
137
+ _gh_api_has_body() {
138
+ printf '%s' "$1" | grep -qE '(^|[[:space:]])(--field|--raw-field|--input|-f|-F)([[:space:]]|=)'
139
+ }
140
+
128
141
  # ---------- Surface detection ----------
129
142
  SURFACE=""
130
143
  DRAFT=""
@@ -153,9 +166,19 @@ except Exception:
153
166
  elif echo "$COMMAND" | grep -qE '(^|;|&&|\|\|)\s*gh pr edit(\s|$)'; then
154
167
  SURFACE="gh-pr-edit"
155
168
  elif echo "$COMMAND" | grep -qE 'gh api .*security-advisories'; then
156
- SURFACE="gh-api-security-advisories"
169
+ # P405: gate only advisory-DRAFT writes; read-only polls (no body flag) skip.
170
+ if _gh_api_has_body "$COMMAND"; then
171
+ SURFACE="gh-api-security-advisories"
172
+ else
173
+ exit 0
174
+ fi
157
175
  elif echo "$COMMAND" | grep -qE 'gh api .*/comments'; then
158
- SURFACE="gh-api-comments"
176
+ # P405: gate only comment-body writes; read-only polls (no body flag) skip.
177
+ if _gh_api_has_body "$COMMAND"; then
178
+ SURFACE="gh-api-comments"
179
+ else
180
+ exit 0
181
+ fi
159
182
  elif echo "$COMMAND" | grep -qE '(^|;|&&|\|\|)\s*npm publish(\s|$)'; then
160
183
  SURFACE="npm-publish"
161
184
  elif echo "$COMMAND" | grep -qE '(^|;|&&|\|\|)\s*git commit(\s|$)'; then
@@ -211,6 +211,44 @@ run_hook() {
211
211
  [[ "$output" == *"wr-risk-scorer:external-comms"* ]]
212
212
  }
213
213
 
214
+ # ---------------------------------------------------------------------------
215
+ # P405 — read-only `gh api` polls must NOT trip the gate. `gh api` defaults to
216
+ # GET; it only carries an outbound prose body (the thing this gate reviews)
217
+ # when a request-body flag (-f/--field, -F/--raw-field, --input) is present.
218
+ # The `/wr-itil:review-problems` Step 4.5c security-advisories discovery poll
219
+ # is read-only (`--jq` filter, no body flag) and was being denied as if it
220
+ # were an advisory draft, silently blacking out one discovery channel.
221
+ # ---------------------------------------------------------------------------
222
+
223
+ @test "P405: read-only gh api security-advisories poll (--jq, no body flag) is not gated" {
224
+ INPUT=$(build_bash_input "gh api repos/foo/bar/security-advisories --jq '.[].ghsa_id'")
225
+ run_hook "$INPUT"
226
+ [ "$status" -eq 0 ]
227
+ [ -z "$output" ]
228
+ }
229
+
230
+ @test "P405: bare gh api security-advisories read (no flags) is not gated" {
231
+ INPUT=$(build_bash_input "gh api repos/foo/bar/security-advisories")
232
+ run_hook "$INPUT"
233
+ [ "$status" -eq 0 ]
234
+ [ -z "$output" ]
235
+ }
236
+
237
+ @test "P405: read-only gh api comments poll (--jq, no body flag) is not gated" {
238
+ INPUT=$(build_bash_input "gh api repos/foo/bar/issues/1/comments --jq '.[].body'")
239
+ run_hook "$INPUT"
240
+ [ "$status" -eq 0 ]
241
+ [ -z "$output" ]
242
+ }
243
+
244
+ @test "P405: gh api security-advisories write with -f body flag still triggers the gate" {
245
+ INPUT=$(build_bash_input "gh api repos/foo/bar/security-advisories -f summary='new advisory'")
246
+ run_hook "$INPUT"
247
+ [ "$status" -eq 0 ]
248
+ [[ "$output" == *"deny"* ]]
249
+ [[ "$output" == *"wr-risk-scorer:external-comms"* ]]
250
+ }
251
+
214
252
  @test "npm publish triggers the gate" {
215
253
  INPUT=$(build_bash_input "npm publish")
216
254
  run_hook "$INPUT"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/risk-scorer",
3
- "version": "0.15.1",
3
+ "version": "0.16.0-preview.885",
4
4
  "description": "Pipeline risk scoring, commit/push gates, and secret leak detection",
5
5
  "bin": {
6
6
  "windyroad-risk-scorer": "./bin/install.mjs"
@@ -26,6 +26,7 @@
26
26
  ".claude-plugin/",
27
27
  "lib/",
28
28
  "scripts/",
29
- "!skills/*/eval/"
29
+ "!skills/*/eval/",
30
+ "!agents/eval/"
30
31
  ]
31
32
  }