oauthlint 0.2.4 → 0.3.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 +55 -1
- package/dist/adapters/semgrep.d.ts +7 -2
- package/dist/adapters/semgrep.d.ts.map +1 -1
- package/dist/adapters/semgrep.js +12 -3
- package/dist/adapters/semgrep.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +8 -4
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +1 -1
- package/dist/commands/scan.d.ts +18 -1
- package/dist/commands/scan.d.ts.map +1 -1
- package/dist/commands/scan.js +60 -4
- package/dist/commands/scan.js.map +1 -1
- package/dist/core/changed-files.d.ts +38 -0
- package/dist/core/changed-files.d.ts.map +1 -0
- package/dist/core/changed-files.js +186 -0
- package/dist/core/changed-files.js.map +1 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -89,12 +89,66 @@ npx oauthlint scan ./src --format sarif > oauthlint.sarif
|
|
|
89
89
|
|
|
90
90
|
# auto-apply safe fixes (e.g. cookie flags)
|
|
91
91
|
npx oauthlint scan ./src --fix
|
|
92
|
+
|
|
93
|
+
# scan several explicit paths (e.g. a list of changed files)
|
|
94
|
+
npx oauthlint scan src/auth.ts src/session.ts
|
|
95
|
+
|
|
96
|
+
# scan only what changed vs the default branch (fast, incremental)
|
|
97
|
+
npx oauthlint scan --diff
|
|
98
|
+
|
|
99
|
+
# scan only git-staged files (ideal in a pre-commit hook)
|
|
100
|
+
npx oauthlint scan --staged
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Incremental scanning
|
|
104
|
+
|
|
105
|
+
For pre-commit hooks and editor integrations, scanning the whole tree on every
|
|
106
|
+
keystroke is wasteful. OAuthLint can scan **only the files that changed**:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# files changed vs the merge-base with the repo's default branch
|
|
110
|
+
oauthlint scan --diff
|
|
111
|
+
|
|
112
|
+
# files changed vs an explicit ref (branch, tag, or commit)
|
|
113
|
+
oauthlint scan --diff origin/main
|
|
114
|
+
oauthlint scan --diff HEAD~5
|
|
115
|
+
|
|
116
|
+
# only git-staged files — drop this in a pre-commit hook
|
|
117
|
+
oauthlint scan --staged --fail-on HIGH
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
How the change set is resolved:
|
|
121
|
+
|
|
122
|
+
- **`--diff [ref]`** — when no `ref` is given, the base is the merge-base with the
|
|
123
|
+
repo's default branch (`origin/HEAD` → `origin/main` → `origin/master`, falling
|
|
124
|
+
back to `HEAD` when there's no remote). The change set is everything Added /
|
|
125
|
+
Copied / Modified / Renamed since that base, plus uncommitted work-tree and
|
|
126
|
+
staged changes, plus new untracked files. Deleted files are skipped.
|
|
127
|
+
- **`--staged`** — only the staged set (`git diff --cached`), the same files a
|
|
128
|
+
commit is about to capture.
|
|
129
|
+
- Explicit path args (`oauthlint scan a.ts b.ts`) scan exactly those paths.
|
|
130
|
+
|
|
131
|
+
In every mode, files in a language the rule pack doesn't cover (Markdown,
|
|
132
|
+
lockfiles, images, …) are filtered out automatically, and an **empty change set
|
|
133
|
+
exits `0`** with a `No changed files to scan.` note — it never fails your commit.
|
|
134
|
+
Outside a git repository, `--diff` / `--staged` print a clear error and exit `2`
|
|
135
|
+
instead of crashing. Git is always invoked with arguments passed as an array
|
|
136
|
+
(never a shell string), so a ref name can't inject a shell command.
|
|
137
|
+
|
|
138
|
+
Example pre-commit hook (`.git/hooks/pre-commit`):
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
#!/bin/sh
|
|
142
|
+
npx oauthlint scan --staged --fail-on HIGH
|
|
92
143
|
```
|
|
93
144
|
|
|
94
145
|
## Commands
|
|
95
146
|
|
|
96
147
|
```
|
|
97
|
-
oauthlint scan [
|
|
148
|
+
oauthlint scan [paths...] Scan files/directories (default: current dir)
|
|
149
|
+
oauthlint scan a.ts b.ts Scan an explicit list of paths
|
|
150
|
+
oauthlint scan --diff [ref] Scan only files changed vs a git ref
|
|
151
|
+
oauthlint scan --staged Scan only git-staged files (pre-commit)
|
|
98
152
|
oauthlint scan --json Emit machine-readable JSON
|
|
99
153
|
oauthlint scan --format sarif Emit SARIF for GitHub Code Scanning
|
|
100
154
|
oauthlint scan --severity HIGH Only show findings ≥ HIGH
|
|
@@ -24,7 +24,12 @@ export declare class SemgrepAdapter {
|
|
|
24
24
|
private readonly cwd?;
|
|
25
25
|
constructor(opts: SemgrepAdapterOptions);
|
|
26
26
|
/**
|
|
27
|
-
* Run semgrep against
|
|
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(
|
|
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
|
|
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"}
|
package/dist/adapters/semgrep.js
CHANGED
|
@@ -30,7 +30,12 @@ export class SemgrepAdapter {
|
|
|
30
30
|
this.cwd = opts.cwd;
|
|
31
31
|
}
|
|
32
32
|
/**
|
|
33
|
-
* Run semgrep against
|
|
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(
|
|
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
|
-
|
|
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":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC1C,OAAO,EAAgB,oBAAoB,EAAmB,MAAM,aAAa,CAAC;AA6BlF,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IACjD;QACE,KAAK,CACH,6BAA6B;YAC3B,uEAAuE;YACvE,iEAAiE,CACpE,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C,YAAY,MAAc,EAAE,OAAgB;QAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,oCAAoC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC1E,KAAK,CACH,mCAAmC,MAAM,2IAA2I,IAAI,EAAE,CAC3L,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;IACnC,CAAC;CACF;AAWD,MAAM,OAAO,cAAc;IACR,MAAM,CAAS;IACf,UAAU,CAAS;IACnB,GAAG,CAAU;IAE9B,YAAY,IAA2B;QACrC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,SAAS,CAAC;QACvC,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,CAAC;QAClC,IAAI,CAAC,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC;IACtB,CAAC;IAED
|
|
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,
|
|
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,CAuErD"}
|
package/dist/cli.js
CHANGED
|
@@ -56,17 +56,21 @@ export async function buildProgram() {
|
|
|
56
56
|
.version(version, '-v, --version');
|
|
57
57
|
program
|
|
58
58
|
.command('scan')
|
|
59
|
-
.argument('[
|
|
60
|
-
.description('Scan
|
|
59
|
+
.argument('[paths...]', 'One or more files/directories to scan', ['.'])
|
|
60
|
+
.description('Scan files or directories for auth misconfigurations')
|
|
61
61
|
.option('--json', 'Emit JSON (shortcut for --format json)')
|
|
62
62
|
.option('--format <fmt>', 'Output format: pretty | json | sarif', parseFormat)
|
|
63
63
|
.option('--severity <level>', 'Only emit findings ≥ this severity', parseSeverity)
|
|
64
64
|
.option('--fail-on <level>', 'Process exits non-zero if any finding ≥ this severity', parseFailOn)
|
|
65
|
+
.option('--diff [ref]', 'Scan only files changed vs a git ref (default: merge-base with the default branch)')
|
|
66
|
+
.option('--staged', 'Scan only git-staged files (useful for pre-commit hooks)')
|
|
65
67
|
.option('--rules-dir <path>', 'Override the bundled rules directory')
|
|
66
68
|
.option('--fix', 'Apply auto-fixes (rewrites source in place where possible)')
|
|
67
|
-
.action(async (
|
|
69
|
+
.action(async (paths, opts) => {
|
|
68
70
|
const code = await runScan({
|
|
69
|
-
|
|
71
|
+
paths,
|
|
72
|
+
diff: opts.diff,
|
|
73
|
+
staged: opts.staged,
|
|
70
74
|
json: opts.json,
|
|
71
75
|
format: opts.format,
|
|
72
76
|
severity: opts.severity,
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAmB,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAqB,MAAM,YAAY,CAAC;AAM3D;;;;;;;;GAQG;AACH,KAAK,UAAU,cAAc,CAAC,IAAY;IACxC,MAAM,KAAK,GAAG,CAAC,CAAqB,EAAiB,EAAE,CACrD,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QAClB,IAAI,CAAC,CAAC,cAAc,KAAK,CAAC,EAAE,CAAC;YAC3B,GAAG,EAAE,CAAC;YACN,OAAO;QACT,CAAC;QACD,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IACL,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAClE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED,KAAK,UAAU,kBAAkB;IAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,iDAAiD;IACjD,8DAA8D;IAC9D,KAAK,MAAM,SAAS,IAAI;QACtB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC;QACnC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC;KAC1C,EAAE,CAAC;QACF,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAAY,CAAC;YACrE,IAAI,GAAG,CAAC,OAAO;gBAAE,OAAO,GAAG,CAAC,OAAO,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAE3C,OAAO;SACJ,IAAI,CAAC,WAAW,CAAC;SACjB,WAAW,CACV,4FAA4F,CAC7F;SACA,OAAO,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IAErC,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,MAAM,YAAY,CAAC;AAC5B,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAmB,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAqB,MAAM,YAAY,CAAC;AAM3D;;;;;;;;GAQG;AACH,KAAK,UAAU,cAAc,CAAC,IAAY;IACxC,MAAM,KAAK,GAAG,CAAC,CAAqB,EAAiB,EAAE,CACrD,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QAClB,IAAI,CAAC,CAAC,cAAc,KAAK,CAAC,EAAE,CAAC;YAC3B,GAAG,EAAE,CAAC;YACN,OAAO;QACT,CAAC;QACD,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IACL,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAClE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC;AAED,KAAK,UAAU,kBAAkB;IAC/B,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,iDAAiD;IACjD,8DAA8D;IAC9D,KAAK,MAAM,SAAS,IAAI;QACtB,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC;QACnC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC;KAC1C,EAAE,CAAC;QACF,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAAY,CAAC;YACrE,IAAI,GAAG,CAAC,OAAO;gBAAE,OAAO,GAAG,CAAC,OAAO,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,cAAc;QAChB,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAG,MAAM,kBAAkB,EAAE,CAAC;IAE3C,OAAO;SACJ,IAAI,CAAC,WAAW,CAAC;SACjB,WAAW,CACV,4FAA4F,CAC7F;SACA,OAAO,CAAC,OAAO,EAAE,eAAe,CAAC,CAAC;IAErC,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,QAAQ,CAAC,YAAY,EAAE,uCAAuC,EAAE,CAAC,GAAG,CAAC,CAAC;SACtE,WAAW,CAAC,sDAAsD,CAAC;SACnE,MAAM,CAAC,QAAQ,EAAE,wCAAwC,CAAC;SAC1D,MAAM,CAAC,gBAAgB,EAAE,sCAAsC,EAAE,WAAW,CAAC;SAC7E,MAAM,CAAC,oBAAoB,EAAE,oCAAoC,EAAE,aAAa,CAAC;SACjF,MAAM,CACL,mBAAmB,EACnB,uDAAuD,EACvD,WAAW,CACZ;SACA,MAAM,CACL,cAAc,EACd,oFAAoF,CACrF;SACA,MAAM,CAAC,UAAU,EAAE,0DAA0D,CAAC;SAC9E,MAAM,CAAC,oBAAoB,EAAE,sCAAsC,CAAC;SACpE,MAAM,CAAC,OAAO,EAAE,4DAA4D,CAAC;SAC7E,MAAM,CAAC,KAAK,EAAE,KAAe,EAAE,IAAoB,EAAE,EAAE;QACtD,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC;YACzB,KAAK;YACL,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,MAAM,EAAE,IAAI,CAAC,MAAM;YACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,GAAG,EAAE,IAAI,CAAC,GAAG;SACd,CAAC,CAAC;QACH,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,gDAAgD,CAAC;SAC7D,MAAM,CAAC,QAAQ,EAAE,oCAAoC,CAAC;SACtD,MAAM,CAAC,KAAK,EAAE,IAAwB,EAAE,EAAE;QACzC,MAAM,cAAc,CAAC,MAAM,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,sDAAsD,CAAC;SACnE,MAAM,CAAC,aAAa,EAAE,mCAAmC,CAAC;SAC1D,MAAM,CAAC,KAAK,EAAE,IAAyB,EAAE,EAAE;QAC1C,MAAM,cAAc,CAAC,MAAM,OAAO,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,4DAA4D,CAAC;SACzE,MAAM,CAAC,QAAQ,EAAE,oCAAoC,CAAC;SACtD,MAAM,CAAC,KAAK,EAAE,IAAwB,EAAE,EAAE;QACzC,MAAM,cAAc,CAAC,MAAM,SAAS,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEL,OAAO,CAAC,kBAAkB,CAAC,EAAE,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC,CAAC;IACtF,OAAO,OAAO,CAAC;AACjB,CAAC;AAcD,SAAS,aAAa,CAAC,CAAS;IAC9B,MAAM,KAAK,GAAG,CAAC,CAAC,WAAW,EAAkB,CAAC;IAC9C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,uBAAuB,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,WAAW,CAAC,CAAS;IAC5B,IAAI,CAAC,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAC9B,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,OAAO,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAU,CAAC;AACrD,SAAS,WAAW,CAAC,CAAS;IAC5B,MAAM,KAAK,GAAG,CAAC,CAAC,WAAW,EAAgB,CAAC;IAC5C,IAAI,CAAE,OAA6B,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,uBAAuB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/commands/init.d.ts
CHANGED
|
@@ -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/
|
|
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,
|
|
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"}
|
package/dist/commands/init.js
CHANGED
|
@@ -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/
|
|
6
|
+
# Documentation: https://oauthlint.dev/docs/configuration
|
|
7
7
|
version: 1
|
|
8
8
|
|
|
9
9
|
# Files to scan
|
package/dist/commands/scan.d.ts
CHANGED
|
@@ -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
|
-
|
|
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. */
|
|
@@ -19,6 +34,8 @@ export interface ScanCommandOptions {
|
|
|
19
34
|
adapter?: SemgrepAdapter;
|
|
20
35
|
/** Used by tests to capture output. */
|
|
21
36
|
stream?: NodeJS.WritableStream;
|
|
37
|
+
/** Override the directory git/relative paths resolve from (defaults to cwd). */
|
|
38
|
+
cwd?: string;
|
|
22
39
|
}
|
|
23
40
|
export declare function runScan(opts: ScanCommandOptions): Promise<number>;
|
|
24
41
|
//# 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;
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,cAAc,EAGf,MAAM,wBAAwB,CAAC;AAOhC,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,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,CAoHvE"}
|
package/dist/commands/scan.js
CHANGED
|
@@ -1,25 +1,81 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
2
|
import { RULES_ROOT } from 'oauthlint-rules';
|
|
3
3
|
import { SemgrepAdapter, SemgrepNotInstalledError, SemgrepOutputError, } from '../adapters/semgrep.js';
|
|
4
|
+
import { GitError, resolveDiffFiles, resolveStagedFiles } from '../core/changed-files.js';
|
|
4
5
|
import { loadConfig } from '../core/config.js';
|
|
5
6
|
import { Reporter } from '../core/reporter.js';
|
|
6
7
|
import { toSarif } from '../core/sarif.js';
|
|
7
8
|
import { exitCodeFor, highestSeverity, meetsThreshold } from '../core/severity.js';
|
|
8
9
|
import { applySuppressions } from '../core/suppress.js';
|
|
9
10
|
export async function runScan(opts) {
|
|
10
|
-
const
|
|
11
|
-
const config = await loadConfig(
|
|
11
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
12
|
+
const config = await loadConfig(cwd);
|
|
12
13
|
const rulesDir = opts.rulesDir ?? config.customRulesDir ?? RULES_ROOT;
|
|
13
14
|
const failOn = opts.failOn ?? config.failOn ?? 'HIGH';
|
|
14
15
|
const format = opts.format ?? (opts.json ? 'json' : 'pretty');
|
|
15
16
|
const stream = opts.stream ?? process.stdout;
|
|
17
|
+
const errStream = opts.stream ?? process.stderr;
|
|
18
|
+
// Resolve the set of targets to hand Semgrep. Incremental flags (--diff /
|
|
19
|
+
// --staged) win and narrow the scan to changed files only; otherwise we scan
|
|
20
|
+
// the explicit path args (default ['.']).
|
|
21
|
+
let targets;
|
|
22
|
+
let incremental = false;
|
|
23
|
+
try {
|
|
24
|
+
if (opts.diff !== undefined && opts.diff !== false) {
|
|
25
|
+
incremental = true;
|
|
26
|
+
const ref = typeof opts.diff === 'string' ? opts.diff : undefined;
|
|
27
|
+
targets = await resolveDiffFiles(cwd, ref);
|
|
28
|
+
}
|
|
29
|
+
else if (opts.staged) {
|
|
30
|
+
incremental = true;
|
|
31
|
+
targets = await resolveStagedFiles(cwd);
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
const requested = opts.paths?.length
|
|
35
|
+
? opts.paths
|
|
36
|
+
: opts.path !== undefined
|
|
37
|
+
? [opts.path]
|
|
38
|
+
: ['.'];
|
|
39
|
+
targets = requested.map((p) => resolve(cwd, p));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch (err) {
|
|
43
|
+
if (err instanceof GitError) {
|
|
44
|
+
errStream.write(`${err.message}\n`);
|
|
45
|
+
return 2;
|
|
46
|
+
}
|
|
47
|
+
throw err;
|
|
48
|
+
}
|
|
49
|
+
// Incremental change set is empty (nothing in a supported language changed).
|
|
50
|
+
// That's a success, not an error — pre-commit hooks and editors call this
|
|
51
|
+
// constantly and should exit 0 with a clear note rather than failing.
|
|
52
|
+
if (incremental && targets.length === 0) {
|
|
53
|
+
if (format === 'json') {
|
|
54
|
+
stream.write(`${JSON.stringify({ schemaVersion: 'oauthlint-v1', findings: [] })}\n`);
|
|
55
|
+
}
|
|
56
|
+
else if (format === 'sarif') {
|
|
57
|
+
const empty = await toSarif({
|
|
58
|
+
findings: [],
|
|
59
|
+
scannedFiles: 0,
|
|
60
|
+
durationMs: 0,
|
|
61
|
+
semgrepVersion: null,
|
|
62
|
+
errors: [],
|
|
63
|
+
});
|
|
64
|
+
stream.write(`${JSON.stringify(empty, null, 2)}\n`);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
stream.write('No changed files to scan.\n');
|
|
68
|
+
}
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
const label = incremental ? `${targets.length} changed file(s)` : targets.join(', ');
|
|
16
72
|
const reporter = new Reporter({ json: format === 'json', stream });
|
|
17
73
|
if (format === 'pretty')
|
|
18
|
-
reporter.reportStart(
|
|
74
|
+
reporter.reportStart(label, await countRuleFiles(rulesDir));
|
|
19
75
|
const adapter = opts.adapter ?? new SemgrepAdapter({ configPath: rulesDir });
|
|
20
76
|
let result;
|
|
21
77
|
try {
|
|
22
|
-
result = await adapter.scan(
|
|
78
|
+
result = await adapter.scan(targets, { applyFixes: opts.fix });
|
|
23
79
|
}
|
|
24
80
|
catch (err) {
|
|
25
81
|
if (err instanceof SemgrepNotInstalledError) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EACL,cAAc,EACd,wBAAwB,EACxB,kBAAkB,GACnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Raised when a git operation can't be performed — most commonly because the
|
|
3
|
+
* target directory is not inside a git work tree, or `git` itself is missing.
|
|
4
|
+
* Callers (the scan command) translate this into a clean, non-crashing error
|
|
5
|
+
* message rather than a stack trace.
|
|
6
|
+
*/
|
|
7
|
+
export declare class GitError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
/** True when `file` has an extension the rule pack can actually scan. */
|
|
11
|
+
export declare function isScannableSourceFile(file: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Files changed versus `ref` (or the default branch's merge-base when `ref` is
|
|
14
|
+
* undefined), as absolute paths, filtered to scannable source files.
|
|
15
|
+
*
|
|
16
|
+
* Combines four sets so nothing in flight is missed:
|
|
17
|
+
* - committed changes since `ref` (`git diff --name-only <ref>...`)
|
|
18
|
+
* - unstaged work-tree changes (`git diff --name-only`)
|
|
19
|
+
* - staged-but-uncommitted changes (`git diff --name-only --cached`)
|
|
20
|
+
* - new, not-yet-tracked files (`git ls-files --others --exclude-standard`)
|
|
21
|
+
*
|
|
22
|
+
* `--diff-filter=ACMR` keeps Added / Copied / Modified / Renamed and drops
|
|
23
|
+
* Deleted files (we can't scan a file that no longer exists). Untracked files
|
|
24
|
+
* are picked up separately because plain `git diff` only reports tracked paths —
|
|
25
|
+
* a freshly written, un-`add`ed source file would otherwise be missed.
|
|
26
|
+
*
|
|
27
|
+
* @throws GitError when not in a git repo (or git is unavailable).
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveDiffFiles(cwd: string, ref?: string): Promise<string[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Staged files (`git diff --name-only --cached --diff-filter=ACMR`) as absolute
|
|
32
|
+
* paths, filtered to scannable source files. This is the set a pre-commit hook
|
|
33
|
+
* cares about.
|
|
34
|
+
*
|
|
35
|
+
* @throws GitError when not in a git repo (or git is unavailable).
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveStagedFiles(cwd: string): Promise<string[]>;
|
|
38
|
+
//# sourceMappingURL=changed-files.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changed-files.d.ts","sourceRoot":"","sources":["../../src/core/changed-files.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,qBAAa,QAAS,SAAQ,KAAK;gBACrB,OAAO,EAAE,MAAM;CAI5B;AAiCD,yEAAyE;AACzE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE3D;AA0FD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAmBnF;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAMvE"}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { extname } from 'node:path';
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
/**
|
|
4
|
+
* Raised when a git operation can't be performed — most commonly because the
|
|
5
|
+
* target directory is not inside a git work tree, or `git` itself is missing.
|
|
6
|
+
* Callers (the scan command) translate this into a clean, non-crashing error
|
|
7
|
+
* message rather than a stack trace.
|
|
8
|
+
*/
|
|
9
|
+
export class GitError extends Error {
|
|
10
|
+
constructor(message) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'GitError';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* File extensions for the languages the rule pack supports
|
|
17
|
+
* (javascript, typescript, python, go, java, rust). The change-set resolvers
|
|
18
|
+
* filter to these so we never hand Semgrep a Markdown/lockfile/binary path:
|
|
19
|
+
* incremental scanning only makes sense for source files semgrep can analyse,
|
|
20
|
+
* and skipping the rest keeps the scan fast.
|
|
21
|
+
*
|
|
22
|
+
* Kept deliberately broad within each supported language (e.g. both `.mjs`
|
|
23
|
+
* and `.cjs`) so a changed file is never silently dropped.
|
|
24
|
+
*/
|
|
25
|
+
const SUPPORTED_EXTENSIONS = new Set([
|
|
26
|
+
// JavaScript / TypeScript
|
|
27
|
+
'.js',
|
|
28
|
+
'.jsx',
|
|
29
|
+
'.mjs',
|
|
30
|
+
'.cjs',
|
|
31
|
+
'.ts',
|
|
32
|
+
'.tsx',
|
|
33
|
+
'.mts',
|
|
34
|
+
'.cts',
|
|
35
|
+
// Python
|
|
36
|
+
'.py',
|
|
37
|
+
'.pyi',
|
|
38
|
+
// Go
|
|
39
|
+
'.go',
|
|
40
|
+
// Java
|
|
41
|
+
'.java',
|
|
42
|
+
// Rust
|
|
43
|
+
'.rs',
|
|
44
|
+
]);
|
|
45
|
+
/** True when `file` has an extension the rule pack can actually scan. */
|
|
46
|
+
export function isScannableSourceFile(file) {
|
|
47
|
+
return SUPPORTED_EXTENSIONS.has(extname(file).toLowerCase());
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Run `git` with the given args as an ARRAY (never a shell string), so user
|
|
51
|
+
* input — branch names, refs — can't be interpreted by a shell. `execa`
|
|
52
|
+
* spawns the process directly without `/bin/sh`, eliminating shell injection.
|
|
53
|
+
*
|
|
54
|
+
* @throws GitError when git is not installed or the command fails.
|
|
55
|
+
*/
|
|
56
|
+
async function git(cwd, args) {
|
|
57
|
+
try {
|
|
58
|
+
const { stdout } = await execa('git', args, { cwd, reject: true });
|
|
59
|
+
return stdout;
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
if (isMissingGitBinary(err)) {
|
|
63
|
+
throw new GitError('git is not installed or not on PATH — cannot resolve changed files.');
|
|
64
|
+
}
|
|
65
|
+
const stderr = typeof err.stderr === 'string'
|
|
66
|
+
? err.stderr.trim()
|
|
67
|
+
: '';
|
|
68
|
+
throw new GitError(stderr || (err instanceof Error ? err.message : String(err)));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
function isMissingGitBinary(err) {
|
|
72
|
+
if (typeof err !== 'object' || err === null)
|
|
73
|
+
return false;
|
|
74
|
+
const e = err;
|
|
75
|
+
return e.code === 'ENOENT' || e.cause?.code === 'ENOENT';
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Throw a clear GitError unless `cwd` is inside a git work tree. Used by the
|
|
79
|
+
* diff/staged resolvers so "not a git repo" surfaces as a friendly message
|
|
80
|
+
* instead of a confusing low-level git error.
|
|
81
|
+
*/
|
|
82
|
+
async function assertGitRepo(cwd) {
|
|
83
|
+
let inside;
|
|
84
|
+
try {
|
|
85
|
+
inside = await git(cwd, ['rev-parse', '--is-inside-work-tree']);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
if (err instanceof GitError && /not a git repository/i.test(err.message)) {
|
|
89
|
+
throw new GitError(`Not a git repository: ${cwd}`);
|
|
90
|
+
}
|
|
91
|
+
throw err;
|
|
92
|
+
}
|
|
93
|
+
if (inside.trim() !== 'true') {
|
|
94
|
+
throw new GitError(`Not a git repository: ${cwd}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Resolve the git ref to diff against when `--diff` is passed without a value.
|
|
99
|
+
* We want the merge-base with the repository's default branch so a feature
|
|
100
|
+
* branch only scans what it actually changed (not unrelated commits already on
|
|
101
|
+
* the default branch). Resolution order:
|
|
102
|
+
*
|
|
103
|
+
* 1. `origin/HEAD` — the remote's default branch symref (most accurate)
|
|
104
|
+
* 2. `origin/main`
|
|
105
|
+
* 3. `origin/master`
|
|
106
|
+
* 4. `HEAD` — fallback when there is no remote (diffs only the work tree)
|
|
107
|
+
*
|
|
108
|
+
* For each candidate we use its merge-base with the current HEAD so the diff
|
|
109
|
+
* is scoped to the branch's own changes.
|
|
110
|
+
*/
|
|
111
|
+
async function resolveDefaultRef(cwd) {
|
|
112
|
+
for (const candidate of ['origin/HEAD', 'origin/main', 'origin/master']) {
|
|
113
|
+
try {
|
|
114
|
+
const base = (await git(cwd, ['merge-base', candidate, 'HEAD'])).trim();
|
|
115
|
+
if (base)
|
|
116
|
+
return base;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
// candidate doesn't exist (no remote / different default) — try the next.
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return 'HEAD';
|
|
123
|
+
}
|
|
124
|
+
/** Absolute repo root for `cwd`, used to turn git's repo-relative paths absolute. */
|
|
125
|
+
async function repoRoot(cwd) {
|
|
126
|
+
return (await git(cwd, ['rev-parse', '--show-toplevel'])).trim();
|
|
127
|
+
}
|
|
128
|
+
function toAbsolute(root, relPaths) {
|
|
129
|
+
// git emits forward-slash, repo-relative paths; join under the repo root.
|
|
130
|
+
return relPaths
|
|
131
|
+
.map((p) => p.trim())
|
|
132
|
+
.filter((p) => p.length > 0)
|
|
133
|
+
.map((p) => `${root}/${p}`);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Files changed versus `ref` (or the default branch's merge-base when `ref` is
|
|
137
|
+
* undefined), as absolute paths, filtered to scannable source files.
|
|
138
|
+
*
|
|
139
|
+
* Combines four sets so nothing in flight is missed:
|
|
140
|
+
* - committed changes since `ref` (`git diff --name-only <ref>...`)
|
|
141
|
+
* - unstaged work-tree changes (`git diff --name-only`)
|
|
142
|
+
* - staged-but-uncommitted changes (`git diff --name-only --cached`)
|
|
143
|
+
* - new, not-yet-tracked files (`git ls-files --others --exclude-standard`)
|
|
144
|
+
*
|
|
145
|
+
* `--diff-filter=ACMR` keeps Added / Copied / Modified / Renamed and drops
|
|
146
|
+
* Deleted files (we can't scan a file that no longer exists). Untracked files
|
|
147
|
+
* are picked up separately because plain `git diff` only reports tracked paths —
|
|
148
|
+
* a freshly written, un-`add`ed source file would otherwise be missed.
|
|
149
|
+
*
|
|
150
|
+
* @throws GitError when not in a git repo (or git is unavailable).
|
|
151
|
+
*/
|
|
152
|
+
export async function resolveDiffFiles(cwd, ref) {
|
|
153
|
+
await assertGitRepo(cwd);
|
|
154
|
+
const baseRef = ref ?? (await resolveDefaultRef(cwd));
|
|
155
|
+
const root = await repoRoot(cwd);
|
|
156
|
+
const seen = new Set();
|
|
157
|
+
const batches = await Promise.all([
|
|
158
|
+
// `<ref>...` (three-dot) diffs against the merge-base of ref and HEAD,
|
|
159
|
+
// matching how code review compares a branch to its base.
|
|
160
|
+
git(cwd, ['diff', '--name-only', '--diff-filter=ACMR', `${baseRef}...`]),
|
|
161
|
+
git(cwd, ['diff', '--name-only', '--diff-filter=ACMR']),
|
|
162
|
+
git(cwd, ['diff', '--name-only', '--cached', '--diff-filter=ACMR']),
|
|
163
|
+
// Untracked (but not git-ignored) files — `git diff` never lists these.
|
|
164
|
+
git(cwd, ['ls-files', '--others', '--exclude-standard']),
|
|
165
|
+
]);
|
|
166
|
+
for (const out of batches) {
|
|
167
|
+
for (const abs of toAbsolute(root, out.split('\n')))
|
|
168
|
+
seen.add(abs);
|
|
169
|
+
}
|
|
170
|
+
return [...seen].filter(isScannableSourceFile).sort();
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Staged files (`git diff --name-only --cached --diff-filter=ACMR`) as absolute
|
|
174
|
+
* paths, filtered to scannable source files. This is the set a pre-commit hook
|
|
175
|
+
* cares about.
|
|
176
|
+
*
|
|
177
|
+
* @throws GitError when not in a git repo (or git is unavailable).
|
|
178
|
+
*/
|
|
179
|
+
export async function resolveStagedFiles(cwd) {
|
|
180
|
+
await assertGitRepo(cwd);
|
|
181
|
+
const root = await repoRoot(cwd);
|
|
182
|
+
const out = await git(cwd, ['diff', '--name-only', '--cached', '--diff-filter=ACMR']);
|
|
183
|
+
const abs = toAbsolute(root, out.split('\n'));
|
|
184
|
+
return [...new Set(abs)].filter(isScannableSourceFile).sort();
|
|
185
|
+
}
|
|
186
|
+
//# sourceMappingURL=changed-files.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"changed-files.js","sourceRoot":"","sources":["../../src/core/changed-files.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oauthlint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Catch the OAuth/OIDC/JWT anti-patterns AI coding tools systematically produce. CLI wrapper around the oauthlint-rules Semgrep rule pack.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"picocolors": "1.1.1",
|
|
48
48
|
"yaml": "2.9.0",
|
|
49
49
|
"zod": "3.24.1",
|
|
50
|
-
"oauthlint-rules": "0.2.
|
|
50
|
+
"oauthlint-rules": "0.2.3"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/node": "22.10.5",
|