@windyroad/risk-scorer 0.17.0 → 0.17.2-preview.975

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.17.0"
313
+ "version": "0.17.2"
314
314
  }
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "wr-risk-scorer",
3
+ "version": "0.17.2",
4
+ "description": "Pipeline risk scoring, commit/push gates, and secret leak detection",
5
+ "author": {
6
+ "name": "Windy Road Technology",
7
+ "url": "https://windyroad.com.au"
8
+ },
9
+ "homepage": "https://github.com/windyroad/agent-plugins/tree/main/packages/risk-scorer",
10
+ "repository": "https://github.com/windyroad/agent-plugins",
11
+ "license": "MIT",
12
+ "keywords": [
13
+ "risk",
14
+ "pipeline",
15
+ "governance",
16
+ "secret-leak-detection",
17
+ "codex",
18
+ "claude-code"
19
+ ],
20
+ "skills": "./skills/",
21
+ "interface": {
22
+ "displayName": "Windy Road Risk Scorer",
23
+ "shortDescription": "Score pipeline risk and guard risky changes",
24
+ "longDescription": "Pipeline risk scoring, commit and push gates, release risk checks, and secret leak detection for AI coding workflows.",
25
+ "developerName": "Windy Road Technology",
26
+ "category": "Developer Tools",
27
+ "capabilities": [
28
+ "Interactive",
29
+ "Read",
30
+ "Write"
31
+ ],
32
+ "websiteURL": "https://windyroad.com.au",
33
+ "privacyPolicyURL": "https://windyroad.com.au/privacy",
34
+ "termsOfServiceURL": "https://windyroad.com.au/terms",
35
+ "defaultPrompt": [
36
+ "Assess release risk for the current changes",
37
+ "Review this outbound message for secret leaks",
38
+ "Update this project's risk policy"
39
+ ],
40
+ "brandColor": "#B45309",
41
+ "screenshots": []
42
+ }
43
+ }
package/bin/install.mjs CHANGED
@@ -21,6 +21,7 @@ Options:
21
21
  --update Update this plugin and its skills
22
22
  --uninstall Remove this plugin
23
23
  --scope Installation scope: project (default) or user
24
+ --runtime Runtime to install for: claude (default), codex, or both
24
25
  --dry-run Show what would be done without executing
25
26
  --help, -h Show this help
