oauthlint 0.2.4 → 0.4.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/README.md CHANGED
@@ -63,8 +63,9 @@ oauthlint gives you is the work most people never do:
63
63
  ([validation report](https://oauthlint.dev/VALIDATION)).
64
64
  - **One coherent product across every language it covers.** Same concepts, same ID scheme,
65
65
  same docs — not a patchwork of community rules with mismatched styles.
66
- - **Every finding teaches.** All 90 rules link to a fix page with CWE and OWASP
67
- mappings. It's a lesson, not a grep hit.
66
+ - **Every finding teaches.** The 100+ rules across JS/TS · Python · Go · Java
67
+ · Rust — each link to a fix page with CWE and OWASP mappings. It's a lesson,
68
+ not a grep hit.
68
69
  - **The angle the registry doesn't have:** oauthlint specifically targets the
69
70
  auth bugs AI coding tools ship on repeat, encoded in each rule's
70
71
  `llm-prevalence` metadata and measured by a [reproducible benchmark](https://github.com/Auspeo/oauthlint/tree/main/benchmark).
@@ -89,22 +90,121 @@ npx oauthlint scan ./src --format sarif > oauthlint.sarif
89
90
 
90
91
  # auto-apply safe fixes (e.g. cookie flags)
91
92
  npx oauthlint scan ./src --fix
93
+
94
+ # scan several explicit paths (e.g. a list of changed files)
95
+ npx oauthlint scan src/auth.ts src/session.ts
96
+
97
+ # scan only what changed vs the default branch (fast, incremental)
98
+ npx oauthlint scan --diff
99
+
100
+ # scan only git-staged files (ideal in a pre-commit hook)
101
+ npx oauthlint scan --staged
102
+
103
+ # adopt on a large existing codebase: snapshot today's findings…
104
+ npx oauthlint baseline ./src
105
+ # …then only get alerted on NEW findings from here on
106
+ npx oauthlint scan ./src --baseline --fail-on HIGH
107
+ ```
108
+
109
+ ## Adopting on an existing codebase (baseline)
110
+
111
+ Turning a linter on for the first time on a large repo usually drowns you in
112
+ pre-existing findings. A **baseline** snapshots the findings that exist *today*
113
+ so `scan` only alerts on **new** ones — letting you adopt OAuthLint without
114
+ fixing everything up front.
115
+
116
+ ```bash
117
+ # 1. capture the current findings into .oauthlint-baseline.json (commit this file)
118
+ oauthlint baseline ./src
119
+
120
+ # 2. from now on, scan reports only findings NOT in the baseline
121
+ oauthlint scan ./src --baseline --fail-on HIGH
122
+ ```
123
+
124
+ - **`oauthlint baseline [paths...]`** scans and writes
125
+ `.oauthlint-baseline.json` (override with `-o, --output <file>`). It prints how
126
+ many findings were baselined. Commit the file so the whole team shares it.
127
+ - **`oauthlint scan --baseline [file]`** runs a normal scan, then suppresses any
128
+ finding already in the baseline and reports only the rest. `--fail-on` and the
129
+ exit code consider **only the new findings**. With no value it defaults to
130
+ `.oauthlint-baseline.json`; a missing baseline file is a **clear error**
131
+ (exit `2`), never silently treated as empty.
132
+
133
+ **How a finding is fingerprinted.** Each finding gets a stable fingerprint —
134
+ `sha256(oauthlintRuleId + repo-relative path + a whitespace-normalised snapshot
135
+ of the matched code)`. Crucially the **raw line number is not part of the hash**,
136
+ so moving a finding up or down (adding imports, reformatting) keeps it
137
+ baselined, while **changing the flagged code** surfaces it as new. The same
138
+ fingerprint occurring multiple times in one file is disambiguated by a
139
+ deterministic occurrence index. Paths are normalised to repo/cwd-relative
140
+ (POSIX separators) so a baseline is portable across machines, and unreadable
141
+ files (deleted/binary) degrade gracefully instead of crashing. The baseline
142
+ JSON is small, sorted and human-diffable (a `version`, a `generatedAt`, and the
143
+ fingerprint list).
144
+
145
+ ## Incremental scanning
146
+
147
+ For pre-commit hooks and editor integrations, scanning the whole tree on every
148
+ keystroke is wasteful. OAuthLint can scan **only the files that changed**:
149
+
150
+ ```bash
151
+ # files changed vs the merge-base with the repo's default branch
152
+ oauthlint scan --diff
153
+
154
+ # files changed vs an explicit ref (branch, tag, or commit)
155
+ oauthlint scan --diff origin/main
156
+ oauthlint scan --diff HEAD~5
157
+
158
+ # only git-staged files — drop this in a pre-commit hook
159
+ oauthlint scan --staged --fail-on HIGH
160
+ ```
161
+
162
+ How the change set is resolved:
163
+
164
+ - **`--diff [ref]`** — when no `ref` is given, the base is the merge-base with the
165
+ repo's default branch (`origin/HEAD` → `origin/main` → `origin/master`, falling
166
+ back to `HEAD` when there's no remote). The change set is everything Added /
167
+ Copied / Modified / Renamed since that base, plus uncommitted work-tree and
168
+ staged changes, plus new untracked files. Deleted files are skipped.
169
+ - **`--staged`** — only the staged set (`git diff --cached`), the same files a
170
+ commit is about to capture.
171
+ - Explicit path args (`oauthlint scan a.ts b.ts`) scan exactly those paths.
172
+
173
+ In every mode, files in a language the rule pack doesn't cover (Markdown,
174
+ lockfiles, images, …) are filtered out automatically, and an **empty change set
175
+ exits `0`** with a `No changed files to scan.` note — it never fails your commit.
176
+ Outside a git repository, `--diff` / `--staged` print a clear error and exit `2`
177
+ instead of crashing. Git is always invoked with arguments passed as an array
178
+ (never a shell string), so a ref name can't inject a shell command.
179
+
180
+ Example pre-commit hook (`.git/hooks/pre-commit`):
181
+
182
+ ```bash
183
+ #!/bin/sh
184
+ npx oauthlint scan --staged --fail-on HIGH
92
185
  ```
93
186
 
94
187
  ## Commands
95
188
 
96
189
  ```
97
- oauthlint scan [path] Scan a directory (default: current dir)
190
+ oauthlint scan [paths...] Scan files/directories (default: current dir)
191
+ oauthlint scan a.ts b.ts Scan an explicit list of paths
192
+ oauthlint scan --diff [ref] Scan only files changed vs a git ref
193
+ oauthlint scan --staged Scan only git-staged files (pre-commit)
98
194
  oauthlint scan --json Emit machine-readable JSON
99
195
  oauthlint scan --format sarif Emit SARIF for GitHub Code Scanning
100
196
  oauthlint scan --severity HIGH Only show findings ≥ HIGH
101
197
  oauthlint scan --fail-on off Never fail the build (CI dry-run)
102
198
  oauthlint scan --fix Auto-apply safe fixes
199
+ oauthlint scan --baseline Report only findings NOT in the baseline
200
+ oauthlint baseline [paths...] Snapshot current findings to a baseline file
201
+ oauthlint baseline -o <file> Write the baseline to a custom path
103
202
  oauthlint list List every shipped rule
104
203
  oauthlint list --json Same, as JSON
105
204
  oauthlint init Generate .oauthlintrc.yml at cwd
106
205
  oauthlint init --force Overwrite an existing config
107
206
  oauthlint doctor Check your setup (Semgrep, config, …)
207
+ oauthlint --no-update-check Skip the "update available" check (any command)
108
208
  ```
109
209
 
110
210
  ## Use it in CI
@@ -128,8 +228,20 @@ jobs:
128
228
 
129
229
  Or just fail the build on HIGH findings: `npx oauthlint scan ./src --fail-on HIGH`.
130
230
 
131
- > A dedicated **GitHub Action** and a **VS Code extension** (inline diagnostics +
132
- > Quick Fix suppressions) are on the way — follow the [repo](https://github.com/Auspeo/oauthlint) for releases.
231
+ ### GitHub Action
232
+
233
+ Prefer not to wire up the CLI by hand? The **[GitHub Action](https://github.com/Auspeo/oauthlint/tree/main/action)** wraps it for you — it's Docker-based, so it runs in any repo regardless of language:
234
+
235
+ ```yaml
236
+ - uses: Auspeo/oauthlint/action@v1
237
+ with:
238
+ severity: HIGH
239
+ fail-on: HIGH
240
+ ```
241
+
242
+ ### VS Code extension
243
+
244
+ Catch findings as you type. Install **[oauthlint](https://marketplace.visualstudio.com/items?itemName=auspeo.oauthlint-vscode)** (`auspeo.oauthlint-vscode`) from the VS Code Marketplace for inline diagnostics on save, plus Quick Fix suppressions.
133
245
 
134
246
  ## What it catches
135
247
 
@@ -179,9 +291,26 @@ the next reviewer needs to see exactly which lines opted out, and why.
179
291
  |:----:|------|
180
292
  | `0` | No finding at or above the `--fail-on` threshold |
181
293
  | `1` | At least one **HIGH** finding |
182
- | `2` | At least one **CRITICAL** finding, or a scan whose output could not be parsed (it never silently exits clean) |
294
+ | `2` | At least one **CRITICAL** finding, a scan whose output could not be parsed (it never silently exits clean), or a missing/malformed `--baseline` file |
183
295
  | `127` | Semgrep is not installed |
184
296
 
297
+ > With `--baseline`, the `--fail-on` gate and these exit codes consider only the
298
+ > **new** (non-baselined) findings.
299
+
300
+ ## Stay up to date
301
+
302
+ oauthlint occasionally prints a short *"Update available"* notice to **stderr**
303
+ when a newer version is on npm. It's designed to stay out of your way:
304
+
305
+ - It's **non-blocking** and checks npm at most **once a day** (the result is
306
+ cached), so it never slows a scan down.
307
+ - It writes to **stderr only** and is **silent** under `--json` / `--format
308
+ sarif`, when output is piped, in CI, and offline — so it can never corrupt a
309
+ machine-readable report or nag automated runs.
310
+
311
+ To turn it off entirely, pass `--no-update-check` or set the standard
312
+ `NO_UPDATE_NOTIFIER=1` environment variable.
313
+
185
314
  ## License
186
315
 
187
316
  MIT — see [LICENSE](https://github.com/Auspeo/oauthlint/blob/main/LICENSE).
@@ -24,7 +24,12 @@ export declare class SemgrepAdapter {
24
24
  private readonly cwd?;
25
25
  constructor(opts: SemgrepAdapterOptions);
26
26
  /**
27
- * Run semgrep against `targetPath`, returning a normalised scan result.
27
+ * Run semgrep against one or more targets, returning a normalised scan
28
+ * result. `target` may be a single path (directory or file) or an explicit
29
+ * list of files — Semgrep accepts multiple targets natively, which is how
30
+ * incremental scanning (`--diff` / `--staged` / explicit file args) only
31
+ * pays for the files that actually changed.
32
+ *
28
33
  * When `applyFixes` is true, Semgrep rewrites the source files in place
29
34
  * using each rule's `fix:` template. The returned report reflects what
30
35
  * was matched BEFORE the rewrite — callers should re-scan if they want
@@ -32,7 +37,7 @@ export declare class SemgrepAdapter {
32
37
  *
33
38
  * @throws SemgrepNotInstalledError if the binary cannot be found.
34
39
  */
35
- scan(targetPath: string, options?: {
40
+ scan(target: string | string[], options?: {
36
41
  applyFixes?: boolean;
37
42
  }): Promise<ScanResult>;
38
43
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"semgrep.d.ts","sourceRoot":"","sources":["../../src/adapters/semgrep.ts"],"names":[],"mappings":"AACA,OAAO,EAAsC,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AA6BlF,qBAAa,wBAAyB,SAAQ,KAAK;;CASlD;AAED;;;;GAIG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAO7C;AAED,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAS;gBAElB,IAAI,EAAE,qBAAqB;IAMvC;;;;;;;;OAQG;IACG,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAA;KAAO,GAAG,OAAO,CAAC,UAAU,CAAC;IAyD3F;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAS3C;AA4CD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGrD"}
1
+ {"version":3,"file":"semgrep.d.ts","sourceRoot":"","sources":["../../src/adapters/semgrep.ts"],"names":[],"mappings":"AACA,OAAO,EAAsC,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AA6BlF,qBAAa,wBAAyB,SAAQ,KAAK;;CASlD;AAED;;;;GAIG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;CAO7C;AAED,MAAM,WAAW,qBAAqB;IACpC,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAS;gBAElB,IAAI,EAAE,qBAAqB;IAMvC;;;;;;;;;;;;;OAaG;IACG,IAAI,CACR,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,EACzB,OAAO,GAAE;QAAE,UAAU,CAAC,EAAE,OAAO,CAAA;KAAO,GACrC,OAAO,CAAC,UAAU,CAAC;IA6DtB;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAS3C;AA4CD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGrD"}
@@ -30,7 +30,12 @@ export class SemgrepAdapter {
30
30
  this.cwd = opts.cwd;
31
31
  }
32
32
  /**
33
- * Run semgrep against `targetPath`, returning a normalised scan result.
33
+ * Run semgrep against one or more targets, returning a normalised scan
34
+ * result. `target` may be a single path (directory or file) or an explicit
35
+ * list of files — Semgrep accepts multiple targets natively, which is how
36
+ * incremental scanning (`--diff` / `--staged` / explicit file args) only
37
+ * pays for the files that actually changed.
38
+ *
34
39
  * When `applyFixes` is true, Semgrep rewrites the source files in place
35
40
  * using each rule's `fix:` template. The returned report reflects what
36
41
  * was matched BEFORE the rewrite — callers should re-scan if they want
@@ -38,8 +43,9 @@ export class SemgrepAdapter {
38
43
  *
39
44
  * @throws SemgrepNotInstalledError if the binary cannot be found.
40
45
  */
41
- async scan(targetPath, options = {}) {
46
+ async scan(target, options = {}) {
42
47
  const start = Date.now();
48
+ const targets = Array.isArray(target) ? target : [target];
43
49
  const args = [
44
50
  'scan',
45
51
  '--config',
@@ -51,7 +57,10 @@ export class SemgrepAdapter {
51
57
  ];
52
58
  if (options.applyFixes)
53
59
  args.push('--autofix');
54
- args.push(targetPath);
60
+ // `--` terminates option parsing so a path that starts with `-` is never
61
+ // mistaken for a flag. Targets are passed as discrete argv entries (never a
62
+ // shell string), so there is no shell-injection surface.
63
+ args.push('--', ...targets);
55
64
  let result;
56
65
  try {
57
66
  result = await execa(this.binary, args, {
@@ -1 +1 @@
1
- {"version":3,"file":"semgrep.js","sourceRoot":"","sources":["../../src/adapters/semgrep.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"semgrep.js","sourceRoot":"","sources":["../../src/adapters/semgrep.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoDpC,wBAAsB,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,CAgErD"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyEpC,wBAAsB,YAAY,IAAI,OAAO,CAAC,OAAO,CAAC,CAwHrD"}
package/dist/cli.js CHANGED
@@ -3,10 +3,12 @@ import { dirname, resolve } from 'node:path';
3
3
  import { fileURLToPath } from 'node:url';
4
4
  import { Command } from 'commander';
5
5
  import pc from 'picocolors';
6
+ import { runBaseline } from './commands/baseline.js';
6
7
  import { runDoctor } from './commands/doctor.js';
7
8
  import { runInit } from './commands/init.js';
8
9
  import { runList } from './commands/list.js';
9
10
  import { runScan } from './commands/scan.js';
11
+ import { maybeNotifyUpdate } from './core/update-notifier.js';
10
12
  import { SEVERITIES } from './types.js';
11
13
  /**
12
14
  * Exit only once buffered stdout/stderr have drained.
@@ -28,6 +30,21 @@ async function exitAfterFlush(code) {
28
30
  await Promise.all([flush(process.stdout), flush(process.stderr)]);
29
31
  process.exit(code);
30
32
  }
33
+ /**
34
+ * Print the "update available" notice (when allowed) AFTER the command's normal
35
+ * output, then exit once everything is flushed. The notifier is fire-and-forget
36
+ * and self-suppressing: it never blocks, never touches stdout, and is silent
37
+ * under `--json`/`--format sarif`, in CI, when piped, when `NO_UPDATE_NOTIFIER`
38
+ * is set, or when `--no-update-check` is passed.
39
+ */
40
+ async function finishWithNotice(code, ctx) {
41
+ await maybeNotifyUpdate({
42
+ currentVersion: ctx.version,
43
+ machineReadable: ctx.machineReadable,
44
+ disabled: !ctx.updateCheck,
45
+ });
46
+ return exitAfterFlush(code);
47
+ }
31
48
  async function readPackageVersion() {
32
49
  const here = dirname(fileURLToPath(import.meta.url));
33
50
  // dist/cli.js → ../package.json (when published)
@@ -53,49 +70,94 @@ export async function buildProgram() {
53
70
  program
54
71
  .name('oauthlint')
55
72
  .description('OAuthLint — catch the OAuth/OIDC/JWT anti-patterns AI coding tools systematically produce.')
56
- .version(version, '-v, --version');
73
+ .version(version, '-v, --version')
74
+ .option('--no-update-check', 'Do not check npm for a newer oauthlint version');
75
+ // Resolve the global update-check opt-out once, lazily, from the root program.
76
+ // Commander sets `updateCheck: false` when `--no-update-check` is given.
77
+ const updateCheckEnabled = () => program.opts().updateCheck !== false;
57
78
  program
58
79
  .command('scan')
59
- .argument('[path]', 'Path to scan', '.')
60
- .description('Scan a directory for auth misconfigurations')
80
+ .argument('[paths...]', 'One or more files/directories to scan', ['.'])
81
+ .description('Scan files or directories for auth misconfigurations')
61
82
  .option('--json', 'Emit JSON (shortcut for --format json)')
62
83
  .option('--format <fmt>', 'Output format: pretty | json | sarif', parseFormat)
63
84
  .option('--severity <level>', 'Only emit findings ≥ this severity', parseSeverity)
64
85
  .option('--fail-on <level>', 'Process exits non-zero if any finding ≥ this severity', parseFailOn)
86
+ .option('--diff [ref]', 'Scan only files changed vs a git ref (default: merge-base with the default branch)')
87
+ .option('--staged', 'Scan only git-staged files (useful for pre-commit hooks)')
65
88
  .option('--rules-dir <path>', 'Override the bundled rules directory')
66
89
  .option('--fix', 'Apply auto-fixes (rewrites source in place where possible)')
67
- .action(async (path, opts) => {
90
+ .option('--baseline [file]', 'Suppress findings already in a baseline file; report only NEW findings (default: .oauthlint-baseline.json)')
91
+ .action(async (paths, opts) => {
68
92
  const code = await runScan({
69
- path,
93
+ paths,
94
+ diff: opts.diff,
95
+ staged: opts.staged,
70
96
  json: opts.json,
71
97
  format: opts.format,
72
98
  severity: opts.severity,
73
99
  failOn: opts.failOn,
74
100
  rulesDir: opts.rulesDir,
75
101
  fix: opts.fix,
102
+ baseline: opts.baseline,
103
+ });
104
+ const machineReadable = opts.json === true || opts.format === 'json' || opts.format === 'sarif';
105
+ await finishWithNotice(code, { version, machineReadable, updateCheck: updateCheckEnabled() });
106
+ });
107
+ program
108
+ .command('baseline')
109
+ .argument('[paths...]', 'One or more files/directories to scan', ['.'])
110
+ .description('Scan and write a baseline of current findings (for adopting on an existing codebase)')
111
+ .option('-o, --output <file>', 'Where to write the baseline JSON', '.oauthlint-baseline.json')
112
+ .option('--rules-dir <path>', 'Override the bundled rules directory')
113
+ .action(async (paths, opts) => {
114
+ const code = await runBaseline({
115
+ paths,
116
+ output: opts.output,
117
+ rulesDir: opts.rulesDir,
118
+ });
119
+ // baseline writes a JSON file but its stdout is a human summary.
120
+ await finishWithNotice(code, {
121
+ version,
122
+ machineReadable: false,
123
+ updateCheck: updateCheckEnabled(),
76
124
  });
77
- await exitAfterFlush(code);
78
125
  });
79
126
  program
80
127
  .command('list')
81
128
  .description('List every rule the current install ships with')
82
129
  .option('--json', 'Emit JSON instead of pretty output')
83
130
  .action(async (opts) => {
84
- await exitAfterFlush(await runList({ json: opts.json }));
131
+ const code = await runList({ json: opts.json });
132
+ await finishWithNotice(code, {
133
+ version,
134
+ machineReadable: opts.json === true,
135
+ updateCheck: updateCheckEnabled(),
136
+ });
85
137
  });
86
138
  program
87
139
  .command('init')
88
140
  .description('Generate a .oauthlintrc.yml at the current directory')
89
141
  .option('-f, --force', 'Overwrite an existing config file')
90
142
  .action(async (opts) => {
91
- await exitAfterFlush(await runInit({ cwd: process.cwd(), force: opts.force }));
143
+ const code = await runInit({ cwd: process.cwd(), force: opts.force });
144
+ await finishWithNotice(code, {
145
+ version,
146
+ machineReadable: false,
147
+ updateCheck: updateCheckEnabled(),
148
+ });
92
149
  });
93
150
  program
94
151
  .command('doctor')
95
152
  .description('Diagnose your OAuthLint install (Node, Semgrep, rule pack)')
96
153
  .option('--json', 'Emit JSON instead of pretty output')
97
154
  .action(async (opts) => {
98
- await exitAfterFlush(await runDoctor({ json: opts.json }));
155
+ const code = await runDoctor({ json: opts.json });
156
+ await finishWithNotice(code, {
157
+ version,
158
+ machineReadable: opts.json === true,
159
+ updateCheck: updateCheckEnabled(),
160
+ });
99
161
  });
100
162
  program.showHelpAfterError(pc.dim('(run `oauthlint --help` for available commands)'));
101
163
  return program;
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { SemgrepAdapter } from '../adapters/semgrep.js';
2
+ export interface BaselineCommandOptions {
3
+ /** Path(s) to scan when capturing the baseline. Defaults to `['.']`. */
4
+ paths?: string[];
5
+ /** Where to write the baseline JSON. Defaults to `.oauthlint-baseline.json`. */
6
+ output?: string;
7
+ rulesDir?: string;
8
+ /** Used by tests to inject a mock adapter. */
9
+ adapter?: SemgrepAdapter;
10
+ /** Used by tests to capture output. */
11
+ stream?: NodeJS.WritableStream;
12
+ /** Override the directory git/relative paths resolve from (defaults to cwd). */
13
+ cwd?: string;
14
+ }
15
+ /**
16
+ * `oauthlint baseline [paths...]` — scan the codebase and write a baseline file
17
+ * capturing the CURRENT findings by stable fingerprint, so a later
18
+ * `scan --baseline` only surfaces NEW findings.
19
+ */
20
+ export declare function runBaseline(opts: BaselineCommandOptions): Promise<number>;
21
+ //# sourceMappingURL=baseline.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../../src/commands/baseline.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,cAAc,EAGf,MAAM,wBAAwB,CAAC;AAMhC,MAAM,WAAW,sBAAsB;IACrC,wEAAwE;IACxE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,gFAAgF;IAChF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CA+C/E"}
@@ -0,0 +1,50 @@
1
+ import { writeFile } from 'node:fs/promises';
2
+ import { resolve } from 'node:path';
3
+ import { RULES_ROOT } from 'oauthlint-rules';
4
+ import pc from 'picocolors';
5
+ import { SemgrepAdapter, SemgrepNotInstalledError, SemgrepOutputError, } from '../adapters/semgrep.js';
6
+ import { DEFAULT_BASELINE_FILE, buildBaseline, serialiseBaseline } from '../core/baseline.js';
7
+ import { loadConfig } from '../core/config.js';
8
+ import { applySuppressions } from '../core/suppress.js';
9
+ /**
10
+ * `oauthlint baseline [paths...]` — scan the codebase and write a baseline file
11
+ * capturing the CURRENT findings by stable fingerprint, so a later
12
+ * `scan --baseline` only surfaces NEW findings.
13
+ */
14
+ export async function runBaseline(opts) {
15
+ const cwd = opts.cwd ?? process.cwd();
16
+ const config = await loadConfig(cwd);
17
+ const rulesDir = opts.rulesDir ?? config.customRulesDir ?? RULES_ROOT;
18
+ const stream = opts.stream ?? process.stdout;
19
+ const errStream = opts.stream ?? process.stderr;
20
+ const requested = opts.paths?.length ? opts.paths : ['.'];
21
+ const targets = requested.map((p) => resolve(cwd, p));
22
+ const adapter = opts.adapter ?? new SemgrepAdapter({ configPath: rulesDir });
23
+ let result;
24
+ try {
25
+ result = await adapter.scan(targets);
26
+ }
27
+ catch (err) {
28
+ if (err instanceof SemgrepNotInstalledError) {
29
+ errStream.write(`${err.message}\n`);
30
+ return 127;
31
+ }
32
+ if (err instanceof SemgrepOutputError) {
33
+ errStream.write(`${err.message}\n`);
34
+ return 2;
35
+ }
36
+ throw err;
37
+ }
38
+ // Honour inline suppression directives so the baseline mirrors what `scan`
39
+ // would actually report (we don't want to baseline already-suppressed noise).
40
+ const { kept } = await applySuppressions(result.findings);
41
+ const findings = kept;
42
+ const outputPath = resolve(cwd, opts.output ?? DEFAULT_BASELINE_FILE);
43
+ const baseline = await buildBaseline(findings, cwd);
44
+ await writeFile(outputPath, serialiseBaseline(baseline), 'utf8');
45
+ const n = baseline.findings.length;
46
+ stream.write(pc.green(`✓ Baselined ${n} finding${n === 1 ? '' : 's'} → ${opts.output ?? DEFAULT_BASELINE_FILE}\n`));
47
+ stream.write(pc.dim(`Future runs of ${pc.bold('oauthlint scan --baseline')} will report only NEW findings.\n`));
48
+ return 0;
49
+ }
50
+ //# sourceMappingURL=baseline.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baseline.js","sourceRoot":"","sources":["../../src/commands/baseline.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAC9F,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAiBxD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAA4B;IAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACtC,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,GAAG,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAC,cAAc,IAAI,UAAU,CAAC;IACtE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,CAAC;IAEhD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IAEtD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,cAAc,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC7E,IAAI,MAAmD,CAAC;IACxD,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,wBAAwB,EAAE,CAAC;YAC5C,SAAS,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;YACpC,OAAO,GAAG,CAAC;QACb,CAAC;QACD,IAAI,GAAG,YAAY,kBAAkB,EAAE,CAAC;YACtC,SAAS,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC;YACpC,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,2EAA2E;IAC3E,8EAA8E;IAC9E,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,iBAAiB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1D,MAAM,QAAQ,GAAc,IAAI,CAAC;IAEjC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,MAAM,IAAI,qBAAqB,CAAC,CAAC;IACtE,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IACpD,MAAM,SAAS,CAAC,UAAU,EAAE,iBAAiB,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC;IAEjE,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;IACnC,MAAM,CAAC,KAAK,CACV,EAAE,CAAC,KAAK,CACN,eAAe,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC,MAAM,IAAI,qBAAqB,IAAI,CAC5F,CACF,CAAC;IACF,MAAM,CAAC,KAAK,CACV,EAAE,CAAC,GAAG,CACJ,kBAAkB,EAAE,CAAC,IAAI,CAAC,2BAA2B,CAAC,mCAAmC,CAC1F,CACF,CAAC;IACF,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -4,6 +4,6 @@ export interface InitOptions {
4
4
  stream?: NodeJS.WritableStream;
5
5
  }
6
6
  export declare function runInit(opts: InitOptions): Promise<number>;
7
- export declare const __TEMPLATE = "# OAuthLint config\n# Documentation: https://oauthlint.dev/docs/config\nversion: 1\n\n# Files to scan\ninclude:\n - \"src/**/*.{ts,tsx,js,jsx,mjs,cjs}\"\nexclude:\n - \"**/*.test.{ts,tsx,js,jsx}\"\n - \"**/*.spec.{ts,tsx,js,jsx}\"\n - \"node_modules/**\"\n - \"dist/**\"\n - \"build/**\"\n\n# Per-rule overrides:\n# off \u2192 disable the rule\n# warn \u2192 emit but don't affect exit code\n# <SEV> \u2192 override severity (INFO | LOW | MEDIUM | HIGH | CRITICAL)\n# rules:\n# auth.cookie.no-samesite: warn\n# auth.session.id-in-url: off\n\n# Custom rules directory (in addition to the bundled rules)\n# customRulesDir: ./security/oauthlint-rules\n\n# Exit code policy: fail when any finding \u2265 this severity is present.\n# Use \"off\" to never fail the run.\nfailOn: HIGH\n";
7
+ export declare const __TEMPLATE = "# OAuthLint config\n# Documentation: https://oauthlint.dev/docs/configuration\nversion: 1\n\n# Files to scan\ninclude:\n - \"src/**/*.{ts,tsx,js,jsx,mjs,cjs}\"\nexclude:\n - \"**/*.test.{ts,tsx,js,jsx}\"\n - \"**/*.spec.{ts,tsx,js,jsx}\"\n - \"node_modules/**\"\n - \"dist/**\"\n - \"build/**\"\n\n# Per-rule overrides:\n# off \u2192 disable the rule\n# warn \u2192 emit but don't affect exit code\n# <SEV> \u2192 override severity (INFO | LOW | MEDIUM | HIGH | CRITICAL)\n# rules:\n# auth.cookie.no-samesite: warn\n# auth.session.id-in-url: off\n\n# Custom rules directory (in addition to the bundled rules)\n# customRulesDir: ./security/oauthlint-rules\n\n# Exit code policy: fail when any finding \u2265 this severity is present.\n# Use \"off\" to never fail the run.\nfailOn: HIGH\n";
8
8
  export declare const __join: (...paths: string[]) => string;
9
9
  //# sourceMappingURL=init.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAmCA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CAChC;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAWhE;AAGD,eAAO,MAAM,UAAU,syBAAW,CAAC;AAGnC,eAAO,MAAM,MAAM,gCAAO,CAAC"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAmCA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CAChC;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAWhE;AAGD,eAAO,MAAM,UAAU,6yBAAW,CAAC;AAGnC,eAAO,MAAM,MAAM,gCAAO,CAAC"}
@@ -3,7 +3,7 @@ import { writeFile } from 'node:fs/promises';
3
3
  import { join, resolve } from 'node:path';
4
4
  import pc from 'picocolors';
5
5
  const TEMPLATE = `# OAuthLint config
6
- # Documentation: https://oauthlint.dev/docs/config
6
+ # Documentation: https://oauthlint.dev/docs/configuration
7
7
  version: 1
8
8
 
9
9
  # Files to scan
@@ -2,7 +2,22 @@ import { SemgrepAdapter } from '../adapters/semgrep.js';
2
2
  import type { SeverityName } from '../types.js';
3
3
  export type ScanFormat = 'pretty' | 'json' | 'sarif';
4
4
  export interface ScanCommandOptions {
5
- path: string;
5
+ /**
6
+ * Path(s) to scan. Accepts one or many — e.g. a pre-commit hook or editor
7
+ * integration passing the list of changed files. Defaults to `['.']`.
8
+ * The legacy singular `path` is still honoured for backwards compatibility.
9
+ */
10
+ paths?: string[];
11
+ /** @deprecated single-path form, kept for backwards compatibility. */
12
+ path?: string;
13
+ /**
14
+ * Incremental: scan only files changed versus a git ref. When the flag is
15
+ * given without a value (`true`), the ref defaults to the merge-base with the
16
+ * repo's default branch (origin/HEAD → origin/main → origin/master → HEAD).
17
+ */
18
+ diff?: string | boolean;
19
+ /** Incremental: scan only git-staged files (`--cached`). For pre-commit. */
20
+ staged?: boolean;
6
21
  /** Legacy boolean — equivalent to `format: 'json'`. */
7
22
  json?: boolean;
8
23
  /** Output format. Overrides `json` when set. */
@@ -15,10 +30,19 @@ export interface ScanCommandOptions {
15
30
  * ship a `fix:` template. Currently the cookie-* rules.
16
31
  */
17
32
  fix?: boolean;
33
+ /**
34
+ * Suppress findings already captured in a baseline file, reporting only NEW
35
+ * findings. A bare `true` uses the default `.oauthlint-baseline.json`; a
36
+ * string is treated as an explicit baseline path. A missing file is a clear
37
+ * error, never silently an empty allow-list.
38
+ */
39
+ baseline?: string | boolean;
18
40
  /** Used by tests to inject a mock adapter. */
19
41
  adapter?: SemgrepAdapter;
20
42
  /** Used by tests to capture output. */
21
43
  stream?: NodeJS.WritableStream;
44
+ /** Override the directory git/relative paths resolve from (defaults to cwd). */
45
+ cwd?: string;
22
46
  }
23
47
  export declare function runScan(opts: ScanCommandOptions): Promise<number>;
24
48
  //# sourceMappingURL=scan.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,cAAc,EAGf,MAAM,wBAAwB,CAAC;AAMhC,OAAO,KAAK,EAAW,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,gDAAgD;IAChD,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,MAAM,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,8CAA8C;IAC9C,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;CAChC;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgEvE"}
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,cAAc,EAGf,MAAM,wBAAwB,CAAC;AAchC,OAAO,KAAK,EAAW,YAAY,EAAE,MAAM,aAAa,CAAC;AAEzD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,sEAAsE;IACtE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACxB,4EAA4E;IAC5E,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,uDAAuD;IACvD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,gDAAgD;IAChD,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,MAAM,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC5B,8CAA8C;IAC9C,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAC/B,gFAAgF;IAChF,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuJvE"}