codegate-ai 0.1.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 +22 -0
- package/README.md +390 -0
- package/dist/cli-prompts.d.ts +6 -0
- package/dist/cli-prompts.js +94 -0
- package/dist/cli.d.ts +64 -0
- package/dist/cli.js +443 -0
- package/dist/commands/run-policy.d.ts +27 -0
- package/dist/commands/run-policy.js +39 -0
- package/dist/commands/scan-command/helpers.d.ts +28 -0
- package/dist/commands/scan-command/helpers.js +233 -0
- package/dist/commands/scan-command.d.ts +90 -0
- package/dist/commands/scan-command.js +403 -0
- package/dist/commands/undo.d.ts +5 -0
- package/dist/commands/undo.js +14 -0
- package/dist/config.d.ts +50 -0
- package/dist/config.js +187 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/knowledge-base/claude-code.json +152 -0
- package/dist/knowledge-base/cline.json +224 -0
- package/dist/knowledge-base/codex.json +162 -0
- package/dist/knowledge-base/copilot.json +132 -0
- package/dist/knowledge-base/cursor.json +134 -0
- package/dist/knowledge-base/gemini-cli.json +112 -0
- package/dist/knowledge-base/jetbrains-junie.json +208 -0
- package/dist/knowledge-base/kiro.json +102 -0
- package/dist/knowledge-base/opencode.json +128 -0
- package/dist/knowledge-base/roo-code.json +116 -0
- package/dist/knowledge-base/schema.json +77 -0
- package/dist/knowledge-base/windsurf.json +80 -0
- package/dist/knowledge-base/zed.json +88 -0
- package/dist/layer1-discovery/config-parser.d.ts +12 -0
- package/dist/layer1-discovery/config-parser.js +52 -0
- package/dist/layer1-discovery/file-walker.d.ts +13 -0
- package/dist/layer1-discovery/file-walker.js +77 -0
- package/dist/layer1-discovery/knowledge-base.d.ts +36 -0
- package/dist/layer1-discovery/knowledge-base.js +58 -0
- package/dist/layer1-discovery/tool-detector.d.ts +20 -0
- package/dist/layer1-discovery/tool-detector.js +138 -0
- package/dist/layer2-static/detectors/command-exec.d.ts +11 -0
- package/dist/layer2-static/detectors/command-exec.js +343 -0
- package/dist/layer2-static/detectors/consent-bypass.d.ts +8 -0
- package/dist/layer2-static/detectors/consent-bypass.js +330 -0
- package/dist/layer2-static/detectors/env-override.d.ts +8 -0
- package/dist/layer2-static/detectors/env-override.js +132 -0
- package/dist/layer2-static/detectors/git-hooks.d.ts +11 -0
- package/dist/layer2-static/detectors/git-hooks.js +61 -0
- package/dist/layer2-static/detectors/ide-settings.d.ts +8 -0
- package/dist/layer2-static/detectors/ide-settings.js +66 -0
- package/dist/layer2-static/detectors/plugin-manifest.d.ts +9 -0
- package/dist/layer2-static/detectors/plugin-manifest.js +1943 -0
- package/dist/layer2-static/detectors/rule-file.d.ts +7 -0
- package/dist/layer2-static/detectors/rule-file.js +299 -0
- package/dist/layer2-static/detectors/symlink.d.ts +9 -0
- package/dist/layer2-static/detectors/symlink.js +45 -0
- package/dist/layer2-static/engine.d.ts +28 -0
- package/dist/layer2-static/engine.js +83 -0
- package/dist/layer2-static/evidence.d.ts +12 -0
- package/dist/layer2-static/evidence.js +128 -0
- package/dist/layer2-static/rule-engine.d.ts +24 -0
- package/dist/layer2-static/rule-engine.js +138 -0
- package/dist/layer2-static/state/scan-state.d.ts +32 -0
- package/dist/layer2-static/state/scan-state.js +296 -0
- package/dist/layer3-dynamic/command-builder.d.ts +15 -0
- package/dist/layer3-dynamic/command-builder.js +39 -0
- package/dist/layer3-dynamic/local-text-analysis.d.ts +19 -0
- package/dist/layer3-dynamic/local-text-analysis.js +73 -0
- package/dist/layer3-dynamic/meta-agent.d.ts +17 -0
- package/dist/layer3-dynamic/meta-agent.js +33 -0
- package/dist/layer3-dynamic/prompt-templates/local-text-analysis.md +32 -0
- package/dist/layer3-dynamic/prompt-templates/security-analysis.md +13 -0
- package/dist/layer3-dynamic/prompt-templates/tool-poisoning.md +15 -0
- package/dist/layer3-dynamic/resource-fetcher.d.ts +25 -0
- package/dist/layer3-dynamic/resource-fetcher.js +119 -0
- package/dist/layer3-dynamic/sandbox.d.ts +13 -0
- package/dist/layer3-dynamic/sandbox.js +40 -0
- package/dist/layer3-dynamic/tool-description-acquisition.d.ts +22 -0
- package/dist/layer3-dynamic/tool-description-acquisition.js +76 -0
- package/dist/layer3-dynamic/tool-description-scanner.d.ts +11 -0
- package/dist/layer3-dynamic/tool-description-scanner.js +53 -0
- package/dist/layer3-dynamic/toxic-flow.d.ts +12 -0
- package/dist/layer3-dynamic/toxic-flow.js +57 -0
- package/dist/layer4-remediation/actions/quarantine.d.ts +1 -0
- package/dist/layer4-remediation/actions/quarantine.js +8 -0
- package/dist/layer4-remediation/actions/remove-field.d.ts +5 -0
- package/dist/layer4-remediation/actions/remove-field.js +53 -0
- package/dist/layer4-remediation/actions/replace-value.d.ts +5 -0
- package/dist/layer4-remediation/actions/replace-value.js +26 -0
- package/dist/layer4-remediation/actions/strip-unicode.d.ts +5 -0
- package/dist/layer4-remediation/actions/strip-unicode.js +8 -0
- package/dist/layer4-remediation/backup-manager.d.ts +32 -0
- package/dist/layer4-remediation/backup-manager.js +138 -0
- package/dist/layer4-remediation/diff-generator.d.ts +6 -0
- package/dist/layer4-remediation/diff-generator.js +29 -0
- package/dist/layer4-remediation/remediation-runner.d.ts +36 -0
- package/dist/layer4-remediation/remediation-runner.js +230 -0
- package/dist/layer4-remediation/remediator.d.ts +36 -0
- package/dist/layer4-remediation/remediator.js +117 -0
- package/dist/path-display.d.ts +1 -0
- package/dist/path-display.js +20 -0
- package/dist/pipeline.d.ts +34 -0
- package/dist/pipeline.js +259 -0
- package/dist/report-summary.d.ts +6 -0
- package/dist/report-summary.js +48 -0
- package/dist/reporter/html.d.ts +2 -0
- package/dist/reporter/html.js +103 -0
- package/dist/reporter/json.d.ts +2 -0
- package/dist/reporter/json.js +3 -0
- package/dist/reporter/markdown.d.ts +2 -0
- package/dist/reporter/markdown.js +52 -0
- package/dist/reporter/sarif.d.ts +2 -0
- package/dist/reporter/sarif.js +84 -0
- package/dist/reporter/terminal.d.ts +5 -0
- package/dist/reporter/terminal.js +94 -0
- package/dist/runtime/signal-handlers.d.ts +10 -0
- package/dist/runtime/signal-handlers.js +17 -0
- package/dist/scan-target/helpers.d.ts +20 -0
- package/dist/scan-target/helpers.js +268 -0
- package/dist/scan-target/staging.d.ts +5 -0
- package/dist/scan-target/staging.js +114 -0
- package/dist/scan-target/types.d.ts +18 -0
- package/dist/scan-target/types.js +1 -0
- package/dist/scan-target.d.ts +3 -0
- package/dist/scan-target.js +31 -0
- package/dist/scan.d.ts +54 -0
- package/dist/scan.js +593 -0
- package/dist/tui/app.d.ts +10 -0
- package/dist/tui/app.js +21 -0
- package/dist/tui/theme.d.ts +8 -0
- package/dist/tui/theme.js +7 -0
- package/dist/tui/views/dashboard.d.ts +6 -0
- package/dist/tui/views/dashboard.js +8 -0
- package/dist/tui/views/deep-scan-consent.d.ts +5 -0
- package/dist/tui/views/deep-scan-consent.js +6 -0
- package/dist/tui/views/progress.d.ts +4 -0
- package/dist/tui/views/progress.js +6 -0
- package/dist/tui/views/summary.d.ts +5 -0
- package/dist/tui/views/summary.js +16 -0
- package/dist/types/discovery.d.ts +12 -0
- package/dist/types/discovery.js +1 -0
- package/dist/types/finding.d.ts +46 -0
- package/dist/types/finding.js +15 -0
- package/dist/types/report.d.ts +25 -0
- package/dist/types/report.js +23 -0
- package/dist/wrapper.d.ts +35 -0
- package/dist/wrapper.js +220 -0
- package/package.json +97 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jonathan Santilli
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
# CodeGate
|
|
2
|
+
|
|
3
|
+
[](https://github.com/jonathansantilli/codegate/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/jonathansantilli/codegate/actions/workflows/codeql.yml)
|
|
5
|
+
[](https://www.npmjs.com/package/codegate-ai)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
|
|
8
|
+

|
|
9
|
+
|
|
10
|
+
CodeGate is a pre-flight security scanner and remediation tool for AI coding tool configuration risk.
|
|
11
|
+
|
|
12
|
+
It exists to help people see what they are about to trust before their coding agent executes it.
|
|
13
|
+
|
|
14
|
+
## Why This Project Exists
|
|
15
|
+
|
|
16
|
+
CodeGate was born from repeated vulnerability disclosures against major AI coding tools where dangerous behavior was often treated as "documented behavior" instead of a security issue. The practical reality is that most users do not read documentation, trust dialogs, policy text, or configuration references before running tools.
|
|
17
|
+
|
|
18
|
+
When repository-controlled files can alter execution behavior (MCP settings, hooks, rules, skills, extensions, workspace settings), documented risk is still real risk. CodeGate is a response to that gap: make hidden execution surfaces visible before launch.
|
|
19
|
+
|
|
20
|
+
Some of the public incidents and disclosures that shaped this project:
|
|
21
|
+
|
|
22
|
+
- Check Point: `CVE-2025-59536` (MCP consent bypass) and `CVE-2026-21852` (API key exfiltration path)
|
|
23
|
+
- Check Point: `CVE-2025-61260` (Codex CLI command injection, CVSS 9.8)
|
|
24
|
+
- IDEsaster research: 30+ CVEs across major AI IDEs and agents
|
|
25
|
+
|
|
26
|
+
Public background documents:
|
|
27
|
+
|
|
28
|
+
- [Why CodeGate Exists](docs/why-codegate.md)
|
|
29
|
+
- [Public Evidence Map](docs/public-evidence-map.md)
|
|
30
|
+
- [Feature Evidence Ledger](docs/feature-evidence-ledger.md)
|
|
31
|
+
|
|
32
|
+
## What CodeGate Is
|
|
33
|
+
|
|
34
|
+
- An awareness and pre-flight inspection tool
|
|
35
|
+
- A way to visualize risky configuration and instruction surfaces before execution
|
|
36
|
+
- A layered scanner (discovery, static analysis, optional deep scan, remediation guidance)
|
|
37
|
+
- A workflow gate that can block dangerous launches (`codegate run <tool>`)
|
|
38
|
+
|
|
39
|
+
## What CodeGate Is Not
|
|
40
|
+
|
|
41
|
+
- Not a guarantee of safety
|
|
42
|
+
- Not a replacement for secure engineering judgment, review, and hardening
|
|
43
|
+
- Not perfect: it can produce false positives and false negatives
|
|
44
|
+
- Not a promise that every malicious pattern will be detected
|
|
45
|
+
|
|
46
|
+
CodeGate is designed to improve visibility and decision quality, not to function as an absolute safety net.
|
|
47
|
+
|
|
48
|
+
## Safety Model and Limits
|
|
49
|
+
|
|
50
|
+
- Layers 1 and 2 are offline-first and deterministic.
|
|
51
|
+
- Layer 3 deep scan is opt-in and consent-driven per resource and per command.
|
|
52
|
+
- Tool-description acquisition does not execute untrusted MCP stdio command arrays.
|
|
53
|
+
- Deep scan still increases exposure compared to static-only scans because it may fetch remote metadata/content and invoke a selected local AI tool.
|
|
54
|
+
- Remediation is best-effort and reversible (`.codegate-backup/`, `codegate undo`), but users should still review changes.
|
|
55
|
+
|
|
56
|
+
Use CodeGate to inspect first, then decide whether to trust and run.
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
Run without global install:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx codegate-ai scan .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Install globally:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm install -g codegate-ai
|
|
70
|
+
codegate scan .
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## System Capabilities
|
|
74
|
+
|
|
75
|
+
1. Multi-layer analysis pipeline:
|
|
76
|
+
Layer 1 discovery of known AI config files and installed tools.
|
|
77
|
+
Layer 2 static risk detection without network calls.
|
|
78
|
+
Layer 3 deep scan (opt-in) for external resources and meta-agent analysis.
|
|
79
|
+
Layer 4 remediation with backup and undo.
|
|
80
|
+
2. Static detections include:
|
|
81
|
+
`ENV_OVERRIDE`, `COMMAND_EXEC`, `CONSENT_BYPASS`, `RULE_INJECTION`, `IDE_SETTINGS`, `SYMLINK_ESCAPE`, `GIT_HOOK`, `NEW_SERVER`, `CONFIG_CHANGE`.
|
|
82
|
+
3. Layer 3 analysis can derive:
|
|
83
|
+
tool description findings, toxic flow findings (`TOXIC_FLOW`), and parse/availability findings (`PARSE_ERROR`).
|
|
84
|
+
It can also perform text-only analysis of local instruction files such as `AGENTS.md`, `CODEX.md`, and discovered skill/rule markdown when a safe tool-less agent mode is available.
|
|
85
|
+
4. Output formats:
|
|
86
|
+
`terminal`, `json`, `sarif`, `markdown`, `html`.
|
|
87
|
+
5. Wrapper mode:
|
|
88
|
+
`codegate run <tool>` scans first, blocks dangerous launches, rechecks the scanned config surface for post-scan file changes, and can require confirmation for warning-level findings.
|
|
89
|
+
|
|
90
|
+
## Core Commands
|
|
91
|
+
|
|
92
|
+
| Command | Purpose |
|
|
93
|
+
| ----------------------- | ---------------------------------------------------------------------- |
|
|
94
|
+
| `codegate scan [dir]` | Scan a directory for AI tool config risks. Defaults to `.`. |
|
|
95
|
+
| `codegate run <tool>` | Scan current directory, then launch selected AI tool if policy allows. |
|
|
96
|
+
| `codegate undo [dir]` | Restore the most recent remediation backup session. Defaults to `.`. |
|
|
97
|
+
| `codegate init` | Create `~/.codegate/config.json` with defaults. |
|
|
98
|
+
| `codegate update-kb` | Show knowledge-base update guidance. |
|
|
99
|
+
| `codegate update-rules` | Show rules update guidance. |
|
|
100
|
+
| `codegate --help` | Show CLI usage. |
|
|
101
|
+
|
|
102
|
+
## `scan` Command Flags
|
|
103
|
+
|
|
104
|
+
| Flag | Purpose |
|
|
105
|
+
| ---------------------- | --------------------------------------------------------------------------------------------------------- |
|
|
106
|
+
| `--deep` | Enable Layer 3 dynamic analysis. |
|
|
107
|
+
| `--remediate` | Enter remediation mode after scan. |
|
|
108
|
+
| `--fix-safe` | Auto-fix unambiguous critical findings. |
|
|
109
|
+
| `--dry-run` | Show proposed fixes but write nothing. |
|
|
110
|
+
| `--patch` | Generate a patch file for review workflows. |
|
|
111
|
+
| `--no-tui` | Disable TUI and interactive prompts. |
|
|
112
|
+
| `--format <type>` | Output format: `terminal`, `json`, `sarif`, `markdown`, `html`. |
|
|
113
|
+
| `--output <path>` | Write report to file instead of stdout. |
|
|
114
|
+
| `--verbose` | Show extended output in terminal format. |
|
|
115
|
+
| `--config <path>` | Use a specific global config file path. |
|
|
116
|
+
| `--force` | Skip interactive confirmations. |
|
|
117
|
+
| `--include-user-scope` | Force-enable user/home AI tool config paths for this run (useful if config disables user-scope scanning). |
|
|
118
|
+
| `--reset-state` | Clear persisted scan-state history and exit. |
|
|
119
|
+
|
|
120
|
+
Examples:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
codegate scan .
|
|
124
|
+
codegate scan . --format json
|
|
125
|
+
codegate scan . --format sarif --output codegate.sarif
|
|
126
|
+
codegate scan . --deep
|
|
127
|
+
codegate scan . --deep --include-user-scope
|
|
128
|
+
codegate scan . --deep --force
|
|
129
|
+
codegate scan . --remediate
|
|
130
|
+
codegate scan . --fix-safe
|
|
131
|
+
codegate scan . --remediate --dry-run --patch
|
|
132
|
+
codegate scan . --reset-state
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## `run` Command
|
|
136
|
+
|
|
137
|
+
`codegate run <tool>` runs scan-first wrapper mode.
|
|
138
|
+
|
|
139
|
+
- Valid run targets: `claude`, `opencode`, `codex`, `cursor`, `windsurf`, `kiro`.
|
|
140
|
+
- On dangerous findings (exit threshold reached), tool launch is blocked.
|
|
141
|
+
- If files change between scan and launch check, launch is blocked and rescan is required.
|
|
142
|
+
- Warning-level findings below the blocking threshold can still require confirmation before launch.
|
|
143
|
+
|
|
144
|
+
`run` flags:
|
|
145
|
+
|
|
146
|
+
| Flag | Purpose |
|
|
147
|
+
| ----------------- | -------------------------------------------------- |
|
|
148
|
+
| `--no-tui` | Disable TUI and interactive prompts. |
|
|
149
|
+
| `--config <path>` | Use a specific global config file path. |
|
|
150
|
+
| `--force` | Skip the warning-level launch confirmation prompt. |
|
|
151
|
+
|
|
152
|
+
`run` behavior notes:
|
|
153
|
+
|
|
154
|
+
- `codegate run` always renders terminal/TUI output. Machine-readable output formats are available from `codegate scan`.
|
|
155
|
+
- If the scan returns exit code `1` and findings exist, launch proceeds without prompting only when one of these is true:
|
|
156
|
+
- `--force` is provided
|
|
157
|
+
- `auto_proceed_below_threshold` is `true`
|
|
158
|
+
- the current working directory is inside a configured `trusted_directories` path
|
|
159
|
+
- Post-scan change detection covers the same local config surface that was scanned, including selected user-scope config files when user-scope scanning is enabled.
|
|
160
|
+
|
|
161
|
+
Examples:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
codegate run claude
|
|
165
|
+
codegate run claude --force
|
|
166
|
+
codegate run codex
|
|
167
|
+
codegate run cursor
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Deep Scan (Layer 3)
|
|
171
|
+
|
|
172
|
+
Deep scan is opt-in and only runs with `--deep`.
|
|
173
|
+
|
|
174
|
+
Current behavior:
|
|
175
|
+
|
|
176
|
+
- Discovers eligible external resources from known config paths.
|
|
177
|
+
- Discovers eligible local instruction files from the selected markdown/text scan surface.
|
|
178
|
+
- If no eligible resources are found, prints an explicit message and completes scan.
|
|
179
|
+
- In interactive mode, if supported meta-agents are installed, asks user to select one: `claude` (Claude Code), `codex` (Codex CLI), `opencode` (OpenCode via generic stdin mode).
|
|
180
|
+
- Prompts for per-resource deep scan consent.
|
|
181
|
+
- Prompts for per-command meta-agent execution consent with command preview.
|
|
182
|
+
- Parses meta-agent output (raw JSON or fenced JSON) and merges findings.
|
|
183
|
+
- If parsing or command execution fails, reports Layer 3 findings instead of crashing.
|
|
184
|
+
- In non-interactive mode, deep actions are skipped unless `--force` is provided.
|
|
185
|
+
- Use `--include-user-scope` to include user/home config surfaces in Layer 1/2 and Layer 3 resource discovery.
|
|
186
|
+
- Local instruction-file analysis is text-only: CodeGate passes file content and referenced URL strings as inert text and does not execute referenced content.
|
|
187
|
+
|
|
188
|
+
For MCP tool-description analysis, CodeGate does not execute untrusted MCP stdio command arrays during scanning.
|
|
189
|
+
|
|
190
|
+
Current local instruction-file agent support:
|
|
191
|
+
|
|
192
|
+
- Claude Code is supported for tool-less local text analysis.
|
|
193
|
+
- Codex CLI and OpenCode are not used for local text analysis until CodeGate can prove a shell-less mode for them.
|
|
194
|
+
|
|
195
|
+
Deep scan behavior is documented in this README and verified by CLI/integration tests.
|
|
196
|
+
|
|
197
|
+
## Remediation and Undo
|
|
198
|
+
|
|
199
|
+
- `--remediate` supports guided file remediation.
|
|
200
|
+
- `--fix-safe` applies unambiguous critical fixes automatically.
|
|
201
|
+
- `--dry-run` previews changes without writing.
|
|
202
|
+
- `--patch` writes patch-style output for review.
|
|
203
|
+
- Remediation writes backup sessions under `.codegate-backup/`.
|
|
204
|
+
- `codegate undo [dir]` restores the latest backup session.
|
|
205
|
+
|
|
206
|
+
Remediation and undo behavior is documented in this README and covered by Layer 4 + CLI tests.
|
|
207
|
+
|
|
208
|
+
## Scan-State Baseline and `--reset-state`
|
|
209
|
+
|
|
210
|
+
CodeGate maintains MCP baseline state for rug-pull detection at:
|
|
211
|
+
|
|
212
|
+
- default: `~/.codegate/scan-state.json`
|
|
213
|
+
- override: `scan_state_path` in config
|
|
214
|
+
|
|
215
|
+
Paths beginning with `~` resolve against the current user's home directory.
|
|
216
|
+
|
|
217
|
+
What state tracks:
|
|
218
|
+
|
|
219
|
+
- `NEW_SERVER`: first seen MCP server identifier
|
|
220
|
+
- `CONFIG_CHANGE`: MCP server config hash changed since prior scan
|
|
221
|
+
|
|
222
|
+
`--reset-state` clears that baseline file and exits immediately.
|
|
223
|
+
|
|
224
|
+
## Configuration
|
|
225
|
+
|
|
226
|
+
### Config File Locations
|
|
227
|
+
|
|
228
|
+
- Global config: `~/.codegate/config.json`
|
|
229
|
+
- Project config override: `<scan-target>/.codegate.json`
|
|
230
|
+
|
|
231
|
+
Create defaults:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
codegate init
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
`init` flags:
|
|
238
|
+
|
|
239
|
+
- `--path <path>` write config to custom location
|
|
240
|
+
- `--force` overwrite existing config file
|
|
241
|
+
|
|
242
|
+
### Precedence and Merge Rules
|
|
243
|
+
|
|
244
|
+
- Scalar values: CLI overrides -> project config -> global config -> defaults.
|
|
245
|
+
- List values are merged and de-duplicated across levels.
|
|
246
|
+
- `trusted_directories` is global-only; project config cannot set it.
|
|
247
|
+
- `blocked_commands` is merged with defaults; defaults are always retained.
|
|
248
|
+
|
|
249
|
+
### Full Configuration Reference
|
|
250
|
+
|
|
251
|
+
| Key | Type | Allowed Values | Default |
|
|
252
|
+
| -------------------------------- | ---------------- | --------------------------------------------------------------------------- | -------------------------------------------------- |
|
|
253
|
+
| `severity_threshold` | string | `critical`, `high`, `medium`, `low`, `info` | `high` |
|
|
254
|
+
| `auto_proceed_below_threshold` | boolean | `true`, `false` | `true` |
|
|
255
|
+
| `output_format` | string | `terminal`, `json`, `sarif`, `markdown`, `html` | `terminal` |
|
|
256
|
+
| `scan_state_path` | string | file path | `~/.codegate/scan-state.json` |
|
|
257
|
+
| `scan_user_scope` | boolean | `true`, `false` | `true` |
|
|
258
|
+
| `tui.enabled` | boolean | `true`, `false` | `true` |
|
|
259
|
+
| `tui.colour_scheme` | string | free string (currently `default`) | `default` |
|
|
260
|
+
| `tui.compact_mode` | boolean | `true`, `false` | `false` |
|
|
261
|
+
| `tool_discovery.preferred_agent` | string | practical values: `claude`, `claude-code`, `codex`, `codex-cli`, `opencode` | `claude` |
|
|
262
|
+
| `tool_discovery.agent_paths` | object | map of agent key -> binary path | `{}` |
|
|
263
|
+
| `tool_discovery.skip_tools` | array of strings | tool keys to skip in discovery/selection | `[]` |
|
|
264
|
+
| `trusted_directories` | array of strings | directory paths | `[]` |
|
|
265
|
+
| `blocked_commands` | array of strings | command names | `["bash","sh","curl","wget","nc","python","node"]` |
|
|
266
|
+
| `known_safe_mcp_servers` | array of strings | package/server identifiers | prefilled |
|
|
267
|
+
| `known_safe_formatters` | array of strings | formatter names | prefilled |
|
|
268
|
+
| `known_safe_lsp_servers` | array of strings | lsp server names | prefilled |
|
|
269
|
+
| `known_safe_hooks` | array of strings | relative hook paths such as `.git/hooks/pre-commit` | `[]` |
|
|
270
|
+
| `unicode_analysis` | boolean | `true`, `false` | `true` |
|
|
271
|
+
| `check_ide_settings` | boolean | `true`, `false` | `true` |
|
|
272
|
+
| `owasp_mapping` | boolean | `true`, `false` | `true` |
|
|
273
|
+
| `trusted_api_domains` | array of strings | domain names | `[]` |
|
|
274
|
+
| `suppress_findings` | array of strings | finding IDs/fingerprints | `[]` |
|
|
275
|
+
|
|
276
|
+
### Default Config Example
|
|
277
|
+
|
|
278
|
+
```json
|
|
279
|
+
{
|
|
280
|
+
"severity_threshold": "high",
|
|
281
|
+
"auto_proceed_below_threshold": true,
|
|
282
|
+
"output_format": "terminal",
|
|
283
|
+
"scan_state_path": "~/.codegate/scan-state.json",
|
|
284
|
+
"scan_user_scope": true,
|
|
285
|
+
"tui": {
|
|
286
|
+
"enabled": true,
|
|
287
|
+
"colour_scheme": "default",
|
|
288
|
+
"compact_mode": false
|
|
289
|
+
},
|
|
290
|
+
"tool_discovery": {
|
|
291
|
+
"preferred_agent": "claude",
|
|
292
|
+
"agent_paths": {},
|
|
293
|
+
"skip_tools": []
|
|
294
|
+
},
|
|
295
|
+
"trusted_directories": [],
|
|
296
|
+
"blocked_commands": ["bash", "sh", "curl", "wget", "nc", "python", "node"],
|
|
297
|
+
"known_safe_mcp_servers": [
|
|
298
|
+
"@anthropic/mcp-server-filesystem",
|
|
299
|
+
"@modelcontextprotocol/server-github"
|
|
300
|
+
],
|
|
301
|
+
"known_safe_formatters": ["prettier", "black", "gofmt", "rustfmt", "clang-format"],
|
|
302
|
+
"known_safe_lsp_servers": ["typescript-language-server", "pyright", "rust-analyzer", "gopls"],
|
|
303
|
+
"known_safe_hooks": [],
|
|
304
|
+
"unicode_analysis": true,
|
|
305
|
+
"check_ide_settings": true,
|
|
306
|
+
"owasp_mapping": true,
|
|
307
|
+
"trusted_api_domains": [],
|
|
308
|
+
"suppress_findings": []
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Configuration notes:
|
|
313
|
+
|
|
314
|
+
- `trusted_directories` is evaluated against resolved absolute paths and applies only to warning-level `codegate run` confirmations.
|
|
315
|
+
- `scan_state_path` accepts `~` and `~/...`, both of which resolve to the home directory before read/write/reset operations.
|
|
316
|
+
- `known_safe_hooks` matches discovered hook file paths relative to the repository root, for example `.git/hooks/pre-commit`.
|
|
317
|
+
- `unicode_analysis=false` disables hidden-unicode findings in Layer 2 rule-file scanning and Layer 3 tool-description scanning. Other rule-file heuristics remain enabled.
|
|
318
|
+
- `check_ide_settings=false` disables `IDE_SETTINGS` findings.
|
|
319
|
+
- `owasp_mapping=false` keeps detection behavior unchanged and emits empty `owasp` arrays in reports.
|
|
320
|
+
|
|
321
|
+
## Output Formats
|
|
322
|
+
|
|
323
|
+
- `terminal` (default)
|
|
324
|
+
- `json`
|
|
325
|
+
- `sarif`
|
|
326
|
+
- `markdown`
|
|
327
|
+
- `html`
|
|
328
|
+
|
|
329
|
+
SARIF output is designed for GitHub Code Scanning and other security tooling.
|
|
330
|
+
|
|
331
|
+
## Exit Codes
|
|
332
|
+
|
|
333
|
+
| Code | Meaning |
|
|
334
|
+
| ---- | ----------------------------------------- |
|
|
335
|
+
| `0` | No unsuppressed findings |
|
|
336
|
+
| `1` | Findings exist below configured threshold |
|
|
337
|
+
| `2` | Findings at or above configured threshold |
|
|
338
|
+
| `3` | Scanner/runtime error |
|
|
339
|
+
|
|
340
|
+
## CI Integration (GitHub Actions + SARIF)
|
|
341
|
+
|
|
342
|
+
```yaml
|
|
343
|
+
- name: Run CodeGate
|
|
344
|
+
run: codegate scan . --no-tui --format sarif --output codegate.sarif
|
|
345
|
+
|
|
346
|
+
- name: Upload SARIF
|
|
347
|
+
uses: github/codeql-action/upload-sarif@v3
|
|
348
|
+
with:
|
|
349
|
+
sarif_file: codegate.sarif
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Manual Showcase Kit
|
|
353
|
+
|
|
354
|
+
Internal showcase packs and runbooks are intentionally kept out of the public GitHub repository.
|
|
355
|
+
|
|
356
|
+
Public quick demo (env override):
|
|
357
|
+
|
|
358
|
+
```bash
|
|
359
|
+
npm run build
|
|
360
|
+
node dist/cli.js scan . --no-tui --format json
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
## Release Process
|
|
364
|
+
|
|
365
|
+
- [CHANGELOG.md](./CHANGELOG.md)
|
|
366
|
+
- Public release automation: [`.github/workflows/release.yml`](./.github/workflows/release.yml) (semantic-release on `main`)
|
|
367
|
+
- Release validation: [`.github/workflows/release-dry-run.yml`](./.github/workflows/release-dry-run.yml)
|
|
368
|
+
- PR title semantic policy: [`.github/workflows/semantic-pr-title.yml`](./.github/workflows/semantic-pr-title.yml)
|
|
369
|
+
- Weekly dependency upkeep: [`.github/dependabot.yml`](./.github/dependabot.yml)
|
|
370
|
+
- Security analysis automation: [`.github/workflows/codeql.yml`](./.github/workflows/codeql.yml)
|
|
371
|
+
- npm publishing is configured for trusted publishing from GitHub Actions. Before the first release, configure npmjs.com trusted publisher settings for `.github/workflows/release.yml`.
|
|
372
|
+
- Versioning follows conventional commit semantics:
|
|
373
|
+
- `feat` => minor
|
|
374
|
+
- `fix`, `docs`, `refactor`, `perf`, `test`, `build`, `ci`, `style`, `chore`, `revert` => patch
|
|
375
|
+
- `!` or `BREAKING CHANGE` => major
|
|
376
|
+
- Internal release checklists are intentionally private.
|
|
377
|
+
|
|
378
|
+
## Security
|
|
379
|
+
|
|
380
|
+
If you discover a vulnerability in CodeGate itself, do not open a public issue first.
|
|
381
|
+
|
|
382
|
+
See [SECURITY.md](./SECURITY.md) for private disclosure.
|
|
383
|
+
|
|
384
|
+
## Contributing
|
|
385
|
+
|
|
386
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
|
387
|
+
|
|
388
|
+
## Support
|
|
389
|
+
|
|
390
|
+
See [SUPPORT.md](./SUPPORT.md).
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DeepAgentOption, MetaAgentCommandConsentContext, RemediationConsentContext } from "./commands/scan-command.js";
|
|
2
|
+
import type { DeepScanResource } from "./pipeline.js";
|
|
3
|
+
export declare function promptDeepScanConsent(resource: DeepScanResource): Promise<boolean>;
|
|
4
|
+
export declare function promptDeepAgentSelection(options: DeepAgentOption[]): Promise<DeepAgentOption | null>;
|
|
5
|
+
export declare function promptMetaAgentCommandConsent(context: MetaAgentCommandConsentContext): Promise<boolean>;
|
|
6
|
+
export declare function promptRemediationConsent(context: RemediationConsentContext): Promise<boolean>;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
function commandPreview(value) {
|
|
3
|
+
const maxLength = 900;
|
|
4
|
+
if (value.length <= maxLength) {
|
|
5
|
+
return value;
|
|
6
|
+
}
|
|
7
|
+
return `${value.slice(0, maxLength)}\n...[command preview truncated ${value.length - maxLength} chars]`;
|
|
8
|
+
}
|
|
9
|
+
export async function promptDeepScanConsent(resource) {
|
|
10
|
+
const preview = resource.commandPreview.length > 0 ? `\n${resource.commandPreview}` : "";
|
|
11
|
+
const rl = createInterface({
|
|
12
|
+
input: process.stdin,
|
|
13
|
+
output: process.stdout,
|
|
14
|
+
});
|
|
15
|
+
try {
|
|
16
|
+
const answer = await rl.question(`Approve deep scan for ${resource.id}?${preview}\n[y/N]: `);
|
|
17
|
+
return /^y(es)?$/iu.test(answer.trim());
|
|
18
|
+
}
|
|
19
|
+
finally {
|
|
20
|
+
rl.close();
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export async function promptDeepAgentSelection(options) {
|
|
24
|
+
if (options.length === 0) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
const rl = createInterface({
|
|
28
|
+
input: process.stdin,
|
|
29
|
+
output: process.stdout,
|
|
30
|
+
});
|
|
31
|
+
const optionLines = options.map((option, index) => ` ${index + 1}. ${option.label} (${option.id}) -> ${option.binary}`);
|
|
32
|
+
const prompt = [
|
|
33
|
+
"Select a deep-scan meta-agent:",
|
|
34
|
+
...optionLines,
|
|
35
|
+
`Choose [1-${options.length}] or press Enter for 1 (q to skip): `,
|
|
36
|
+
].join("\n");
|
|
37
|
+
try {
|
|
38
|
+
const answer = (await rl.question(prompt)).trim().toLowerCase();
|
|
39
|
+
if (answer === "q" || answer === "skip") {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
if (answer.length === 0) {
|
|
43
|
+
return options[0] ?? null;
|
|
44
|
+
}
|
|
45
|
+
const numeric = Number.parseInt(answer, 10);
|
|
46
|
+
if (Number.isNaN(numeric) || numeric < 1 || numeric > options.length) {
|
|
47
|
+
return options[0] ?? null;
|
|
48
|
+
}
|
|
49
|
+
return options[numeric - 1] ?? null;
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
rl.close();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
export async function promptMetaAgentCommandConsent(context) {
|
|
56
|
+
const rl = createInterface({
|
|
57
|
+
input: process.stdin,
|
|
58
|
+
output: process.stdout,
|
|
59
|
+
});
|
|
60
|
+
const subjectLabel = context.localFile?.reportPath ?? context.resource?.id ?? "analysis target";
|
|
61
|
+
const prompt = [
|
|
62
|
+
`Deep scan command for ${subjectLabel}`,
|
|
63
|
+
`Agent: ${context.agent.label} (${context.agent.binary})`,
|
|
64
|
+
"Command preview:",
|
|
65
|
+
commandPreview(context.command.preview),
|
|
66
|
+
"Approve command execution? [y/N]: ",
|
|
67
|
+
].join("\n");
|
|
68
|
+
try {
|
|
69
|
+
const answer = await rl.question(prompt);
|
|
70
|
+
return /^y(es)?$/iu.test(answer.trim());
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
rl.close();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
export async function promptRemediationConsent(context) {
|
|
77
|
+
const rl = createInterface({
|
|
78
|
+
input: process.stdin,
|
|
79
|
+
output: process.stdout,
|
|
80
|
+
});
|
|
81
|
+
const prompt = [
|
|
82
|
+
`Remediation will modify files under: ${context.scanTarget}`,
|
|
83
|
+
`Findings in scope: ${context.totalFindings} (${context.fixableFindings} fixable, ${context.criticalFindings} critical)`,
|
|
84
|
+
"A backup session will be created in .codegate-backup/ before changes.",
|
|
85
|
+
"Proceed with remediation? [y/N]: ",
|
|
86
|
+
].join("\n");
|
|
87
|
+
try {
|
|
88
|
+
const answer = await rl.question(prompt);
|
|
89
|
+
return /^y(es)?$/iu.test(answer.trim());
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
rl.close();
|
|
93
|
+
}
|
|
94
|
+
}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { type CodeGateConfig, type ResolveConfigOptions } from "./config.js";
|
|
4
|
+
import { type ResourceFetchResult } from "./layer3-dynamic/resource-fetcher.js";
|
|
5
|
+
import type { LocalTextAnalysisTarget } from "./layer3-dynamic/local-text-analysis.js";
|
|
6
|
+
import { type DeepScanResource } from "./pipeline.js";
|
|
7
|
+
import { type ScanDiscoveryCandidate, type ScanDiscoveryContext } from "./scan.js";
|
|
8
|
+
import { type ResolvedScanTarget } from "./scan-target.js";
|
|
9
|
+
import type { CodeGateReport } from "./types/report.js";
|
|
10
|
+
import { type RemediationRunnerInput, type RemediationRunnerResult } from "./layer4-remediation/remediation-runner.js";
|
|
11
|
+
import { type DeepAgentOption, type MetaAgentCommandConsentContext, type MetaAgentCommandRunResult, type RemediationConsentContext, type ScanRunnerInput } from "./commands/scan-command.js";
|
|
12
|
+
export interface RunWarningConsentContext {
|
|
13
|
+
target: string;
|
|
14
|
+
report: CodeGateReport;
|
|
15
|
+
}
|
|
16
|
+
export interface CliDeps {
|
|
17
|
+
cwd: () => string;
|
|
18
|
+
isTTY: () => boolean;
|
|
19
|
+
homeDir?: () => string;
|
|
20
|
+
pathExists?: (path: string) => boolean;
|
|
21
|
+
resolveConfig: (options: ResolveConfigOptions) => CodeGateConfig;
|
|
22
|
+
runScan: (input: ScanRunnerInput) => Promise<CodeGateReport>;
|
|
23
|
+
prepareScanDiscovery?: (scanTarget: string, config?: CodeGateConfig, options?: {
|
|
24
|
+
explicitCandidates?: ScanDiscoveryCandidate[];
|
|
25
|
+
}) => Promise<ScanDiscoveryContext> | ScanDiscoveryContext;
|
|
26
|
+
resolveScanTarget?: (input: {
|
|
27
|
+
rawTarget: string;
|
|
28
|
+
cwd: string;
|
|
29
|
+
}) => Promise<ResolvedScanTarget> | ResolvedScanTarget;
|
|
30
|
+
stdout: (message: string) => void;
|
|
31
|
+
stderr: (message: string) => void;
|
|
32
|
+
writeFile: (path: string, content: string) => void;
|
|
33
|
+
setExitCode: (code: number) => void;
|
|
34
|
+
renderTui?: (props: {
|
|
35
|
+
view: "dashboard" | "summary";
|
|
36
|
+
report: CodeGateReport;
|
|
37
|
+
notices?: string[];
|
|
38
|
+
}) => void;
|
|
39
|
+
runRemediation?: (input: RemediationRunnerInput) => Promise<RemediationRunnerResult> | RemediationRunnerResult;
|
|
40
|
+
runUndo?: (projectRoot: string) => {
|
|
41
|
+
restoredFiles: number;
|
|
42
|
+
sessionId: string;
|
|
43
|
+
};
|
|
44
|
+
resetScanState?: (path?: string) => Promise<void> | void;
|
|
45
|
+
discoverDeepResources?: (scanTarget: string, config?: CodeGateConfig, discoveryContext?: ScanDiscoveryContext) => Promise<DeepScanResource[]> | DeepScanResource[];
|
|
46
|
+
discoverLocalTextTargets?: (scanTarget: string, config?: CodeGateConfig, discoveryContext?: ScanDiscoveryContext) => Promise<LocalTextAnalysisTarget[]> | LocalTextAnalysisTarget[];
|
|
47
|
+
requestDeepScanConsent?: (resource: DeepScanResource) => Promise<boolean> | boolean;
|
|
48
|
+
requestDeepAgentSelection?: (options: DeepAgentOption[]) => Promise<DeepAgentOption | null> | DeepAgentOption | null;
|
|
49
|
+
requestMetaAgentCommandConsent?: (context: MetaAgentCommandConsentContext) => Promise<boolean> | boolean;
|
|
50
|
+
runMetaAgentCommand?: (context: MetaAgentCommandConsentContext) => Promise<MetaAgentCommandRunResult> | MetaAgentCommandRunResult;
|
|
51
|
+
requestRemediationConsent?: (context: RemediationConsentContext) => Promise<boolean> | boolean;
|
|
52
|
+
requestRunWarningConsent?: (context: RunWarningConsentContext) => Promise<boolean> | boolean;
|
|
53
|
+
executeDeepResource?: (resource: DeepScanResource) => Promise<ResourceFetchResult>;
|
|
54
|
+
runWrapper?: (input: {
|
|
55
|
+
target: string;
|
|
56
|
+
cwd: string;
|
|
57
|
+
version: string;
|
|
58
|
+
config: CodeGateConfig;
|
|
59
|
+
force?: boolean;
|
|
60
|
+
requestWarningProceed?: (report: CodeGateReport) => Promise<boolean> | boolean;
|
|
61
|
+
}) => Promise<void>;
|
|
62
|
+
}
|
|
63
|
+
export declare function createCli(version?: string, deps?: CliDeps): Command;
|
|
64
|
+
export declare function runCli(argv?: string[], version?: string, deps?: CliDeps): Promise<void>;
|