26
27
  `);
@@ -32,12 +33,12 @@ if (flags.dryRun) {
32
33
  console.log("[dry-run mode — no commands will be executed]\n");
33
34
  }
34
35
 
35
- utils.checkPrerequisites();
36
+ utils.checkPrerequisites({ runtime: flags.runtime });
36
37
 
37
38
  if (flags.uninstall) {
38
- utils.uninstallPackage(PLUGIN);
39
+ utils.uninstallPackage(PLUGIN, { runtime: flags.runtime });
39
40
  } else if (flags.update) {
40
- utils.updatePackage(PLUGIN, { scope: flags.scope });
41
+ utils.updatePackage(PLUGIN, { scope: flags.scope, runtime: flags.runtime });
41
42
  } else {
42
- utils.installPackage(PLUGIN, { deps: DEPS, scope: flags.scope });
43
+ utils.installPackage(PLUGIN, { deps: DEPS, scope: flags.scope, runtime: flags.runtime });
43
44
  }
package/hooks/hooks.json CHANGED
@@ -4,23 +4,13 @@
4
4
  { "matcher": "startup", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/risk-scorer-scaffold-nudge.sh" }] }
5
5
  ],
6
6
  "UserPromptSubmit": [
7
- { "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/risk-score.sh" }] },
8
- { "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/staleness-check.sh" }] }
7
+ { "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/risk-scorer-dispatch.sh user-prompt" }] }
9
8
  ],
10
9
  "PreToolUse": [
11
- { "matcher": "Edit|Write", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/secret-leak-gate.sh" }, { "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/wip-risk-gate.sh" }] },
12
- { "matcher": "Bash", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/git-push-gate.sh" }] },
13
- { "matcher": "Bash", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/risk-score-commit-gate.sh" }] },
14
- { "matcher": "Bash|Edit|Write", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/external-comms-gate.sh" }] },
15
- { "matcher": "Edit|Write", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/risk-policy-enforce-edit.sh" }] },
16
- { "matcher": "ExitPlanMode", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/risk-score-plan-enforce.sh" }] },
17
- { "matcher": "EnterPlanMode", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/plan-risk-guidance.sh" }] }
10
+ { "matcher": "Bash|Edit|Write|ExitPlanMode|EnterPlanMode", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/risk-scorer-dispatch.sh pre-tool" }] }
18
11
  ],
19
12
  "PostToolUse": [
20
- { "matcher": "Edit|Write", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/wip-risk-mark.sh" }] },
21
- { "matcher": "Agent", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/risk-score-mark.sh" }] },
22
- { "matcher": "Bash", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/risk-hash-refresh.sh" }] },
23
- { "matcher": "Agent|Bash|Skill", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/risk-slide-marker.sh" }] }
13
+ { "matcher": "Agent|Bash|Skill", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/risk-scorer-dispatch.sh post-tool" }] }
24
14
  ]
25
15
  }
26
16
  }
@@ -0,0 +1,67 @@
1
+ #!/bin/bash
2
+ # Fan out risk-scorer hooks from one registered hook per event.
3
+
4
+ set -euo pipefail
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
7
+ EVENT="${1:-}"
8
+ INPUT="$(cat)"
9
+
10
+ run_hook() {
11
+ local output
12
+ output="$(printf '%s' "$INPUT" | "$SCRIPT_DIR/$1")"
13
+ if [ -n "$output" ]; then
14
+ printf '%s\n' "$output"
15
+ exit 0
16
+ fi
17
+ }
18
+
19
+ tool_name() {
20
+ printf '%s' "$INPUT" | python3 -c 'import json,sys; print((json.load(sys.stdin).get("tool_name") or ""))' 2>/dev/null || true
21
+ }
22
+
23
+ case "$EVENT" in
24
+ user-prompt)
25
+ run_hook risk-score.sh
26
+ run_hook staleness-check.sh
27
+ ;;
28
+ pre-tool)
29
+ case "$(tool_name)" in
30
+ Edit|Write)
31
+ run_hook secret-leak-gate.sh
32
+ run_hook wip-risk-gate.sh
33
+ run_hook external-comms-gate.sh
34
+ run_hook risk-policy-enforce-edit.sh
35
+ ;;
36
+ Bash)
37
+ run_hook git-push-gate.sh
38
+ run_hook risk-score-commit-gate.sh
39
+ run_hook external-comms-gate.sh
40
+ ;;
41
+ ExitPlanMode)
42
+ run_hook risk-score-plan-enforce.sh
43
+ ;;
44
+ EnterPlanMode)
45
+ run_hook plan-risk-guidance.sh
46
+ ;;
47
+ esac
48
+ ;;
49
+ post-tool)
50
+ case "$(tool_name)" in
51
+ Agent)
52
+ run_hook risk-score-mark.sh
53
+ run_hook risk-slide-marker.sh
54
+ ;;
55
+ Bash)
56
+ run_hook risk-hash-refresh.sh
57
+ run_hook risk-slide-marker.sh
58
+ ;;
59
+ Skill)
60
+ run_hook risk-slide-marker.sh
61
+ ;;
62
+ esac
63
+ ;;
64
+ *)
65
+ exit 0
66
+ ;;
67
+ esac
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env bats
2
+
3
+ setup() {
4
+ REPO_ROOT="$(cd "$(dirname "$BATS_TEST_FILENAME")/../../../.." && pwd)"
5
+ HOOKS="$REPO_ROOT/packages/risk-scorer/hooks"
6
+ }
7
+
8
+ @test "hooks.json registers four command hooks" {
9
+ run python3 - "$HOOKS/hooks.json" <<'PY'
10
+ import json, sys
11
+ data = json.load(open(sys.argv[1]))
12
+ print(sum(len(entry["hooks"]) for entries in data["hooks"].values() for entry in entries))
13
+ PY
14
+ [ "$status" -eq 0 ]
15
+ [ "$output" = "4" ]
16
+ }
17
+
18
+ @test "dispatcher is registered for prompt, pre-tool, and post-tool events" {
19
+ run grep -n "risk-scorer-dispatch.sh user-prompt" "$HOOKS/hooks.json"
20
+ [ "$status" -eq 0 ]
21
+ run grep -n "risk-scorer-dispatch.sh pre-tool" "$HOOKS/hooks.json"
22
+ [ "$status" -eq 0 ]
23
+ run grep -n "risk-scorer-dispatch.sh post-tool" "$HOOKS/hooks.json"
24
+ [ "$status" -eq 0 ]
25
+ }
26
+
27
+ @test "dispatcher routes Write through the secret leak gate" {
28
+ local fake_key input
29
+ fake_key="AKIA""ABCDEFGHIJKLMNOP"
30
+ input="$(python3 - "$fake_key" <<'PY'
31
+ import json, sys
32
+ print(json.dumps({
33
+ "tool_name": "Write",
34
+ "session_id": "dispatch-test",
35
+ "tool_input": {"file_path": "src/example.txt", "content": sys.argv[1]},
36
+ }))
37
+ PY
38
+ )"
39
+
40
+ run bash "$HOOKS/risk-scorer-dispatch.sh" pre-tool <<<"$input"
41
+ [ "$status" -eq 0 ]
42
+ [[ "$output" == *"permissionDecision"* ]]
43
+ [[ "$output" == *"deny"* ]]
44
+ [[ "$output" == *"AWS access key"* ]]
45
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windyroad/risk-scorer",
3
- "version": "0.17.0",
3
+ "version": "0.17.2-preview.975",
4
4
  "description": "Pipeline risk scoring, commit/push gates, and secret leak detection",
5
5
  "bin": {
6
6
  "windyroad-risk-scorer": "./bin/install.mjs"
@@ -24,6 +24,7 @@
24
24
  "hooks/",
25
25
  "skills/",
26
26
  ".claude-plugin/",
27
+ ".codex-plugin/",
27
28
  "lib/",
28
29
  "scripts/",
29
30
  "!skills/*/eval/",