azcodr 1.5.2 โ 2.0.0
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.
- package/.agents/hooks.json +42 -42
- package/.agents/hooks.json.example +42 -42
- package/.agents/mcp_config.json.example +29 -29
- package/.agents/scripts/safety_guard.sh +143 -34
- package/.agents/scripts/verify_completion.sh +90 -27
- package/.agents/skills/agentic-architect/SKILL.md +125 -125
- package/.agents/skills/agentic-architect/references/agents_md_template.md +62 -62
- package/.agents/skills/agentic-architect/references/refinement_workflow.md +32 -32
- package/.agents/skills/agentic-architect/references/skill_architecture_inquiry.md +63 -63
- package/.agents/skills/agentic-architect/references/skill_template.md +56 -56
- package/.agents/skills/agentic-architect/scripts/validate_agentic_configs.sh +402 -402
- package/.agents/skills/clean-code-refactor/SKILL.md +91 -91
- package/.agents/skills/clean-code-refactor/references/clean_code_smells.md +27 -27
- package/.agents/skills/clean-code-refactor/references/design_patterns_ts.md +65 -65
- package/.agents/skills/compliance-audit/SKILL.md +120 -120
- package/.agents/skills/compliance-audit/references/owasp_top10_controls.md +16 -16
- package/.agents/skills/compliance-audit/references/soc2_iso_controls.md +28 -28
- package/.agents/skills/lets-build/SKILL.md +173 -173
- package/.agents/skills/lets-build/references/architecture_interview_matrix.md +115 -115
- package/.agents/skills/lets-build/references/hexagonal_bootstrap_scaffolds.md +160 -160
- package/.agents/skills/lets-build/references/project_readme_template.md +79 -79
- package/.agents/skills/lets-build/scripts/bootstrap_workspace.sh +419 -255
- package/.agents/skills/product-analyst/SKILL.md +154 -154
- package/.agents/skills/product-analyst/references/backlog_ordering_techniques.md +107 -107
- package/.agents/skills/product-analyst/references/gherkin_patterns.md +46 -46
- package/.agents/skills/product-analyst/references/invest_checklist.md +38 -38
- package/.agents/skills/product-analyst/references/okr_alignment_guide.md +76 -76
- package/.agents/skills/product-analyst/references/smart_tasks.md +59 -59
- package/.agents/skills/relentless-questioner/SKILL.md +128 -128
- package/.agents/skills/relentless-questioner/references/adaptive_question_trees.md +102 -102
- package/.editorconfig +19 -19
- package/.github/workflows/ci.yml +167 -78
- package/.github/workflows/publish.yml +200 -0
- package/.gitignore +40 -25
- package/AGENTS.md +103 -102
- package/LICENSE +21 -21
- package/README.md +168 -165
- package/bin/azcodr.js +14 -228
- package/docs/knowledge/ubiquitous_language.md +31 -18
- package/docs/rules/agentic_configuration.md +259 -259
- package/docs/rules/api_architecture.md +179 -179
- package/docs/rules/authentication.md +76 -76
- package/docs/rules/authorization.md +75 -75
- package/docs/rules/caching.md +69 -69
- package/docs/rules/clean_code.md +62 -62
- package/docs/rules/cloud_native.md +41 -41
- package/docs/rules/cqrs.md +203 -203
- package/docs/rules/database_design.md +125 -125
- package/docs/rules/database_operations.md +69 -69
- package/docs/rules/design_patterns.md +98 -98
- package/docs/rules/devops_ci_cd.md +76 -76
- package/docs/rules/domain_driven_design.md +122 -122
- package/docs/rules/error_handling.md +54 -52
- package/docs/rules/feature_flags.md +59 -59
- package/docs/rules/frontend_architecture.md +157 -157
- package/docs/rules/multitenancy_architecture.md +98 -98
- package/docs/rules/product_ownership.md +127 -127
- package/docs/rules/project_management.md +49 -49
- package/docs/rules/relentless_questioning.md +52 -52
- package/docs/rules/requirements_engineering.md +98 -98
- package/docs/rules/security_compliance.md +53 -53
- package/docs/rules/server_driven_ui.md +88 -88
- package/docs/rules/test_driven_development.md +185 -185
- package/docs/rules/transactional_email.md +27 -27
- package/docs/rules/type_safety.md +65 -65
- package/docs/rules/ui_ux_architecture.md +150 -150
- package/docs/rules/workflow_state_machines.md +117 -117
- package/lib/cli-parse.js +51 -0
- package/lib/cli-target.js +109 -0
- package/lib/cli.js +180 -0
- package/lib/errors.js +28 -0
- package/lib/git.js +29 -0
- package/lib/guards.js +96 -0
- package/lib/index.d.ts +199 -134
- package/lib/index.js +5 -5
- package/lib/links.js +123 -0
- package/lib/permissions.js +44 -0
- package/lib/repo.js +90 -0
- package/lib/scaffold.js +238 -448
- package/memory.md +119 -36
- package/package.json +65 -62
- package/scripts/test_coverage.js +66 -38
- package/scripts/validate/adr.js +151 -0
- package/scripts/validate/io.js +84 -0
- package/scripts/validate/links.js +167 -0
- package/scripts/validate/parity.js +124 -0
- package/scripts/validate/root.js +184 -0
- package/scripts/validate/rules.js +44 -0
- package/scripts/validate/skills.js +96 -0
- package/scripts/validate/text.js +29 -0
- package/scripts/validate-cli.js +13 -0
- package/scripts/validate.js +140 -258
- package/.github/copilot-instructions.md +0 -1
package/.agents/hooks.json
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
{
|
|
2
|
-
"safety-guard": {
|
|
3
|
-
"enabled": true,
|
|
4
|
-
"PreToolUse": [
|
|
5
|
-
{
|
|
6
|
-
"matcher": "run_command",
|
|
7
|
-
"hooks": [
|
|
8
|
-
{
|
|
9
|
-
"type": "command",
|
|
10
|
-
"command": "./.agents/scripts/safety_guard.sh",
|
|
11
|
-
"timeout": 15
|
|
12
|
-
}
|
|
13
|
-
]
|
|
14
|
-
}
|
|
15
|
-
]
|
|
16
|
-
},
|
|
17
|
-
"post-tool-lint": {
|
|
18
|
-
"enabled": true,
|
|
19
|
-
"PostToolUse": [
|
|
20
|
-
{
|
|
21
|
-
"matcher": "run_command",
|
|
22
|
-
"hooks": [
|
|
23
|
-
{
|
|
24
|
-
"type": "command",
|
|
25
|
-
"command": "npm run lint",
|
|
26
|
-
"timeout": 30
|
|
27
|
-
}
|
|
28
|
-
]
|
|
29
|
-
}
|
|
30
|
-
]
|
|
31
|
-
},
|
|
32
|
-
"stop-verifier": {
|
|
33
|
-
"enabled": true,
|
|
34
|
-
"Stop": [
|
|
35
|
-
{
|
|
36
|
-
"type": "command",
|
|
37
|
-
"command": "./.agents/scripts/verify_completion.sh",
|
|
38
|
-
"timeout": 120
|
|
39
|
-
}
|
|
40
|
-
]
|
|
41
|
-
}
|
|
42
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"safety-guard": {
|
|
3
|
+
"enabled": true,
|
|
4
|
+
"PreToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "run_command",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "./.agents/scripts/safety_guard.sh",
|
|
11
|
+
"timeout": 15
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"post-tool-lint": {
|
|
18
|
+
"enabled": true,
|
|
19
|
+
"PostToolUse": [
|
|
20
|
+
{
|
|
21
|
+
"matcher": "run_command",
|
|
22
|
+
"hooks": [
|
|
23
|
+
{
|
|
24
|
+
"type": "command",
|
|
25
|
+
"command": "npm run lint",
|
|
26
|
+
"timeout": 30
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"stop-verifier": {
|
|
33
|
+
"enabled": true,
|
|
34
|
+
"Stop": [
|
|
35
|
+
{
|
|
36
|
+
"type": "command",
|
|
37
|
+
"command": "./.agents/scripts/verify_completion.sh",
|
|
38
|
+
"timeout": 120
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
{
|
|
2
|
-
"safety-guard": {
|
|
3
|
-
"enabled": false,
|
|
4
|
-
"PreToolUse": [
|
|
5
|
-
{
|
|
6
|
-
"matcher": "run_command",
|
|
7
|
-
"hooks": [
|
|
8
|
-
{
|
|
9
|
-
"type": "command",
|
|
10
|
-
"command": "./.agents/scripts/safety_guard.sh",
|
|
11
|
-
"timeout": 15
|
|
12
|
-
}
|
|
13
|
-
]
|
|
14
|
-
}
|
|
15
|
-
]
|
|
16
|
-
},
|
|
17
|
-
"post-tool-lint": {
|
|
18
|
-
"enabled": false,
|
|
19
|
-
"PostToolUse": [
|
|
20
|
-
{
|
|
21
|
-
"matcher": "run_command",
|
|
22
|
-
"hooks": [
|
|
23
|
-
{
|
|
24
|
-
"type": "command",
|
|
25
|
-
"command": "npm run lint",
|
|
26
|
-
"timeout": 30
|
|
27
|
-
}
|
|
28
|
-
]
|
|
29
|
-
}
|
|
30
|
-
]
|
|
31
|
-
},
|
|
32
|
-
"stop-verifier": {
|
|
33
|
-
"enabled": false,
|
|
34
|
-
"Stop": [
|
|
35
|
-
{
|
|
36
|
-
"type": "command",
|
|
37
|
-
"command": "./.agents/scripts/verify_completion.sh",
|
|
38
|
-
"timeout": 15
|
|
39
|
-
}
|
|
40
|
-
]
|
|
41
|
-
}
|
|
42
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"safety-guard": {
|
|
3
|
+
"enabled": false,
|
|
4
|
+
"PreToolUse": [
|
|
5
|
+
{
|
|
6
|
+
"matcher": "run_command",
|
|
7
|
+
"hooks": [
|
|
8
|
+
{
|
|
9
|
+
"type": "command",
|
|
10
|
+
"command": "./.agents/scripts/safety_guard.sh",
|
|
11
|
+
"timeout": 15
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"post-tool-lint": {
|
|
18
|
+
"enabled": false,
|
|
19
|
+
"PostToolUse": [
|
|
20
|
+
{
|
|
21
|
+
"matcher": "run_command",
|
|
22
|
+
"hooks": [
|
|
23
|
+
{
|
|
24
|
+
"type": "command",
|
|
25
|
+
"command": "npm run lint",
|
|
26
|
+
"timeout": 30
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"stop-verifier": {
|
|
33
|
+
"enabled": false,
|
|
34
|
+
"Stop": [
|
|
35
|
+
{
|
|
36
|
+
"type": "command",
|
|
37
|
+
"command": "./.agents/scripts/verify_completion.sh",
|
|
38
|
+
"timeout": 15
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
{
|
|
2
|
-
"_notes": [
|
|
3
|
-
"Copy to .agents/mcp_config.json and replace placeholders before use.",
|
|
4
|
-
"Create ./data/ (shipped with .gitkeep) before starting the sqlite server.",
|
|
5
|
-
"Replace remote-service.url with your deployment; example.com is intentionally non-functional."
|
|
6
|
-
],
|
|
7
|
-
"mcpServers": {
|
|
8
|
-
"sqlite": {
|
|
9
|
-
"command": "npx",
|
|
10
|
-
"args": [
|
|
11
|
-
"-y",
|
|
12
|
-
"@modelcontextprotocol/server-sqlite",
|
|
13
|
-
"--db-path",
|
|
14
|
-
"./data/app.db"
|
|
15
|
-
]
|
|
16
|
-
},
|
|
17
|
-
"filesystem": {
|
|
18
|
-
"command": "npx",
|
|
19
|
-
"args": [
|
|
20
|
-
"-y",
|
|
21
|
-
"@modelcontextprotocol/server-filesystem",
|
|
22
|
-
"./docs"
|
|
23
|
-
]
|
|
24
|
-
},
|
|
25
|
-
"remote-service": {
|
|
26
|
-
"url": "https://mcp.example.com/sse"
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"_notes": [
|
|
3
|
+
"Copy to .agents/mcp_config.json and replace placeholders before use.",
|
|
4
|
+
"Create ./data/ (shipped with .gitkeep) before starting the sqlite server.",
|
|
5
|
+
"Replace remote-service.url with your deployment; example.com is intentionally non-functional."
|
|
6
|
+
],
|
|
7
|
+
"mcpServers": {
|
|
8
|
+
"sqlite": {
|
|
9
|
+
"command": "npx",
|
|
10
|
+
"args": [
|
|
11
|
+
"-y",
|
|
12
|
+
"@modelcontextprotocol/server-sqlite",
|
|
13
|
+
"--db-path",
|
|
14
|
+
"./data/app.db"
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"filesystem": {
|
|
18
|
+
"command": "npx",
|
|
19
|
+
"args": [
|
|
20
|
+
"-y",
|
|
21
|
+
"@modelcontextprotocol/server-filesystem",
|
|
22
|
+
"./docs"
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
"remote-service": {
|
|
26
|
+
"url": "https://mcp.example.com/sse"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -1,34 +1,143 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
#
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
if
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# PreToolUse safety guard.
|
|
4
|
+
#
|
|
5
|
+
# Blocking is the goal. When the guard cannot determine what it is looking at,
|
|
6
|
+
# it permits the action and records why: a guard that fails closed on an
|
|
7
|
+
# unparseable payload locks an agent out of its own toolchain, which gets the
|
|
8
|
+
# guard switched off entirely. The deterministic, high-severity denylist below
|
|
9
|
+
# is the compensating control.
|
|
10
|
+
#
|
|
11
|
+
# Two input channels are read, because harnesses differ:
|
|
12
|
+
# 1. argv -- `safety_guard.sh 'rm -rf /'`
|
|
13
|
+
# 2. stdin -- `echo '{"tool_input":{"command":"rm -rf /"}}' | safety_guard.sh`
|
|
14
|
+
# Both are scanned. Neither alone is sufficient.
|
|
15
|
+
# =============================================================================
|
|
16
|
+
set -uo pipefail
|
|
17
|
+
|
|
18
|
+
PAYLOAD=""
|
|
19
|
+
|
|
20
|
+
# --- Channel 1: argv ----------------------------------------------------------
|
|
21
|
+
if [ "$#" -gt 0 ]; then
|
|
22
|
+
PAYLOAD="$*"
|
|
23
|
+
fi
|
|
24
|
+
|
|
25
|
+
# --- Channel 2: stdin (JSON tool-call envelope) ------------------------------
|
|
26
|
+
# Read with a short timeout so an interactive terminal does not hang the hook.
|
|
27
|
+
STDIN_JSON=""
|
|
28
|
+
if [ ! -t 0 ]; then
|
|
29
|
+
if command -v timeout >/dev/null 2>&1; then
|
|
30
|
+
STDIN_JSON="$(timeout 2 cat 2>/dev/null || true)"
|
|
31
|
+
else
|
|
32
|
+
STDIN_JSON="$(cat 2>/dev/null || true)"
|
|
33
|
+
fi
|
|
34
|
+
fi
|
|
35
|
+
|
|
36
|
+
if [ -n "$STDIN_JSON" ]; then
|
|
37
|
+
# Flatten the common envelope shapes into a scannable string. We are not
|
|
38
|
+
# executing anything, so crude extraction is acceptable here.
|
|
39
|
+
#
|
|
40
|
+
# Only JSON *structural* characters are removed. Spaces MUST be preserved:
|
|
41
|
+
# stripping them collapses `rm -rf /` into `rm-rf/`, which defeats every
|
|
42
|
+
# pattern below. That bug shipped once; the regression test pins it.
|
|
43
|
+
FLAT="$(printf '%s' "$STDIN_JSON" \
|
|
44
|
+
| tr ',' '\n' \
|
|
45
|
+
| sed -e 's/^[^:]*://' \
|
|
46
|
+
| tr -d '"{}[]' \
|
|
47
|
+
| tr '\n' ' ')"
|
|
48
|
+
if [ -n "$FLAT" ]; then
|
|
49
|
+
PAYLOAD="${PAYLOAD} ${FLAT}"
|
|
50
|
+
fi
|
|
51
|
+
fi
|
|
52
|
+
|
|
53
|
+
if [ -z "$(printf '%s' "$PAYLOAD" | tr -d '[:space:]')" ]; then
|
|
54
|
+
# Nothing inspectable. Permit, and say so, rather than guessing.
|
|
55
|
+
exit 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# Normalise once: lowercase copy for case-insensitive matching, plus a
|
|
59
|
+
# whitespace-collapsed copy so `rm -rf /` cannot slip past.
|
|
60
|
+
NORMALISED="$(printf '%s' "$PAYLOAD" | tr '[:upper:]' '[:lower:]')"
|
|
61
|
+
COLLAPSED="$(printf '%s' "$NORMALISED" | tr '\n\t' ' ' | tr -s ' ')"
|
|
62
|
+
|
|
63
|
+
block() {
|
|
64
|
+
echo "๐จ Safety Guard: $1" >&2
|
|
65
|
+
echo " command: ${PAYLOAD:0:300}" >&2
|
|
66
|
+
exit 1
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
# =============================================================================
|
|
70
|
+
# Denylist. Each pattern is matched against the normalised payload.
|
|
71
|
+
# =============================================================================
|
|
72
|
+
check() {
|
|
73
|
+
local pattern="$1"
|
|
74
|
+
local reason="$2"
|
|
75
|
+
if printf '%s' "$COLLAPSED" | grep -Eq -- "$pattern"; then
|
|
76
|
+
block "$reason"
|
|
77
|
+
fi
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# --- 1. Destructive filesystem deletion --------------------------------------
|
|
81
|
+
# Targets: /, /*, ~, $HOME, ., .., and the OS drive roots. `rm -rf .` is the
|
|
82
|
+
# single most dangerous omission in the previous version: it annihilates the
|
|
83
|
+
# working directory and is strictly worse for a developer than `rm -rf /`.
|
|
84
|
+
check 'rm[[:space:]]+(-[a-z-]*[rf][a-z-]*[[:space:]]+)+(/|/\*|~|~/\*|\$home|\$\{home\}|\.|\.\.|\.\/|c:\\\\|c:/|d:\\\\)' \
|
|
85
|
+
"destructive rm targeting root, home, drive, or the current directory"
|
|
86
|
+
check '(^|[[:space:]])rm[[:space:]]+(-[a-z-]*[[:space:]]+)*(/|~|c:\\|c:/)($|[[:space:]])' \
|
|
87
|
+
"destructive rm targeting root or home"
|
|
88
|
+
|
|
89
|
+
# Long-form flag variants that the short-flag class misses.
|
|
90
|
+
check 'rm[[:space:]]+--recursive.*--force[[:space:]]+(/|~|\$home|\.)' \
|
|
91
|
+
"destructive rm using long-form flags"
|
|
92
|
+
check 'rm[[:space:]].*--no-preserve-root' \
|
|
93
|
+
"rm --no-preserve-root is never appropriate under an agent"
|
|
94
|
+
|
|
95
|
+
# Whole-tree wipes that are not `rm` at all.
|
|
96
|
+
check '(wipefs[[:space:]]+-a|shred[[:space:]]+-u|find[[:space:]].*-delete)' \
|
|
97
|
+
"irreversible disk or mass-delete operation"
|
|
98
|
+
|
|
99
|
+
# --- 2. Git history / remote destruction -------------------------------------
|
|
100
|
+
# The previous pattern required `--force` immediately after `push`, so the most
|
|
101
|
+
# natural real invocation -- `git push origin main --force` -- passed.
|
|
102
|
+
check 'git[[:space:]]+push.*(-f|--force|--mirror)' \
|
|
103
|
+
"force-push or mirror-push can destroy remote history"
|
|
104
|
+
check 'git[[:space:]]+.*--force-with-lease' \
|
|
105
|
+
"force-push variant detected"
|
|
106
|
+
check 'git[[:space:]]+(reset[[:space:]]+--hard|clean[[:space:]]+-[a-z]*[fd])' \
|
|
107
|
+
"destructive git worktree operation (reset --hard / clean)"
|
|
108
|
+
check 'git[[:space:]]+checkout[[:space:]]+--[[:space:]]+\.' \
|
|
109
|
+
"git checkout -- . discards all uncommitted work"
|
|
110
|
+
check 'git[[:space:]]+branch[[:space:]]+-D' \
|
|
111
|
+
"force branch delete"
|
|
112
|
+
|
|
113
|
+
# --- 3. Destructive SQL ------------------------------------------------------
|
|
114
|
+
# Case-insensitive (bash =~ is case-sensitive by default), and no trailing
|
|
115
|
+
# semicolon requirement -- `DELETE FROM users` was previously allowed.
|
|
116
|
+
check '(drop[[:space:]]+(database|schema|table)|truncate[[:space:]]+(table[[:space:]]+)?[a-z_])' \
|
|
117
|
+
"destructive SQL DDL"
|
|
118
|
+
check '(delete[[:space:]]+from|update[[:space:]]+[a-z_]+[[:space:]]+set|alter[[:space:]]+table)' \
|
|
119
|
+
"destructive SQL DML"
|
|
120
|
+
check '(grant[[:space:]]+all|revoke[[:space:]]+all)' \
|
|
121
|
+
"privilege escalation in SQL"
|
|
122
|
+
|
|
123
|
+
# --- 4. Disk / device --------------------------------------------------------
|
|
124
|
+
check '(mkfs|dd[[:space:]]+if=|fdisk[[:space:]]|parted[[:space:]]+/dev)' \
|
|
125
|
+
"raw disk operation"
|
|
126
|
+
# Fork bomb. `:` is shell metacharacter-free, so match the structural shape
|
|
127
|
+
# directly rather than relying on character classes around `:`.
|
|
128
|
+
check '\{[[:space:]]*:[[:space:]]*\|[[:space:]]*:[[:space:]]*;[[:space:]]*\}' \
|
|
129
|
+
"fork bomb"
|
|
130
|
+
|
|
131
|
+
# --- 5. Credential exfiltration ---------------------------------------------
|
|
132
|
+
check '(curl|wget)[[:space:]].*\|[[:space:]]*(sudo[[:space:]]+)?(ba)?sh' \
|
|
133
|
+
"piping a download straight into a shell"
|
|
134
|
+
check '(base64[[:space:]]+-d|base64[[:space:]]+--decode).*\|' \
|
|
135
|
+
"decoding an encoded payload into a pipe"
|
|
136
|
+
|
|
137
|
+
# --- 6. Package publishing ---------------------------------------------------
|
|
138
|
+
# An agent has no business publishing from an unprompted tool call; the release
|
|
139
|
+
# workflow owns this. This is a guardrail, not an authorisation.
|
|
140
|
+
check '(npm|yarn|pnpm)[[:space:]]+publish' \
|
|
141
|
+
"package publish must go through the release workflow, not an ad-hoc tool call"
|
|
142
|
+
|
|
143
|
+
exit 0
|
|
@@ -1,27 +1,90 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
#
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
exit
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# Stop hook: block premature exit when a verification gate fails.
|
|
4
|
+
#
|
|
5
|
+
# Design notes (each corrects a defect proven in a prior version):
|
|
6
|
+
#
|
|
7
|
+
# - Script discovery uses node + exact key lookup, not grep. `grep -q '"test"'`
|
|
8
|
+
# also matches "test:coverage", "pretest", and any dependency named "test",
|
|
9
|
+
# so the old gate could fire on the wrong script or skip a real one.
|
|
10
|
+
# - The 100% coverage gate is run. It was previously never invoked, so an
|
|
11
|
+
# agent could stop at any coverage level and be told it was verified.
|
|
12
|
+
# - Lint is run. It previously only ran as a PostToolUse hook matched on
|
|
13
|
+
# run_command, so a file edited via a write/edit tool never triggered it.
|
|
14
|
+
# - When nothing can be verified, the hook says so explicitly instead of
|
|
15
|
+
# returning 0. The old version failed OPEN: no package.json, or a non-"test"
|
|
16
|
+
# script name, meant the entire body was skipped and the hook reported
|
|
17
|
+
# success for work it never checked.
|
|
18
|
+
# =============================================================================
|
|
19
|
+
set -uo pipefail
|
|
20
|
+
|
|
21
|
+
# Echo the script body if package.json declares exactly this script name.
|
|
22
|
+
has_script() {
|
|
23
|
+
node -e '
|
|
24
|
+
const fs = require("fs");
|
|
25
|
+
let pkg;
|
|
26
|
+
try { pkg = JSON.parse(fs.readFileSync("package.json", "utf-8")); }
|
|
27
|
+
catch { process.exit(2); }
|
|
28
|
+
if (pkg.scripts && typeof pkg.scripts[process.argv[1]] === "string") {
|
|
29
|
+
console.log(pkg.scripts[process.argv[1]]);
|
|
30
|
+
process.exit(0);
|
|
31
|
+
}
|
|
32
|
+
process.exit(1);
|
|
33
|
+
' "$1" 2>/dev/null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
fail=0
|
|
37
|
+
ran_any=0
|
|
38
|
+
|
|
39
|
+
if [ -f "package.json" ]; then
|
|
40
|
+
# --- Architecture validation ------------------------------------------------
|
|
41
|
+
if [ -n "$(has_script validate)" ]; then
|
|
42
|
+
ran_any=1
|
|
43
|
+
echo "๐ Running architecture validation..." >&2
|
|
44
|
+
if ! npm run validate --silent; then
|
|
45
|
+
echo "๐จ Stop Verifier: 'npm run validate' failed. Fix agentic configuration before stopping." >&2
|
|
46
|
+
fail=1
|
|
47
|
+
fi
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# --- Coverage gate ----------------------------------------------------------
|
|
51
|
+
if [ -n "$(has_script test:coverage)" ]; then
|
|
52
|
+
if node -e 'const[m,n]=process.versions.node.split(".").map(Number);process.exit((m>22||(m===22&&n>=8))?0:1)'; then
|
|
53
|
+
ran_any=1
|
|
54
|
+
echo "๐ Running coverage gate..." >&2
|
|
55
|
+
if ! npm run test:coverage --silent; then
|
|
56
|
+
echo "๐จ Stop Verifier: coverage gate failed. Reach 100% before stopping." >&2
|
|
57
|
+
fail=1
|
|
58
|
+
fi
|
|
59
|
+
else
|
|
60
|
+
echo "โ ๏ธ Skipping coverage gate: needs Node >= 22.8 (current: $(node --version))" >&2
|
|
61
|
+
fi
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
# --- Tests ------------------------------------------------------------------
|
|
65
|
+
if [ -n "$(has_script test)" ]; then
|
|
66
|
+
ran_any=1
|
|
67
|
+
echo "๐งช Running test suite..." >&2
|
|
68
|
+
if ! npm test --silent; then
|
|
69
|
+
echo "๐จ Stop Verifier: 'npm test' failed. Fix failing tests before stopping." >&2
|
|
70
|
+
fail=1
|
|
71
|
+
fi
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
# --- Lint -------------------------------------------------------------------
|
|
75
|
+
if [ -n "$(has_script lint)" ]; then
|
|
76
|
+
ran_any=1
|
|
77
|
+
echo "๐ Running lint..." >&2
|
|
78
|
+
if ! npm run lint --silent; then
|
|
79
|
+
echo "๐จ Stop Verifier: lint failed. Fix lint errors before stopping." >&2
|
|
80
|
+
fail=1
|
|
81
|
+
fi
|
|
82
|
+
fi
|
|
83
|
+
fi
|
|
84
|
+
|
|
85
|
+
if [ "$ran_any" -eq 0 ]; then
|
|
86
|
+
echo "โ ๏ธ Stop Verifier: no verifiable scripts found in package.json -- nothing was checked." >&2
|
|
87
|
+
echo " If this workspace has no Node toolchain, disable the stop-verifier hook." >&2
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
exit $fail
|