@aegis-scan/core 0.3.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +83 -4
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +18 -0
- package/dist/orchestrator.js.map +1 -1
- package/dist/precision-tiers.d.ts +48 -0
- package/dist/precision-tiers.d.ts.map +1 -0
- package/dist/precision-tiers.js +111 -0
- package/dist/precision-tiers.js.map +1 -0
- package/dist/suppression-filter.d.ts +38 -0
- package/dist/suppression-filter.d.ts.map +1 -0
- package/dist/suppression-filter.js +147 -0
- package/dist/suppression-filter.js.map +1 -0
- package/dist/suppressions.d.ts +43 -0
- package/dist/suppressions.d.ts.map +1 -0
- package/dist/suppressions.js +115 -0
- package/dist/suppressions.js.map +1 -0
- package/dist/types.d.ts +104 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,WAAW,EAAiB,MAAM,YAAY,CAAC;AAuG7D;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,GAAG,MAAM,CAAC,CAAC,CAAC;AA0CjF,wBAAsB,UAAU,CAC9B,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,WAAW,CAAC,MAAM,CAAU,GACjC,OAAO,CAAC,WAAW,CAAC,CA4DtB"}
|
package/dist/config.js
CHANGED
|
@@ -2,6 +2,31 @@ import * as fs from 'node:fs';
|
|
|
2
2
|
import * as path from 'node:path';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { detectStack } from './detect.js';
|
|
5
|
+
const CweStringSchema = z.string().regex(/^CWE-\d+$/, { message: 'expected CWE-<digits>' });
|
|
6
|
+
const SeverityEnum = z.enum(['blocker', 'critical', 'high', 'medium', 'low', 'info']);
|
|
7
|
+
const CustomSourceSchema = z.object({
|
|
8
|
+
pattern: z.string().min(1, { message: 'pattern must not be empty' }),
|
|
9
|
+
}).strict();
|
|
10
|
+
const CustomSinkSchema = z.object({
|
|
11
|
+
pattern: z.string().min(1, { message: 'pattern must not be empty' }),
|
|
12
|
+
type: z.enum(['call', 'constructor', 'property']).default('call'),
|
|
13
|
+
cwe: CweStringSchema,
|
|
14
|
+
severity: SeverityEnum.default('high'),
|
|
15
|
+
category: z.string().optional(),
|
|
16
|
+
}).strict();
|
|
17
|
+
const CustomSanitizerSchema = z.object({
|
|
18
|
+
pattern: z.string().min(1, { message: 'pattern must not be empty' }),
|
|
19
|
+
cwes: z.array(CweStringSchema).min(1, { message: 'sanitizer must neutralize at least one CWE' }),
|
|
20
|
+
}).strict();
|
|
21
|
+
const SuppressionEntrySchema = z.object({
|
|
22
|
+
file: z.string().min(1, { message: 'file glob must not be empty' }),
|
|
23
|
+
rule: z.string().optional(),
|
|
24
|
+
reason: z.string().min(10, { message: 'reason must be at least 10 characters so future readers understand WHY' }),
|
|
25
|
+
}).strict();
|
|
26
|
+
const SuppressionOptionsSchema = z.object({
|
|
27
|
+
warnUnused: z.boolean().default(true),
|
|
28
|
+
warnNaked: z.boolean().default(true),
|
|
29
|
+
}).strict();
|
|
5
30
|
const ConfigFileSchema = z.object({
|
|
6
31
|
stack: z.object({
|
|
7
32
|
framework: z.string().optional(),
|
|
@@ -20,6 +45,12 @@ const ConfigFileSchema = z.object({
|
|
|
20
45
|
rules: z.record(z.string()).optional(),
|
|
21
46
|
ignore: z.array(z.string()).optional(),
|
|
22
47
|
target: z.string().optional(),
|
|
48
|
+
customSources: z.array(CustomSourceSchema).optional(),
|
|
49
|
+
customSinks: z.array(CustomSinkSchema).optional(),
|
|
50
|
+
customSanitizers: z.array(CustomSanitizerSchema).optional(),
|
|
51
|
+
suppressions: z.array(SuppressionEntrySchema).optional(),
|
|
52
|
+
suppressionOptions: SuppressionOptionsSchema.optional(),
|
|
53
|
+
allowOverrides: z.boolean().optional(),
|
|
23
54
|
}).strict();
|
|
24
55
|
const DEFAULT_IGNORE = [
|
|
25
56
|
'node_modules',
|
|
@@ -43,6 +74,26 @@ const DEFAULT_IGNORE = [
|
|
|
43
74
|
'.gradle',
|
|
44
75
|
'.idea',
|
|
45
76
|
'.vscode',
|
|
77
|
+
'.auto-claude',
|
|
78
|
+
'.claude',
|
|
79
|
+
'.cursor',
|
|
80
|
+
'.windsurf',
|
|
81
|
+
'.codex',
|
|
82
|
+
'.aider',
|
|
83
|
+
// Test + benchmark fixtures (v0.7.1): scanning these is almost always
|
|
84
|
+
// noise — they contain intentionally-vulnerable code OR mocked data.
|
|
85
|
+
// Users who DO want to scan their tests can override via
|
|
86
|
+
// aegis.config.json `ignore` (unions with this list) or explicitly
|
|
87
|
+
// include paths on the CLI.
|
|
88
|
+
'__tests__',
|
|
89
|
+
'__test__',
|
|
90
|
+
'test',
|
|
91
|
+
'tests',
|
|
92
|
+
'__mocks__',
|
|
93
|
+
'__fixtures__',
|
|
94
|
+
'fixtures',
|
|
95
|
+
'benchmark',
|
|
96
|
+
'benchmarks',
|
|
46
97
|
];
|
|
47
98
|
/**
|
|
48
99
|
* Attempt to load aegis.config.json from the project directory.
|
|
@@ -59,12 +110,22 @@ async function loadConfigFile(projectPath) {
|
|
|
59
110
|
if (result.success) {
|
|
60
111
|
return result.data;
|
|
61
112
|
}
|
|
62
|
-
// Validation failed —
|
|
63
|
-
|
|
113
|
+
// Validation failed — escalate to console.error so it doesn't get lost in
|
|
114
|
+
// CI output noise. The whole config is discarded and auto-detection runs
|
|
115
|
+
// (the safer default — better than applying a partial config).
|
|
116
|
+
const details = result.error.issues
|
|
117
|
+
.map((i) => ` - ${i.path.length > 0 ? i.path.join('.') : '<root>'}: ${i.message}`)
|
|
118
|
+
.join('\n');
|
|
119
|
+
console.error(`[aegis] CONFIG REJECTED — ${jsonPath} failed validation.\n` +
|
|
120
|
+
`Custom rules, suppressions, and all other fields WILL NOT BE APPLIED.\n` +
|
|
121
|
+
`Issues:\n${details}\n` +
|
|
122
|
+
`Fix the config file and re-run. Falling back to auto-detection.`);
|
|
64
123
|
return null;
|
|
65
124
|
}
|
|
66
|
-
catch {
|
|
67
|
-
// Malformed JSON —
|
|
125
|
+
catch (err) {
|
|
126
|
+
// Malformed JSON — also escalate (same problem: user thinks config is applied but isn't)
|
|
127
|
+
console.error(`[aegis] CONFIG REJECTED — ${jsonPath} is not valid JSON: ${err instanceof Error ? err.message : String(err)}.\n` +
|
|
128
|
+
`Falling back to auto-detection.`);
|
|
68
129
|
}
|
|
69
130
|
}
|
|
70
131
|
return null;
|
|
@@ -105,6 +166,24 @@ export async function loadConfig(projectPath, mode = 'scan') {
|
|
|
105
166
|
if (fileConfig.target !== undefined) {
|
|
106
167
|
config.target = fileConfig.target;
|
|
107
168
|
}
|
|
169
|
+
if (fileConfig.customSources !== undefined) {
|
|
170
|
+
config.customSources = fileConfig.customSources;
|
|
171
|
+
}
|
|
172
|
+
if (fileConfig.customSinks !== undefined) {
|
|
173
|
+
config.customSinks = fileConfig.customSinks;
|
|
174
|
+
}
|
|
175
|
+
if (fileConfig.customSanitizers !== undefined) {
|
|
176
|
+
config.customSanitizers = fileConfig.customSanitizers;
|
|
177
|
+
}
|
|
178
|
+
if (fileConfig.suppressions !== undefined) {
|
|
179
|
+
config.suppressions = fileConfig.suppressions;
|
|
180
|
+
}
|
|
181
|
+
if (fileConfig.suppressionOptions !== undefined) {
|
|
182
|
+
config.suppressionOptions = fileConfig.suppressionOptions;
|
|
183
|
+
}
|
|
184
|
+
if (fileConfig.allowOverrides !== undefined) {
|
|
185
|
+
config.allowOverrides = fileConfig.allowOverrides;
|
|
186
|
+
}
|
|
108
187
|
}
|
|
109
188
|
return config;
|
|
110
189
|
}
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG1C,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC/B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC3B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QACzB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC9B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC7B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QAC/B,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;QAC/B,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;KACjC,CAAC,CAAC,QAAQ,EAAE;IACb,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC1C,QAAQ,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE;IACpD,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACtC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACtC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,4 +5,7 @@ export { loadConfig, type ConfigFileShape } from './config.js';
|
|
|
5
5
|
export { Orchestrator } from './orchestrator.js';
|
|
6
6
|
export { exec, commandExists, walkFiles, readFileSafe, clearWalkFilesCache, getChangedFiles, type ExecResult, type ExecOptions } from './utils.js';
|
|
7
7
|
export { getVersion } from './version.js';
|
|
8
|
+
export { parseSuppressions, isSuppressed, getUnusedSuppressions, getNakedSuppressions, type Suppression, } from './suppressions.js';
|
|
9
|
+
export { globToRegex, configSuppressionMatches, applyPipelineSuppressions, type SuppressionStats, } from './suppression-filter.js';
|
|
10
|
+
export { PRECISION_GATES, SCANNER_TIERS, tierOf, gateFor, passesPrecisionGate, type PrecisionTier, } from './precision-tiers.js';
|
|
8
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACnJ,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACnJ,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,qBAAqB,EACrB,oBAAoB,EACpB,KAAK,WAAW,GACjB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,WAAW,EACX,wBAAwB,EACxB,yBAAyB,EACzB,KAAK,gBAAgB,GACtB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,eAAe,EACf,aAAa,EACb,MAAM,EACN,OAAO,EACP,mBAAmB,EACnB,KAAK,aAAa,GACnB,MAAM,sBAAsB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -5,4 +5,7 @@ export { loadConfig } from './config.js';
|
|
|
5
5
|
export { Orchestrator } from './orchestrator.js';
|
|
6
6
|
export { exec, commandExists, walkFiles, readFileSafe, clearWalkFilesCache, getChangedFiles } from './utils.js';
|
|
7
7
|
export { getVersion } from './version.js';
|
|
8
|
+
export { parseSuppressions, isSuppressed, getUnusedSuppressions, getNakedSuppressions, } from './suppressions.js';
|
|
9
|
+
export { globToRegex, configSuppressionMatches, applyPipelineSuppressions, } from './suppression-filter.js';
|
|
10
|
+
export { PRECISION_GATES, SCANNER_TIERS, tierOf, gateFor, passesPrecisionGate, } from './precision-tiers.js';
|
|
8
11
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,UAAU,EAAwB,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAqC,MAAM,YAAY,CAAC;AACnJ,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,QAAQ,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACpF,OAAO,EAAE,UAAU,EAAwB,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,SAAS,EAAE,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAqC,MAAM,YAAY,CAAC;AACnJ,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,qBAAqB,EACrB,oBAAoB,GAErB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,WAAW,EACX,wBAAwB,EACxB,yBAAyB,GAE1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,eAAe,EACf,aAAa,EACb,MAAM,EACN,OAAO,EACP,mBAAmB,GAEpB,MAAM,sBAAsB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAmC,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAmC,MAAM,YAAY,CAAC;AAgBrG,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAiB;IAEjC,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAI1B,GAAG,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;CA2HrD"}
|
package/dist/orchestrator.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { calculateScore } from './scoring.js';
|
|
2
|
+
import { applyPipelineSuppressions } from './suppression-filter.js';
|
|
3
|
+
import { walkFiles } from './utils.js';
|
|
2
4
|
const SCANNER_TIMEOUT_MS = 120_000; // 2 minutes per scanner
|
|
3
5
|
function withTimeout(promise, ms, label) {
|
|
4
6
|
return new Promise((resolve, reject) => {
|
|
@@ -72,6 +74,22 @@ export class Orchestrator {
|
|
|
72
74
|
return diffSet.has(f.file);
|
|
73
75
|
});
|
|
74
76
|
}
|
|
77
|
+
// Pipeline-level suppressions — applies to ALL scanners, not just taint-analyzer.
|
|
78
|
+
// Inline (// aegis-ignore) + Config-level (aegis.config.json suppressions[]).
|
|
79
|
+
// When warnUnused is enabled, also walk the project for stale suppressions
|
|
80
|
+
// in files that produced no findings (cheap — pre-filtered by substring).
|
|
81
|
+
const warnUnused = config.suppressionOptions?.warnUnused !== false;
|
|
82
|
+
const scannedFiles = warnUnused
|
|
83
|
+
? walkFiles(config.projectPath, config.ignore ?? [], ['ts', 'js', 'tsx', 'jsx'])
|
|
84
|
+
: undefined;
|
|
85
|
+
const suppressionResult = applyPipelineSuppressions(allFindings, config, scannedFiles);
|
|
86
|
+
allFindings = suppressionResult.kept;
|
|
87
|
+
for (const msg of suppressionResult.stats.nakedWarnings) {
|
|
88
|
+
process.stderr.write(`${msg}\n`);
|
|
89
|
+
}
|
|
90
|
+
for (const msg of suppressionResult.stats.unusedWarnings) {
|
|
91
|
+
process.stderr.write(`${msg}\n`);
|
|
92
|
+
}
|
|
75
93
|
// Calculate confidence based on SECURITY-focused external tools.
|
|
76
94
|
// npm-audit, react-doctor, license-checker are always available (built-in node tools)
|
|
77
95
|
// and don't indicate real external security tool installation.
|
package/dist/orchestrator.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"orchestrator.js","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Precision-Tier Classification for Scanners.
|
|
3
|
+
*
|
|
4
|
+
* Different scanner types have different realistic precision ceilings:
|
|
5
|
+
* - Pattern-matching on explicit syntax (CSP headers, cookie flags) can hit 85-95%
|
|
6
|
+
* - Taint propagation through AST is 70-85% due to inference limits
|
|
7
|
+
* - Heuristic "missing X guard" checks are 50-70% because context is fuzzy
|
|
8
|
+
*
|
|
9
|
+
* Flat 70% gates would unfairly punish heuristic scanners and be too lax for
|
|
10
|
+
* pattern ones. This module defines tiered gates, each scanner classified once
|
|
11
|
+
* and explicitly — no inline code-review arguments about where a scanner belongs.
|
|
12
|
+
*
|
|
13
|
+
* Scanners below their tier's gate on the measurement corpus ship as
|
|
14
|
+
* `--experimental` only (quarantine tier) and don't count toward the overall
|
|
15
|
+
* precision score.
|
|
16
|
+
*/
|
|
17
|
+
export type PrecisionTier = 'definitive' | 'pattern' | 'taint' | 'heuristic' | 'quarantine';
|
|
18
|
+
/**
|
|
19
|
+
* Merge-gate per tier. A scanner whose measured precision on the dogfood
|
|
20
|
+
* corpus is below its gate cannot ship in the default scan output.
|
|
21
|
+
*/
|
|
22
|
+
export declare const PRECISION_GATES: Record<PrecisionTier, number>;
|
|
23
|
+
/**
|
|
24
|
+
* Explicit scanner → tier mapping.
|
|
25
|
+
*
|
|
26
|
+
* NOT classified here (by design):
|
|
27
|
+
* - External tool wrappers (semgrep, gitleaks, trivy, …) inherit the tool's
|
|
28
|
+
* own precision; AEGIS doesn't re-assess.
|
|
29
|
+
* - Runtime probes (auth-probe, race-probe, …) measure live behavior, not
|
|
30
|
+
* static precision.
|
|
31
|
+
* - Compliance meta-scanners (gdpr-engine, iso27001-checker, …) aggregate
|
|
32
|
+
* findings from underlying scanners; precision inherited.
|
|
33
|
+
*
|
|
34
|
+
* New scanners MUST be added here before merge. The `tierOf` function returns
|
|
35
|
+
* undefined for unclassified scanners, which the precision CLI reports as an
|
|
36
|
+
* error so merge isn't silently possible.
|
|
37
|
+
*/
|
|
38
|
+
export declare const SCANNER_TIERS: Partial<Record<string, PrecisionTier>>;
|
|
39
|
+
/** Look up a scanner's tier. Returns undefined for unclassified/external/probe. */
|
|
40
|
+
export declare function tierOf(scannerName: string): PrecisionTier | undefined;
|
|
41
|
+
/** Return the precision gate for a scanner, or undefined if unclassified. */
|
|
42
|
+
export declare function gateFor(scannerName: string): number | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Check whether a measured precision passes the scanner's tier gate.
|
|
45
|
+
* Returns false if scanner is unclassified (must be explicit before merge).
|
|
46
|
+
*/
|
|
47
|
+
export declare function passesPrecisionGate(scannerName: string, precision: number): boolean;
|
|
48
|
+
//# sourceMappingURL=precision-tiers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"precision-tiers.d.ts","sourceRoot":"","sources":["../src/precision-tiers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG,SAAS,GAAG,OAAO,GAAG,WAAW,GAAG,YAAY,CAAC;AAE5F;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,aAAa,EAAE,MAAM,CAWzD,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAgDhE,CAAC;AAEF,mFAAmF;AACnF,wBAAgB,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAErE;AAED,6EAA6E;AAC7E,wBAAgB,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG/D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAGnF"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Precision-Tier Classification for Scanners.
|
|
3
|
+
*
|
|
4
|
+
* Different scanner types have different realistic precision ceilings:
|
|
5
|
+
* - Pattern-matching on explicit syntax (CSP headers, cookie flags) can hit 85-95%
|
|
6
|
+
* - Taint propagation through AST is 70-85% due to inference limits
|
|
7
|
+
* - Heuristic "missing X guard" checks are 50-70% because context is fuzzy
|
|
8
|
+
*
|
|
9
|
+
* Flat 70% gates would unfairly punish heuristic scanners and be too lax for
|
|
10
|
+
* pattern ones. This module defines tiered gates, each scanner classified once
|
|
11
|
+
* and explicitly — no inline code-review arguments about where a scanner belongs.
|
|
12
|
+
*
|
|
13
|
+
* Scanners below their tier's gate on the measurement corpus ship as
|
|
14
|
+
* `--experimental` only (quarantine tier) and don't count toward the overall
|
|
15
|
+
* precision score.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Merge-gate per tier. A scanner whose measured precision on the dogfood
|
|
19
|
+
* corpus is below its gate cannot ship in the default scan output.
|
|
20
|
+
*/
|
|
21
|
+
export const PRECISION_GATES = {
|
|
22
|
+
/** Definitive signal — entropy, known-bad strings. High confidence expected. */
|
|
23
|
+
definitive: 0.80,
|
|
24
|
+
/** Syntax-level pattern matching. Clear, objective signal. */
|
|
25
|
+
pattern: 0.75,
|
|
26
|
+
/** Taint propagation — inference limits keep this from pattern-level precision. */
|
|
27
|
+
taint: 0.70,
|
|
28
|
+
/** Context-heavy heuristics — accept lower precision for harder signal. */
|
|
29
|
+
heuristic: 0.60,
|
|
30
|
+
/** Below any tier's gate — ships `--experimental` only, not default scan. */
|
|
31
|
+
quarantine: 0.0,
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Explicit scanner → tier mapping.
|
|
35
|
+
*
|
|
36
|
+
* NOT classified here (by design):
|
|
37
|
+
* - External tool wrappers (semgrep, gitleaks, trivy, …) inherit the tool's
|
|
38
|
+
* own precision; AEGIS doesn't re-assess.
|
|
39
|
+
* - Runtime probes (auth-probe, race-probe, …) measure live behavior, not
|
|
40
|
+
* static precision.
|
|
41
|
+
* - Compliance meta-scanners (gdpr-engine, iso27001-checker, …) aggregate
|
|
42
|
+
* findings from underlying scanners; precision inherited.
|
|
43
|
+
*
|
|
44
|
+
* New scanners MUST be added here before merge. The `tierOf` function returns
|
|
45
|
+
* undefined for unclassified scanners, which the precision CLI reports as an
|
|
46
|
+
* error so merge isn't silently possible.
|
|
47
|
+
*/
|
|
48
|
+
export const SCANNER_TIERS = {
|
|
49
|
+
// Definitive (80% gate) — signal is objective, high-confidence
|
|
50
|
+
'entropy-scanner': 'definitive',
|
|
51
|
+
'gitleaks': 'definitive',
|
|
52
|
+
'trufflehog': 'definitive',
|
|
53
|
+
// Pattern (75% gate) — syntax-level pattern matching
|
|
54
|
+
'cookie-checker': 'pattern',
|
|
55
|
+
'cors-checker': 'pattern',
|
|
56
|
+
'header-checker': 'pattern',
|
|
57
|
+
'crypto-auditor': 'pattern',
|
|
58
|
+
'config-auditor': 'pattern',
|
|
59
|
+
'console-checker': 'pattern',
|
|
60
|
+
'http-timeout-checker': 'pattern',
|
|
61
|
+
'jwt-checker': 'pattern',
|
|
62
|
+
'open-redirect-checker': 'pattern',
|
|
63
|
+
'redos-checker': 'pattern',
|
|
64
|
+
'timing-safe-checker': 'pattern',
|
|
65
|
+
'xss-checker': 'pattern',
|
|
66
|
+
'error-leakage-checker': 'pattern',
|
|
67
|
+
'rls-bypass-checker': 'pattern',
|
|
68
|
+
'rsc-data-checker': 'pattern',
|
|
69
|
+
'license-checker': 'pattern',
|
|
70
|
+
// v0.6 additions:
|
|
71
|
+
'next-public-leak': 'pattern',
|
|
72
|
+
// Taint (70% gate) — AST-based dataflow
|
|
73
|
+
'taint-analyzer': 'taint',
|
|
74
|
+
'sql-concat-checker': 'taint',
|
|
75
|
+
'ssrf-checker': 'taint',
|
|
76
|
+
'path-traversal-checker': 'taint',
|
|
77
|
+
// Heuristic (60% gate) — context-heavy "missing X guard"-style signals
|
|
78
|
+
'auth-enforcer': 'heuristic',
|
|
79
|
+
'rate-limit-checker': 'heuristic',
|
|
80
|
+
'tenant-isolation-checker': 'heuristic',
|
|
81
|
+
'mass-assignment-checker': 'heuristic',
|
|
82
|
+
'pagination-checker': 'heuristic',
|
|
83
|
+
'zod-enforcer': 'heuristic',
|
|
84
|
+
'csrf-checker': 'heuristic',
|
|
85
|
+
'env-validation-checker': 'heuristic',
|
|
86
|
+
'logging-checker': 'heuristic',
|
|
87
|
+
'upload-validator': 'heuristic',
|
|
88
|
+
'prompt-injection-checker': 'heuristic',
|
|
89
|
+
'supply-chain': 'heuristic',
|
|
90
|
+
'react-doctor': 'heuristic',
|
|
91
|
+
'dep-confusion-checker': 'heuristic',
|
|
92
|
+
'i18n-quality': 'heuristic',
|
|
93
|
+
};
|
|
94
|
+
/** Look up a scanner's tier. Returns undefined for unclassified/external/probe. */
|
|
95
|
+
export function tierOf(scannerName) {
|
|
96
|
+
return SCANNER_TIERS[scannerName];
|
|
97
|
+
}
|
|
98
|
+
/** Return the precision gate for a scanner, or undefined if unclassified. */
|
|
99
|
+
export function gateFor(scannerName) {
|
|
100
|
+
const tier = tierOf(scannerName);
|
|
101
|
+
return tier !== undefined ? PRECISION_GATES[tier] : undefined;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Check whether a measured precision passes the scanner's tier gate.
|
|
105
|
+
* Returns false if scanner is unclassified (must be explicit before merge).
|
|
106
|
+
*/
|
|
107
|
+
export function passesPrecisionGate(scannerName, precision) {
|
|
108
|
+
const gate = gateFor(scannerName);
|
|
109
|
+
return gate !== undefined && precision >= gate;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=precision-tiers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"precision-tiers.js","sourceRoot":"","sources":["../src/precision-tiers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAkC;IAC5D,gFAAgF;IAChF,UAAU,EAAE,IAAI;IAChB,8DAA8D;IAC9D,OAAO,EAAK,IAAI;IAChB,mFAAmF;IACnF,KAAK,EAAO,IAAI;IAChB,2EAA2E;IAC3E,SAAS,EAAG,IAAI;IAChB,6EAA6E;IAC7E,UAAU,EAAE,GAAG;CAChB,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,aAAa,GAA2C;IACnE,+DAA+D;IAC/D,iBAAiB,EAAW,YAAY;IACxC,UAAU,EAAkB,YAAY;IACxC,YAAY,EAAgB,YAAY;IAExC,qDAAqD;IACrD,gBAAgB,EAAY,SAAS;IACrC,cAAc,EAAc,SAAS;IACrC,gBAAgB,EAAY,SAAS;IACrC,gBAAgB,EAAY,SAAS;IACrC,gBAAgB,EAAY,SAAS;IACrC,iBAAiB,EAAW,SAAS;IACrC,sBAAsB,EAAM,SAAS;IACrC,aAAa,EAAe,SAAS;IACrC,uBAAuB,EAAK,SAAS;IACrC,eAAe,EAAa,SAAS;IACrC,qBAAqB,EAAO,SAAS;IACrC,aAAa,EAAe,SAAS;IACrC,uBAAuB,EAAK,SAAS;IACrC,oBAAoB,EAAQ,SAAS;IACrC,kBAAkB,EAAU,SAAS;IACrC,iBAAiB,EAAW,SAAS;IACrC,kBAAkB;IAClB,kBAAkB,EAAU,SAAS;IAErC,wCAAwC;IACxC,gBAAgB,EAAY,OAAO;IACnC,oBAAoB,EAAQ,OAAO;IACnC,cAAc,EAAc,OAAO;IACnC,wBAAwB,EAAI,OAAO;IAEnC,uEAAuE;IACvE,eAAe,EAAa,WAAW;IACvC,oBAAoB,EAAQ,WAAW;IACvC,0BAA0B,EAAE,WAAW;IACvC,yBAAyB,EAAG,WAAW;IACvC,oBAAoB,EAAQ,WAAW;IACvC,cAAc,EAAc,WAAW;IACvC,cAAc,EAAc,WAAW;IACvC,wBAAwB,EAAI,WAAW;IACvC,iBAAiB,EAAW,WAAW;IACvC,kBAAkB,EAAU,WAAW;IACvC,0BAA0B,EAAE,WAAW;IACvC,cAAc,EAAc,WAAW;IACvC,cAAc,EAAc,WAAW;IACvC,uBAAuB,EAAK,WAAW;IACvC,cAAc,EAAc,WAAW;CACxC,CAAC;AAEF,mFAAmF;AACnF,MAAM,UAAU,MAAM,CAAC,WAAmB;IACxC,OAAO,aAAa,CAAC,WAAW,CAAC,CAAC;AACpC,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,OAAO,CAAC,WAAmB;IACzC,MAAM,IAAI,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC;IACjC,OAAO,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAChE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,WAAmB,EAAE,SAAiB;IACxE,MAAM,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAClC,OAAO,IAAI,KAAK,SAAS,IAAI,SAAS,IAAI,IAAI,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { AegisConfig, Finding, SuppressionEntry } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Convert a user-provided glob to a RegExp.
|
|
4
|
+
*
|
|
5
|
+
* Supported tokens:
|
|
6
|
+
* - `**` — zero or more path segments (crosses `/`)
|
|
7
|
+
* - `*` — zero or more characters in a single segment (no `/`)
|
|
8
|
+
* - `?` — exactly one character (no `/`)
|
|
9
|
+
* - everything else is literal
|
|
10
|
+
*
|
|
11
|
+
* Leading `/` in the glob is treated literally (don't confuse absolute paths
|
|
12
|
+
* — inputs are always POSIX-normalized relative paths inside the orchestrator).
|
|
13
|
+
*/
|
|
14
|
+
export declare function globToRegex(glob: string): RegExp;
|
|
15
|
+
/**
|
|
16
|
+
* Check whether a config-level suppression entry covers the given finding.
|
|
17
|
+
*/
|
|
18
|
+
export declare function configSuppressionMatches(entry: SuppressionEntry, relPath: string, scannerName: string, cwe: number | undefined): boolean;
|
|
19
|
+
export interface SuppressionStats {
|
|
20
|
+
suppressedByInline: number;
|
|
21
|
+
suppressedByConfig: number;
|
|
22
|
+
nakedWarnings: string[];
|
|
23
|
+
unusedWarnings: string[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Filter findings by suppressions. Returns kept findings + diagnostic stats.
|
|
27
|
+
* Caller is responsible for emitting nakedWarnings/unusedWarnings if desired.
|
|
28
|
+
*
|
|
29
|
+
* @param scannedFiles Optional list of all files that scanners visited. When
|
|
30
|
+
* provided AND `warnUnused !== false`, suppressions in these files are
|
|
31
|
+
* checked even if the file produced zero findings (catches stale
|
|
32
|
+
* suppressions left behind after refactors).
|
|
33
|
+
*/
|
|
34
|
+
export declare function applyPipelineSuppressions(findings: Finding[], config: AegisConfig, scannedFiles?: string[]): {
|
|
35
|
+
kept: Finding[];
|
|
36
|
+
stats: SuppressionStats;
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=suppression-filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suppression-filter.d.ts","sourceRoot":"","sources":["../src/suppression-filter.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAUzE;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkBhD;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,gBAAgB,EACvB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,GAAG,SAAS,GACtB,OAAO,CAST;AAED,MAAM,WAAW,gBAAgB;IAC/B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,OAAO,EAAE,EACnB,MAAM,EAAE,WAAW,EACnB,YAAY,CAAC,EAAE,MAAM,EAAE,GACtB;IAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAAC,KAAK,EAAE,gBAAgB,CAAA;CAAE,CAuF9C"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pipeline-level suppression filter.
|
|
3
|
+
*
|
|
4
|
+
* Applied by the Orchestrator AFTER all scanners have produced findings and
|
|
5
|
+
* AFTER dedup. This makes suppressions cross-cutting: they affect every
|
|
6
|
+
* scanner (auth-enforcer, csrf-checker, header-checker, taint-analyzer, …),
|
|
7
|
+
* not only the taint-analyzer that originally spoke this DSL.
|
|
8
|
+
*
|
|
9
|
+
* Two layers:
|
|
10
|
+
* 1. Inline — `// aegis-ignore` comments in source files (finding.line scoped)
|
|
11
|
+
* 2. Config — `suppressions[]` in aegis.config.json (file glob + rule scoped)
|
|
12
|
+
*/
|
|
13
|
+
import { relative } from 'node:path';
|
|
14
|
+
import { readFileSafe } from './utils.js';
|
|
15
|
+
import { parseSuppressions, isSuppressed, getUnusedSuppressions, getNakedSuppressions, } from './suppressions.js';
|
|
16
|
+
/**
|
|
17
|
+
* Convert a user-provided glob to a RegExp.
|
|
18
|
+
*
|
|
19
|
+
* Supported tokens:
|
|
20
|
+
* - `**` — zero or more path segments (crosses `/`)
|
|
21
|
+
* - `*` — zero or more characters in a single segment (no `/`)
|
|
22
|
+
* - `?` — exactly one character (no `/`)
|
|
23
|
+
* - everything else is literal
|
|
24
|
+
*
|
|
25
|
+
* Leading `/` in the glob is treated literally (don't confuse absolute paths
|
|
26
|
+
* — inputs are always POSIX-normalized relative paths inside the orchestrator).
|
|
27
|
+
*/
|
|
28
|
+
export function globToRegex(glob) {
|
|
29
|
+
// All transformations use placeholders so that intermediate regex output
|
|
30
|
+
// (e.g., `.*` from `**`) is not re-matched by later rules (`*` → `[^/]*`).
|
|
31
|
+
const escaped = glob
|
|
32
|
+
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
33
|
+
.replace(/\/\*\*\//g, '__AEGIS_MIDSTAR__')
|
|
34
|
+
.replace(/^\*\*\//g, '__AEGIS_PRESTAR__')
|
|
35
|
+
.replace(/\/\*\*$/g, '__AEGIS_POSTSTAR__')
|
|
36
|
+
.replace(/\*\*/g, '__AEGIS_DOUBLESTAR__')
|
|
37
|
+
.replace(/\*/g, '__AEGIS_STAR__')
|
|
38
|
+
.replace(/\?/g, '__AEGIS_QMARK__')
|
|
39
|
+
.replace(/__AEGIS_MIDSTAR__/g, '/(?:.+/)?')
|
|
40
|
+
.replace(/__AEGIS_PRESTAR__/g, '(?:.+/)?')
|
|
41
|
+
.replace(/__AEGIS_POSTSTAR__/g, '(?:/.+)?')
|
|
42
|
+
.replace(/__AEGIS_DOUBLESTAR__/g, '.*')
|
|
43
|
+
.replace(/__AEGIS_STAR__/g, '[^/]*')
|
|
44
|
+
.replace(/__AEGIS_QMARK__/g, '[^/]');
|
|
45
|
+
return new RegExp('^' + escaped + '$');
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Check whether a config-level suppression entry covers the given finding.
|
|
49
|
+
*/
|
|
50
|
+
export function configSuppressionMatches(entry, relPath, scannerName, cwe) {
|
|
51
|
+
if (!globToRegex(entry.file).test(relPath))
|
|
52
|
+
return false;
|
|
53
|
+
if (entry.rule === undefined)
|
|
54
|
+
return true; // catch-all for this file
|
|
55
|
+
if (entry.rule === scannerName)
|
|
56
|
+
return true;
|
|
57
|
+
if (cwe !== undefined) {
|
|
58
|
+
const m = entry.rule.match(/^CWE-(\d+)$/);
|
|
59
|
+
if (m && Number.parseInt(m[1], 10) === cwe)
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Filter findings by suppressions. Returns kept findings + diagnostic stats.
|
|
66
|
+
* Caller is responsible for emitting nakedWarnings/unusedWarnings if desired.
|
|
67
|
+
*
|
|
68
|
+
* @param scannedFiles Optional list of all files that scanners visited. When
|
|
69
|
+
* provided AND `warnUnused !== false`, suppressions in these files are
|
|
70
|
+
* checked even if the file produced zero findings (catches stale
|
|
71
|
+
* suppressions left behind after refactors).
|
|
72
|
+
*/
|
|
73
|
+
export function applyPipelineSuppressions(findings, config, scannedFiles) {
|
|
74
|
+
const diagnostics = config.suppressionOptions ?? {};
|
|
75
|
+
const warnUnused = diagnostics.warnUnused !== false;
|
|
76
|
+
const warnNaked = diagnostics.warnNaked !== false;
|
|
77
|
+
const configSups = config.suppressions ?? [];
|
|
78
|
+
const fileCache = new Map();
|
|
79
|
+
const warnedNakedFiles = new Set();
|
|
80
|
+
const stats = {
|
|
81
|
+
suppressedByInline: 0,
|
|
82
|
+
suppressedByConfig: 0,
|
|
83
|
+
nakedWarnings: [],
|
|
84
|
+
unusedWarnings: [],
|
|
85
|
+
};
|
|
86
|
+
const kept = [];
|
|
87
|
+
function getSups(file) {
|
|
88
|
+
let sups = fileCache.get(file);
|
|
89
|
+
if (sups !== undefined)
|
|
90
|
+
return sups;
|
|
91
|
+
const content = readFileSafe(file);
|
|
92
|
+
sups = content ? parseSuppressions(content) : [];
|
|
93
|
+
fileCache.set(file, sups);
|
|
94
|
+
if (warnNaked && !warnedNakedFiles.has(file)) {
|
|
95
|
+
warnedNakedFiles.add(file);
|
|
96
|
+
for (const naked of getNakedSuppressions(sups)) {
|
|
97
|
+
stats.nakedWarnings.push(`[aegis] Naked suppression in ${file}:${naked.startLine} — please add a reason after '—' so future readers understand WHY.`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return sups;
|
|
101
|
+
}
|
|
102
|
+
for (const f of findings) {
|
|
103
|
+
// Inline suppression — per-file comment, finest granularity
|
|
104
|
+
if (f.file && f.line !== undefined) {
|
|
105
|
+
const sups = getSups(f.file);
|
|
106
|
+
if (isSuppressed(f.line, f.cwe, sups)) {
|
|
107
|
+
stats.suppressedByInline++;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Config-level suppression — glob + rule
|
|
112
|
+
if (configSups.length > 0) {
|
|
113
|
+
const relPath = f.file
|
|
114
|
+
? relative(config.projectPath, f.file).split('\\').join('/')
|
|
115
|
+
: '';
|
|
116
|
+
const match = configSups.some((s) => configSuppressionMatches(s, relPath, f.scanner, f.cwe));
|
|
117
|
+
if (match) {
|
|
118
|
+
stats.suppressedByConfig++;
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
kept.push(f);
|
|
123
|
+
}
|
|
124
|
+
if (warnUnused) {
|
|
125
|
+
// Scan files that produced zero findings but may still contain
|
|
126
|
+
// stale `// aegis-ignore` directives. Cheap pre-filter: quick substring
|
|
127
|
+
// check skips files that certainly have no suppressions.
|
|
128
|
+
if (scannedFiles) {
|
|
129
|
+
for (const file of scannedFiles) {
|
|
130
|
+
if (fileCache.has(file))
|
|
131
|
+
continue;
|
|
132
|
+
const content = readFileSafe(file);
|
|
133
|
+
if (!content || !content.includes('aegis-ignore'))
|
|
134
|
+
continue;
|
|
135
|
+
fileCache.set(file, parseSuppressions(content));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
for (const [file, sups] of fileCache) {
|
|
139
|
+
for (const u of getUnusedSuppressions(sups)) {
|
|
140
|
+
stats.unusedWarnings.push(`[aegis] Unused suppression in ${file}:${u.startLine} — ` +
|
|
141
|
+
`${u.cwe ? `CWE-${u.cwe}` : 'catch-all'} never matched a finding. Consider removing it.`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return { kept, stats };
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=suppression-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suppression-filter.js","sourceRoot":"","sources":["../src/suppression-filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline suppression parsing and matching.
|
|
3
|
+
*
|
|
4
|
+
* Syntax:
|
|
5
|
+
* // aegis-ignore — reason text (applies to NEXT line)
|
|
6
|
+
* // aegis-ignore CWE-918 — legitimer proxy call (CWE-specific, next line)
|
|
7
|
+
* /* aegis-ignore-block CWE-78 * / (applies until aegis-ignore-end)
|
|
8
|
+
* /* aegis-ignore-end * /
|
|
9
|
+
*
|
|
10
|
+
* A suppression without a CWE is a catch-all for that line.
|
|
11
|
+
* A suppression WITH a CWE only matches findings with that exact CWE number.
|
|
12
|
+
* Reason text is recommended (warned if missing/too short).
|
|
13
|
+
*/
|
|
14
|
+
export interface Suppression {
|
|
15
|
+
/** 1-indexed line where suppression starts applying. */
|
|
16
|
+
startLine: number;
|
|
17
|
+
/** 1-indexed line where suppression stops applying (inclusive). */
|
|
18
|
+
endLine: number;
|
|
19
|
+
/** Optional specific CWE; undefined = any CWE on this line. */
|
|
20
|
+
cwe?: number;
|
|
21
|
+
/** Free-text reason for the suppression. */
|
|
22
|
+
reason: string;
|
|
23
|
+
/** Mutable — flipped to true when a finding matched this suppression. */
|
|
24
|
+
used: boolean;
|
|
25
|
+
/** Kind for diagnostics. */
|
|
26
|
+
kind: 'next-line' | 'block';
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse suppression directives from source content.
|
|
30
|
+
* Returns all suppressions found, including orphan block-starts (which are logged
|
|
31
|
+
* as warnings later).
|
|
32
|
+
*/
|
|
33
|
+
export declare function parseSuppressions(content: string): Suppression[];
|
|
34
|
+
/**
|
|
35
|
+
* Return true if the given (line, cwe) is covered by any suppression.
|
|
36
|
+
* Mutates matching suppression's `used` flag.
|
|
37
|
+
*/
|
|
38
|
+
export declare function isSuppressed(findingLine: number | undefined, findingCwe: number | undefined, suppressions: Suppression[]): boolean;
|
|
39
|
+
/** Return the list of suppressions that were never triggered by a finding. */
|
|
40
|
+
export declare function getUnusedSuppressions(suppressions: Suppression[]): Suppression[];
|
|
41
|
+
/** Return suppressions missing a meaningful reason (fewer than 3 non-space chars). */
|
|
42
|
+
export declare function getNakedSuppressions(suppressions: Suppression[]): Suppression[];
|
|
43
|
+
//# sourceMappingURL=suppressions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suppressions.d.ts","sourceRoot":"","sources":["../src/suppressions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,SAAS,EAAE,MAAM,CAAC;IAClB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,yEAAyE;IACzE,IAAI,EAAE,OAAO,CAAC;IACd,4BAA4B;IAC5B,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC;CAC7B;AAmBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,EAAE,CAqEhE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,YAAY,EAAE,WAAW,EAAE,GAC1B,OAAO,CAST;AAED,8EAA8E;AAC9E,wBAAgB,qBAAqB,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAEhF;AAED,sFAAsF;AACtF,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAE/E"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inline suppression parsing and matching.
|
|
3
|
+
*
|
|
4
|
+
* Syntax:
|
|
5
|
+
* // aegis-ignore — reason text (applies to NEXT line)
|
|
6
|
+
* // aegis-ignore CWE-918 — legitimer proxy call (CWE-specific, next line)
|
|
7
|
+
* /* aegis-ignore-block CWE-78 * / (applies until aegis-ignore-end)
|
|
8
|
+
* /* aegis-ignore-end * /
|
|
9
|
+
*
|
|
10
|
+
* A suppression without a CWE is a catch-all for that line.
|
|
11
|
+
* A suppression WITH a CWE only matches findings with that exact CWE number.
|
|
12
|
+
* Reason text is recommended (warned if missing/too short).
|
|
13
|
+
*/
|
|
14
|
+
// Accept em-dash (—), en-dash (–), double-dash (--), or single-dash separator.
|
|
15
|
+
// Negative lookahead `(?!-)` prevents `aegis-ignore-block` from matching as a
|
|
16
|
+
// single-line directive with reason="block" (that's what BLOCK_START_RE is for).
|
|
17
|
+
const SINGLE_LINE_RE = /\/\/\s*aegis-ignore(?!-)(?:\s+CWE-(\d+))?\s*(?:[\u2014\u2013]|--|-)?\s*(.*)$/;
|
|
18
|
+
// Block start: /* aegis-ignore-block [CWE-nnn] [— reason] */
|
|
19
|
+
const BLOCK_START_RE = /\/\*\s*aegis-ignore-block(?:\s+CWE-(\d+))?\s*(?:[\u2014\u2013]|--|-)?\s*([^*]*?)\s*\*\//;
|
|
20
|
+
// Block end: /* aegis-ignore-end */
|
|
21
|
+
const BLOCK_END_RE = /\/\*\s*aegis-ignore-end\s*\*\//;
|
|
22
|
+
// Known limitation (v1): these regexes run on raw line text, not TS comment ranges.
|
|
23
|
+
// String literals containing suppression syntax (e.g., `const doc = "// aegis-ignore"`)
|
|
24
|
+
// WILL be matched. Documented — ts.getLeadingCommentRanges migration planned for v2.
|
|
25
|
+
/**
|
|
26
|
+
* Parse suppression directives from source content.
|
|
27
|
+
* Returns all suppressions found, including orphan block-starts (which are logged
|
|
28
|
+
* as warnings later).
|
|
29
|
+
*/
|
|
30
|
+
export function parseSuppressions(content) {
|
|
31
|
+
const lines = content.split('\n');
|
|
32
|
+
const suppressions = [];
|
|
33
|
+
let openBlock = null;
|
|
34
|
+
for (let i = 0; i < lines.length; i++) {
|
|
35
|
+
const line = lines[i];
|
|
36
|
+
const lineNumber = i + 1;
|
|
37
|
+
if (openBlock) {
|
|
38
|
+
if (BLOCK_END_RE.test(line)) {
|
|
39
|
+
suppressions.push({
|
|
40
|
+
startLine: openBlock.startLine,
|
|
41
|
+
endLine: lineNumber,
|
|
42
|
+
cwe: openBlock.cwe,
|
|
43
|
+
reason: openBlock.reason,
|
|
44
|
+
used: false,
|
|
45
|
+
kind: 'block',
|
|
46
|
+
});
|
|
47
|
+
openBlock = null;
|
|
48
|
+
}
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const blockMatch = line.match(BLOCK_START_RE);
|
|
52
|
+
if (blockMatch) {
|
|
53
|
+
const cwe = blockMatch[1] ? Number.parseInt(blockMatch[1], 10) : undefined;
|
|
54
|
+
const reason = (blockMatch[2] ?? '').trim();
|
|
55
|
+
// Same-line close? `/* aegis-ignore-block */ exec(x); /* aegis-ignore-end */`
|
|
56
|
+
// Search for BLOCK_END_RE in the text AFTER the block-start match.
|
|
57
|
+
const afterBlockStart = line.slice(blockMatch.index + blockMatch[0].length);
|
|
58
|
+
if (BLOCK_END_RE.test(afterBlockStart)) {
|
|
59
|
+
suppressions.push({
|
|
60
|
+
startLine: lineNumber,
|
|
61
|
+
endLine: lineNumber,
|
|
62
|
+
cwe,
|
|
63
|
+
reason,
|
|
64
|
+
used: false,
|
|
65
|
+
kind: 'block',
|
|
66
|
+
});
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
openBlock = { startLine: lineNumber, cwe, reason };
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const singleMatch = line.match(SINGLE_LINE_RE);
|
|
73
|
+
if (singleMatch) {
|
|
74
|
+
const cwe = singleMatch[1] ? Number.parseInt(singleMatch[1], 10) : undefined;
|
|
75
|
+
const reason = (singleMatch[2] ?? '').trim();
|
|
76
|
+
// Applies to the NEXT line (common convention — same as eslint-disable-next-line)
|
|
77
|
+
suppressions.push({
|
|
78
|
+
startLine: lineNumber + 1,
|
|
79
|
+
endLine: lineNumber + 1,
|
|
80
|
+
cwe,
|
|
81
|
+
reason,
|
|
82
|
+
used: false,
|
|
83
|
+
kind: 'next-line',
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Orphan block-start (no end) — leave openBlock discarded; caller can check via logs
|
|
88
|
+
return suppressions;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Return true if the given (line, cwe) is covered by any suppression.
|
|
92
|
+
* Mutates matching suppression's `used` flag.
|
|
93
|
+
*/
|
|
94
|
+
export function isSuppressed(findingLine, findingCwe, suppressions) {
|
|
95
|
+
if (findingLine === undefined)
|
|
96
|
+
return false;
|
|
97
|
+
for (const s of suppressions) {
|
|
98
|
+
if (findingLine < s.startLine || findingLine > s.endLine)
|
|
99
|
+
continue;
|
|
100
|
+
if (s.cwe !== undefined && s.cwe !== findingCwe)
|
|
101
|
+
continue;
|
|
102
|
+
s.used = true;
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
/** Return the list of suppressions that were never triggered by a finding. */
|
|
108
|
+
export function getUnusedSuppressions(suppressions) {
|
|
109
|
+
return suppressions.filter((s) => !s.used);
|
|
110
|
+
}
|
|
111
|
+
/** Return suppressions missing a meaningful reason (fewer than 3 non-space chars). */
|
|
112
|
+
export function getNakedSuppressions(suppressions) {
|
|
113
|
+
return suppressions.filter((s) => s.reason.replace(/\s/g, '').length < 3);
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=suppressions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"suppressions.js","sourceRoot":"","sources":["../src/suppressions.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -14,6 +14,49 @@ export interface Finding {
|
|
|
14
14
|
owasp?: string;
|
|
15
15
|
cwe?: number;
|
|
16
16
|
reference?: string;
|
|
17
|
+
/**
|
|
18
|
+
* True when the finding is about the file AS A WHOLE, not a specific line
|
|
19
|
+
* (e.g., "this route file lacks an auth guard", "this config lacks a CSP").
|
|
20
|
+
* Scanners that emit such findings conventionally set `line: 1`, but the
|
|
21
|
+
* precision-CLI fingerprint must not depend on source context near line 1 —
|
|
22
|
+
* that context shifts when unrelated edits are made above.
|
|
23
|
+
*
|
|
24
|
+
* Set this to `true` on file-level emit sites. The precision CLI uses it to
|
|
25
|
+
* short-circuit context-window hashing in favor of a stable
|
|
26
|
+
* `scanner|file|title` identity that survives arbitrary line-drift.
|
|
27
|
+
*
|
|
28
|
+
* Optional (backward-compat). Undefined / false means "per-line finding" —
|
|
29
|
+
* the default behavior remains unchanged.
|
|
30
|
+
*/
|
|
31
|
+
fileLevel?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* v0.7 Phase 2: true when the finding spans a cross-module call — the
|
|
34
|
+
* sink was reached via a summary of an exported function declared in a
|
|
35
|
+
* different file from the one containing the taint source. Consumers
|
|
36
|
+
* (SARIF reporter, precision CLI) treat this as a signal to emit
|
|
37
|
+
* `relatedLocations` pointing at {@link crossFileOrigin}.
|
|
38
|
+
*/
|
|
39
|
+
crossFile?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* v0.7 Phase 2: absolute path of the file declaring the cross-file
|
|
42
|
+
* function that triggered the finding. Present only when `crossFile:
|
|
43
|
+
* true`. The SARIF reporter emits this as a `relatedLocations` entry
|
|
44
|
+
* so GitHub Code Scanning, Azure DevOps, and other SARIF consumers can
|
|
45
|
+
* jump to the cross-module origin of the vulnerability.
|
|
46
|
+
*/
|
|
47
|
+
crossFileOrigin?: string;
|
|
48
|
+
/**
|
|
49
|
+
* v0.7 Phase 5 calibration lever: per-finding confidence tier,
|
|
50
|
+
* distinct from the scan-level `AuditResult.confidence`. Scanners
|
|
51
|
+
* opt in when a finding class has measurement uncertainty that isn't
|
|
52
|
+
* captured by severity alone. Cross-file findings in v0.7 set
|
|
53
|
+
* `confidence: 'medium'` pending the n≥20 dogfood measurement that
|
|
54
|
+
* v0.8 targets — the sample size in the v0.7 pre-tag dogfood (n=2)
|
|
55
|
+
* was below the plan §3 TBD-3 threshold, so the FP-rate zone is
|
|
56
|
+
* unmeasurable, not failed. Default (undefined / absent) continues
|
|
57
|
+
* to mean "scanner's default confidence tier (typically high)".
|
|
58
|
+
*/
|
|
59
|
+
confidence?: Confidence;
|
|
17
60
|
}
|
|
18
61
|
export interface ScanResult {
|
|
19
62
|
scanner: string;
|
|
@@ -42,6 +85,55 @@ export interface DetectedStack {
|
|
|
42
85
|
hasI18n: boolean;
|
|
43
86
|
hasTests: boolean;
|
|
44
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* User-defined taint source (extends built-in TAINT_SOURCES).
|
|
90
|
+
* Pattern is the exact expression prefix — e.g., `internalCtx.userInput`.
|
|
91
|
+
*/
|
|
92
|
+
export interface CustomSource {
|
|
93
|
+
pattern: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* User-defined sink.
|
|
97
|
+
* `type` selects which sink registry to extend (call / constructor / property).
|
|
98
|
+
* `cwe` is required — without it the scanner cannot report a meaningful finding.
|
|
99
|
+
*/
|
|
100
|
+
export interface CustomSink {
|
|
101
|
+
pattern: string;
|
|
102
|
+
type?: 'call' | 'constructor' | 'property';
|
|
103
|
+
cwe: string;
|
|
104
|
+
severity?: Severity;
|
|
105
|
+
category?: string;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* User-defined sanitizer — neutralizes taint for the listed CWEs.
|
|
109
|
+
* If `cwes` is empty, the sanitizer is treated as blocking ALL taint classes.
|
|
110
|
+
*/
|
|
111
|
+
export interface CustomSanitizer {
|
|
112
|
+
pattern: string;
|
|
113
|
+
cwes: string[];
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Config-level suppression — glob-matched file filter.
|
|
117
|
+
* Applies before inline `// aegis-ignore` runs, so this is the coarser layer.
|
|
118
|
+
*/
|
|
119
|
+
export interface SuppressionEntry {
|
|
120
|
+
/** Glob pattern, relative to projectPath (e.g., `src/legacy/**`). */
|
|
121
|
+
file: string;
|
|
122
|
+
/** Optional CWE (`CWE-918`) or scanner-id (`taint-analyzer`) filter. */
|
|
123
|
+
rule?: string;
|
|
124
|
+
/** Required — why this suppression exists. */
|
|
125
|
+
reason: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Options for the inline suppression diagnostic layer.
|
|
129
|
+
* Controls whether unused/naked suppressions warn on stderr.
|
|
130
|
+
*/
|
|
131
|
+
export interface SuppressionOptions {
|
|
132
|
+
/** Default true — log a warning for each suppression that never matched. */
|
|
133
|
+
warnUnused?: boolean;
|
|
134
|
+
/** Default true — log a warning for suppressions without a reason. */
|
|
135
|
+
warnNaked?: boolean;
|
|
136
|
+
}
|
|
45
137
|
export interface AegisConfig {
|
|
46
138
|
projectPath: string;
|
|
47
139
|
stack: DetectedStack;
|
|
@@ -54,6 +146,18 @@ export interface AegisConfig {
|
|
|
54
146
|
mode: 'scan' | 'audit' | 'pentest' | 'siege' | 'fortress';
|
|
55
147
|
/** When set, only report findings for files in this list (diff mode). Absolute paths. */
|
|
56
148
|
diffFiles?: string[];
|
|
149
|
+
/** User-defined taint sources extending built-in TAINT_SOURCES. */
|
|
150
|
+
customSources?: CustomSource[];
|
|
151
|
+
/** User-defined sinks extending built-in TAINT_SINKS/CONSTRUCTOR_SINKS/PROPERTY_SINKS. */
|
|
152
|
+
customSinks?: CustomSink[];
|
|
153
|
+
/** User-defined sanitizers extending built-in TAINT_SANITIZER_DEFS. */
|
|
154
|
+
customSanitizers?: CustomSanitizer[];
|
|
155
|
+
/** Config-level file/rule suppressions (coarse layer; complements inline `// aegis-ignore`). */
|
|
156
|
+
suppressions?: SuppressionEntry[];
|
|
157
|
+
/** Controls stderr diagnostic output for inline suppressions. */
|
|
158
|
+
suppressionOptions?: SuppressionOptions;
|
|
159
|
+
/** Opt-in override of built-in security defaults (e.g., PARSE_NOT_SANITIZER). Default false. */
|
|
160
|
+
allowOverrides?: boolean;
|
|
57
161
|
}
|
|
58
162
|
export type Grade = 'S' | 'A' | 'B' | 'C' | 'D' | 'F';
|
|
59
163
|
export type Badge = 'FORTRESS' | 'HARDENED' | 'SOLID' | 'NEEDS_WORK' | 'AT_RISK' | 'CRITICAL';
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAEnF,MAAM,MAAM,YAAY,GACpB,UAAU,GAAG,MAAM,GAAG,cAAc,GAAG,YAAY,GAAG,SAAS,GAC/D,eAAe,GAAG,aAAa,GAAG,gBAAgB,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAClF,QAAQ,CAAC;AAEb,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,YAAY,CAAC;IACvB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|