code-as-plan 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/LICENSE +21 -0
- package/README.ja-JP.md +834 -0
- package/README.ko-KR.md +823 -0
- package/README.md +1006 -0
- package/README.pt-BR.md +452 -0
- package/README.zh-CN.md +800 -0
- package/agents/cap-brainstormer.md +154 -0
- package/agents/cap-debugger.md +221 -0
- package/agents/cap-prototyper.md +170 -0
- package/agents/cap-reviewer.md +230 -0
- package/agents/cap-tester.md +193 -0
- package/bin/install.js +5002 -0
- package/cap/bin/gsd-tools.cjs +1141 -0
- package/cap/bin/lib/arc-scanner.cjs +341 -0
- package/cap/bin/lib/cap-feature-map.cjs +506 -0
- package/cap/bin/lib/cap-session.cjs +191 -0
- package/cap/bin/lib/cap-stack-docs.cjs +598 -0
- package/cap/bin/lib/cap-tag-scanner.cjs +458 -0
- package/cap/bin/lib/commands.cjs +959 -0
- package/cap/bin/lib/config.cjs +466 -0
- package/cap/bin/lib/convention-reader.cjs +180 -0
- package/cap/bin/lib/core.cjs +1230 -0
- package/cap/bin/lib/feature-aggregator.cjs +422 -0
- package/cap/bin/lib/frontmatter.cjs +336 -0
- package/cap/bin/lib/init.cjs +1442 -0
- package/cap/bin/lib/manifest-generator.cjs +381 -0
- package/cap/bin/lib/milestone.cjs +252 -0
- package/cap/bin/lib/model-profiles.cjs +68 -0
- package/cap/bin/lib/monorepo-context.cjs +224 -0
- package/cap/bin/lib/monorepo-migrator.cjs +507 -0
- package/cap/bin/lib/phase.cjs +888 -0
- package/cap/bin/lib/profile-output.cjs +952 -0
- package/cap/bin/lib/profile-pipeline.cjs +539 -0
- package/cap/bin/lib/roadmap.cjs +329 -0
- package/cap/bin/lib/security.cjs +382 -0
- package/cap/bin/lib/session-manager.cjs +290 -0
- package/cap/bin/lib/skeleton-generator.cjs +177 -0
- package/cap/bin/lib/state.cjs +1031 -0
- package/cap/bin/lib/template.cjs +222 -0
- package/cap/bin/lib/test-detector.cjs +61 -0
- package/cap/bin/lib/uat.cjs +282 -0
- package/cap/bin/lib/verify.cjs +888 -0
- package/cap/bin/lib/workspace-detector.cjs +369 -0
- package/cap/bin/lib/workstream.cjs +491 -0
- package/cap/commands/gsd/workstreams.md +63 -0
- package/cap/references/arc-standard.md +315 -0
- package/cap/references/cap-agent-architecture.md +102 -0
- package/cap/references/cap-gitignore-template +9 -0
- package/cap/references/cap-zero-deps.md +158 -0
- package/cap/references/checkpoints.md +778 -0
- package/cap/references/continuation-format.md +249 -0
- package/cap/references/decimal-phase-calculation.md +64 -0
- package/cap/references/feature-map-template.md +25 -0
- package/cap/references/git-integration.md +295 -0
- package/cap/references/git-planning-commit.md +38 -0
- package/cap/references/model-profile-resolution.md +36 -0
- package/cap/references/model-profiles.md +139 -0
- package/cap/references/phase-argument-parsing.md +61 -0
- package/cap/references/planning-config.md +202 -0
- package/cap/references/questioning.md +162 -0
- package/cap/references/session-template.json +8 -0
- package/cap/references/tdd.md +263 -0
- package/cap/references/ui-brand.md +160 -0
- package/cap/references/user-profiling.md +681 -0
- package/cap/references/verification-patterns.md +612 -0
- package/cap/references/workstream-flag.md +58 -0
- package/cap/templates/DEBUG.md +164 -0
- package/cap/templates/UAT.md +265 -0
- package/cap/templates/UI-SPEC.md +100 -0
- package/cap/templates/VALIDATION.md +76 -0
- package/cap/templates/claude-md.md +122 -0
- package/cap/templates/codebase/architecture.md +255 -0
- package/cap/templates/codebase/concerns.md +310 -0
- package/cap/templates/codebase/conventions.md +307 -0
- package/cap/templates/codebase/integrations.md +280 -0
- package/cap/templates/codebase/stack.md +186 -0
- package/cap/templates/codebase/structure.md +285 -0
- package/cap/templates/codebase/testing.md +480 -0
- package/cap/templates/config.json +44 -0
- package/cap/templates/context.md +352 -0
- package/cap/templates/continue-here.md +78 -0
- package/cap/templates/copilot-instructions.md +7 -0
- package/cap/templates/debug-subagent-prompt.md +91 -0
- package/cap/templates/dev-preferences.md +21 -0
- package/cap/templates/discovery.md +146 -0
- package/cap/templates/discussion-log.md +63 -0
- package/cap/templates/milestone-archive.md +123 -0
- package/cap/templates/milestone.md +115 -0
- package/cap/templates/phase-prompt.md +610 -0
- package/cap/templates/planner-subagent-prompt.md +117 -0
- package/cap/templates/project.md +186 -0
- package/cap/templates/requirements.md +231 -0
- package/cap/templates/research-project/ARCHITECTURE.md +204 -0
- package/cap/templates/research-project/FEATURES.md +147 -0
- package/cap/templates/research-project/PITFALLS.md +200 -0
- package/cap/templates/research-project/STACK.md +120 -0
- package/cap/templates/research-project/SUMMARY.md +170 -0
- package/cap/templates/research.md +552 -0
- package/cap/templates/retrospective.md +54 -0
- package/cap/templates/roadmap.md +202 -0
- package/cap/templates/state.md +176 -0
- package/cap/templates/summary-complex.md +59 -0
- package/cap/templates/summary-minimal.md +41 -0
- package/cap/templates/summary-standard.md +48 -0
- package/cap/templates/summary.md +248 -0
- package/cap/templates/user-profile.md +146 -0
- package/cap/templates/user-setup.md +311 -0
- package/cap/templates/verification-report.md +322 -0
- package/cap/workflows/add-phase.md +112 -0
- package/cap/workflows/add-tests.md +351 -0
- package/cap/workflows/add-todo.md +158 -0
- package/cap/workflows/audit-milestone.md +340 -0
- package/cap/workflows/audit-uat.md +109 -0
- package/cap/workflows/autonomous.md +891 -0
- package/cap/workflows/check-todos.md +177 -0
- package/cap/workflows/cleanup.md +152 -0
- package/cap/workflows/complete-milestone.md +767 -0
- package/cap/workflows/diagnose-issues.md +231 -0
- package/cap/workflows/discovery-phase.md +289 -0
- package/cap/workflows/discuss-phase-assumptions.md +653 -0
- package/cap/workflows/discuss-phase.md +1049 -0
- package/cap/workflows/do.md +104 -0
- package/cap/workflows/execute-phase.md +846 -0
- package/cap/workflows/execute-plan.md +514 -0
- package/cap/workflows/fast.md +105 -0
- package/cap/workflows/forensics.md +265 -0
- package/cap/workflows/health.md +181 -0
- package/cap/workflows/help.md +660 -0
- package/cap/workflows/insert-phase.md +130 -0
- package/cap/workflows/list-phase-assumptions.md +178 -0
- package/cap/workflows/list-workspaces.md +56 -0
- package/cap/workflows/manager.md +362 -0
- package/cap/workflows/map-codebase.md +377 -0
- package/cap/workflows/milestone-summary.md +223 -0
- package/cap/workflows/new-milestone.md +486 -0
- package/cap/workflows/new-project.md +1250 -0
- package/cap/workflows/new-workspace.md +237 -0
- package/cap/workflows/next.md +97 -0
- package/cap/workflows/node-repair.md +92 -0
- package/cap/workflows/note.md +156 -0
- package/cap/workflows/pause-work.md +176 -0
- package/cap/workflows/plan-milestone-gaps.md +273 -0
- package/cap/workflows/plan-phase.md +859 -0
- package/cap/workflows/plant-seed.md +169 -0
- package/cap/workflows/pr-branch.md +129 -0
- package/cap/workflows/profile-user.md +450 -0
- package/cap/workflows/progress.md +507 -0
- package/cap/workflows/quick.md +757 -0
- package/cap/workflows/remove-phase.md +155 -0
- package/cap/workflows/remove-workspace.md +90 -0
- package/cap/workflows/research-phase.md +82 -0
- package/cap/workflows/resume-project.md +326 -0
- package/cap/workflows/review.md +228 -0
- package/cap/workflows/session-report.md +146 -0
- package/cap/workflows/settings.md +283 -0
- package/cap/workflows/ship.md +228 -0
- package/cap/workflows/stats.md +60 -0
- package/cap/workflows/transition.md +671 -0
- package/cap/workflows/ui-phase.md +302 -0
- package/cap/workflows/ui-review.md +165 -0
- package/cap/workflows/update.md +323 -0
- package/cap/workflows/validate-phase.md +174 -0
- package/cap/workflows/verify-phase.md +254 -0
- package/cap/workflows/verify-work.md +637 -0
- package/commands/cap/annotate.md +165 -0
- package/commands/cap/brainstorm.md +238 -0
- package/commands/cap/debug.md +297 -0
- package/commands/cap/init.md +262 -0
- package/commands/cap/iterate.md +234 -0
- package/commands/cap/prototype.md +281 -0
- package/commands/cap/refresh-docs.md +37 -0
- package/commands/cap/review.md +272 -0
- package/commands/cap/scan.md +249 -0
- package/commands/cap/start.md +234 -0
- package/commands/cap/status.md +189 -0
- package/commands/cap/test.md +250 -0
- package/hooks/dist/gsd-check-update.js +114 -0
- package/hooks/dist/gsd-context-monitor.js +156 -0
- package/hooks/dist/gsd-prompt-guard.js +96 -0
- package/hooks/dist/gsd-statusline.js +119 -0
- package/hooks/dist/gsd-workflow-guard.js +94 -0
- package/package.json +51 -0
- package/scripts/base64-scan.sh +262 -0
- package/scripts/build-hooks.js +82 -0
- package/scripts/cap-removal-checklist.md +202 -0
- package/scripts/prompt-injection-scan.sh +198 -0
- package/scripts/run-tests.cjs +29 -0
- package/scripts/secret-scan.sh +227 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# CAP v2.0 -- GSD Removal Checklist
|
|
2
|
+
|
|
3
|
+
<!-- @gsd-context This document defines the COMPLETE removal plan for transitioning from GSD to CAP. It is NOT executed during prototyping -- it documents what gets removed when the clean break is made. -->
|
|
4
|
+
<!-- @gsd-decision Removal is documented as a checklist, not executed during prototype. This allows the current GSD infrastructure to keep working during development while clearly defining the target end state. -->
|
|
5
|
+
|
|
6
|
+
<!-- @gsd-todo(ref:AC-71) All /gsd:* commands shall be removed from the codebase -->
|
|
7
|
+
<!-- @gsd-todo(ref:AC-72) All gsd-* agent files shall be removed from the agents/ directory -->
|
|
8
|
+
<!-- @gsd-todo(ref:AC-73) Explicitly killed agents: gsd-discuss, gsd-planner, gsd-milestone-*, gsd-executor, gsd-annotator, and all discuss/plan phase agents -->
|
|
9
|
+
<!-- @gsd-todo(ref:AC-74) Artifacts no longer created or referenced: ROADMAP.md, REQUIREMENTS.md, STATE.md, MILESTONES.md, VERIFICATION.md, PLAN.md -->
|
|
10
|
+
<!-- @gsd-todo(ref:AC-75) CODE-INVENTORY.md evolved into enriched FEATURE-MAP.md -- standalone file removed -->
|
|
11
|
+
<!-- @gsd-todo(ref:AC-76) bin/install.js updated to reference CAP branding and commands -->
|
|
12
|
+
<!-- @gsd-todo(ref:AC-77) package.json name updated to cap (or code-as-plan fallback) -->
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## 1. Agent Files to Remove (AC-72, AC-73)
|
|
17
|
+
|
|
18
|
+
The following agent files in `agents/` shall be deleted:
|
|
19
|
+
|
|
20
|
+
### Explicitly Killed Agents (AC-73)
|
|
21
|
+
|
|
22
|
+
These agents represent the discuss/plan workflow that CAP eliminates:
|
|
23
|
+
|
|
24
|
+
- [ ] `agents/gsd-planner.md` -- replaced by Feature Map + cap-prototyper
|
|
25
|
+
- [ ] `agents/gsd-executor.md` -- replaced by cap-prototyper (prototype/iterate modes)
|
|
26
|
+
- [ ] `agents/gsd-annotator.md` -- replaced by cap-prototyper (annotate mode)
|
|
27
|
+
- [ ] `agents/gsd-brainstormer.md` -- replaced by cap-brainstormer
|
|
28
|
+
- [ ] `agents/gsd-roadmapper.md` -- ROADMAP.md no longer exists
|
|
29
|
+
- [ ] `agents/gsd-plan-checker.md` -- no plan phase to check
|
|
30
|
+
- [ ] `agents/gsd-reviewer.md` -- replaced by cap-reviewer
|
|
31
|
+
- [ ] `agents/gsd-tester.md` -- replaced by cap-tester
|
|
32
|
+
- [ ] `agents/gsd-debugger.md` -- replaced by cap-debugger
|
|
33
|
+
|
|
34
|
+
### Supporting Agents to Remove
|
|
35
|
+
|
|
36
|
+
- [ ] `agents/gsd-advisor-researcher.md`
|
|
37
|
+
- [ ] `agents/gsd-arc-executor.md`
|
|
38
|
+
- [ ] `agents/gsd-arc-planner.md`
|
|
39
|
+
- [ ] `agents/gsd-assumptions-analyzer.md`
|
|
40
|
+
- [ ] `agents/gsd-code-planner.md`
|
|
41
|
+
- [ ] `agents/gsd-codebase-mapper.md`
|
|
42
|
+
- [ ] `agents/gsd-integration-checker.md`
|
|
43
|
+
- [ ] `agents/gsd-nyquist-auditor.md`
|
|
44
|
+
- [ ] `agents/gsd-phase-researcher.md`
|
|
45
|
+
- [ ] `agents/gsd-project-researcher.md`
|
|
46
|
+
- [ ] `agents/gsd-prototyper.md`
|
|
47
|
+
- [ ] `agents/gsd-research-synthesizer.md`
|
|
48
|
+
- [ ] `agents/gsd-ui-auditor.md`
|
|
49
|
+
- [ ] `agents/gsd-ui-checker.md`
|
|
50
|
+
- [ ] `agents/gsd-ui-researcher.md`
|
|
51
|
+
- [ ] `agents/gsd-user-profiler.md`
|
|
52
|
+
- [ ] `agents/gsd-verifier.md`
|
|
53
|
+
|
|
54
|
+
**Agents to KEEP (CAP v2.0 agent set per AC-67):**
|
|
55
|
+
- `agents/cap-brainstormer.md`
|
|
56
|
+
- `agents/cap-prototyper.md`
|
|
57
|
+
- `agents/cap-tester.md`
|
|
58
|
+
- `agents/cap-reviewer.md`
|
|
59
|
+
- `agents/cap-debugger.md`
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 2. Command Files to Remove (AC-71)
|
|
64
|
+
|
|
65
|
+
All files in `commands/gsd/` shall be deleted. Current GSD commands:
|
|
66
|
+
|
|
67
|
+
- [ ] `commands/gsd/add-backlog.md`
|
|
68
|
+
- [ ] `commands/gsd/add-phase.md`
|
|
69
|
+
- [ ] `commands/gsd/add-tests.md`
|
|
70
|
+
- [ ] `commands/gsd/add-todo.md`
|
|
71
|
+
- [ ] `commands/gsd/annotate.md`
|
|
72
|
+
- [ ] `commands/gsd/audit-milestone.md`
|
|
73
|
+
- [ ] `commands/gsd/audit-uat.md`
|
|
74
|
+
- [ ] `commands/gsd/autonomous.md`
|
|
75
|
+
- [ ] `commands/gsd/brainstorm.md`
|
|
76
|
+
- [ ] `commands/gsd/check-todos.md`
|
|
77
|
+
- [ ] `commands/gsd/cleanup.md`
|
|
78
|
+
- [ ] `commands/gsd/complete-milestone.md`
|
|
79
|
+
- [ ] `commands/gsd/debug.md`
|
|
80
|
+
- [ ] `commands/gsd/deep-plan.md`
|
|
81
|
+
- [ ] `commands/gsd/discuss-phase.md`
|
|
82
|
+
- [ ] `commands/gsd/do.md`
|
|
83
|
+
- [ ] `commands/gsd/execute-phase.md`
|
|
84
|
+
- [ ] `commands/gsd/extract-plan.md`
|
|
85
|
+
- [ ] `commands/gsd/fast.md`
|
|
86
|
+
- [ ] `commands/gsd/forensics.md`
|
|
87
|
+
- [ ] All remaining `commands/gsd/*.md` files
|
|
88
|
+
|
|
89
|
+
**Commands to KEEP (CAP v2.0 command set):**
|
|
90
|
+
- `commands/cap/init.md`
|
|
91
|
+
- `commands/cap/brainstorm.md`
|
|
92
|
+
- `commands/cap/prototype.md`
|
|
93
|
+
- `commands/cap/iterate.md`
|
|
94
|
+
- `commands/cap/annotate.md`
|
|
95
|
+
- `commands/cap/scan.md`
|
|
96
|
+
- `commands/cap/test.md`
|
|
97
|
+
- `commands/cap/review.md`
|
|
98
|
+
- `commands/cap/debug.md`
|
|
99
|
+
- `commands/cap/status.md`
|
|
100
|
+
- `commands/cap/start.md`
|
|
101
|
+
- `commands/cap/refresh-docs.md`
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 3. Artifact References to Remove (AC-74)
|
|
106
|
+
|
|
107
|
+
These planning artifacts shall no longer be created or referenced anywhere in the codebase:
|
|
108
|
+
|
|
109
|
+
- [ ] `ROADMAP.md` -- eliminated; features are in FEATURE-MAP.md
|
|
110
|
+
- [ ] `REQUIREMENTS.md` -- eliminated; ACs are in FEATURE-MAP.md
|
|
111
|
+
- [ ] `STATE.md` -- eliminated; state is in SESSION.json
|
|
112
|
+
- [ ] `MILESTONES.md` -- eliminated; no milestone concept in CAP
|
|
113
|
+
- [ ] `VERIFICATION.md` -- eliminated; review output goes to .cap/REVIEW.md
|
|
114
|
+
- [ ] `PLAN.md` -- eliminated; code is the plan
|
|
115
|
+
- [ ] `CODE-INVENTORY.md` -- evolved into FEATURE-MAP.md (AC-75)
|
|
116
|
+
|
|
117
|
+
### Files to grep and update:
|
|
118
|
+
- [ ] `CLAUDE.md` -- remove all references to gsd:* commands and GSD workflow
|
|
119
|
+
- [ ] `cap/references/arc-standard.md` -- update @gsd-* references to @cap-* or archive
|
|
120
|
+
- [ ] Any README or documentation referencing GSD commands
|
|
121
|
+
|
|
122
|
+
---
|
|
123
|
+
|
|
124
|
+
## 4. Package Configuration Changes (AC-76, AC-77)
|
|
125
|
+
|
|
126
|
+
### package.json updates (AC-77)
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"name": "cap",
|
|
131
|
+
"description": "CAP (Code As Plan) -- AI-native development where code IS the plan",
|
|
132
|
+
"bin": {
|
|
133
|
+
"cap": "bin/install.js"
|
|
134
|
+
},
|
|
135
|
+
"keywords": [
|
|
136
|
+
"cap",
|
|
137
|
+
"code-as-plan",
|
|
138
|
+
"claude",
|
|
139
|
+
"claude-code",
|
|
140
|
+
"ai",
|
|
141
|
+
"development-workflow"
|
|
142
|
+
]
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Fallback name if `cap` is taken on npm: `code-as-plan`
|
|
147
|
+
|
|
148
|
+
### bin/install.js updates (AC-76)
|
|
149
|
+
|
|
150
|
+
- [ ] Update branding strings from "GSD" / "Get Shit Done" to "CAP" / "Code As Plan"
|
|
151
|
+
- [ ] Update command references from `/gsd:*` to `/cap:*`
|
|
152
|
+
- [ ] Update binary name from `cap-cc` to `cap`
|
|
153
|
+
- [ ] Update repository URLs if repo is renamed
|
|
154
|
+
|
|
155
|
+
### npm files array update (AC-99)
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"files": [
|
|
160
|
+
"bin",
|
|
161
|
+
"commands/cap",
|
|
162
|
+
"cap",
|
|
163
|
+
"agents",
|
|
164
|
+
"hooks/dist",
|
|
165
|
+
"scripts"
|
|
166
|
+
]
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Note: `commands/cap` instead of `commands` to exclude `commands/gsd/` from distribution.
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 5. Distribution Changes (AC-97, AC-98, AC-99)
|
|
175
|
+
|
|
176
|
+
- [ ] Package installable via `npx cap@latest` (AC-97)
|
|
177
|
+
- [ ] Build uses esbuild following `scripts/build-hooks.js` pattern (AC-98)
|
|
178
|
+
- [ ] npm `files` array includes: bin, commands/cap, agents, hooks/dist, scripts (AC-99)
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 6. Post-Removal Verification
|
|
183
|
+
|
|
184
|
+
After executing the removal:
|
|
185
|
+
|
|
186
|
+
1. [ ] `ls agents/` shows only 5 cap-* files
|
|
187
|
+
2. [ ] `ls commands/` shows only `commands/cap/` directory
|
|
188
|
+
3. [ ] `grep -r "gsd:" commands/ agents/` returns no results
|
|
189
|
+
4. [ ] `grep -r "ROADMAP\|REQUIREMENTS\|STATE\.md\|MILESTONES\|VERIFICATION\|PLAN\.md" commands/ agents/` returns no results
|
|
190
|
+
5. [ ] `npm test` passes
|
|
191
|
+
6. [ ] `npx cap@latest` installs and runs
|
|
192
|
+
7. [ ] `/cap:init` creates correct structure
|
|
193
|
+
8. [ ] `/cap:scan` detects tags correctly
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Execution Notes
|
|
198
|
+
|
|
199
|
+
- This removal should be executed as a SINGLE atomic operation (one commit)
|
|
200
|
+
- All tests must be updated to reference CAP instead of GSD before removal
|
|
201
|
+
- The `.planning/` directory contents are NOT part of the distributed package and can remain as historical reference
|
|
202
|
+
- The `cap/` directory name is a legacy artifact that may be renamed in a future pass (low priority)
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# prompt-injection-scan.sh — Scan files for prompt injection patterns
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# scripts/prompt-injection-scan.sh --diff origin/main # CI mode: scan changed .md files
|
|
6
|
+
# scripts/prompt-injection-scan.sh --file path/to/file # Scan a single file
|
|
7
|
+
# scripts/prompt-injection-scan.sh --dir agents/ # Scan all files in a directory
|
|
8
|
+
#
|
|
9
|
+
# Exit codes:
|
|
10
|
+
# 0 = clean
|
|
11
|
+
# 1 = findings detected
|
|
12
|
+
# 2 = usage error
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
# ─── Patterns ────────────────────────────────────────────────────────────────
|
|
16
|
+
# Each pattern is a POSIX extended regex. Keep alphabetized by category.
|
|
17
|
+
|
|
18
|
+
PATTERNS=(
|
|
19
|
+
# Instruction override
|
|
20
|
+
'ignore[[:space:]]+(all[[:space:]]+)?(previous|prior|above|earlier|preceding)[[:space:]]+(instructions|prompts|rules|directives|context)'
|
|
21
|
+
'disregard[[:space:]]+(all[[:space:]]+)?(previous|prior|above)[[:space:]]+(instructions|prompts|rules)'
|
|
22
|
+
'forget[[:space:]]+(all[[:space:]]+)?(previous|prior|above)[[:space:]]+(instructions|prompts|rules|context)'
|
|
23
|
+
'override[[:space:]]+(all[[:space:]]+)?(system|previous|safety)[[:space:]]+(instructions|prompts|rules|checks|filters|guards)'
|
|
24
|
+
'override[[:space:]]+(system|safety|security)[[:space:]]'
|
|
25
|
+
|
|
26
|
+
# Role manipulation
|
|
27
|
+
'you[[:space:]]+are[[:space:]]+now[[:space:]]+(a|an|my)[[:space:]]'
|
|
28
|
+
'from[[:space:]]+now[[:space:]]+on[[:space:]]+(you|pretend|act|behave)'
|
|
29
|
+
'pretend[[:space:]]+(you[[:space:]]+are|to[[:space:]]+be)[[:space:]]'
|
|
30
|
+
'act[[:space:]]+as[[:space:]]+(a|an|if|my)[[:space:]]'
|
|
31
|
+
'roleplay[[:space:]]+as[[:space:]]'
|
|
32
|
+
'assume[[:space:]]+the[[:space:]]+role[[:space:]]+of[[:space:]]'
|
|
33
|
+
|
|
34
|
+
# System prompt extraction
|
|
35
|
+
'output[[:space:]]+(your|the)[[:space:]]+(system[[:space:]]+)?(prompt|instructions)'
|
|
36
|
+
'reveal[[:space:]]+(your|the)[[:space:]]+(system[[:space:]]+)?(prompt|instructions)'
|
|
37
|
+
'show[[:space:]]+me[[:space:]]+(your|the)[[:space:]]+(system[[:space:]]+)?(prompt|instructions)'
|
|
38
|
+
'print[[:space:]]+(your|the)[[:space:]]+(system[[:space:]]+)?(prompt|instructions)'
|
|
39
|
+
'what[[:space:]]+(is|are)[[:space:]]+(your|the)[[:space:]]+(system[[:space:]]+)?(prompt|instructions)'
|
|
40
|
+
'repeat[[:space:]]+(your|the|all)[[:space:]]+(system[[:space:]]+)?(prompt|instructions|rules)'
|
|
41
|
+
|
|
42
|
+
# Fake message boundaries
|
|
43
|
+
'</?system>'
|
|
44
|
+
'</?assistant>'
|
|
45
|
+
'</?human>'
|
|
46
|
+
'\[SYSTEM\]'
|
|
47
|
+
'\[/SYSTEM\]'
|
|
48
|
+
'\[INST\]'
|
|
49
|
+
'\[/INST\]'
|
|
50
|
+
'<<SYS>>'
|
|
51
|
+
'<</SYS>>'
|
|
52
|
+
|
|
53
|
+
# Tool call injection / code execution in markdown
|
|
54
|
+
'eval[[:space:]]*\([[:space:]]*["\x27]'
|
|
55
|
+
'exec[[:space:]]*\([[:space:]]*["\x27]'
|
|
56
|
+
'Function[[:space:]]*\([[:space:]]*["\x27].*return'
|
|
57
|
+
|
|
58
|
+
# Jailbreak / DAN patterns
|
|
59
|
+
'do[[:space:]]+anything[[:space:]]+now'
|
|
60
|
+
'DAN[[:space:]]+mode'
|
|
61
|
+
'developer[[:space:]]+mode[[:space:]]+(enabled|output|activated)'
|
|
62
|
+
'jailbreak'
|
|
63
|
+
'bypass[[:space:]]+(safety|content|security)[[:space:]]+(filter|check|rule|guard)'
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
# ─── Allowlist ───────────────────────────────────────────────────────────────
|
|
67
|
+
# Files that legitimately discuss injection patterns (security docs, tests, this script)
|
|
68
|
+
ALLOWLIST=(
|
|
69
|
+
'scripts/prompt-injection-scan.sh'
|
|
70
|
+
'scripts/base64-scan.sh'
|
|
71
|
+
'scripts/secret-scan.sh'
|
|
72
|
+
'tests/security-scan.test.cjs'
|
|
73
|
+
'tests/security.test.cjs'
|
|
74
|
+
'tests/prompt-injection-scan.test.cjs'
|
|
75
|
+
'get-shit-done/bin/lib/security.cjs'
|
|
76
|
+
'hooks/gsd-prompt-guard.js'
|
|
77
|
+
'SECURITY.md'
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
is_allowlisted() {
|
|
81
|
+
local file="$1"
|
|
82
|
+
for allowed in "${ALLOWLIST[@]}"; do
|
|
83
|
+
if [[ "$file" == *"$allowed" ]]; then
|
|
84
|
+
return 0
|
|
85
|
+
fi
|
|
86
|
+
done
|
|
87
|
+
return 1
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# ─── File Collection ─────────────────────────────────────────────────────────
|
|
91
|
+
|
|
92
|
+
collect_files() {
|
|
93
|
+
local mode="$1"
|
|
94
|
+
shift
|
|
95
|
+
|
|
96
|
+
case "$mode" in
|
|
97
|
+
--diff)
|
|
98
|
+
local base="${1:-origin/main}"
|
|
99
|
+
# Get changed files in the diff, filter to scannable extensions
|
|
100
|
+
git diff --name-only --diff-filter=ACMR "$base"...HEAD 2>/dev/null \
|
|
101
|
+
| grep -E '\.(md|cjs|js|json|yml|yaml|sh)$' || true
|
|
102
|
+
;;
|
|
103
|
+
--file)
|
|
104
|
+
if [[ -f "$1" ]]; then
|
|
105
|
+
echo "$1"
|
|
106
|
+
else
|
|
107
|
+
echo "Error: file not found: $1" >&2
|
|
108
|
+
exit 2
|
|
109
|
+
fi
|
|
110
|
+
;;
|
|
111
|
+
--dir)
|
|
112
|
+
local dir="$1"
|
|
113
|
+
if [[ ! -d "$dir" ]]; then
|
|
114
|
+
echo "Error: directory not found: $dir" >&2
|
|
115
|
+
exit 2
|
|
116
|
+
fi
|
|
117
|
+
find "$dir" -type f \( -name '*.md' -o -name '*.cjs' -o -name '*.js' -o -name '*.json' -o -name '*.yml' -o -name '*.yaml' -o -name '*.sh' \) \
|
|
118
|
+
! -path '*/node_modules/*' ! -path '*/.git/*' ! -path '*/dist/*' 2>/dev/null || true
|
|
119
|
+
;;
|
|
120
|
+
--stdin)
|
|
121
|
+
cat
|
|
122
|
+
;;
|
|
123
|
+
*)
|
|
124
|
+
echo "Usage: $0 --diff [base] | --file <path> | --dir <path> | --stdin" >&2
|
|
125
|
+
exit 2
|
|
126
|
+
;;
|
|
127
|
+
esac
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
# ─── Scanner ─────────────────────────────────────────────────────────────────
|
|
131
|
+
|
|
132
|
+
scan_file() {
|
|
133
|
+
local file="$1"
|
|
134
|
+
local found=0
|
|
135
|
+
|
|
136
|
+
if is_allowlisted "$file"; then
|
|
137
|
+
return 0
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
for pattern in "${PATTERNS[@]}"; do
|
|
141
|
+
# Use grep -iE for case-insensitive extended regex
|
|
142
|
+
# -n for line numbers, -c for count mode first to check
|
|
143
|
+
local matches
|
|
144
|
+
matches=$(grep -inE -e "$pattern" "$file" 2>/dev/null || true)
|
|
145
|
+
if [[ -n "$matches" ]]; then
|
|
146
|
+
if [[ $found -eq 0 ]]; then
|
|
147
|
+
echo "FAIL: $file"
|
|
148
|
+
found=1
|
|
149
|
+
fi
|
|
150
|
+
echo "$matches" | while IFS= read -r line; do
|
|
151
|
+
echo " $line"
|
|
152
|
+
done
|
|
153
|
+
fi
|
|
154
|
+
done
|
|
155
|
+
|
|
156
|
+
return $found
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
# ─── Main ────────────────────────────────────────────────────────────────────
|
|
160
|
+
|
|
161
|
+
main() {
|
|
162
|
+
if [[ $# -eq 0 ]]; then
|
|
163
|
+
echo "Usage: $0 --diff [base] | --file <path> | --dir <path>" >&2
|
|
164
|
+
exit 2
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
local mode="$1"
|
|
168
|
+
shift
|
|
169
|
+
|
|
170
|
+
local files
|
|
171
|
+
files=$(collect_files "$mode" "$@")
|
|
172
|
+
|
|
173
|
+
if [[ -z "$files" ]]; then
|
|
174
|
+
echo "prompt-injection-scan: no files to scan"
|
|
175
|
+
exit 0
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
local total=0
|
|
179
|
+
local failed=0
|
|
180
|
+
|
|
181
|
+
while IFS= read -r file; do
|
|
182
|
+
[[ -z "$file" ]] && continue
|
|
183
|
+
total=$((total + 1))
|
|
184
|
+
if ! scan_file "$file"; then
|
|
185
|
+
failed=$((failed + 1))
|
|
186
|
+
fi
|
|
187
|
+
done <<< "$files"
|
|
188
|
+
|
|
189
|
+
echo ""
|
|
190
|
+
echo "prompt-injection-scan: scanned $total files, $failed with findings"
|
|
191
|
+
|
|
192
|
+
if [[ $failed -gt 0 ]]; then
|
|
193
|
+
exit 1
|
|
194
|
+
fi
|
|
195
|
+
exit 0
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
main "$@"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Cross-platform test runner — resolves test file globs via Node
|
|
3
|
+
// instead of relying on shell expansion (which fails on Windows PowerShell/cmd).
|
|
4
|
+
// Propagates NODE_V8_COVERAGE so c8 collects coverage from the child process.
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const { readdirSync } = require('fs');
|
|
8
|
+
const { join } = require('path');
|
|
9
|
+
const { execFileSync } = require('child_process');
|
|
10
|
+
|
|
11
|
+
const testDir = join(__dirname, '..', 'tests');
|
|
12
|
+
const files = readdirSync(testDir)
|
|
13
|
+
.filter(f => f.endsWith('.test.cjs'))
|
|
14
|
+
.sort()
|
|
15
|
+
.map(f => join('tests', f));
|
|
16
|
+
|
|
17
|
+
if (files.length === 0) {
|
|
18
|
+
console.error('No test files found in tests/');
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
execFileSync(process.execPath, ['--test', ...files], {
|
|
24
|
+
stdio: 'inherit',
|
|
25
|
+
env: { ...process.env },
|
|
26
|
+
});
|
|
27
|
+
} catch (err) {
|
|
28
|
+
process.exit(err.status || 1);
|
|
29
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# secret-scan.sh — Check files for accidentally committed secrets/credentials
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# scripts/secret-scan.sh --diff origin/main # CI mode: scan changed files
|
|
6
|
+
# scripts/secret-scan.sh --file path/to/file # Scan a single file
|
|
7
|
+
# scripts/secret-scan.sh --dir agents/ # Scan all files in a directory
|
|
8
|
+
#
|
|
9
|
+
# Exit codes:
|
|
10
|
+
# 0 = clean
|
|
11
|
+
# 1 = findings detected
|
|
12
|
+
# 2 = usage error
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
# ─── Secret Patterns ─────────────────────────────────────────────────────────
|
|
16
|
+
# Format: "LABEL:::REGEX"
|
|
17
|
+
# Each entry is a human label paired with a POSIX extended regex.
|
|
18
|
+
|
|
19
|
+
SECRET_PATTERNS=(
|
|
20
|
+
# AWS
|
|
21
|
+
"AWS Access Key:::AKIA[0-9A-Z]{16}"
|
|
22
|
+
"AWS Secret Key:::aws_secret_access_key[[:space:]]*=[[:space:]]*[A-Za-z0-9/+=]{40}"
|
|
23
|
+
|
|
24
|
+
# OpenAI / Anthropic / AI providers
|
|
25
|
+
"OpenAI API Key:::sk-[A-Za-z0-9]{20,}"
|
|
26
|
+
"Anthropic API Key:::sk-ant-[A-Za-z0-9_-]{20,}"
|
|
27
|
+
|
|
28
|
+
# GitHub
|
|
29
|
+
"GitHub PAT:::ghp_[A-Za-z0-9]{36}"
|
|
30
|
+
"GitHub OAuth:::gho_[A-Za-z0-9]{36}"
|
|
31
|
+
"GitHub App Token:::ghs_[A-Za-z0-9]{36}"
|
|
32
|
+
"GitHub Fine-grained PAT:::github_pat_[A-Za-z0-9_]{20,}"
|
|
33
|
+
|
|
34
|
+
# Stripe
|
|
35
|
+
"Stripe Secret Key:::sk_live_[A-Za-z0-9]{24,}"
|
|
36
|
+
"Stripe Publishable Key:::pk_live_[A-Za-z0-9]{24,}"
|
|
37
|
+
|
|
38
|
+
# Generic patterns
|
|
39
|
+
"Private Key Header:::-----BEGIN[[:space:]]+(RSA|EC|DSA|OPENSSH)?[[:space:]]*PRIVATE[[:space:]]+KEY-----"
|
|
40
|
+
"Generic API Key Assignment:::api[_-]?key[[:space:]]*[:=][[:space:]]*['\"][A-Za-z0-9_-]{20,}['\"]"
|
|
41
|
+
"Generic Secret Assignment:::secret[[:space:]]*[:=][[:space:]]*['\"][A-Za-z0-9_-]{20,}['\"]"
|
|
42
|
+
"Generic Token Assignment:::token[[:space:]]*[:=][[:space:]]*['\"][A-Za-z0-9_-]{20,}['\"]"
|
|
43
|
+
"Generic Password Assignment:::password[[:space:]]*[:=][[:space:]]*['\"][^'\"]{8,}['\"]"
|
|
44
|
+
|
|
45
|
+
# Slack
|
|
46
|
+
"Slack Bot Token:::xoxb-[0-9]{10,}-[A-Za-z0-9]{20,}"
|
|
47
|
+
"Slack Webhook:::hooks\.slack\.com/services/T[A-Z0-9]{8,}/B[A-Z0-9]{8,}/[A-Za-z0-9]{24}"
|
|
48
|
+
|
|
49
|
+
# Google
|
|
50
|
+
"Google API Key:::AIza[A-Za-z0-9_-]{35}"
|
|
51
|
+
|
|
52
|
+
# NPM
|
|
53
|
+
"NPM Token:::npm_[A-Za-z0-9]{36}"
|
|
54
|
+
|
|
55
|
+
# .env file content (key=value with sensitive-looking keys)
|
|
56
|
+
"Env Variable Leak:::(DATABASE_URL|DB_PASSWORD|REDIS_URL|MONGO_URI|JWT_SECRET|SESSION_SECRET|ENCRYPTION_KEY)[[:space:]]*=[[:space:]]*[^[:space:]]{8,}"
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
# ─── Ignorelist ──────────────────────────────────────────────────────────────
|
|
60
|
+
|
|
61
|
+
IGNOREFILE=".secretscanignore"
|
|
62
|
+
IGNORED_FILES=()
|
|
63
|
+
|
|
64
|
+
load_ignorelist() {
|
|
65
|
+
if [[ -f "$IGNOREFILE" ]]; then
|
|
66
|
+
while IFS= read -r line; do
|
|
67
|
+
[[ "$line" =~ ^[[:space:]]*# ]] && continue
|
|
68
|
+
[[ -z "${line// }" ]] && continue
|
|
69
|
+
IGNORED_FILES+=("$line")
|
|
70
|
+
done < "$IGNOREFILE"
|
|
71
|
+
fi
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
is_ignored() {
|
|
75
|
+
local file="$1"
|
|
76
|
+
if [[ ${#IGNORED_FILES[@]} -eq 0 ]]; then
|
|
77
|
+
return 1
|
|
78
|
+
fi
|
|
79
|
+
for pattern in "${IGNORED_FILES[@]}"; do
|
|
80
|
+
# Support glob-style matching
|
|
81
|
+
# shellcheck disable=SC2254
|
|
82
|
+
case "$file" in
|
|
83
|
+
$pattern) return 0 ;;
|
|
84
|
+
esac
|
|
85
|
+
done
|
|
86
|
+
return 1
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
# ─── Skip Rules ──────────────────────────────────────────────────────────────
|
|
90
|
+
|
|
91
|
+
should_skip_file() {
|
|
92
|
+
local file="$1"
|
|
93
|
+
# Skip binary files
|
|
94
|
+
case "$file" in
|
|
95
|
+
*.png|*.jpg|*.jpeg|*.gif|*.ico|*.woff|*.woff2|*.ttf|*.eot|*.otf) return 0 ;;
|
|
96
|
+
*.zip|*.tar|*.gz|*.bz2|*.xz|*.7z) return 0 ;;
|
|
97
|
+
*.pdf|*.doc|*.docx|*.xls|*.xlsx) return 0 ;;
|
|
98
|
+
esac
|
|
99
|
+
# Skip lockfiles and node_modules
|
|
100
|
+
case "$file" in
|
|
101
|
+
*/node_modules/*) return 0 ;;
|
|
102
|
+
*/package-lock.json) return 0 ;;
|
|
103
|
+
*/yarn.lock) return 0 ;;
|
|
104
|
+
*/pnpm-lock.yaml) return 0 ;;
|
|
105
|
+
esac
|
|
106
|
+
# Skip the scan scripts themselves and test files
|
|
107
|
+
case "$file" in
|
|
108
|
+
*/secret-scan.sh) return 0 ;;
|
|
109
|
+
*/security-scan.test.cjs) return 0 ;;
|
|
110
|
+
esac
|
|
111
|
+
return 1
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
# ─── File Collection ─────────────────────────────────────────────────────────
|
|
115
|
+
|
|
116
|
+
collect_files() {
|
|
117
|
+
local mode="$1"
|
|
118
|
+
shift
|
|
119
|
+
|
|
120
|
+
case "$mode" in
|
|
121
|
+
--diff)
|
|
122
|
+
local base="${1:-origin/main}"
|
|
123
|
+
git diff --name-only --diff-filter=ACMR "$base"...HEAD 2>/dev/null \
|
|
124
|
+
| grep -vE '\.(png|jpg|jpeg|gif|ico|woff|woff2|ttf|eot|otf|zip|tar|gz|pdf)$' || true
|
|
125
|
+
;;
|
|
126
|
+
--file)
|
|
127
|
+
if [[ -f "$1" ]]; then
|
|
128
|
+
echo "$1"
|
|
129
|
+
else
|
|
130
|
+
echo "Error: file not found: $1" >&2
|
|
131
|
+
exit 2
|
|
132
|
+
fi
|
|
133
|
+
;;
|
|
134
|
+
--dir)
|
|
135
|
+
local dir="$1"
|
|
136
|
+
if [[ ! -d "$dir" ]]; then
|
|
137
|
+
echo "Error: directory not found: $dir" >&2
|
|
138
|
+
exit 2
|
|
139
|
+
fi
|
|
140
|
+
find "$dir" -type f ! -path '*/node_modules/*' ! -path '*/.git/*' ! -path '*/dist/*' \
|
|
141
|
+
! -name '*.png' ! -name '*.jpg' ! -name '*.gif' ! -name '*.woff*' 2>/dev/null || true
|
|
142
|
+
;;
|
|
143
|
+
--stdin)
|
|
144
|
+
cat
|
|
145
|
+
;;
|
|
146
|
+
*)
|
|
147
|
+
echo "Usage: $0 --diff [base] | --file <path> | --dir <path> | --stdin" >&2
|
|
148
|
+
exit 2
|
|
149
|
+
;;
|
|
150
|
+
esac
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
# ─── Scanner ─────────────────────────────────────────────────────────────────
|
|
154
|
+
|
|
155
|
+
scan_file() {
|
|
156
|
+
local file="$1"
|
|
157
|
+
local found=0
|
|
158
|
+
|
|
159
|
+
if is_ignored "$file"; then
|
|
160
|
+
return 0
|
|
161
|
+
fi
|
|
162
|
+
|
|
163
|
+
for entry in "${SECRET_PATTERNS[@]}"; do
|
|
164
|
+
local label="${entry%%:::*}"
|
|
165
|
+
local pattern="${entry#*:::}"
|
|
166
|
+
|
|
167
|
+
local matches
|
|
168
|
+
matches=$(grep -nE -e "$pattern" "$file" 2>/dev/null || true)
|
|
169
|
+
if [[ -n "$matches" ]]; then
|
|
170
|
+
if [[ $found -eq 0 ]]; then
|
|
171
|
+
echo "FAIL: $file"
|
|
172
|
+
found=1
|
|
173
|
+
fi
|
|
174
|
+
echo "$matches" | while IFS= read -r line; do
|
|
175
|
+
echo " [$label] $line"
|
|
176
|
+
done
|
|
177
|
+
fi
|
|
178
|
+
done
|
|
179
|
+
|
|
180
|
+
return $found
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
# ─── Main ────────────────────────────────────────────────────────────────────
|
|
184
|
+
|
|
185
|
+
main() {
|
|
186
|
+
if [[ $# -eq 0 ]]; then
|
|
187
|
+
echo "Usage: $0 --diff [base] | --file <path> | --dir <path>" >&2
|
|
188
|
+
exit 2
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
load_ignorelist
|
|
192
|
+
|
|
193
|
+
local mode="$1"
|
|
194
|
+
shift
|
|
195
|
+
|
|
196
|
+
local files
|
|
197
|
+
files=$(collect_files "$mode" "$@")
|
|
198
|
+
|
|
199
|
+
if [[ -z "$files" ]]; then
|
|
200
|
+
echo "secret-scan: no files to scan"
|
|
201
|
+
exit 0
|
|
202
|
+
fi
|
|
203
|
+
|
|
204
|
+
local total=0
|
|
205
|
+
local failed=0
|
|
206
|
+
|
|
207
|
+
while IFS= read -r file; do
|
|
208
|
+
[[ -z "$file" ]] && continue
|
|
209
|
+
if should_skip_file "$file"; then
|
|
210
|
+
continue
|
|
211
|
+
fi
|
|
212
|
+
total=$((total + 1))
|
|
213
|
+
if ! scan_file "$file"; then
|
|
214
|
+
failed=$((failed + 1))
|
|
215
|
+
fi
|
|
216
|
+
done <<< "$files"
|
|
217
|
+
|
|
218
|
+
echo ""
|
|
219
|
+
echo "secret-scan: scanned $total files, $failed with findings"
|
|
220
|
+
|
|
221
|
+
if [[ $failed -gt 0 ]]; then
|
|
222
|
+
exit 1
|
|
223
|
+
fi
|
|
224
|
+
exit 0
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
main "$@"
|