@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.
|
@@ -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-
|
|
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/
|
|
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": "
|
|
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.
|
|
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/",
|