canship 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README-zh-CN.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # canship
2
2
 
3
- 面向 JavaScript / TypeScript 项目的本地静态扫描器,检测凭据暴露和访问控制配置错误。不执行项目代码,不上传文件,扫描过程不联网。
3
+ 面向 JavaScript / TypeScript 项目的本地静态扫描器,检测凭据暴露与访问控制配置错误。扫描不执行项目代码、不上传文件、不联网。
4
+
5
+ 本文档对应 0.3.x,适用于匹配的 [npm 版本](https://www.npmjs.com/package/canship) 或本地构建。
4
6
 
5
7
  ```powershell
6
8
  npx canship .
7
9
  ```
8
10
 
9
- 要求 Node.js ≥18,无运行时依赖。Git 用于读取本地历史;仓库中无法使用 Git 时,扫描标记为未完成。首次使用 `npx` 可能需要从 npm 下载软件包。
11
+ 要求 Node.js ≥18,无运行时依赖。`npx` 可能联网下载软件包;扫描仅使用本地文件与 Git 历史。Git 仓库中无法调用 Git 时,扫描标记为未完成。
10
12
 
11
13
  [English](./README.md)
12
14
 
@@ -16,18 +18,18 @@ npx canship .
16
18
  |---|---|
17
19
  | 硬编码凭据、私钥及含密码的数据库连接串 | P0 |
18
20
  | 公开环境变量中的私密值 | P0 |
19
- | 客户端可访问的 Supabase 管理员密钥 | P0 |
21
+ | Supabase 管理员密钥暴露至客户端 | P0 |
20
22
  | Git 跟踪及历史 `.env` 文件中的凭据或疑似私密值 | P0 |
21
- | Supabase 表未启用行级安全(RLS) | P1 |
23
+ | Supabase 迁移记录中未启用行级安全(RLS)的表 | P1 |
22
24
  | Firebase 无条件访问及固定日期测试规则 | P1 |
23
- | Next.js API 数据操作缺少鉴权 | P0 / P1 |
25
+ | Next.js API 数据操作未识别到鉴权 | P0 / P1 |
24
26
  | 携带凭据的 CORS 来源回显或通配符配置 | P1 / P2 |
25
27
 
26
- 识别 OpenAI、Anthropic、AWS、Stripe、GitHub、npm、Slack、SendGrid 等凭据格式及常见前端框架的公开环境变量前缀。API 鉴权检查限于 Next.js 的 `/api` 处理函数,支持 App Router、Pages Router、路由组和工作区应用。
28
+ 支持 OpenAI、Anthropic、AWS、Stripe、GitHub、npm、Slack、SendGrid 等凭据格式及常见前端公开环境变量前缀。API 鉴权检查仅覆盖 Next.js `/api`,支持 App Router、Pages Router、路由组和工作区应用。
27
29
 
28
- 置信度分为确定(`certain`)和疑似(`likely`)。默认只展示确定结果;隐藏的疑似结果仍影响退出码。
30
+ 置信度分为确定(`certain`)和疑似(`likely`),仅描述静态证据,不验证凭据有效性或线上状态。默认只展示确定结果;隐藏的疑似结果仍影响退出码。
29
31
 
30
- ## 参数
32
+ ## 用法
31
33
 
32
34
  省略路径时扫描当前目录。
33
35
 
@@ -35,32 +37,80 @@ npx canship .
35
37
  |---|---|
36
38
  | `-a`, `--all` | 展示疑似结果 |
37
39
  | `--json` | 输出 JSON |
38
- | `--fix-prompt` | 输出编程助手修复指令及独立的人工操作清单 |
39
- | `--report[=文件]` | 写入 HTML 报告,默认 `canship-report.html` |
40
- | `--sarif[=文件]` | 写入 SARIF 2.1.0 报告,默认 `canship.sarif` |
40
+ | `--fix-prompt` | 输出修复指令及独立的人工操作清单 |
41
+ | `--report[=file]` | 写入 HTML,默认 `canship-report.html` |
42
+ | `--sarif[=file]` | 写入 SARIF 2.1.0,默认 `canship.sarif` |
41
43
  | `--best-effort` | 无结果时,允许不完整扫描退出 `0` |
42
- | `--baseline[=文件]` | 应用基线,默认 `canship-baseline.json` |
43
- | `--baseline-write[=文件]` | 记录当前结果为基线后退出 |
44
- | `--only=规则` | 仅执行匹配规则,支持逗号分隔及重复参数 |
45
- | `--skip=规则` | 排除匹配规则,支持逗号分隔及重复参数 |
44
+ | `--baseline[=file]` | 应用基线,默认 `canship-baseline.json` |
45
+ | `--baseline-write[=file]` | 写入当前结果为基线后退出,同上默认路径 |
46
+ | `--only=ids` | 仅执行匹配规则,支持逗号分隔及重复参数 |
47
+ | `--skip=ids` | 排除匹配规则,支持逗号分隔及重复参数 |
46
48
  | `--no-config` | 忽略项目配置 |
49
+ | `--no-ignore-markers` | 不遵从被扫描源码中的忽略标记 |
50
+ | `--list-rules` | 列出规则及限制,不扫描;支持 `--json` |
51
+ | `--no-excerpts` | 所有报告省略源码摘录,不改变结果和退出码 |
47
52
  | `-h`, `--help` | 显示帮助 |
48
53
  | `-v`, `--version` | 显示版本 |
49
54
 
50
- `--json` 与 `--fix-prompt` 互斥;HTML 和 SARIF 可与任一输出模式组合。报告正文为英文,各格式均用 `--all` 包含疑似结果。
55
+ `--json` 与 `--fix-prompt` 互斥;HTML、SARIF 可与任一模式组合。报告正文为英文,`--all` 对所有格式生效。
51
56
 
52
57
  ### 退出码
53
58
 
54
59
  | 退出码 | 含义 |
55
60
  |---|---|
56
- | `0` | 无结果且扫描完整,或由 `--best-effort` 接受不完整扫描 |
61
+ | `0` | 无结果,且扫描完整或由 `--best-effort` 接受不完整扫描 |
57
62
  | `1` | 存在 `certain` 的 P0/P1 结果 |
58
63
  | `2` | 存在其他结果,包括被隐藏的 `likely` |
59
64
  | `3` | 参数或工具错误,或未被接受的不完整扫描 |
60
65
 
61
- 结果对应的退出码优先于不完整状态;`--best-effort` 不改变 `1` 或 `2`。JSON 用 `partial`、`errors`、`skipped` 保留完整性信息,SARIF 提供执行状态和诊断通知。
66
+ 结果退出码优先于不完整状态;`--best-effort` 不改变 `1` 或 `2`。
67
+
68
+ ### 机器可读输出
69
+
70
+ JSON 使用独立于包版本的 `schemaVersion: 1`,npm 包附带 [结构定义](./schemas/scan-report-v1.schema.json)。调用方应兼容新增字段、拒绝不支持的结构版本;`--list-rules --json` 为独立的 `kind: "rule-catalog"` 文档。
71
+
72
+ `findings` 为抑制和筛选后的结果;`hiddenLikely`、`baselineSuppressed`、`baselineStale` 提供相关统计。完整性需另查 `partial`、`errors`、`skipped`、`filesScanned`;SARIF 提供执行状态与诊断通知。
73
+
74
+ ## GitHub Action
75
+
76
+ 保存为 `.github/workflows/canship.yml`,在推送和 PR 时扫描并生成统计摘要。安装扫描器需要联网,扫描不联网;不安装或执行项目依赖,默认不上传 SARIF。
77
+
78
+ 示例固定 Action 提交,显式安装 npm 版 `0.3.0`;`version` 不使用仓库中的未发布源码。Action 兼容 0.2.1 无 `schemaVersion` 的报告。
62
79
 
63
- ## 配置与忽略
80
+ ```yaml
81
+ name: canship
82
+ on: [push, pull_request]
83
+ permissions:
84
+ contents: read
85
+ jobs:
86
+ scan:
87
+ runs-on: ubuntu-latest
88
+ steps:
89
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803
90
+ with:
91
+ fetch-depth: 0
92
+ persist-credentials: false
93
+ - uses: Tasomei/canship@8b1a3aa88c77e92e2806b343af6003372855bc70
94
+ with:
95
+ version: '0.3.0'
96
+ ```
97
+
98
+ | 输入 | 默认值 | 说明 |
99
+ |---|---|---|
100
+ | `path` | `.` | 检出目录内的扫描路径 |
101
+ | `version` | `0.3.0` | 精确 npm 版本,不接受范围或标签 |
102
+ | `fail-on` | `blocking` | `blocking`:确定的 P0/P1;`any`:全部结果;`none`:仅报告结果 |
103
+ | `only` / `skip` | 未设置 | 互斥,逗号分隔的规则选择器 |
104
+ | `baseline` | 未设置 | 相对扫描目录的已有基线 |
105
+ | `use-config` | `false` | 启用项目配置 |
106
+ | `upload-sarif` | `false` | 上传 SARIF 至 GitHub 代码扫描 |
107
+ | `category` | `canship` | 每个扫描目标使用独立分类 |
108
+
109
+ 输出:`exit-code`、`findings`、`blocking`、`partial`。策略统计包含疑似结果,基线与忽略仍生效;扫描不完整、工具错误或报告不兼容始终失败,包括 `fail-on: none`。
110
+
111
+ 上传 SARIF 需 `security-events: write` 及 [GitHub 代码扫描支持](https://docs.github.com/en/code-security/how-tos/find-and-fix-code-vulnerabilities/integrate-with-existing-tools/upload-sarif-file),Fork PR 可能无权限。上传前审阅报告中的路径与详情;不可信 PR 使用 `pull_request`,不要使用 `pull_request_target`。Action 为后续步骤设置 Node.js 22,需要其他版本时应使用独立扫描任务。
112
+
113
+ ## 配置与基线
64
114
 
65
115
  扫描目录中的 `canship.config.json` 支持 `baseline`、`only`、`skip`、`all`:
66
116
 
@@ -71,18 +121,20 @@ npx canship .
71
121
  }
72
122
  ```
73
123
 
74
- 命令行参数优先;`only` 与 `skip` 互斥,接受完整规则 ID 或命名空间。无关规则不执行;`ruleSelection.removed` 仅统计已执行规则中被过滤的结果。扫描不可信项目时使用 `--no-config`;`bestEffort` 仅支持命令行设置。
124
+ 命令行参数优先;`only`、`skip` 互斥,接受规则 ID 或命名空间。未选规则不执行,`ruleSelection.removed` 仅统计已执行规则中被过滤的结果。扫描不可信项目时同时使用 `--no-config --no-ignore-markers`,二者均由被扫描项目控制;`bestEffort` 仅限命令行设置。
125
+
126
+ ### 忽略标记
75
127
 
76
- 以独占注释行的 `canship-ignore-file` 排除整个文件,或用 `canship-ignore-next-line` 忽略下一行。后者可附加规则 ID:
128
+ 独占注释行的 `canship-ignore-file` 排除整个文件;`canship-ignore-next-line` 忽略下一行,可附规则 ID:
77
129
 
78
130
  ```ts
79
131
  // canship-ignore-next-line cors/wildcard-with-credentials
80
132
  const corsOptions = { origin: '*', credentials: true }
81
133
  ```
82
134
 
83
- 报告披露忽略、筛选和基线抑制信息。主动忽略不使扫描标记为未完成。
135
+ 报告披露忽略、规则筛选和基线抑制信息;主动排除不标记为未完成。标记可使退出码降为 `0`;`--no-config` 不影响标记,`--no-ignore-markers` 使两种标记均失效。
84
136
 
85
- ## 基线
137
+ ### 基线
86
138
 
87
139
  记录已有结果:
88
140
 
@@ -96,21 +148,22 @@ npx canship --baseline-write
96
148
  npx canship --baseline
97
149
  ```
98
150
 
99
- 裸参数使用扫描目录,显式路径相对工作目录。写入成功退出 `0`;扫描不完整或启用规则筛选时会提示。
151
+ 默认基线位于扫描目录,显式路径相对工作目录。写入成功退出 `0`,不代表无问题;扫描不完整或启用规则筛选时会提示。
100
152
 
101
- 基线格式为第 2 版,不含源码摘录,但披露路径、规则、标题和问题类型,提交前需审阅。指纹不含行号,移动行号不会产生新结果,替换凭据会。缺失、损坏及第 1 版基线均退出 `3`。
153
+ 基线格式为 v2,移动行号不改变指纹,替换凭据会改变。缺失、损坏及 v1 基线均退出 `3`。基线不含源码,但包含路径、规则和问题描述,提交前需审阅。
102
154
 
103
- ## 限制
155
+ ## 隐私与限制
104
156
 
105
- - 静态启发式分析可能误报或漏报,不验证运行时行为、限流、注入、依赖漏洞及业务授权。无发现不代表项目安全。
106
- - 脱敏仅覆盖已识别格式;未知秘密可能出现在证据行中,报告应作为内部材料。Google/Firebase/Maps 的 `AIza...` 值按公开标识符处理。
107
- - 单文件最多读取 2 MiB;单次累计读取最多 128 MiB、10,000 个文件;目录最多 16 层。跨规则每文件最多输出 100 条结果,优先保留高严重度、高置信度结果。
108
- - Git 历史每文件最多检查 100 个相关版本,单条 Git 命令超时为 30 秒。超限或超时均披露检查缺口。
109
- - 不跟随符号链接;嵌套仓库及子模块需分别扫描。扫描范围内的跳过项使扫描未完成,已排除的构建和依赖目录除外。
157
+ - 静态分析可能误报或漏报,不验证线上行为,不覆盖限流、注入、依赖漏洞或业务授权。无结果不等于安全。
158
+ - 脱敏仅覆盖已识别格式,未知秘密可能出现在源码摘录中。`--no-excerpts` 省略摘录,JSON 以 `excerptsOmitted` 标明;路径、名称、说明及基线不匿名化,分享前仍需审阅。
159
+ - Google/Firebase/Maps 的 `AIza...` 值按公开标识符处理,不单凭其值判定泄露。
160
+ - 读取上限:单文件 2 MiB,单次 128 MiB、10,000 个文件,目录 16 层。每文件跨规则最多 100 条结果,优先保留高严重度、高置信度结果。
161
+ - Git 历史每文件最多 100 个相关版本,单条 Git 命令超时 30 秒。超限、超时均报告检查缺口。
162
+ - 不跟随符号链接;嵌套仓库、子模块需单独扫描。范围内跳过项使扫描未完成,内置排除的构建和依赖目录除外。
110
163
 
111
164
  ## 开发
112
165
 
113
- 检测规则需同时包含应检出和不应检出的用例,参见 [测试夹具](./test/fixtures/)。
166
+ 新增规则需包含应检出与不应检出的 [测试用例](./test/fixtures/)。
114
167
 
115
168
  ```powershell
116
169
  npm ci
@@ -120,6 +173,28 @@ npm ci
120
173
  npm run prepublishOnly
121
174
  ```
122
175
 
176
+ 离线评估:
177
+
178
+ ```powershell
179
+ npm run evaluate
180
+ ```
181
+
182
+ 评估集含 10 个构造用例、9 个固定版本上游示例及变体,同时纳入 `npm test`;[来源与许可](./test/fixtures/evaluation/) 随样本保存。断言覆盖规则、文件、严重度、置信度与扫描完整性,不代表真实项目检出率。
183
+
184
+ 另有 5 个 [应用目录快照](./test/evaluation/projects.json)。准备阶段联网并校验 Git 对象摘要,目标须为 Git 仓库外的新目录:
185
+
186
+ ```powershell
187
+ node scripts/fetch-evaluation-projects.mjs "$env:TEMP/canship-evaluation"
188
+ ```
189
+
190
+ 随后离线评估,不安装或运行样本依赖:
191
+
192
+ ```powershell
193
+ npm run evaluate:projects -- "$env:TEMP/canship-evaluation"
194
+ ```
195
+
196
+ CI 使用同一评估集,不验证 Git 历史或线上行为。
197
+
123
198
  ## 许可
124
199
 
125
- [MIT](./LICENSE)
200
+ [MIT](./LICENSE)。Supabase、Firebase 样本保留 Apache-2.0,Next.js、`cors` 样本保留 MIT;各样本附来源及许可证。
package/README.md CHANGED
@@ -1,12 +1,14 @@
1
1
  # canship
2
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.
3
+ A local static scanner for JavaScript and TypeScript projects. Detects exposed credentials and access-control misconfigurations. Scans do not execute project code, upload files, or use the network.
4
+
5
+ This documentation covers 0.3.x: use a matching [npm version](https://www.npmjs.com/package/canship) or local build.
4
6
 
5
7
  ```powershell
6
8
  npx canship .
7
9
  ```
8
10
 
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.
11
+ Requires Node.js ≥18; no runtime dependencies. `npx` may download the package; scans use only local files and Git history. Unavailable Git in a repository marks the scan incomplete.
10
12
 
11
13
  [简体中文](./README-zh-CN.md)
12
14
 
@@ -16,18 +18,18 @@ Requires Node.js ≥18; no runtime dependencies. Git is used for local history c
16
18
  |---|---|
17
19
  | Hardcoded credentials, private keys, and database URLs containing passwords | P0 |
18
20
  | Private values in public environment variables | P0 |
19
- | Client-accessible Supabase admin keys | P0 |
21
+ | Supabase admin keys exposed to clients | P0 |
20
22
  | Credentials or suspected private values in Git-tracked and historical `.env` files | P0 |
21
- | Supabase tables without Row Level Security (RLS) | P1 |
23
+ | Supabase tables without Row Level Security (RLS) in migrations | P1 |
22
24
  | Firebase unconditional access and date-based test rules | P1 |
23
- | Next.js API data operations without authentication | P0 / P1 |
25
+ | Next.js API data operations without recognised authentication | P0 / P1 |
24
26
  | Credentialed CORS with reflected or wildcard origins | P1 / P2 |
25
27
 
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.
28
+ Supports OpenAI, Anthropic, AWS, Stripe, GitHub, npm, Slack, SendGrid, and other credential formats, plus common frontend public environment prefixes. API authentication checks cover only Next.js `/api`: App Router, Pages Router, route groups, and workspace applications.
27
29
 
28
- Confidence is `certain` or `likely`. Only certain findings are shown by default; hidden likely findings still affect the exit code.
30
+ Confidence is `certain` or `likely`, describing static evidence rather than credential validity or deployed state. Only certain findings are shown by default; hidden likely findings still affect the exit code.
29
31
 
30
- ## Options
32
+ ## Usage
31
33
 
32
34
  Omitting the path scans the current directory.
33
35
 
@@ -35,32 +37,80 @@ Omitting the path scans the current directory.
35
37
  |---|---|
36
38
  | `-a`, `--all` | Include likely findings |
37
39
  | `--json` | Output JSON |
38
- | `--fix-prompt` | Output assistant instructions and separate manual actions |
40
+ | `--fix-prompt` | Output remediation instructions and separate manual actions |
39
41
  | `--report[=file]` | Write HTML; default: `canship-report.html` |
40
42
  | `--sarif[=file]` | Write SARIF 2.1.0; default: `canship.sarif` |
41
43
  | `--best-effort` | Permit exit `0` for an incomplete scan with no findings |
42
44
  | `--baseline[=file]` | Apply a baseline; default: `canship-baseline.json` |
43
- | `--baseline-write[=file]` | Record current findings as a baseline and exit |
45
+ | `--baseline-write[=file]` | Write current findings as a baseline and exit; same default path |
44
46
  | `--only=ids` | Run matching rules; comma-separated and repeatable |
45
47
  | `--skip=ids` | Exclude matching rules; comma-separated and repeatable |
46
48
  | `--no-config` | Ignore project configuration |
49
+ | `--no-ignore-markers` | Disregard ignore markers in scanned source |
50
+ | `--list-rules` | List rules and limits without scanning; supports `--json` |
51
+ | `--no-excerpts` | Omit source excerpts from every report; preserve findings and exit status |
47
52
  | `-h`, `--help` | Show help |
48
53
  | `-v`, `--version` | Show version |
49
54
 
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.
55
+ `--json` and `--fix-prompt` are mutually exclusive; HTML and SARIF work with either. Reports are in English. `--all` applies to every format.
51
56
 
52
57
  ### Exit codes
53
58
 
54
59
  | Code | Meaning |
55
60
  |---|---|
56
- | `0` | No findings and a complete scan, or an incomplete scan accepted with `--best-effort` |
61
+ | `0` | No findings, with a complete scan or an incomplete scan accepted by `--best-effort` |
57
62
  | `1` | At least one certain P0/P1 finding |
58
63
  | `2` | Other findings, including hidden likely findings |
59
64
  | `3` | Invalid arguments, a tool error, or an unaccepted incomplete scan |
60
65
 
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.
66
+ Finding exit codes take precedence over incompleteness; `--best-effort` does not change `1` or `2`.
67
+
68
+ ### Machine-readable output
69
+
70
+ JSON uses `schemaVersion: 1`, independent of the package version; the npm package includes its [schema](./schemas/scan-report-v1.schema.json). Accept additive fields and reject unsupported schema versions. `--list-rules --json` is a separate `kind: "rule-catalog"` document.
71
+
72
+ `findings` contains results after suppressions and filtering; `hiddenLikely`, `baselineSuppressed`, and `baselineStale` provide related counts. Check coverage separately through `partial`, `errors`, `skipped`, and `filesScanned`. SARIF includes execution status and diagnostic notifications.
73
+
74
+ ## GitHub Action
75
+
76
+ Save as `.github/workflows/canship.yml` to scan on pushes and pull requests, with a counts-only summary. Scanner installation requires network access; scanning does not. Project dependencies are not installed or executed, and SARIF upload is disabled by default.
77
+
78
+ The example pins the Action commit and explicitly installs npm version `0.3.0`; `version` does not use unreleased repository source. The Action accepts 0.2.1 reports without `schemaVersion`.
62
79
 
63
- ## Configuration and suppressions
80
+ ```yaml
81
+ name: canship
82
+ on: [push, pull_request]
83
+ permissions:
84
+ contents: read
85
+ jobs:
86
+ scan:
87
+ runs-on: ubuntu-latest
88
+ steps:
89
+ - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803
90
+ with:
91
+ fetch-depth: 0
92
+ persist-credentials: false
93
+ - uses: Tasomei/canship@8b1a3aa88c77e92e2806b343af6003372855bc70
94
+ with:
95
+ version: '0.3.0'
96
+ ```
97
+
98
+ | Input | Default | Meaning |
99
+ |---|---|---|
100
+ | `path` | `.` | Directory within the checkout |
101
+ | `version` | `0.3.0` | Exact npm version; no ranges or tags |
102
+ | `fail-on` | `blocking` | `blocking`: certain P0/P1; `any`: all findings; `none`: findings only reported |
103
+ | `only` / `skip` | unset | Mutually exclusive, comma-separated rule selectors |
104
+ | `baseline` | unset | Existing baseline relative to the scanned directory |
105
+ | `use-config` | `false` | Enable project configuration |
106
+ | `upload-sarif` | `false` | Upload SARIF to GitHub code scanning |
107
+ | `category` | `canship` | Distinct SARIF category for each scan target |
108
+
109
+ Outputs: `exit-code`, `findings`, `blocking`, `partial`. Policies include likely findings; baselines and exclusions still apply. Incomplete scans, tool errors, and incompatible reports always fail, including with `fail-on: none`.
110
+
111
+ SARIF upload requires `security-events: write` and [GitHub code scanning support](https://docs.github.com/en/code-security/how-tos/find-and-fix-code-vulnerabilities/integrate-with-existing-tools/upload-sarif-file); fork PRs may lack permission. Review paths and finding details before upload. Use `pull_request`, not `pull_request_target`, for untrusted PRs. The Action sets Node.js 22 for subsequent steps; use a separate scan job if another version is needed.
112
+
113
+ ## Configuration and baselines
64
114
 
65
115
  Place `canship.config.json` in the scanned directory. Supported keys: `baseline`, `only`, `skip`, `all`.
66
116
 
@@ -71,18 +121,20 @@ Place `canship.config.json` in the scanned directory. Supported keys: `baseline`
71
121
  }
72
122
  ```
73
123
 
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.
124
+ CLI options take precedence. `only` and `skip` are mutually exclusive and accept rule IDs or namespaces. Unselected rules do not run; `ruleSelection.removed` counts filtered findings only from executed rules. For untrusted projects use `--no-config --no-ignore-markers`; the scanned project controls both. `bestEffort` is CLI-only.
125
+
126
+ ### Ignore markers
75
127
 
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:
128
+ A standalone `canship-ignore-file` comment excludes a file; `canship-ignore-next-line` suppresses the next line, with an optional rule ID:
77
129
 
78
130
  ```ts
79
131
  // canship-ignore-next-line cors/wildcard-with-credentials
80
132
  const corsOptions = { origin: '*', credentials: true }
81
133
  ```
82
134
 
83
- Reports disclose exclusions, rule selection, and baseline suppression. Deliberate exclusions do not make the scan incomplete.
135
+ Reports disclose exclusions, rule selection, and baseline suppression. Deliberate exclusions do not mark the scan incomplete. Markers can lower the exit code to `0`; `--no-config` does not affect them, `--no-ignore-markers` disables both kinds.
84
136
 
85
- ## Baselines
137
+ ### Baselines
86
138
 
87
139
  Record existing findings:
88
140
 
@@ -96,21 +148,22 @@ Report only new findings:
96
148
  npx canship --baseline
97
149
  ```
98
150
 
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.
151
+ The default baseline is in the scanned directory; explicit paths are relative to the working directory. A successful write exits `0`, regardless of findings; incomplete or selectively scanned input produces a warning.
100
152
 
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`.
153
+ Baseline format v2 fingerprints survive line moves but change when credentials change. Missing, malformed, and v1 baselines exit `3`. Baselines omit source but retain paths, rules, and issue descriptions; review before committing.
102
154
 
103
- ## Limitations
155
+ ## Privacy and limitations
104
156
 
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.
157
+ - Static analysis may produce false positives or negatives. Deployed behaviour, rate limiting, injection, dependency vulnerabilities, and business authorisation are outside scope. No findings does not prove security.
158
+ - Redaction covers recognised formats only; unknown secrets may appear in source excerpts. `--no-excerpts` omits excerpts, recorded as `excerptsOmitted` in JSON. Paths, names, descriptions, and baselines are not anonymised; review before sharing.
159
+ - Google/Firebase/Maps `AIza...` values are public identifiers, not evidence of a leak on their own.
160
+ - Read limits: 2 MiB per file, 128 MiB and 10,000 files per scan, 16 directory levels. At most 100 findings per file across rules, prioritising severity and confidence.
161
+ - Git history checks cover up to 100 relevant revisions per file, with a 30-second timeout per Git command. Exceeded limits and timeouts report coverage gaps.
162
+ - Symbolic links are not followed; scan nested repositories and submodules separately. Skipped paths within scope mark the scan incomplete; built-in build and dependency exclusions do not.
110
163
 
111
164
  ## Development
112
165
 
113
- Detection rules require positive and negative cases; see [test fixtures](./test/fixtures/).
166
+ New rules require positive and negative [test cases](./test/fixtures/).
114
167
 
115
168
  ```powershell
116
169
  npm ci
@@ -120,6 +173,28 @@ npm ci
120
173
  npm run prepublishOnly
121
174
  ```
122
175
 
176
+ Offline evaluation:
177
+
178
+ ```powershell
179
+ npm run evaluate
180
+ ```
181
+
182
+ The corpus has 10 synthetic cases and nine pinned upstream examples and mutations, also run by `npm test`. [Sources and licences](./test/fixtures/evaluation/) accompany the fixtures. Assertions cover rules, files, severity, confidence, and coverage, not real-world detection rates.
183
+
184
+ Five [application-directory snapshots](./test/evaluation/projects.json) provide additional evaluation. Preparation uses the network and verifies Git object hashes; the target must be a new directory outside Git:
185
+
186
+ ```powershell
187
+ node scripts/fetch-evaluation-projects.mjs "$env:TEMP/canship-evaluation"
188
+ ```
189
+
190
+ Then evaluate offline without installing or running sample dependencies:
191
+
192
+ ```powershell
193
+ npm run evaluate:projects -- "$env:TEMP/canship-evaluation"
194
+ ```
195
+
196
+ CI uses the same corpus. Git history and deployed behaviour are outside this evaluation.
197
+
123
198
  ## License
124
199
 
125
- [MIT](./LICENSE)
200
+ [MIT](./LICENSE). Supabase and Firebase fixtures retain Apache-2.0; Next.js and `cors` fixtures retain MIT. Each includes its source and licence.