oauthlint 0.3.0 → 0.5.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 +28 -188
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +68 -7
- package/dist/cli.js.map +1 -1
- package/dist/commands/baseline.d.ts +21 -0
- package/dist/commands/baseline.d.ts.map +1 -0
- package/dist/commands/baseline.js +50 -0
- package/dist/commands/baseline.js.map +1 -0
- package/dist/commands/scan.d.ts +8 -1
- package/dist/commands/scan.d.ts.map +1 -1
- package/dist/commands/scan.js +47 -0
- package/dist/commands/scan.js.map +1 -1
- package/dist/core/baseline.d.ts +102 -0
- package/dist/core/baseline.d.ts.map +1 -0
- package/dist/core/baseline.js +223 -0
- package/dist/core/baseline.js.map +1 -0
- package/dist/core/update-notifier.d.ts +61 -0
- package/dist/core/update-notifier.d.ts.map +1 -0
- package/dist/core/update-notifier.js +267 -0
- package/dist/core/update-notifier.js.map +1 -0
- package/dist/formatters/html.d.ts +50 -0
- package/dist/formatters/html.d.ts.map +1 -0
- package/dist/formatters/html.js +308 -0
- package/dist/formatters/html.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -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,QAAQ,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC1F,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,102 @@
|
|
|
1
|
+
import type { Finding } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Baseline support: capture the CURRENT set of findings so a team can adopt
|
|
4
|
+
* OAuthLint on a large existing codebase and only be alerted on NEW issues.
|
|
5
|
+
*
|
|
6
|
+
* The hard requirement is a fingerprint that is stable across edits that move
|
|
7
|
+
* a finding around without changing it: inserting an import, reformatting a
|
|
8
|
+
* block, or shifting code down N lines must NOT resurface a baselined finding,
|
|
9
|
+
* while genuinely changing the flagged code MUST surface it as new.
|
|
10
|
+
*
|
|
11
|
+
* Fingerprint = sha256 of three parts joined by NULs:
|
|
12
|
+
* 1. the rule identity — `oauthlintRuleId` when present, else `ruleId`
|
|
13
|
+
* 2. the repo/cwd-relative file path (POSIX separators, so it's portable)
|
|
14
|
+
* 3. a NORMALISED snapshot of the matched source (the `startLine..endLine`
|
|
15
|
+
* span, whitespace-collapsed) — explicitly NOT the raw line numbers
|
|
16
|
+
*
|
|
17
|
+
* When the file can't be read (deleted, binary, permission error) we fall back
|
|
18
|
+
* to the trimmed `message` as the snapshot so a fingerprint can still be
|
|
19
|
+
* produced — degraded but deterministic, never a crash.
|
|
20
|
+
*
|
|
21
|
+
* Identical fingerprints within one file (e.g. the same anti-pattern repeated)
|
|
22
|
+
* are disambiguated by a stable per-file occurrence index, assigned in source
|
|
23
|
+
* order, so each physical finding maps to a distinct baseline entry.
|
|
24
|
+
*/
|
|
25
|
+
export declare const BASELINE_VERSION: 1;
|
|
26
|
+
export declare const DEFAULT_BASELINE_FILE = ".oauthlint-baseline.json";
|
|
27
|
+
/** A single baselined finding, keyed by its stable fingerprint. */
|
|
28
|
+
export interface BaselineEntry {
|
|
29
|
+
/** Stable fingerprint (see module docs). Survives line shifts. */
|
|
30
|
+
fingerprint: string;
|
|
31
|
+
/** Rule identity used in the hash — for human-diffability of the file. */
|
|
32
|
+
ruleId: string;
|
|
33
|
+
/** Repo/cwd-relative path used in the hash — for human-diffability. */
|
|
34
|
+
filePath: string;
|
|
35
|
+
}
|
|
36
|
+
export interface BaselineFile {
|
|
37
|
+
version: typeof BASELINE_VERSION;
|
|
38
|
+
generatedAt: string;
|
|
39
|
+
/** Sorted, deterministic list of baselined fingerprints. */
|
|
40
|
+
findings: BaselineEntry[];
|
|
41
|
+
}
|
|
42
|
+
/** In-memory baseline: just the set of fingerprints we suppress against. */
|
|
43
|
+
export interface Baseline {
|
|
44
|
+
fingerprints: Set<string>;
|
|
45
|
+
}
|
|
46
|
+
export declare class BaselineNotFoundError extends Error {
|
|
47
|
+
constructor(path: string);
|
|
48
|
+
}
|
|
49
|
+
export declare class BaselineParseError extends Error {
|
|
50
|
+
constructor(path: string, detail: string);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Turn a finding's `filePath` into a portable, repo/cwd-relative path with
|
|
54
|
+
* POSIX separators. Absolute paths are made relative to `cwd`; paths that are
|
|
55
|
+
* already relative are normalised as-is. We never let an absolute path leak
|
|
56
|
+
* into a fingerprint, so a baseline is portable across machines/checkouts.
|
|
57
|
+
*/
|
|
58
|
+
export declare function toRelativePath(filePath: string, cwd: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Compute the stable fingerprint for a finding (without the occurrence index).
|
|
61
|
+
* Two findings of the same rule on the same (relative) file with the same
|
|
62
|
+
* normalised snippet share this value — they're disambiguated by the index
|
|
63
|
+
* added in {@link fingerprintFindings}.
|
|
64
|
+
*/
|
|
65
|
+
export declare function baseFingerprint(finding: Finding, cwd: string, cache: Map<string, string[] | null>): Promise<string>;
|
|
66
|
+
/** A finding paired with its final, occurrence-disambiguated fingerprint. */
|
|
67
|
+
export interface FingerprintedFinding {
|
|
68
|
+
finding: Finding;
|
|
69
|
+
fingerprint: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Fingerprint a list of findings deterministically. Findings are processed in
|
|
73
|
+
* a stable order, and identical base fingerprints within the run get an
|
|
74
|
+
* occurrence index (`<base>:<n>`) so repeated anti-patterns each get a unique
|
|
75
|
+
* key. The same input list always yields the same fingerprints.
|
|
76
|
+
*/
|
|
77
|
+
export declare function fingerprintFindings(findings: Finding[], cwd: string): Promise<FingerprintedFinding[]>;
|
|
78
|
+
/**
|
|
79
|
+
* Build a serialisable baseline file from a set of findings. The entry list is
|
|
80
|
+
* sorted so the JSON is stable and human-diffable across runs.
|
|
81
|
+
*/
|
|
82
|
+
export declare function buildBaseline(findings: Finding[], cwd: string): Promise<BaselineFile>;
|
|
83
|
+
/** Serialise a baseline file to pretty JSON (trailing newline for clean diffs). */
|
|
84
|
+
export declare function serialiseBaseline(baseline: BaselineFile): string;
|
|
85
|
+
/**
|
|
86
|
+
* Load a baseline from disk into an in-memory fingerprint set.
|
|
87
|
+
*
|
|
88
|
+
* @throws BaselineNotFoundError when the file is absent — deliberately NOT
|
|
89
|
+
* treated as an empty allow-list, so a misspelt `--baseline path` fails loud
|
|
90
|
+
* instead of silently suppressing nothing (or everything).
|
|
91
|
+
* @throws BaselineParseError when the file is present but malformed.
|
|
92
|
+
*/
|
|
93
|
+
export declare function loadBaseline(path: string): Promise<Baseline>;
|
|
94
|
+
/**
|
|
95
|
+
* Split findings into those already present in the baseline (suppressed) and
|
|
96
|
+
* genuinely new ones, by fingerprinting and matching against the baseline set.
|
|
97
|
+
*/
|
|
98
|
+
export declare function partitionByBaseline(findings: Finding[], baseline: Baseline, cwd: string): Promise<{
|
|
99
|
+
newFindings: Finding[];
|
|
100
|
+
baselined: Finding[];
|
|
101
|
+
}>;
|
|
102
|
+
//# sourceMappingURL=baseline.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline.d.ts","sourceRoot":"","sources":["../../src/core/baseline.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,eAAO,MAAM,gBAAgB,EAAG,CAAU,CAAC;AAC3C,eAAO,MAAM,qBAAqB,6BAA6B,CAAC;AAEhE,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,WAAW,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,gBAAgB,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,QAAQ,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED,4EAA4E;AAC5E,MAAM,WAAW,QAAQ;IACvB,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC3B;AAED,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,IAAI,EAAE,MAAM;CAMzB;AAED,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAIzC;AAYD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAGpE;AAuDD;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,GAClC,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED,6EAA6E;AAC7E,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,OAAO,EAAE,EACnB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,oBAAoB,EAAE,CAAC,CAuBjC;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAkB3F;AAED,mFAAmF;AACnF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAEhE;AAED;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CA8BlE;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,OAAO,EAAE,EACnB,QAAQ,EAAE,QAAQ,EAClB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,WAAW,EAAE,OAAO,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,EAAE,CAAA;CAAE,CAAC,CAS3D"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readFile } from 'node:fs/promises';
|
|
3
|
+
import { isAbsolute, relative, resolve } from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* Baseline support: capture the CURRENT set of findings so a team can adopt
|
|
6
|
+
* OAuthLint on a large existing codebase and only be alerted on NEW issues.
|
|
7
|
+
*
|
|
8
|
+
* The hard requirement is a fingerprint that is stable across edits that move
|
|
9
|
+
* a finding around without changing it: inserting an import, reformatting a
|
|
10
|
+
* block, or shifting code down N lines must NOT resurface a baselined finding,
|
|
11
|
+
* while genuinely changing the flagged code MUST surface it as new.
|
|
12
|
+
*
|
|
13
|
+
* Fingerprint = sha256 of three parts joined by NULs:
|
|
14
|
+
* 1. the rule identity — `oauthlintRuleId` when present, else `ruleId`
|
|
15
|
+
* 2. the repo/cwd-relative file path (POSIX separators, so it's portable)
|
|
16
|
+
* 3. a NORMALISED snapshot of the matched source (the `startLine..endLine`
|
|
17
|
+
* span, whitespace-collapsed) — explicitly NOT the raw line numbers
|
|
18
|
+
*
|
|
19
|
+
* When the file can't be read (deleted, binary, permission error) we fall back
|
|
20
|
+
* to the trimmed `message` as the snapshot so a fingerprint can still be
|
|
21
|
+
* produced — degraded but deterministic, never a crash.
|
|
22
|
+
*
|
|
23
|
+
* Identical fingerprints within one file (e.g. the same anti-pattern repeated)
|
|
24
|
+
* are disambiguated by a stable per-file occurrence index, assigned in source
|
|
25
|
+
* order, so each physical finding maps to a distinct baseline entry.
|
|
26
|
+
*/
|
|
27
|
+
export const BASELINE_VERSION = 1;
|
|
28
|
+
export const DEFAULT_BASELINE_FILE = '.oauthlint-baseline.json';
|
|
29
|
+
export class BaselineNotFoundError extends Error {
|
|
30
|
+
constructor(path) {
|
|
31
|
+
super(`Baseline file not found: ${path}\nCreate one first with: oauthlint baseline\n(an absent baseline is treated as an error, not an empty allow-list, so a typo never silently disables suppression).`);
|
|
32
|
+
this.name = 'BaselineNotFoundError';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export class BaselineParseError extends Error {
|
|
36
|
+
constructor(path, detail) {
|
|
37
|
+
super(`Could not parse baseline file ${path}: ${detail}`);
|
|
38
|
+
this.name = 'BaselineParseError';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/** Collapse runs of whitespace and trim, so reformatting doesn't churn fingerprints. */
|
|
42
|
+
function normaliseSnippet(text) {
|
|
43
|
+
return text.replace(/\s+/g, ' ').trim();
|
|
44
|
+
}
|
|
45
|
+
/** Rule identity that goes into the hash — prefer the stable OAuthLint id. */
|
|
46
|
+
function ruleIdentity(finding) {
|
|
47
|
+
return finding.oauthlintRuleId ?? finding.ruleId;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Turn a finding's `filePath` into a portable, repo/cwd-relative path with
|
|
51
|
+
* POSIX separators. Absolute paths are made relative to `cwd`; paths that are
|
|
52
|
+
* already relative are normalised as-is. We never let an absolute path leak
|
|
53
|
+
* into a fingerprint, so a baseline is portable across machines/checkouts.
|
|
54
|
+
*/
|
|
55
|
+
export function toRelativePath(filePath, cwd) {
|
|
56
|
+
const rel = isAbsolute(filePath) ? relative(cwd, filePath) : filePath;
|
|
57
|
+
return rel.split('\\').join('/');
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Read the matched source span for a finding and return it normalised. On any
|
|
61
|
+
* read/decoding problem, fall back to the finding's message so we still get a
|
|
62
|
+
* deterministic value rather than throwing.
|
|
63
|
+
*/
|
|
64
|
+
async function snapshotFor(finding, cwd, cache) {
|
|
65
|
+
const abs = isAbsolute(finding.filePath) ? finding.filePath : resolve(cwd, finding.filePath);
|
|
66
|
+
let lines = cache.get(abs);
|
|
67
|
+
if (lines === undefined) {
|
|
68
|
+
lines = await readLinesSafe(abs);
|
|
69
|
+
cache.set(abs, lines);
|
|
70
|
+
}
|
|
71
|
+
if (lines === null) {
|
|
72
|
+
// Unreadable (missing/binary/permission) — degrade to the message text.
|
|
73
|
+
return normaliseSnippet(finding.message);
|
|
74
|
+
}
|
|
75
|
+
// Finding lines are 1-based and inclusive. Clamp into range defensively in
|
|
76
|
+
// case the file changed between scan and fingerprinting.
|
|
77
|
+
const start = Math.max(1, finding.startLine);
|
|
78
|
+
const end = Math.max(start, finding.endLine);
|
|
79
|
+
const span = lines.slice(start - 1, end).join('\n');
|
|
80
|
+
const normalised = normaliseSnippet(span);
|
|
81
|
+
// If the span is empty (out-of-range lines after a shrink), fall back so the
|
|
82
|
+
// fingerprint is never the hash of an empty string for every such finding.
|
|
83
|
+
return normalised || normaliseSnippet(finding.message);
|
|
84
|
+
}
|
|
85
|
+
/** Read a file as lines, returning null when it's missing or looks binary. */
|
|
86
|
+
async function readLinesSafe(absPath) {
|
|
87
|
+
let buf;
|
|
88
|
+
try {
|
|
89
|
+
buf = await readFile(absPath);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
// Treat NUL bytes as the binary signal (cheap, matches common heuristics).
|
|
95
|
+
if (buf.includes(0))
|
|
96
|
+
return null;
|
|
97
|
+
return buf.toString('utf8').split('\n');
|
|
98
|
+
}
|
|
99
|
+
function hash(parts) {
|
|
100
|
+
const h = createHash('sha256');
|
|
101
|
+
// NUL separator can't appear in any of the parts (path/id are text, the
|
|
102
|
+
// snippet has NULs stripped by the binary check), so there's no collision
|
|
103
|
+
// between e.g. ["ab","c"] and ["a","bc"].
|
|
104
|
+
h.update(parts.join('\0'));
|
|
105
|
+
return h.digest('hex');
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Compute the stable fingerprint for a finding (without the occurrence index).
|
|
109
|
+
* Two findings of the same rule on the same (relative) file with the same
|
|
110
|
+
* normalised snippet share this value — they're disambiguated by the index
|
|
111
|
+
* added in {@link fingerprintFindings}.
|
|
112
|
+
*/
|
|
113
|
+
export async function baseFingerprint(finding, cwd, cache) {
|
|
114
|
+
const rel = toRelativePath(finding.filePath, cwd);
|
|
115
|
+
const snippet = await snapshotFor(finding, cwd, cache);
|
|
116
|
+
return hash([ruleIdentity(finding), rel, snippet]);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Fingerprint a list of findings deterministically. Findings are processed in
|
|
120
|
+
* a stable order, and identical base fingerprints within the run get an
|
|
121
|
+
* occurrence index (`<base>:<n>`) so repeated anti-patterns each get a unique
|
|
122
|
+
* key. The same input list always yields the same fingerprints.
|
|
123
|
+
*/
|
|
124
|
+
export async function fingerprintFindings(findings, cwd) {
|
|
125
|
+
const cache = new Map();
|
|
126
|
+
// Stable processing order so occurrence indices are reproducible regardless
|
|
127
|
+
// of the adapter's emission order: by relative path, then line, then rule.
|
|
128
|
+
const ordered = [...findings]
|
|
129
|
+
.map((finding) => ({ finding, rel: toRelativePath(finding.filePath, cwd) }))
|
|
130
|
+
.sort((a, b) => a.rel.localeCompare(b.rel) ||
|
|
131
|
+
a.finding.startLine - b.finding.startLine ||
|
|
132
|
+
a.finding.endLine - b.finding.endLine ||
|
|
133
|
+
ruleIdentity(a.finding).localeCompare(ruleIdentity(b.finding)));
|
|
134
|
+
const seen = new Map();
|
|
135
|
+
const out = [];
|
|
136
|
+
for (const { finding } of ordered) {
|
|
137
|
+
const base = await baseFingerprint(finding, cwd, cache);
|
|
138
|
+
const n = seen.get(base) ?? 0;
|
|
139
|
+
seen.set(base, n + 1);
|
|
140
|
+
out.push({ finding, fingerprint: `${base}:${n}` });
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Build a serialisable baseline file from a set of findings. The entry list is
|
|
146
|
+
* sorted so the JSON is stable and human-diffable across runs.
|
|
147
|
+
*/
|
|
148
|
+
export async function buildBaseline(findings, cwd) {
|
|
149
|
+
const fingerprinted = await fingerprintFindings(findings, cwd);
|
|
150
|
+
const entries = fingerprinted.map(({ finding, fingerprint }) => ({
|
|
151
|
+
fingerprint,
|
|
152
|
+
ruleId: ruleIdentity(finding),
|
|
153
|
+
filePath: toRelativePath(finding.filePath, cwd),
|
|
154
|
+
}));
|
|
155
|
+
entries.sort((a, b) => a.filePath.localeCompare(b.filePath) ||
|
|
156
|
+
a.ruleId.localeCompare(b.ruleId) ||
|
|
157
|
+
a.fingerprint.localeCompare(b.fingerprint));
|
|
158
|
+
return {
|
|
159
|
+
version: BASELINE_VERSION,
|
|
160
|
+
generatedAt: new Date().toISOString(),
|
|
161
|
+
findings: entries,
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/** Serialise a baseline file to pretty JSON (trailing newline for clean diffs). */
|
|
165
|
+
export function serialiseBaseline(baseline) {
|
|
166
|
+
return `${JSON.stringify(baseline, null, 2)}\n`;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Load a baseline from disk into an in-memory fingerprint set.
|
|
170
|
+
*
|
|
171
|
+
* @throws BaselineNotFoundError when the file is absent — deliberately NOT
|
|
172
|
+
* treated as an empty allow-list, so a misspelt `--baseline path` fails loud
|
|
173
|
+
* instead of silently suppressing nothing (or everything).
|
|
174
|
+
* @throws BaselineParseError when the file is present but malformed.
|
|
175
|
+
*/
|
|
176
|
+
export async function loadBaseline(path) {
|
|
177
|
+
let raw;
|
|
178
|
+
try {
|
|
179
|
+
raw = await readFile(path, 'utf8');
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
if (err.code === 'ENOENT') {
|
|
183
|
+
throw new BaselineNotFoundError(path);
|
|
184
|
+
}
|
|
185
|
+
throw err;
|
|
186
|
+
}
|
|
187
|
+
let parsed;
|
|
188
|
+
try {
|
|
189
|
+
parsed = JSON.parse(raw);
|
|
190
|
+
}
|
|
191
|
+
catch (err) {
|
|
192
|
+
throw new BaselineParseError(path, err instanceof Error ? err.message : String(err));
|
|
193
|
+
}
|
|
194
|
+
if (typeof parsed !== 'object' ||
|
|
195
|
+
parsed === null ||
|
|
196
|
+
!Array.isArray(parsed.findings)) {
|
|
197
|
+
throw new BaselineParseError(path, 'expected an object with a "findings" array');
|
|
198
|
+
}
|
|
199
|
+
const fingerprints = new Set();
|
|
200
|
+
for (const entry of parsed.findings) {
|
|
201
|
+
if (entry && typeof entry.fingerprint === 'string') {
|
|
202
|
+
fingerprints.add(entry.fingerprint);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return { fingerprints };
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Split findings into those already present in the baseline (suppressed) and
|
|
209
|
+
* genuinely new ones, by fingerprinting and matching against the baseline set.
|
|
210
|
+
*/
|
|
211
|
+
export async function partitionByBaseline(findings, baseline, cwd) {
|
|
212
|
+
const fingerprinted = await fingerprintFindings(findings, cwd);
|
|
213
|
+
const newFindings = [];
|
|
214
|
+
const baselined = [];
|
|
215
|
+
for (const { finding, fingerprint } of fingerprinted) {
|
|
216
|
+
if (baseline.fingerprints.has(fingerprint))
|
|
217
|
+
baselined.push(finding);
|
|
218
|
+
else
|
|
219
|
+
newFindings.push(finding);
|
|
220
|
+
}
|
|
221
|
+
return { newFindings, baselined };
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=baseline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline.js","sourceRoot":"","sources":["../../src/core/baseline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export interface NotifierCache {
|
|
2
|
+
/** Epoch ms of the last successful registry check. */
|
|
3
|
+
lastCheck: number;
|
|
4
|
+
/** The latest version string the registry reported, or null on failure. */
|
|
5
|
+
latestVersion: string | null;
|
|
6
|
+
}
|
|
7
|
+
export interface UpdateNotifierOptions {
|
|
8
|
+
/** Currently-installed version (from package.json). */
|
|
9
|
+
currentVersion: string;
|
|
10
|
+
/** True when the command emits machine-readable output (json/sarif). */
|
|
11
|
+
machineReadable?: boolean;
|
|
12
|
+
/** Explicit opt-out (e.g. `--no-update-check` or config). */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Streams/env are injected so tests stay deterministic and offline. */
|
|
15
|
+
stderr?: NodeJS.WriteStream & {
|
|
16
|
+
isTTY?: boolean;
|
|
17
|
+
};
|
|
18
|
+
env?: NodeJS.ProcessEnv;
|
|
19
|
+
/** Override the cache file location (tests). */
|
|
20
|
+
cachePath?: string;
|
|
21
|
+
/** Inject the registry fetch + clock (tests). */
|
|
22
|
+
fetchLatest?: (name: string, timeoutMs: number) => Promise<string | null>;
|
|
23
|
+
now?: () => number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Decide whether a notice may be shown at all, independent of versions.
|
|
27
|
+
* Cheap, synchronous, and the single source of truth for suppression.
|
|
28
|
+
*/
|
|
29
|
+
export declare function shouldCheckForUpdate(opts: {
|
|
30
|
+
machineReadable?: boolean;
|
|
31
|
+
disabled?: boolean;
|
|
32
|
+
stderr?: {
|
|
33
|
+
isTTY?: boolean;
|
|
34
|
+
};
|
|
35
|
+
env?: NodeJS.ProcessEnv;
|
|
36
|
+
}): boolean;
|
|
37
|
+
/** Default cache location: XDG_CACHE_HOME, else ~/.cache. */
|
|
38
|
+
export declare function defaultCachePath(env?: NodeJS.ProcessEnv): string;
|
|
39
|
+
/**
|
|
40
|
+
* Fetch the latest published version from the npm registry.
|
|
41
|
+
* Hits the lightweight dist-tags endpoint, validates the response, and returns
|
|
42
|
+
* null on any error/timeout. Nothing from the response is ever executed.
|
|
43
|
+
*/
|
|
44
|
+
export declare function fetchLatestVersion(name: string, timeoutMs?: number): Promise<string | null>;
|
|
45
|
+
/**
|
|
46
|
+
* Run the update check and, when appropriate, print a single notice to stderr.
|
|
47
|
+
* Designed to be awaited right before the process exits so the notice appears
|
|
48
|
+
* AFTER the command's normal output and never interleaves.
|
|
49
|
+
*
|
|
50
|
+
* It resolves to the notice string it printed (or null), which is handy for
|
|
51
|
+
* tests; production callers can ignore the return value.
|
|
52
|
+
*/
|
|
53
|
+
export declare function maybeNotifyUpdate(opts: UpdateNotifierOptions): Promise<string | null>;
|
|
54
|
+
export declare function isValidVersion(v: string): boolean;
|
|
55
|
+
/**
|
|
56
|
+
* Compare two semver strings. Returns >0 if a>b, <0 if a<b, 0 if equal.
|
|
57
|
+
* Honours prerelease precedence (1.0.0-rc < 1.0.0) per the semver spec's
|
|
58
|
+
* common cases. Invalid input sorts as "not greater" so we never nag wrongly.
|
|
59
|
+
*/
|
|
60
|
+
export declare function compareSemver(a: string, b: string): number;
|
|
61
|
+
//# sourceMappingURL=update-notifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update-notifier.d.ts","sourceRoot":"","sources":["../../src/core/update-notifier.ts"],"names":[],"mappings":"AA4BA,MAAM,WAAW,aAAa;IAC5B,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,qBAAqB;IACpC,uDAAuD;IACvD,cAAc,EAAE,MAAM,CAAC;IACvB,wEAAwE;IACxE,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC,WAAW,GAAG;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAClD,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,gDAAgD;IAChD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE;IACzC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB,GAAG,OAAO,CAYV;AAiBD,6DAA6D;AAC7D,wBAAgB,gBAAgB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAG7E;AAkCD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,SAAS,GAAE,MAA2B,GACrC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAsDxB;AAED;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4C3F;AAgBD,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CA6B1D"}
|