@codyswann/lisa 1.46.4 → 1.47.1
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/all/copy-overwrite/.claude/hooks/verify-completion.sh +77 -0
- package/all/copy-overwrite/.claude/rules/lisa.md +2 -1
- package/all/copy-overwrite/.claude/rules/verfication.md +55 -0
- package/all/copy-overwrite/.claude/settings.json +22 -0
- package/package.json +1 -1
- package/typescript/copy-contents/.husky/pre-push +113 -102
- package/typescript/copy-overwrite/.claude/hooks/lint-on-edit.sh +61 -85
- package/typescript/copy-overwrite/.claude/settings.json +22 -0
- package/typescript/copy-overwrite/.github/workflows/auto-update-pr-branches.yml +15 -1
- package/typescript/copy-overwrite/.github/workflows/claude-ci-auto-fix.yml +34 -1
- package/typescript/copy-overwrite/.github/workflows/claude-code-review-response.yml +12 -11
- package/typescript/copy-overwrite/.github/workflows/claude-deploy-auto-fix.yml +143 -0
- package/typescript/copy-overwrite/.github/workflows/claude-nightly-code-complexity.yml +2 -1
- package/typescript/copy-overwrite/.github/workflows/claude-nightly-test-coverage.yml +2 -1
- package/typescript/copy-overwrite/.github/workflows/claude-nightly-test-improvement.yml +4 -2
- package/typescript/copy-overwrite/.github/workflows/claude.yml +2 -1
- package/typescript/copy-overwrite/.github/workflows/create-github-issue-on-failure.yml +115 -0
- package/typescript/copy-overwrite/.github/workflows/create-issue-on-failure.yml +176 -0
- package/typescript/copy-overwrite/.github/workflows/create-jira-issue-on-failure.yml +197 -0
- package/typescript/copy-overwrite/.github/workflows/create-sentry-issue-on-failure.yml +269 -0
- package/typescript/copy-overwrite/.github/workflows/quality.yml +85 -97
- package/typescript/copy-overwrite/audit.ignore.config.json +87 -0
- package/typescript/copy-overwrite/eslint.ignore.config.json +4 -1
- package/typescript/create-only/audit.ignore.local.json +3 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# This file is managed by Lisa.
|
|
3
|
+
# Do not edit directly — changes will be overwritten on the next `lisa` run.
|
|
4
|
+
# =============================================================================
|
|
5
|
+
# Verification Level Enforcement Hook (Stop)
|
|
6
|
+
# =============================================================================
|
|
7
|
+
# Checks whether the agent declared a verification level when the session
|
|
8
|
+
# involved code changes. Does NOT re-run lint/typecheck/tests (husky does that).
|
|
9
|
+
#
|
|
10
|
+
# Logic:
|
|
11
|
+
# 1. If no Write/Edit tools were used → exit 0 (research/conversation only)
|
|
12
|
+
# 2. If code was written → check last assistant message for verification level
|
|
13
|
+
# 3. If verification level found → exit 0
|
|
14
|
+
# 4. If missing and stop_hook_active is false → block with instructions
|
|
15
|
+
# 5. If missing and stop_hook_active is true → exit 0 (avoid infinite loops)
|
|
16
|
+
#
|
|
17
|
+
# @see .claude/rules/verfication.md "Self-Correction Loop" section
|
|
18
|
+
# =============================================================================
|
|
19
|
+
|
|
20
|
+
# Read JSON input from stdin
|
|
21
|
+
INPUT=$(cat)
|
|
22
|
+
|
|
23
|
+
# Extract transcript path
|
|
24
|
+
TRANSCRIPT_PATH=$(echo "$INPUT" | grep -o '"transcript_path"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*: *"//' | sed 's/"$//')
|
|
25
|
+
|
|
26
|
+
# Exit silently if no transcript available
|
|
27
|
+
if [ -z "$TRANSCRIPT_PATH" ] || [ ! -f "$TRANSCRIPT_PATH" ]; then
|
|
28
|
+
exit 0
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
# Check if Write or Edit tools were used during the session
|
|
32
|
+
# Look for tool_use entries with Write or Edit tool names
|
|
33
|
+
if ! grep -q '"tool_name"[[:space:]]*:[[:space:]]*"\(Write\|Edit\|NotebookEdit\)"' "$TRANSCRIPT_PATH" 2>/dev/null; then
|
|
34
|
+
# No code changes — this was research/conversation, allow stop
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# Code was written — check if a verification level was declared
|
|
39
|
+
# Extract the last assistant message
|
|
40
|
+
LAST_ASSISTANT=$(awk '/"type"[[:space:]]*:[[:space:]]*"assistant"/{line=$0} END{if(line) print line}' "$TRANSCRIPT_PATH" 2>/dev/null)
|
|
41
|
+
|
|
42
|
+
if [ -z "$LAST_ASSISTANT" ]; then
|
|
43
|
+
exit 0
|
|
44
|
+
fi
|
|
45
|
+
|
|
46
|
+
# Extract the text content from the assistant message
|
|
47
|
+
RESPONSE_TEXT=""
|
|
48
|
+
if command -v jq >/dev/null 2>&1; then
|
|
49
|
+
RESPONSE_TEXT=$(echo "$LAST_ASSISTANT" | jq -r '.message.content[] | select(.type == "text") | .text' 2>/dev/null)
|
|
50
|
+
else
|
|
51
|
+
RESPONSE_TEXT=$(echo "$LAST_ASSISTANT" | grep -o '"text"[[:space:]]*:[[:space:]]*"[^"]*"' | sed 's/.*: *"//' | sed 's/"$//')
|
|
52
|
+
fi
|
|
53
|
+
|
|
54
|
+
if [ -z "$RESPONSE_TEXT" ]; then
|
|
55
|
+
exit 0
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# Check for verification level keywords (case-insensitive)
|
|
59
|
+
if echo "$RESPONSE_TEXT" | grep -qi "FULLY VERIFIED\|PARTIALLY VERIFIED\|UNVERIFIED"; then
|
|
60
|
+
exit 0
|
|
61
|
+
fi
|
|
62
|
+
|
|
63
|
+
# Check if this is a retry (stop_hook_active flag)
|
|
64
|
+
# The stop_hook_active field is set to true when a Stop hook has already blocked once
|
|
65
|
+
STOP_HOOK_ACTIVE=$(echo "$INPUT" | grep -o '"stop_hook_active"[[:space:]]*:[[:space:]]*true' || echo "")
|
|
66
|
+
|
|
67
|
+
if [ -n "$STOP_HOOK_ACTIVE" ]; then
|
|
68
|
+
# Already blocked once — allow stop to prevent infinite loop
|
|
69
|
+
exit 0
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
# No verification level declared after code changes — block
|
|
73
|
+
cat << 'EOF'
|
|
74
|
+
{"decision":"block","reason":"You changed code but didn't declare a verification level. Run your verification, then declare FULLY VERIFIED, PARTIALLY VERIFIED, or UNVERIFIED with evidence. See .claude/rules/verfication.md for requirements."}
|
|
75
|
+
EOF
|
|
76
|
+
|
|
77
|
+
exit 0
|
|
@@ -43,7 +43,8 @@ These directories contain files deployed by Lisa **and** files you create. Do no
|
|
|
43
43
|
- `eslint-plugin-code-organization/*`, `eslint-plugin-component-structure/*`, `eslint-plugin-ui-standards/*`
|
|
44
44
|
- `.claude/settings.json`
|
|
45
45
|
- `.claude/README.md`
|
|
46
|
-
- `.github/workflows/quality.yml`, `.github/workflows/release.yml`, `.github/workflows/claude.yml`, `.github/workflows/claude-ci-auto-fix.yml`, `.github/workflows/claude-code-review-response.yml`, `.github/workflows/claude-nightly-test-improvement.yml`, `.github/workflows/claude-nightly-test-coverage.yml`, `.github/workflows/claude-nightly-code-complexity.yml`, `.github/workflows/auto-update-pr-branches.yml`
|
|
46
|
+
- `.github/workflows/quality.yml`, `.github/workflows/release.yml`, `.github/workflows/claude.yml`, `.github/workflows/claude-ci-auto-fix.yml`, `.github/workflows/claude-deploy-auto-fix.yml`, `.github/workflows/claude-code-review-response.yml`, `.github/workflows/claude-nightly-test-improvement.yml`, `.github/workflows/claude-nightly-test-coverage.yml`, `.github/workflows/claude-nightly-code-complexity.yml`, `.github/workflows/auto-update-pr-branches.yml`
|
|
47
|
+
- `.github/workflows/create-issue-on-failure.yml`, `.github/workflows/create-github-issue-on-failure.yml`, `.github/workflows/create-jira-issue-on-failure.yml`, `.github/workflows/create-sentry-issue-on-failure.yml`
|
|
47
48
|
- `.github/workflows/build.yml`, `.github/workflows/lighthouse.yml` (Expo)
|
|
48
49
|
- `.github/workflows/load-test.yml`, `.github/workflows/zap-baseline.yml` (NestJS)
|
|
49
50
|
- `.github/dependabot.yml`, `.github/GITHUB_ACTIONS.md`, `.github/k6/*`
|
|
@@ -150,6 +150,61 @@ Agents must follow this sequence unless explicitly instructed otherwise:
|
|
|
150
150
|
|
|
151
151
|
---
|
|
152
152
|
|
|
153
|
+
## Self-Correction Loop
|
|
154
|
+
|
|
155
|
+
Verification is not a one-shot activity. Agents operate within a four-layer self-correction architecture that catches errors at increasing scope. Each layer is enforced automatically — agents do not need to invoke them manually.
|
|
156
|
+
|
|
157
|
+
### Layer 1 — Inline Correction (PostToolUse)
|
|
158
|
+
|
|
159
|
+
**Trigger:** Every `Write` or `Edit` tool call.
|
|
160
|
+
|
|
161
|
+
**Pipeline:** prettier → ast-grep → eslint (with `--fix --quiet --cache`).
|
|
162
|
+
|
|
163
|
+
Each hook runs on the single file just written. Errors are reported immediately so the agent can fix them before writing more files. This prevents error accumulation across multiple files.
|
|
164
|
+
|
|
165
|
+
- **prettier** formats the file (non-blocking — always exits 0).
|
|
166
|
+
- **ast-grep** scans for structural anti-patterns (blocking — exits 1 on violations).
|
|
167
|
+
- **eslint** auto-fixes what it can, then blocks on unfixable errors (exits 2 on remaining errors).
|
|
168
|
+
|
|
169
|
+
**Agent responsibility:** When a PostToolUse hook blocks, fix the reported errors in the same file before proceeding to other files. Do not accumulate errors.
|
|
170
|
+
|
|
171
|
+
### Layer 2 — Commit-Time Enforcement (husky pre-commit)
|
|
172
|
+
|
|
173
|
+
**Trigger:** Every `git commit`.
|
|
174
|
+
|
|
175
|
+
**Checks:** lint-staged (eslint + prettier on staged files), gitleaks (secret detection), commitlint (conventional commit format), branch protection (no direct commits to environment branches).
|
|
176
|
+
|
|
177
|
+
This layer catches errors that span multiple files or involve staged-but-not-yet-linted changes. It runs automatically via husky and cannot be bypassed (`--no-verify` is prohibited).
|
|
178
|
+
|
|
179
|
+
### Layer 3 — Push-Time Enforcement (husky pre-push)
|
|
180
|
+
|
|
181
|
+
**Trigger:** Every `git push`.
|
|
182
|
+
|
|
183
|
+
**Checks:** Full test suite with coverage thresholds, typecheck, security audit, knip (unused exports), integration tests.
|
|
184
|
+
|
|
185
|
+
This layer validates the complete changeset against the project's quality gates. It is the last automated checkpoint before code reaches the remote.
|
|
186
|
+
|
|
187
|
+
### Layer 4 — Completion Enforcement (Stop hook)
|
|
188
|
+
|
|
189
|
+
**Trigger:** Agent attempts to stop or finish a task.
|
|
190
|
+
|
|
191
|
+
**Check:** If `Write` or `Edit` tools were used during the session, the agent must have declared a verification level (`FULLY VERIFIED`, `PARTIALLY VERIFIED`, or `UNVERIFIED`) in its final message.
|
|
192
|
+
|
|
193
|
+
If no verification level is declared, the Stop hook blocks once with instructions. On retry, it allows the stop to prevent infinite loops.
|
|
194
|
+
|
|
195
|
+
**Agent responsibility:** Before finishing any task that involved code changes, run verification and declare the result with evidence.
|
|
196
|
+
|
|
197
|
+
### Regeneration Over Patching
|
|
198
|
+
|
|
199
|
+
When the root cause of errors is architectural (wrong abstraction, incorrect data flow, fundamentally broken approach), delete and regenerate rather than incrementally patching. Incremental patches on a broken foundation accumulate tech debt faster than the self-correction loop can catch it.
|
|
200
|
+
|
|
201
|
+
Signs that regeneration is needed:
|
|
202
|
+
- The same file has been edited 3+ times in the same loop without converging
|
|
203
|
+
- Fixing one error introduces another in the same file
|
|
204
|
+
- The fix requires disabling a lint rule or adding a type assertion
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
153
208
|
## End-User Verification Patterns
|
|
154
209
|
|
|
155
210
|
Agents must choose the pattern that fits the task.
|
|
@@ -64,6 +64,10 @@
|
|
|
64
64
|
{
|
|
65
65
|
"type": "command",
|
|
66
66
|
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/sg-scan-on-edit.sh"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"type": "command",
|
|
70
|
+
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/lint-on-edit.sh"
|
|
67
71
|
}
|
|
68
72
|
]
|
|
69
73
|
},
|
|
@@ -209,6 +213,24 @@
|
|
|
209
213
|
}
|
|
210
214
|
],
|
|
211
215
|
"Stop": [
|
|
216
|
+
{
|
|
217
|
+
"matcher": "",
|
|
218
|
+
"hooks": [
|
|
219
|
+
{
|
|
220
|
+
"type": "command",
|
|
221
|
+
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/verify-completion.sh"
|
|
222
|
+
}
|
|
223
|
+
]
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
"matcher": "",
|
|
227
|
+
"hooks": [
|
|
228
|
+
{
|
|
229
|
+
"type": "command",
|
|
230
|
+
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/check-tired-boss.sh"
|
|
231
|
+
}
|
|
232
|
+
]
|
|
233
|
+
},
|
|
212
234
|
{
|
|
213
235
|
"matcher": "",
|
|
214
236
|
"hooks": [
|
package/package.json
CHANGED
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
"axios": ">=1.13.5"
|
|
96
96
|
},
|
|
97
97
|
"name": "@codyswann/lisa",
|
|
98
|
-
"version": "1.
|
|
98
|
+
"version": "1.47.1",
|
|
99
99
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
100
100
|
"main": "dist/index.js",
|
|
101
101
|
"bin": {
|
|
@@ -29,27 +29,86 @@ echo "📦 Using package manager: $PACKAGE_MANAGER"
|
|
|
29
29
|
# Run security audit
|
|
30
30
|
echo "🔒 Running security audit..."
|
|
31
31
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
32
|
+
# jq is required for all audit paths (JSON config reading, npm/yarn filtering)
|
|
33
|
+
if ! command -v jq >/dev/null 2>&1; then
|
|
34
|
+
echo ""
|
|
35
|
+
echo "⚠️ WARNING: jq is not installed - required for security audit"
|
|
36
|
+
echo ""
|
|
37
|
+
echo "To install jq:"
|
|
38
|
+
echo " macOS: brew install jq"
|
|
39
|
+
echo " Windows: choco install jq # or scoop install jq"
|
|
40
|
+
echo " Linux: apt-get install jq"
|
|
41
|
+
echo ""
|
|
42
|
+
echo "Continuing without security audit..."
|
|
43
|
+
echo ""
|
|
44
|
+
else
|
|
45
|
+
# Load GHSA exclusion IDs from JSON config files (managed + project-local)
|
|
46
|
+
load_audit_exclusions() {
|
|
47
|
+
_EXCLUSIONS=""
|
|
48
|
+
for _config_file in audit.ignore.config.json audit.ignore.local.json; do
|
|
49
|
+
if [ -f "$_config_file" ]; then
|
|
50
|
+
_FILE_IDS=$(jq -r '.exclusions[].id' "$_config_file" 2>/dev/null)
|
|
51
|
+
if [ -n "$_FILE_IDS" ]; then
|
|
52
|
+
_EXCLUSIONS="$_EXCLUSIONS $_FILE_IDS"
|
|
53
|
+
fi
|
|
54
|
+
fi
|
|
55
|
+
done
|
|
56
|
+
echo "$_EXCLUSIONS" | tr ' ' '\n' | sort -u | grep -v '^$' | tr '\n' ' '
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
# Load CVE exclusion IDs from JSON config files (for yarn's CVE-based filtering)
|
|
60
|
+
load_audit_cves() {
|
|
61
|
+
_CVES=""
|
|
62
|
+
for _config_file in audit.ignore.config.json audit.ignore.local.json; do
|
|
63
|
+
if [ -f "$_config_file" ]; then
|
|
64
|
+
_FILE_CVES=$(jq -r '.exclusions[] | select(.cve != null) | .cve' "$_config_file" 2>/dev/null)
|
|
65
|
+
if [ -n "$_FILE_CVES" ]; then
|
|
66
|
+
_CVES="$_CVES $_FILE_CVES"
|
|
67
|
+
fi
|
|
68
|
+
fi
|
|
69
|
+
done
|
|
70
|
+
echo "$_CVES" | tr ' ' '\n' | sort -u | grep -v '^$' | tr '\n' ' '
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
AUDIT_EXCLUSIONS=$(load_audit_exclusions)
|
|
74
|
+
AUDIT_CVES=$(load_audit_cves)
|
|
75
|
+
|
|
76
|
+
if [ "$PACKAGE_MANAGER" = "yarn" ]; then
|
|
77
|
+
# Build jq filter for GHSA IDs
|
|
78
|
+
GHSA_FILTER=""
|
|
79
|
+
for _id in $AUDIT_EXCLUSIONS; do
|
|
80
|
+
if [ -n "$GHSA_FILTER" ]; then
|
|
81
|
+
GHSA_FILTER="$GHSA_FILTER or .data.advisory.github_advisory_id == \"$_id\""
|
|
82
|
+
else
|
|
83
|
+
GHSA_FILTER=".data.advisory.github_advisory_id == \"$_id\""
|
|
84
|
+
fi
|
|
85
|
+
done
|
|
86
|
+
|
|
87
|
+
# Build jq filter for CVE IDs
|
|
88
|
+
CVE_FILTER=""
|
|
89
|
+
for _cve in $AUDIT_CVES; do
|
|
90
|
+
if [ -n "$CVE_FILTER" ]; then
|
|
91
|
+
CVE_FILTER="$CVE_FILTER or . == \"$_cve\""
|
|
92
|
+
else
|
|
93
|
+
CVE_FILTER=". == \"$_cve\""
|
|
94
|
+
fi
|
|
95
|
+
done
|
|
96
|
+
|
|
97
|
+
# Combine GHSA and CVE filters
|
|
98
|
+
COMBINED_FILTER=""
|
|
99
|
+
if [ -n "$GHSA_FILTER" ] && [ -n "$CVE_FILTER" ]; then
|
|
100
|
+
COMBINED_FILTER="($GHSA_FILTER or (.data.advisory.cves | any($CVE_FILTER)))"
|
|
101
|
+
elif [ -n "$GHSA_FILTER" ]; then
|
|
102
|
+
COMBINED_FILTER="($GHSA_FILTER)"
|
|
103
|
+
elif [ -n "$CVE_FILTER" ]; then
|
|
104
|
+
COMBINED_FILTER="((.data.advisory.cves | any($CVE_FILTER)))"
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
if [ -n "$COMBINED_FILTER" ]; then
|
|
108
|
+
yarn audit --groups dependencies --json | jq -r "select(.type == \"auditAdvisory\") | select(.data.advisory.severity == \"high\" or .data.advisory.severity == \"critical\") | select(($COMBINED_FILTER) | not) | .data.advisory" > high_vulns.json
|
|
109
|
+
else
|
|
110
|
+
yarn audit --groups dependencies --json | jq -r 'select(.type == "auditAdvisory") | select(.data.advisory.severity == "high" or .data.advisory.severity == "critical") | .data.advisory' > high_vulns.json
|
|
111
|
+
fi
|
|
53
112
|
|
|
54
113
|
if [ -s high_vulns.json ]; then
|
|
55
114
|
echo "❌ High or critical vulnerabilities found in production dependencies!"
|
|
@@ -60,91 +119,43 @@ if [ "$PACKAGE_MANAGER" = "yarn" ]; then
|
|
|
60
119
|
|
|
61
120
|
echo "✅ No high or critical vulnerabilities found in production dependencies (excluding known false positives)"
|
|
62
121
|
rm -f high_vulns.json
|
|
63
|
-
fi
|
|
64
|
-
|
|
65
|
-
elif [ "$PACKAGE_MANAGER" = "npm" ]; then
|
|
66
|
-
# Run npm audit in JSON mode and filter out known false positives before failing.
|
|
67
|
-
# npm audit lacks a native --ignore flag, so we parse JSON and exclude by GHSA ID.
|
|
68
|
-
|
|
69
|
-
# Excluding GHSA-3ppc-4f35-3m26: minimatch ReDoS via repeated wildcards
|
|
70
|
-
# Nested dep in aws-cdk-lib; fix requires minimatch v10 (incompatible with ^3.1.2)
|
|
71
|
-
# Risk: None - dev-time CDK tooling, no production runtime exposure
|
|
72
|
-
|
|
73
|
-
# Excluding GHSA-2g4f-4pwh-qvx6: ajv ReDoS with $data option
|
|
74
|
-
# Nested dep in aws-cdk-lib and eslint; no fix available via npm
|
|
75
|
-
# Risk: Low - $data option not used in this application
|
|
76
|
-
|
|
77
|
-
AUDIT_JSON=$(npm audit --production --json 2>/dev/null || true)
|
|
78
|
-
UNFIXED_HIGH=$(echo "$AUDIT_JSON" | jq '[.vulnerabilities | to_entries[] | select(.value.severity == "high" or .value.severity == "critical") | .value.via[] | select(type == "object") | .url | ltrimstr("https://github.com/advisories/")] | unique | map(select(. == "GHSA-3ppc-4f35-3m26" or . == "GHSA-2g4f-4pwh-qvx6" | not)) | length')
|
|
79
|
-
if [ "$UNFIXED_HIGH" -gt 0 ]; then
|
|
80
|
-
echo "⚠️ Security audit failed. Please fix high/critical vulnerabilities before pushing."
|
|
81
|
-
exit 1
|
|
82
|
-
fi
|
|
83
|
-
echo "✅ No high or critical vulnerabilities found in production dependencies (excluding known false positives)"
|
|
84
|
-
|
|
85
|
-
elif [ "$PACKAGE_MANAGER" = "bun" ]; then
|
|
86
|
-
# Excluding GHSA-5j98-mcp5-4vw2 (CVE-2025-64756): glob CLI command injection
|
|
87
|
-
# This vulnerability only affects the glob CLI (--cmd flag), not library usage
|
|
88
|
-
# We only use glob as a library through Babel and other tools - never invoke CLI
|
|
89
122
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
# Resolution to >=5.3.6 set in package.json but bun audit still flags intermediate ranges
|
|
113
|
-
# Risk: Low - no untrusted XML with DOCTYPE entity names processed
|
|
114
|
-
|
|
115
|
-
# Excluding GHSA-r6q2-hw4h-h46w: node-tar race condition via Unicode Ligature Collisions on macOS APFS
|
|
116
|
-
# Transitive via @nestjs/apollo > @apollo/gateway > make-fetch-happen > cacache > tar
|
|
117
|
-
# Resolution to ^7.5.8 set in package.json but bun audit still flags intermediate ranges
|
|
118
|
-
# Risk: None - tar extraction not used in production runtime
|
|
119
|
-
|
|
120
|
-
# Excluding GHSA-34x7-hfp2-rc4v: node-tar arbitrary file creation via hardlink path traversal
|
|
121
|
-
# Same transitive path as GHSA-r6q2-hw4h-h46w
|
|
122
|
-
# Risk: None - tar extraction not used in production runtime
|
|
123
|
-
|
|
124
|
-
# Excluding GHSA-83g3-92jg-28cx: node-tar arbitrary file read/write via hardlink target escape
|
|
125
|
-
# Same transitive path as GHSA-r6q2-hw4h-h46w
|
|
126
|
-
# Risk: None - tar extraction not used in production runtime
|
|
127
|
-
|
|
128
|
-
# Excluding GHSA-3h5v-q93c-6h6q: ws DoS when handling request with many HTTP headers
|
|
129
|
-
# Transitive via @nestjs/graphql, graphql-ws, openai, serverless-offline, serverless-esbuild
|
|
130
|
-
# Resolution to ^8.17.1 set in package.json but bun audit still flags intermediate ranges
|
|
131
|
-
# Risk: Low - WebSocket servers behind API Gateway which limits headers
|
|
132
|
-
|
|
133
|
-
# Excluding GHSA-7r86-cg39-jmmj: minimatch ReDoS via multiple non-adjacent GLOBSTAR segments
|
|
134
|
-
# Same transitive dependency chain as GHSA-3ppc-4f35-3m26 (eslint, jest, ts-morph, etc.)
|
|
135
|
-
# Fix requires minimatch >=3.1.3 but bun cannot override transitive dependency version ranges
|
|
136
|
-
# Risk: None - only devDependency tooling, never processes untrusted user input
|
|
123
|
+
elif [ "$PACKAGE_MANAGER" = "npm" ]; then
|
|
124
|
+
# Build jq exclusion filter for npm audit GHSA IDs
|
|
125
|
+
NPM_EXCLUDE_FILTER=""
|
|
126
|
+
for _id in $AUDIT_EXCLUSIONS; do
|
|
127
|
+
if [ -n "$NPM_EXCLUDE_FILTER" ]; then
|
|
128
|
+
NPM_EXCLUDE_FILTER="$NPM_EXCLUDE_FILTER or . == \"$_id\""
|
|
129
|
+
else
|
|
130
|
+
NPM_EXCLUDE_FILTER=". == \"$_id\""
|
|
131
|
+
fi
|
|
132
|
+
done
|
|
133
|
+
|
|
134
|
+
AUDIT_JSON=$(npm audit --production --json 2>/dev/null || true)
|
|
135
|
+
if [ -n "$NPM_EXCLUDE_FILTER" ]; then
|
|
136
|
+
UNFIXED_HIGH=$(echo "$AUDIT_JSON" | jq "[.vulnerabilities | to_entries[] | select(.value.severity == \"high\" or .value.severity == \"critical\") | .value.via[] | select(type == \"object\") | .url | ltrimstr(\"https://github.com/advisories/\")] | unique | map(select($NPM_EXCLUDE_FILTER | not)) | length")
|
|
137
|
+
else
|
|
138
|
+
UNFIXED_HIGH=$(echo "$AUDIT_JSON" | jq '[.vulnerabilities | to_entries[] | select(.value.severity == "high" or .value.severity == "critical") | .value.via[] | select(type == "object") | .url | ltrimstr("https://github.com/advisories/")] | unique | length')
|
|
139
|
+
fi
|
|
140
|
+
if [ "$UNFIXED_HIGH" -gt 0 ]; then
|
|
141
|
+
echo "⚠️ Security audit failed. Please fix high/critical vulnerabilities before pushing."
|
|
142
|
+
exit 1
|
|
143
|
+
fi
|
|
144
|
+
echo "✅ No high or critical vulnerabilities found in production dependencies (excluding known false positives)"
|
|
137
145
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
146
|
+
elif [ "$PACKAGE_MANAGER" = "bun" ]; then
|
|
147
|
+
# Build --ignore flags dynamically from exclusion list
|
|
148
|
+
BUN_IGNORE_FLAGS=""
|
|
149
|
+
for _id in $AUDIT_EXCLUSIONS; do
|
|
150
|
+
BUN_IGNORE_FLAGS="$BUN_IGNORE_FLAGS --ignore $_id"
|
|
151
|
+
done
|
|
142
152
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
153
|
+
if ! bun audit --audit-level=high $BUN_IGNORE_FLAGS; then
|
|
154
|
+
echo "⚠️ Security audit failed. Please fix high/critical vulnerabilities before pushing."
|
|
155
|
+
exit 1
|
|
156
|
+
fi
|
|
157
|
+
echo "✅ No high or critical vulnerabilities found in production dependencies"
|
|
146
158
|
fi
|
|
147
|
-
echo "✅ No high or critical vulnerabilities found in production dependencies"
|
|
148
159
|
fi
|
|
149
160
|
|
|
150
161
|
# Run slow lint rules - only if script exists
|
|
@@ -1,105 +1,81 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
# This file is managed by Lisa.
|
|
3
3
|
# Do not edit directly — changes will be overwritten on the next `lisa` run.
|
|
4
|
-
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
#
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
4
|
+
# =============================================================================
|
|
5
|
+
# ESLint Lint-on-Edit Hook (PostToolUse - Write|Edit)
|
|
6
|
+
# =============================================================================
|
|
7
|
+
# Runs ESLint --fix with --quiet --cache on each edited TypeScript file.
|
|
8
|
+
# Part of the inline self-correction pipeline: prettier → ast-grep → eslint.
|
|
9
|
+
#
|
|
10
|
+
# Behavior:
|
|
11
|
+
# - Exit 0: lint passes or auto-fix resolved all errors
|
|
12
|
+
# - Exit 2: unfixable errors remain — blocks Claude so it fixes them immediately
|
|
13
|
+
#
|
|
14
|
+
# @see .claude/rules/verfication.md "Self-Correction Loop" section
|
|
15
|
+
# =============================================================================
|
|
16
|
+
|
|
17
|
+
# Extract file path from JSON input
|
|
18
|
+
FILE_PATH=$(cat | grep -o '"file_path":"[^"]*"' | head -1 | cut -d'"' -f4)
|
|
19
|
+
|
|
20
|
+
if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then
|
|
21
|
+
exit 0
|
|
20
22
|
fi
|
|
21
23
|
|
|
22
|
-
# Check if
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
exit 0
|
|
26
|
-
fi
|
|
27
|
-
|
|
28
|
-
# Get the file extension
|
|
29
|
-
FILE_EXT="${FILE_PATH##*.}"
|
|
30
|
-
|
|
31
|
-
# Check if this is a TypeScript file that should be linted
|
|
32
|
-
# Based on package.json lint command: "eslint \"{src,apps,libs,test}/**/*.ts\""
|
|
33
|
-
case "$FILE_EXT" in
|
|
34
|
-
ts|tsx)
|
|
35
|
-
# File type is supported for linting
|
|
36
|
-
;;
|
|
37
|
-
*)
|
|
38
|
-
echo "ℹ Skipping ESLint: File type .$FILE_EXT is not configured for linting"
|
|
39
|
-
exit 0
|
|
40
|
-
;;
|
|
24
|
+
# Check if file type is supported (TypeScript only)
|
|
25
|
+
case "${FILE_PATH##*.}" in
|
|
26
|
+
ts|tsx) ;;
|
|
27
|
+
*) exit 0 ;;
|
|
41
28
|
esac
|
|
42
29
|
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
30
|
+
# Validate project directory
|
|
31
|
+
if [ -z "${CLAUDE_PROJECT_DIR:-}" ]; then
|
|
32
|
+
exit 0
|
|
33
|
+
fi
|
|
46
34
|
|
|
47
|
-
# Check if
|
|
35
|
+
# Check if file is in a source directory
|
|
36
|
+
RELATIVE_PATH="${FILE_PATH#$CLAUDE_PROJECT_DIR/}"
|
|
48
37
|
case "$RELATIVE_PATH" in
|
|
49
|
-
src/*|apps/*|libs/*|test/*|features/*|components/*|hooks/*|screens/*|app/*|constants/*|utils/*|providers/*|stores/*)
|
|
50
|
-
|
|
51
|
-
;;
|
|
52
|
-
*)
|
|
53
|
-
echo "ℹ Skipping ESLint: File is not in src/, apps/, libs/, or test/ directory"
|
|
54
|
-
exit 0
|
|
55
|
-
;;
|
|
38
|
+
src/*|apps/*|libs/*|test/*|tests/*|features/*|components/*|hooks/*|screens/*|app/*|constants/*|utils/*|providers/*|stores/*) ;;
|
|
39
|
+
*) exit 0 ;;
|
|
56
40
|
esac
|
|
57
41
|
|
|
58
|
-
# Change to the project directory to ensure package manager commands work
|
|
59
42
|
cd "$CLAUDE_PROJECT_DIR" || exit 0
|
|
60
43
|
|
|
61
|
-
# Detect package manager
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
else
|
|
72
|
-
echo "npm" # Default fallback
|
|
73
|
-
fi
|
|
74
|
-
}
|
|
44
|
+
# Detect package manager
|
|
45
|
+
if [ -f "bun.lockb" ] || [ -f "bun.lock" ]; then
|
|
46
|
+
PKG_MANAGER="bun"
|
|
47
|
+
elif [ -f "pnpm-lock.yaml" ]; then
|
|
48
|
+
PKG_MANAGER="pnpm"
|
|
49
|
+
elif [ -f "yarn.lock" ]; then
|
|
50
|
+
PKG_MANAGER="yarn"
|
|
51
|
+
else
|
|
52
|
+
PKG_MANAGER="npm"
|
|
53
|
+
fi
|
|
75
54
|
|
|
76
|
-
|
|
55
|
+
# Run ESLint with --fix --quiet --cache on the specific file
|
|
56
|
+
# --quiet: suppress warnings, only show errors
|
|
57
|
+
# --cache: use ESLint cache for performance
|
|
58
|
+
echo "Running ESLint --fix on: $FILE_PATH"
|
|
77
59
|
|
|
78
|
-
#
|
|
79
|
-
|
|
60
|
+
# First pass: attempt auto-fix
|
|
61
|
+
OUTPUT=$($PKG_MANAGER eslint --fix --quiet --cache "$FILE_PATH" 2>&1)
|
|
62
|
+
FIX_EXIT=$?
|
|
80
63
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
[[ ! "$line" =~ "Need to install the following packages" ]] && \
|
|
86
|
-
[[ ! "$line" =~ "Ok to proceed" ]]; then
|
|
87
|
-
echo "$line"
|
|
88
|
-
fi
|
|
89
|
-
done
|
|
64
|
+
if [ $FIX_EXIT -eq 0 ]; then
|
|
65
|
+
echo "ESLint: No errors in $(basename "$FILE_PATH")"
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
90
68
|
|
|
91
|
-
#
|
|
92
|
-
|
|
69
|
+
# Auto-fix resolved some issues but errors remain — re-run to get remaining errors
|
|
70
|
+
OUTPUT=$($PKG_MANAGER eslint --quiet --cache "$FILE_PATH" 2>&1)
|
|
71
|
+
LINT_EXIT=$?
|
|
93
72
|
|
|
94
|
-
if [ $
|
|
95
|
-
echo "
|
|
96
|
-
|
|
97
|
-
echo "✓ ESLint: Fixed issues in $(basename "$FILE_PATH")"
|
|
98
|
-
echo " Some issues were automatically fixed. Please review the changes."
|
|
99
|
-
else
|
|
100
|
-
echo "⚠ ESLint found issues that couldn't be auto-fixed in: $FILE_PATH" >&2
|
|
101
|
-
echo " You may need to run '$PKG_MANAGER run lint:fix' manually or fix the issues by hand." >&2
|
|
73
|
+
if [ $LINT_EXIT -eq 0 ]; then
|
|
74
|
+
echo "ESLint: Auto-fixed all errors in $(basename "$FILE_PATH")"
|
|
75
|
+
exit 0
|
|
102
76
|
fi
|
|
103
77
|
|
|
104
|
-
#
|
|
105
|
-
|
|
78
|
+
# Unfixable errors remain — block with feedback
|
|
79
|
+
echo "ESLint found unfixable errors in: $FILE_PATH" >&2
|
|
80
|
+
echo "$OUTPUT" >&2
|
|
81
|
+
exit 2
|
|
@@ -63,6 +63,10 @@
|
|
|
63
63
|
{
|
|
64
64
|
"type": "command",
|
|
65
65
|
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/sg-scan-on-edit.sh"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"type": "command",
|
|
69
|
+
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/lint-on-edit.sh"
|
|
66
70
|
}
|
|
67
71
|
]
|
|
68
72
|
},
|
|
@@ -208,6 +212,24 @@
|
|
|
208
212
|
}
|
|
209
213
|
],
|
|
210
214
|
"Stop": [
|
|
215
|
+
{
|
|
216
|
+
"matcher": "",
|
|
217
|
+
"hooks": [
|
|
218
|
+
{
|
|
219
|
+
"type": "command",
|
|
220
|
+
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/verify-completion.sh"
|
|
221
|
+
}
|
|
222
|
+
]
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
"matcher": "",
|
|
226
|
+
"hooks": [
|
|
227
|
+
{
|
|
228
|
+
"type": "command",
|
|
229
|
+
"command": "$CLAUDE_PROJECT_DIR/.claude/hooks/check-tired-boss.sh"
|
|
230
|
+
}
|
|
231
|
+
]
|
|
232
|
+
},
|
|
211
233
|
{
|
|
212
234
|
"matcher": "",
|
|
213
235
|
"hooks": [
|