canship 0.2.0 → 0.2.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.
@@ -0,0 +1,125 @@
1
+ # canship
2
+
3
+ 面向 JavaScript / TypeScript 项目的本地静态扫描器,检测凭据暴露和访问控制配置错误。不执行项目代码,不上传文件,扫描过程不联网。
4
+
5
+ ```powershell
6
+ npx canship .
7
+ ```
8
+
9
+ 要求 Node.js ≥18,无运行时依赖。Git 用于读取本地历史;仓库中无法使用 Git 时,扫描标记为未完成。首次使用 `npx` 可能需要从 npm 下载软件包。
10
+
11
+ [English](./README.md)
12
+
13
+ ## 检测范围
14
+
15
+ | 检查项 | 级别 |
16
+ |---|---|
17
+ | 硬编码凭据、私钥及含密码的数据库连接串 | P0 |
18
+ | 公开环境变量中的私密值 | P0 |
19
+ | 客户端可访问的 Supabase 管理员密钥 | P0 |
20
+ | Git 跟踪及历史 `.env` 文件中的凭据或疑似私密值 | P0 |
21
+ | Supabase 表未启用行级安全(RLS) | P1 |
22
+ | Firebase 无条件访问及固定日期测试规则 | P1 |
23
+ | Next.js API 数据操作缺少鉴权 | P0 / P1 |
24
+ | 携带凭据的 CORS 来源回显或通配符配置 | P1 / P2 |
25
+
26
+ 识别 OpenAI、Anthropic、AWS、Stripe、GitHub、npm、Slack、SendGrid 等凭据格式及常见前端框架的公开环境变量前缀。API 鉴权检查限于 Next.js 的 `/api` 处理函数,支持 App Router、Pages Router、路由组和工作区应用。
27
+
28
+ 置信度分为确定(`certain`)和疑似(`likely`)。默认只展示确定结果;隐藏的疑似结果仍影响退出码。
29
+
30
+ ## 参数
31
+
32
+ 省略路径时扫描当前目录。
33
+
34
+ | 参数 | 说明 |
35
+ |---|---|
36
+ | `-a`, `--all` | 展示疑似结果 |
37
+ | `--json` | 输出 JSON |
38
+ | `--fix-prompt` | 输出编程助手修复指令及独立的人工操作清单 |
39
+ | `--report[=文件]` | 写入 HTML 报告,默认 `canship-report.html` |
40
+ | `--sarif[=文件]` | 写入 SARIF 2.1.0 报告,默认 `canship.sarif` |
41
+ | `--best-effort` | 无结果时,允许不完整扫描退出 `0` |
42
+ | `--baseline[=文件]` | 应用基线,默认 `canship-baseline.json` |
43
+ | `--baseline-write[=文件]` | 记录当前结果为基线后退出 |
44
+ | `--only=规则` | 仅执行匹配规则,支持逗号分隔及重复参数 |
45
+ | `--skip=规则` | 排除匹配规则,支持逗号分隔及重复参数 |
46
+ | `--no-config` | 忽略项目配置 |
47
+ | `-h`, `--help` | 显示帮助 |
48
+ | `-v`, `--version` | 显示版本 |
49
+
50
+ `--json` 与 `--fix-prompt` 互斥;HTML 和 SARIF 可与任一输出模式组合。报告正文为英文,各格式均用 `--all` 包含疑似结果。
51
+
52
+ ### 退出码
53
+
54
+ | 退出码 | 含义 |
55
+ |---|---|
56
+ | `0` | 无结果且扫描完整,或由 `--best-effort` 接受不完整扫描 |
57
+ | `1` | 存在 `certain` 的 P0/P1 结果 |
58
+ | `2` | 存在其他结果,包括被隐藏的 `likely` |
59
+ | `3` | 参数或工具错误,或未被接受的不完整扫描 |
60
+
61
+ 结果对应的退出码优先于不完整状态;`--best-effort` 不改变 `1` 或 `2`。JSON 用 `partial`、`errors`、`skipped` 保留完整性信息,SARIF 提供执行状态和诊断通知。
62
+
63
+ ## 配置与忽略
64
+
65
+ 扫描目录中的 `canship.config.json` 支持 `baseline`、`only`、`skip`、`all`:
66
+
67
+ ```json
68
+ {
69
+ "skip": ["cors/wildcard-with-credentials"],
70
+ "all": false
71
+ }
72
+ ```
73
+
74
+ 命令行参数优先;`only` 与 `skip` 互斥,接受完整规则 ID 或命名空间。无关规则不执行;`ruleSelection.removed` 仅统计已执行规则中被过滤的结果。扫描不可信项目时使用 `--no-config`;`bestEffort` 仅支持命令行设置。
75
+
76
+ 以独占注释行的 `canship-ignore-file` 排除整个文件,或用 `canship-ignore-next-line` 忽略下一行。后者可附加规则 ID:
77
+
78
+ ```ts
79
+ // canship-ignore-next-line cors/wildcard-with-credentials
80
+ const corsOptions = { origin: '*', credentials: true }
81
+ ```
82
+
83
+ 报告披露忽略、筛选和基线抑制信息。主动忽略不使扫描标记为未完成。
84
+
85
+ ## 基线
86
+
87
+ 记录已有结果:
88
+
89
+ ```powershell
90
+ npx canship --baseline-write
91
+ ```
92
+
93
+ 仅报告新增结果:
94
+
95
+ ```powershell
96
+ npx canship --baseline
97
+ ```
98
+
99
+ 裸参数使用扫描目录,显式路径相对工作目录。写入成功退出 `0`;扫描不完整或启用规则筛选时会提示。
100
+
101
+ 基线格式为第 2 版,不含源码摘录,但披露路径、规则、标题和问题类型,提交前需审阅。指纹不含行号,移动行号不会产生新结果,替换凭据会。缺失、损坏及第 1 版基线均退出 `3`。
102
+
103
+ ## 限制
104
+
105
+ - 静态启发式分析可能误报或漏报,不验证运行时行为、限流、注入、依赖漏洞及业务授权。无发现不代表项目安全。
106
+ - 脱敏仅覆盖已识别格式;未知秘密可能出现在证据行中,报告应作为内部材料。Google/Firebase/Maps 的 `AIza...` 值按公开标识符处理。
107
+ - 单文件最多读取 2 MiB;单次累计读取最多 128 MiB、10,000 个文件;目录最多 16 层。跨规则每文件最多输出 100 条结果,优先保留高严重度、高置信度结果。
108
+ - Git 历史每文件最多检查 100 个相关版本,单条 Git 命令超时为 30 秒。超限或超时均披露检查缺口。
109
+ - 不跟随符号链接;嵌套仓库及子模块需分别扫描。扫描范围内的跳过项使扫描未完成,已排除的构建和依赖目录除外。
110
+
111
+ ## 开发
112
+
113
+ 检测规则需同时包含应检出和不应检出的用例,参见 [测试夹具](./test/fixtures/)。
114
+
115
+ ```powershell
116
+ npm ci
117
+ ```
118
+
119
+ ```powershell
120
+ npm run prepublishOnly
121
+ ```
122
+
123
+ ## 许可
124
+
125
+ [MIT](./LICENSE)
package/README.md CHANGED
@@ -1,204 +1,125 @@
1
- # canship
2
-
3
- canship is a read-only static scanner for JavaScript and TypeScript web projects. It detects exposed credentials, private values carried into browser-delivered code by a public environment prefix (Next.js, Vite, Nuxt, Create React App, Expo, Gatsby, Vue CLI, SvelteKit), Supabase tables without Row Level Security, Firebase rules left open, and API routes that reach data without checking who is calling.
4
-
5
- That last check covers Next.js only — handlers under `app/api/**` and `pages/api/**`. A SvelteKit `+server.ts` or a Nuxt `server/api/` handler is scanned for everything else and is not checked for a missing authentication check. Every other check is framework-independent.
6
-
7
- The scan does not execute project code, upload content, or initiate network requests. The npm package has no runtime dependencies. When scanning a Git repository, canship reads only the local working tree and local commit history.
8
-
9
- ```bash
10
- npx canship
11
- ```
12
-
13
- Node.js 18 or later is required. Git is optional; only commit-history checks require a local Git installation and a readable repository. If canship is not already in the npm cache, `npx` may download it from the npm registry before the scan starts; that download is performed by npm and is not part of the scan.
14
-
15
- [简体中文](./README.zh-CN.md)
16
-
17
- ## Checks
18
-
19
- | Check | Risk | Severity |
20
- |---|---|---|
21
- | Hardcoded credentials | A scanned file contains a recognised OpenAI, Anthropic, AWS, Stripe, GitHub, npm, Slack, SendGrid, private-key, or database credential | P0 |
22
- | Private values in public environment variables | The value may be included in browser-delivered code | P0 |
23
- | Supabase `service_role` key reachable from client code | A `service_role` key can bypass Row Level Security (RLS) policies | P0 |
24
- | Git-tracked `.env` files | Recognised credentials remain in repository history; substantial unrecognised values may also produce a lower-confidence finding | P0 |
25
- | Supabase tables without RLS | A table exposed through the Supabase Data API lacks row-level access control | P1 |
26
- | Firebase rules allowing unconditional access | Unauthorised clients may be able to read or write data | P1 |
27
- | Next.js API routes accessing data without authentication | An unverified caller may access data or perform administrative operations | P0 / P1 |
28
- | CORS reflecting `Origin` while allowing credentials | Another site may access an endpoint with the user's credentials and read the response | P1 |
29
-
30
- Severity (P0, P1, P2) describes potential impact. Confidence (`certain`, `likely`) describes how strongly the code supports the finding. A `certain` P0/P1 finding blocks release and exits with status `1`; all other findings exit with status `2`.
31
-
32
- `Access-Control-Allow-Origin: *` combined with credentials is reported at P2 because browsers reject that configuration. A bare wildcard is not reported.
33
-
34
- For Git-tracked `.env` files, a recognised credential is reported at `certain` confidence. A substantial value that is not recognised but does not look public or placeholder-like is reported at `likely` confidence. Environment templates, public values, placeholders, and short settings do not trigger this Git rule solely because the file is tracked.
35
-
36
- ## Usage
37
-
38
- ```bash
39
- npx canship [path]
40
- ```
41
-
42
- The current directory is scanned when no path is provided.
43
-
44
- | Option | Description |
45
- |---|---|
46
- | `-a`, `--all` | Show `likely` findings |
47
- | `--json` | Write machine-readable JSON |
48
- | `--fix-prompt` | Write remediation instructions for a coding assistant |
49
- | `--report[=file]` | Write a self-contained HTML report; defaults to `canship-report.html` |
50
- | `--best-effort` | Allow exit `0` when the scan is incomplete and has no findings; does not change the status of existing findings |
51
- | `--baseline[=file]` | Hide findings recorded in the baseline, so only new ones are reported; defaults to `canship-baseline.json` |
52
- | `--baseline-write[=file]` | Record the current findings as a baseline and exit; defaults to `canship-baseline.json` |
53
- | `--only=ids` | Report only these rules; comma-separated and repeatable |
54
- | `--skip=ids` | Report everything except these rules; comma-separated and repeatable |
55
- | `--sarif[=file]` | Write a SARIF 2.1.0 log for CI code scanning; defaults to `canship.sarif` |
56
- | `--no-config` | Ignore `canship.config.json` in the scanned directory |
57
- | `-h`, `--help` | Show help |
58
- | `-v`, `--version` | Show the version |
59
-
60
- `--json` and `--fix-prompt` are mutually exclusive. `--report` writes a separate file and may be combined with either mode.
61
-
62
- ### Exit status
63
-
64
- | Status | Meaning |
65
- |---|---|
66
- | `0` | No findings at any confidence and the scan completed; with `--best-effort`, it may also mean an incomplete scan was accepted |
67
- | `1` | At least one `certain` P0/P1 finding |
68
- | `2` | Findings exist, but none is a confirmed P0/P1 release blocker |
69
- | `3` | Invalid arguments, a tool error, or an incomplete scan without `--best-effort` |
70
-
71
- When findings and an incomplete scan coexist, status `1` or `2` takes precedence. The JSON fields `partial`, `errors`, and `skipped` still preserve the incomplete-scan state.
72
-
73
- The default view expands only `certain` findings. Hidden `likely` findings still produce status `2`; the terminal and HTML report display a warning, and JSON reports the count in `hiddenLikely`. Use `--all` to include their full details.
74
-
75
- ### Excluding a file
76
-
77
- Add `canship-ignore-file` on a line by itself to exclude the entire file. The marker may be wrapped only in `//`, `#`, `--`, `*`, `/* */`, or `<!-- -->` comment syntax. Intentionally excluded files are listed in the report and do not make the scan incomplete.
78
-
79
- ### Excluding a single line
80
-
81
- Add `canship-ignore-next-line` on the line above a finding to suppress it there. The same comment syntax applies, and the marker must be the whole content of its line — a line that also holds code or prose does not suppress anything.
82
-
83
- ```ts
84
- // canship-ignore-next-line
85
- const documentedExample = "sk-proj-not-a-real-key"
86
- ```
87
-
88
- A bare marker suppresses every rule on the following line. A rule id after it narrows the suppression to that rule, so a line with one known false positive is not also blind to a different finding:
89
-
90
- ```ts
91
- // canship-ignore-next-line secrets/hardcoded/openai
92
- const key = process.env.OPENAI_KEY
93
- ```
94
-
95
- Rule ids appear in `--json` output; the terminal and HTML reports do not print them, which is why the bare form exists.
96
-
97
- The marker governs the line immediately after it, with no allowance for blank lines. Suppressed findings are listed by file, line, and rule in the terminal, the HTML report, and the `ignoredFindings` field of `--json`. They do not make the scan incomplete, and the report states that the result is not finding-free.
98
-
99
- ### Configuration
100
-
101
- Settings a project makes once can be committed to `canship.config.json` in the scanned directory. A command-line flag always overrides the file.
102
-
103
- ```json
104
- {
105
- "baseline": "canship-baseline.json",
106
- "skip": ["cors/wildcard-with-credentials"],
107
- "all": false
108
- }
109
- ```
110
-
111
- | Setting | Equivalent flag |
112
- |---|---|
113
- | `baseline` | `--baseline=file` |
114
- | `only` | `--only=ids` |
115
- | `skip` | `--skip=ids` |
116
- | `all` | `--all` |
117
-
118
- The format is JSON and not JavaScript. A `canship.config.js` would be project code, and the scan does not execute project code.
119
-
120
- An unknown setting, a wrong type, a rule id that names no rule, or `only` and `skip` together are all errors and exit `3`. A missing config file is not an error. A `baseline` path must stay inside the scanned project; the `--baseline` flag is not restricted that way.
121
-
122
- **The config file comes out of the directory being scanned.** When that directory is code you control, this is the point of the feature. When it is not — a dependency, a fork, an unreviewed pull request — the project can use it to switch off the rules that would report it. `--no-config` ignores the file entirely.
123
-
124
- `bestEffort` is deliberately not a setting. It turns an incomplete scan from exit `3` into exit `0`, and that is a judgement for whoever runs canship rather than a property of the project being scanned. Naming it in the file is an error rather than something quietly ignored. Use `--best-effort`.
125
-
126
- ### Selecting rules
127
-
128
- `--only` and `--skip` take the rule ids that appear in `--json` output, comma-separated and repeatable. A selector matches an id exactly, or matches every id beneath it at a `/` boundary — `secrets` covers every credential format, `secrets/hardcoded/openai` covers one. A partial id such as `secrets/hardcoded/open` matches nothing and is rejected, so a mistyped id cannot quietly disable a rule.
129
-
130
- `--only` and `--skip` cannot be combined. Selection filters findings rather than skipping the rules themselves, so it does not reduce scan time. Every report states which selection was in force and how many findings it hid.
131
-
132
- ### Baseline
133
-
134
- An existing project usually has findings on the first run. A baseline records them so that subsequent runs report only what appeared afterwards, which is what makes canship usable in continuous integration for a project that did not start with it.
135
-
136
- ```bash
137
- npx canship --baseline-write # accept the current findings
138
- npx canship --baseline # report only new ones
139
- ```
140
-
141
- `--baseline-write` writes `canship-baseline.json` and exits `0` without scanning further. Commit that file: it is the record of what was accepted, and it is meant to be reviewed in the pull request that adds it.
142
-
143
- **Consider what committing it publishes.** Each entry names a file path, a rule id, and a finding title, and every entry describes a problem that has not been fixed. canship searches gitignored credential files by design, so an entry may describe a file the repository does not contain — `.env.local` and the name of a variable in it, for example. The file holds no credential values. On a private repository this is the intended use; on a public one, weigh the disclosure before committing.
144
-
145
- Paths are resolved where they came from: a path typed on the command line is relative to the working directory, a bare `--baseline` or `--baseline-write` uses the scanned project's own `canship-baseline.json`, and a path in `canship.config.json` is relative to that file. So `npx canship ./app --baseline-write` writes into `./app`, which is where `npx canship ./app --baseline` then looks.
146
-
147
- A baseline entry is matched by rule, file, title, and a digest of its original source evidence; only findings without locatable evidence fall back to the excerpt. The source digest is computed before redaction and truncation, so replacing a credential cannot hide behind the old display text. The line number is deliberately excluded, so editing a file above a line-based finding does not report it as new. Each entry carries the number of times it was seen; an additional occurrence beyond that count is reported.
148
-
149
- The baseline format is now version 2, and the SARIF fingerprint is named `canshipFindingV2`. Older baselines are rejected with exit code `3`, never automatically converted or overwritten. Review the findings again before regenerating with `--baseline-write`.
150
-
151
- The baseline stores a SHA-256 hash rather than the excerpt itself, because the file is intended to be committed and canship cannot guarantee that an unrecognised credential is masked.
152
-
153
- A baseline hides real findings. Every output states how many:
154
-
155
- - the terminal and HTML report never show a clean result while a baseline is suppressing findings, and name the count and the file
156
- - `--json` reports `baselineSuppressed`
157
- - baseline entries that no longer match anything are reported as `baselineStale`; they do not affect the exit status
158
-
159
- Findings of every confidence are recorded. A baseline that cannot be read — missing, malformed, or written by a different format version — exits `3` rather than proceeding with no suppression. `--baseline` and `--baseline-write` cannot be combined.
160
-
161
- ### Remediation instructions
162
-
163
- `--fix-prompt` separates code changes that a coding assistant can perform from actions that require the project maintainer, such as rotating credentials, changing provider settings, or rewriting Git history.
164
-
165
- ## Rule activation
166
-
167
- | Rule | Activation conditions |
168
- |---|---|
169
- | Public environment variables | The name starts with `NEXT_PUBLIC_`, `VITE_`, `REACT_APP_`, `EXPO_PUBLIC_`, `NUXT_PUBLIC_`, `GATSBY_`, `VUE_APP_`, or `PUBLIC_` |
170
- | Git-tracked environment files | The target is inside a readable local Git repository whose `.git` metadata is inside the checkout or names it back; templates, public values, placeholders, and short settings are excluded, and at most the 100 most recent relevant revisions of each file are inspected |
171
- | Next.js API authentication | Only data-accessing handlers under `app/api/**` and `pages/api/**`; recognises enforcing authentication calls, identity conditions that control rejection, and middleware `matcher` coverage for the route |
172
- | Supabase RLS | The current project scope contains `supabase/`, an `@supabase/supabase-js` or `@supabase/ssr` import, or a `SUPABASE_URL`; table-related DDL is replayed across migrations within that project scope |
173
- | Other credential and configuration rules | Match known file formats and content patterns without requiring a specific front-end framework |
174
-
175
- ## Known limitations
176
-
177
- - canship uses static heuristics and does not verify runtime behaviour. Custom authentication wrappers, dynamic configuration, and unsupported syntax can cause false positives or false negatives.
178
- - Detection and redaction use the same credential patterns. A credential that canship cannot recognise cannot be guaranteed to be masked; if another rule quotes the same line, the original value may appear in the report. Treat reports as internal material.
179
- - Entropy-based detection is intentionally not used because random identifiers, hashes, and ordinary Base64 text cannot be classified reliably from entropy alone.
180
- - Files are limited to 2 MiB, traversal to 16 directory levels, and output to 100 findings per file. Git history checks inspect at most the 100 most recent relevant revisions of each file. Reaching a limit is recorded explicitly.
181
- - Symbolic links are not followed and make the scan incomplete.
182
- - Nested Git repositories and submodules are not expanded by the parent scan. They are listed as skipped and the parent scan is marked incomplete.
183
- - A `.git` file may point outside the checkout. canship follows it only when the target names this checkout back, which is what git records for a linked worktree and for a submodule. Anything else is read as a redirect to an unrelated repository: file scanning continues, history checks are marked incomplete.
184
- - Google, Firebase, and Maps `AIza...` keys are treated as public identifiers. Their application and API restrictions exist in Google Cloud and cannot be verified from local source, so the key value alone is not reported as a credential leak.
185
- - Rate limiting, injection, dependency vulnerabilities, and business authorisation beyond caller authentication are outside the scan scope.
186
-
187
- A canship result describes only what the implemented rules observed in the files that were read. It is not proof that the project has no other security defects.
188
-
189
- ## Planned
190
-
191
- `--probe` is not implemented. The planned mode would, after explicit confirmation, issue read-only verification requests to service endpoints found in local project configuration. The current release does not initiate network requests.
192
-
193
- ## Contributing
194
-
195
- Every new or changed detection rule should include at least two fixtures: one that must be reported and one that must not. See [`test/fixtures/`](./test/fixtures/).
196
-
197
- ```bash
198
- npm ci
199
- npm run prepublishOnly
200
- ```
201
-
202
- ## License
203
-
204
- [MIT](./LICENSE)
1
+ # canship
2
+
3
+ A local static scanner for JavaScript and TypeScript projects. Detects exposed credentials and access-control misconfigurations without executing project code, uploading files, or making network requests during scans.
4
+
5
+ ```powershell
6
+ npx canship .
7
+ ```
8
+
9
+ Requires Node.js ≥18; no runtime dependencies. Git is used for local history checks. Unavailable Git in a repository makes the scan incomplete. On first use, `npx` may download the package from npm.
10
+
11
+ [简体中文](./README-zh-CN.md)
12
+
13
+ ## Checks
14
+
15
+ | Check | Severity |
16
+ |---|---|
17
+ | Hardcoded credentials, private keys, and database URLs containing passwords | P0 |
18
+ | Private values in public environment variables | P0 |
19
+ | Client-accessible Supabase admin keys | P0 |
20
+ | Credentials or suspected private values in Git-tracked and historical `.env` files | P0 |
21
+ | Supabase tables without Row Level Security (RLS) | P1 |
22
+ | Firebase unconditional access and date-based test rules | P1 |
23
+ | Next.js API data operations without authentication | P0 / P1 |
24
+ | Credentialed CORS with reflected or wildcard origins | P1 / P2 |
25
+
26
+ Recognises OpenAI, Anthropic, AWS, Stripe, GitHub, npm, Slack, SendGrid, and other credential formats, plus common frontend public environment prefixes. API authentication checks cover Next.js `/api` handlers, including App Router, Pages Router, route groups, and workspace applications.
27
+
28
+ Confidence is `certain` or `likely`. Only certain findings are shown by default; hidden likely findings still affect the exit code.
29
+
30
+ ## Options
31
+
32
+ Omitting the path scans the current directory.
33
+
34
+ | Option | Description |
35
+ |---|---|
36
+ | `-a`, `--all` | Include likely findings |
37
+ | `--json` | Output JSON |
38
+ | `--fix-prompt` | Output assistant instructions and separate manual actions |
39
+ | `--report[=file]` | Write HTML; default: `canship-report.html` |
40
+ | `--sarif[=file]` | Write SARIF 2.1.0; default: `canship.sarif` |
41
+ | `--best-effort` | Permit exit `0` for an incomplete scan with no findings |
42
+ | `--baseline[=file]` | Apply a baseline; default: `canship-baseline.json` |
43
+ | `--baseline-write[=file]` | Record current findings as a baseline and exit |
44
+ | `--only=ids` | Run matching rules; comma-separated and repeatable |
45
+ | `--skip=ids` | Exclude matching rules; comma-separated and repeatable |
46
+ | `--no-config` | Ignore project configuration |
47
+ | `-h`, `--help` | Show help |
48
+ | `-v`, `--version` | Show version |
49
+
50
+ `--json` and `--fix-prompt` are mutually exclusive. HTML and SARIF may be combined with either. Reports are in English; use `--all` to include likely findings in any format.
51
+
52
+ ### Exit codes
53
+
54
+ | Code | Meaning |
55
+ |---|---|
56
+ | `0` | No findings and a complete scan, or an incomplete scan accepted with `--best-effort` |
57
+ | `1` | At least one certain P0/P1 finding |
58
+ | `2` | Other findings, including hidden likely findings |
59
+ | `3` | Invalid arguments, a tool error, or an unaccepted incomplete scan |
60
+
61
+ Findings take precedence over incompleteness; `--best-effort` does not change `1` or `2`. JSON retains `partial`, `errors`, and `skipped`; SARIF includes execution status and diagnostic notifications.
62
+
63
+ ## Configuration and suppressions
64
+
65
+ Place `canship.config.json` in the scanned directory. Supported keys: `baseline`, `only`, `skip`, `all`.
66
+
67
+ ```json
68
+ {
69
+ "skip": ["cors/wildcard-with-credentials"],
70
+ "all": false
71
+ }
72
+ ```
73
+
74
+ CLI options take precedence. `only` and `skip` are mutually exclusive and accept complete rule IDs or namespaces. Unrelated rules do not run; `ruleSelection.removed` counts only filtered findings from rules that ran. Use `--no-config` for untrusted projects. `bestEffort` is CLI-only.
75
+
76
+ A standalone comment containing `canship-ignore-file` excludes a file. `canship-ignore-next-line` suppresses the next line and accepts an optional rule ID:
77
+
78
+ ```ts
79
+ // canship-ignore-next-line cors/wildcard-with-credentials
80
+ const corsOptions = { origin: '*', credentials: true }
81
+ ```
82
+
83
+ Reports disclose exclusions, rule selection, and baseline suppression. Deliberate exclusions do not make the scan incomplete.
84
+
85
+ ## Baselines
86
+
87
+ Record existing findings:
88
+
89
+ ```powershell
90
+ npx canship --baseline-write
91
+ ```
92
+
93
+ Report only new findings:
94
+
95
+ ```powershell
96
+ npx canship --baseline
97
+ ```
98
+
99
+ Bare options use the scanned directory; explicit paths are relative to the working directory. A successful write exits `0`, with a warning for incomplete or selectively scanned input.
100
+
101
+ Baseline format v2 contains no source excerpts but discloses paths, rules, titles, and issue types. Review it before committing. Fingerprints exclude line numbers: moving lines preserves identity, replacing credentials changes it. Missing, malformed, and v1 baselines exit `3`.
102
+
103
+ ## Limitations
104
+
105
+ - Static heuristics may produce false positives or negatives. Runtime behaviour, rate limiting, injection, dependency vulnerabilities, and business authorisation are outside scope. No findings does not prove security.
106
+ - Redaction covers recognised formats only; unknown secrets may appear in evidence. Treat reports as internal material. Google/Firebase/Maps `AIza...` values are treated as public identifiers.
107
+ - Reads are limited to 2 MiB per file, 128 MiB and 10,000 files per scan, and 16 directory levels. Across rules, at most 100 findings per file are reported, prioritising severity and confidence.
108
+ - Git history checks cover up to 100 relevant revisions per file. Each Git command has a 30-second timeout. Exceeded limits and timeouts are reported as incomplete coverage.
109
+ - Symbolic links are not followed. Scan nested repositories and submodules separately. Skipped paths within scope make the scan incomplete; excluded build and dependency directories remain excluded.
110
+
111
+ ## Development
112
+
113
+ Detection rules require positive and negative cases; see [test fixtures](./test/fixtures/).
114
+
115
+ ```powershell
116
+ npm ci
117
+ ```
118
+
119
+ ```powershell
120
+ npm run prepublishOnly
121
+ ```
122
+
123
+ ## License
124
+
125
+ [MIT](./LICENSE)