dravix-agent 0.1.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/.claude/settings.example.json +30 -0
- package/ARCHITECTURE.md +410 -0
- package/LICENSE +21 -0
- package/README.md +153 -0
- package/ROADMAP.md +117 -0
- package/data/vulnkb.json +666 -0
- package/dist/bin/aegis.d.ts +3 -0
- package/dist/bin/aegis.d.ts.map +1 -0
- package/dist/bin/aegis.js +489 -0
- package/dist/bin/aegis.js.map +1 -0
- package/dist/cache.d.ts +9 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +146 -0
- package/dist/cache.js.map +1 -0
- package/dist/engines/ai-sinks.d.ts +52 -0
- package/dist/engines/ai-sinks.d.ts.map +1 -0
- package/dist/engines/ai-sinks.js +204 -0
- package/dist/engines/ai-sinks.js.map +1 -0
- package/dist/engines/eslint.d.ts +9 -0
- package/dist/engines/eslint.d.ts.map +1 -0
- package/dist/engines/eslint.js +245 -0
- package/dist/engines/eslint.js.map +1 -0
- package/dist/engines/joern.d.ts +3 -0
- package/dist/engines/joern.d.ts.map +1 -0
- package/dist/engines/joern.js +98 -0
- package/dist/engines/joern.js.map +1 -0
- package/dist/engines/js-sinks.d.ts +70 -0
- package/dist/engines/js-sinks.d.ts.map +1 -0
- package/dist/engines/js-sinks.js +370 -0
- package/dist/engines/js-sinks.js.map +1 -0
- package/dist/engines/llm-critic.d.ts +130 -0
- package/dist/engines/llm-critic.d.ts.map +1 -0
- package/dist/engines/llm-critic.js +551 -0
- package/dist/engines/llm-critic.js.map +1 -0
- package/dist/engines/pragma.d.ts +20 -0
- package/dist/engines/pragma.d.ts.map +1 -0
- package/dist/engines/pragma.js +83 -0
- package/dist/engines/pragma.js.map +1 -0
- package/dist/engines/property-test.d.ts +3 -0
- package/dist/engines/property-test.d.ts.map +1 -0
- package/dist/engines/property-test.js +134 -0
- package/dist/engines/property-test.js.map +1 -0
- package/dist/engines/pyright.d.ts +10 -0
- package/dist/engines/pyright.d.ts.map +1 -0
- package/dist/engines/pyright.js +143 -0
- package/dist/engines/pyright.js.map +1 -0
- package/dist/engines/pysa.d.ts +3 -0
- package/dist/engines/pysa.d.ts.map +1 -0
- package/dist/engines/pysa.js +83 -0
- package/dist/engines/pysa.js.map +1 -0
- package/dist/engines/python-sinks.d.ts +82 -0
- package/dist/engines/python-sinks.d.ts.map +1 -0
- package/dist/engines/python-sinks.js +459 -0
- package/dist/engines/python-sinks.js.map +1 -0
- package/dist/engines/registry.d.ts +26 -0
- package/dist/engines/registry.d.ts.map +1 -0
- package/dist/engines/registry.js +70 -0
- package/dist/engines/registry.js.map +1 -0
- package/dist/engines/secret-scan.d.ts +22 -0
- package/dist/engines/secret-scan.d.ts.map +1 -0
- package/dist/engines/secret-scan.js +179 -0
- package/dist/engines/secret-scan.js.map +1 -0
- package/dist/engines/semgrep.d.ts +10 -0
- package/dist/engines/semgrep.d.ts.map +1 -0
- package/dist/engines/semgrep.js +200 -0
- package/dist/engines/semgrep.js.map +1 -0
- package/dist/engines/treesitter.d.ts +18 -0
- package/dist/engines/treesitter.d.ts.map +1 -0
- package/dist/engines/treesitter.js +135 -0
- package/dist/engines/treesitter.js.map +1 -0
- package/dist/engines/tsc.d.ts +10 -0
- package/dist/engines/tsc.d.ts.map +1 -0
- package/dist/engines/tsc.js +142 -0
- package/dist/engines/tsc.js.map +1 -0
- package/dist/engines/types.d.ts +47 -0
- package/dist/engines/types.d.ts.map +1 -0
- package/dist/engines/types.js +27 -0
- package/dist/engines/types.js.map +1 -0
- package/dist/findings.d.ts +121 -0
- package/dist/findings.d.ts.map +1 -0
- package/dist/findings.js +98 -0
- package/dist/findings.js.map +1 -0
- package/dist/hooks/claude-code.d.ts +3 -0
- package/dist/hooks/claude-code.d.ts.map +1 -0
- package/dist/hooks/claude-code.js +187 -0
- package/dist/hooks/claude-code.js.map +1 -0
- package/dist/index/context.d.ts +127 -0
- package/dist/index/context.d.ts.map +1 -0
- package/dist/index/context.js +267 -0
- package/dist/index/context.js.map +1 -0
- package/dist/index/embeddings.d.ts +68 -0
- package/dist/index/embeddings.d.ts.map +1 -0
- package/dist/index/embeddings.js +570 -0
- package/dist/index/embeddings.js.map +1 -0
- package/dist/index/graph_routing.d.ts +36 -0
- package/dist/index/graph_routing.d.ts.map +1 -0
- package/dist/index/graph_routing.js +170 -0
- package/dist/index/graph_routing.js.map +1 -0
- package/dist/index/joern.d.ts +76 -0
- package/dist/index/joern.d.ts.map +1 -0
- package/dist/index/joern.js +782 -0
- package/dist/index/joern.js.map +1 -0
- package/dist/index/property-test.d.ts +88 -0
- package/dist/index/property-test.d.ts.map +1 -0
- package/dist/index/property-test.js +466 -0
- package/dist/index/property-test.js.map +1 -0
- package/dist/index/proto/scip.proto +897 -0
- package/dist/index/pysa.d.ts +91 -0
- package/dist/index/pysa.d.ts.map +1 -0
- package/dist/index/pysa.js +617 -0
- package/dist/index/pysa.js.map +1 -0
- package/dist/index/scip.d.ts +76 -0
- package/dist/index/scip.d.ts.map +1 -0
- package/dist/index/scip.js +541 -0
- package/dist/index/scip.js.map +1 -0
- package/dist/index/vulrag.d.ts +86 -0
- package/dist/index/vulrag.d.ts.map +1 -0
- package/dist/index/vulrag.js +242 -0
- package/dist/index/vulrag.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/install/claude-code.d.ts +31 -0
- package/dist/install/claude-code.d.ts.map +1 -0
- package/dist/install/claude-code.js +447 -0
- package/dist/install/claude-code.js.map +1 -0
- package/dist/lang.d.ts +5 -0
- package/dist/lang.d.ts.map +1 -0
- package/dist/lang.js +52 -0
- package/dist/lang.js.map +1 -0
- package/dist/learning/suppressions.d.ts +70 -0
- package/dist/learning/suppressions.d.ts.map +1 -0
- package/dist/learning/suppressions.js +179 -0
- package/dist/learning/suppressions.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +187 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/explain.d.ts +58 -0
- package/dist/mcp/tools/explain.d.ts.map +1 -0
- package/dist/mcp/tools/explain.js +60 -0
- package/dist/mcp/tools/explain.js.map +1 -0
- package/dist/mcp/tools/precheck.d.ts +29 -0
- package/dist/mcp/tools/precheck.d.ts.map +1 -0
- package/dist/mcp/tools/precheck.js +42 -0
- package/dist/mcp/tools/precheck.js.map +1 -0
- package/dist/mcp/tools/validate.d.ts +73 -0
- package/dist/mcp/tools/validate.d.ts.map +1 -0
- package/dist/mcp/tools/validate.js +66 -0
- package/dist/mcp/tools/validate.js.map +1 -0
- package/dist/mcp/warm.d.ts +88 -0
- package/dist/mcp/warm.d.ts.map +1 -0
- package/dist/mcp/warm.js +331 -0
- package/dist/mcp/warm.js.map +1 -0
- package/dist/orchestrator.d.ts +46 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +596 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/policy.d.ts +51 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +201 -0
- package/dist/policy.js.map +1 -0
- package/dist/risk.d.ts +31 -0
- package/dist/risk.d.ts.map +1 -0
- package/dist/risk.js +92 -0
- package/dist/risk.js.map +1 -0
- package/dist/stats.d.ts +72 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +217 -0
- package/dist/stats.js.map +1 -0
- package/dist/telemetry/collector.d.ts +10 -0
- package/dist/telemetry/collector.d.ts.map +1 -0
- package/dist/telemetry/collector.js +75 -0
- package/dist/telemetry/collector.js.map +1 -0
- package/dist/telemetry/consent.d.ts +9 -0
- package/dist/telemetry/consent.d.ts.map +1 -0
- package/dist/telemetry/consent.js +42 -0
- package/dist/telemetry/consent.js.map +1 -0
- package/dist/telemetry/installation.d.ts +2 -0
- package/dist/telemetry/installation.d.ts.map +1 -0
- package/dist/telemetry/installation.js +32 -0
- package/dist/telemetry/installation.js.map +1 -0
- package/dist/telemetry/sanitizer.d.ts +5 -0
- package/dist/telemetry/sanitizer.d.ts.map +1 -0
- package/dist/telemetry/sanitizer.js +60 -0
- package/dist/telemetry/sanitizer.js.map +1 -0
- package/dist/telemetry/types.d.ts +39 -0
- package/dist/telemetry/types.d.ts.map +1 -0
- package/dist/telemetry/types.js +4 -0
- package/dist/telemetry/types.js.map +1 -0
- package/dist/telemetry/uploader.d.ts +12 -0
- package/dist/telemetry/uploader.d.ts.map +1 -0
- package/dist/telemetry/uploader.js +92 -0
- package/dist/telemetry/uploader.js.map +1 -0
- package/dist/util/logger.d.ts +19 -0
- package/dist/util/logger.d.ts.map +1 -0
- package/dist/util/logger.js +58 -0
- package/dist/util/logger.js.map +1 -0
- package/dist/util/safe-paths.d.ts +8 -0
- package/dist/util/safe-paths.d.ts.map +1 -0
- package/dist/util/safe-paths.js +102 -0
- package/dist/util/safe-paths.js.map +1 -0
- package/dist/util/subprocess.d.ts +32 -0
- package/dist/util/subprocess.d.ts.map +1 -0
- package/dist/util/subprocess.js +137 -0
- package/dist/util/subprocess.js.map +1 -0
- package/package.json +93 -0
package/dist/policy.d.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const PolicySchema: z.ZodObject<{
|
|
3
|
+
block: z.ZodDefault<z.ZodEffects<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodNull]>, string[], string[] | null>>;
|
|
4
|
+
warn: z.ZodDefault<z.ZodEffects<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodNull]>, string[], string[] | null>>;
|
|
5
|
+
ignore: z.ZodDefault<z.ZodEffects<z.ZodUnion<[z.ZodArray<z.ZodString, "many">, z.ZodNull]>, string[], string[] | null>>;
|
|
6
|
+
}, "strict", z.ZodTypeAny, {
|
|
7
|
+
warn: string[];
|
|
8
|
+
ignore: string[];
|
|
9
|
+
block: string[];
|
|
10
|
+
}, {
|
|
11
|
+
warn?: string[] | null | undefined;
|
|
12
|
+
ignore?: string[] | null | undefined;
|
|
13
|
+
block?: string[] | null | undefined;
|
|
14
|
+
}>;
|
|
15
|
+
export type Policy = z.infer<typeof PolicySchema>;
|
|
16
|
+
/** Compiled policy: pre-normalized sets for O(1) lookup. */
|
|
17
|
+
export interface CompiledPolicy {
|
|
18
|
+
block: Set<string>;
|
|
19
|
+
warn: Set<string>;
|
|
20
|
+
ignore: Set<string>;
|
|
21
|
+
/** Original source path (or null for the empty/default policy). */
|
|
22
|
+
sourcePath: string | null;
|
|
23
|
+
}
|
|
24
|
+
export declare const EMPTY_POLICY: CompiledPolicy;
|
|
25
|
+
/** Canonicalise a CWE id or rule id: uppercase, strip a leading ``CWE-``
|
|
26
|
+
* so both ``"CWE-89"`` and ``"89"`` collapse to the same key. Rule ids
|
|
27
|
+
* (anything not numeric) stay as-is but lowercased for case-insensitive
|
|
28
|
+
* matching against engine rule ids. */
|
|
29
|
+
export declare function normalizeKey(s: string): string;
|
|
30
|
+
/** Does a finding's CWE or rule_id match any key in ``keys``?
|
|
31
|
+
*
|
|
32
|
+
* - CWE match: exact normalized equality (``"89"`` vs ``"89"``).
|
|
33
|
+
* - Rule id match: exact normalized equality OR ``keys`` entry is a
|
|
34
|
+
* prefix followed by ``.*`` (e.g. ``"semgrep.*"`` matches every
|
|
35
|
+
* semgrep rule). The ``.*`` suffix is the only wildcard form we
|
|
36
|
+
* support — we explicitly avoid full regex to keep YAML editable
|
|
37
|
+
* without escaping pitfalls.
|
|
38
|
+
*/
|
|
39
|
+
export declare function findingMatches(cwe: string | undefined, ruleId: string, keys: Set<string>): boolean;
|
|
40
|
+
export declare function policyPath(projectRoot: string): string;
|
|
41
|
+
/** Load and compile the project's policy. Returns ``EMPTY_POLICY`` when:
|
|
42
|
+
* - the file doesn't exist (most projects),
|
|
43
|
+
* - the file fails to parse / validate (we log a warning and refuse to
|
|
44
|
+
* apply a partial policy — better to be uniformly default than half-on).
|
|
45
|
+
*
|
|
46
|
+
* Never throws.
|
|
47
|
+
*/
|
|
48
|
+
export declare function loadPolicy(projectRoot: string): CompiledPolicy;
|
|
49
|
+
/** Generate a starter template the user can drop into their repo. */
|
|
50
|
+
export declare function policyTemplate(): string;
|
|
51
|
+
//# sourceMappingURL=policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AA+BA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAmBxB,eAAO,MAAM,YAAY;;;;;;;;;;;;EAId,CAAC;AACZ,MAAM,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AAElD,4DAA4D;AAC5D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACpB,mEAAmE;IACnE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC3B;AAED,eAAO,MAAM,YAAY,EAAE,cAK1B,CAAC;AAIF;;;uCAGuC;AACvC,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAM9C;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAChB,OAAO,CAiBT;AAID,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,CA0D9D;AAED,qEAAqE;AACrE,wBAAgB,cAAc,IAAI,MAAM,CA2BvC"}
|
package/dist/policy.js
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Policy-as-code — per-project ``aegis.policy.yml``.
|
|
3
|
+
*
|
|
4
|
+
* Teams declare three CWE lists at the project root and Aegis applies them
|
|
5
|
+
* in the orchestrator's final risk-decision step:
|
|
6
|
+
*
|
|
7
|
+
* block: [CWE-89, CWE-78, ...] # always block — overrides confidence/severity
|
|
8
|
+
* warn: [CWE-704, CWE-369, ...] # warn but never block — downgrades a "block" decision
|
|
9
|
+
* ignore: [CWE-1395, ...] # drop the finding entirely (won't appear in the report)
|
|
10
|
+
*
|
|
11
|
+
* Precedence (highest first):
|
|
12
|
+
* 1. ignore — finding is removed before anything else looks at it
|
|
13
|
+
* 2. block — final action forced to "block" regardless of risk score
|
|
14
|
+
* 3. warn — if risk decision would have been "block", downgrade to "warn"
|
|
15
|
+
* 4. (none) — default risk scoring applies
|
|
16
|
+
*
|
|
17
|
+
* The same CWE in multiple lists is a CONFIG ERROR — we log a warning and
|
|
18
|
+
* apply the strictest (ignore > block > warn).
|
|
19
|
+
*
|
|
20
|
+
* **Where the file lives:** ``<project_root>/aegis.policy.yml``. Optional —
|
|
21
|
+
* if absent, behaviour is unchanged (no policy applied). Per-project so a
|
|
22
|
+
* monorepo with multiple sub-projects can have different policies.
|
|
23
|
+
*
|
|
24
|
+
* **CWE normalization:** both ``"CWE-89"`` and ``"89"`` accepted; both
|
|
25
|
+
* cwe and rule_id paths checked. Rule-id matches via prefix (`semgrep.*`
|
|
26
|
+
* matches all semgrep findings).
|
|
27
|
+
*/
|
|
28
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
29
|
+
import { join } from "node:path";
|
|
30
|
+
import { parse as parseYaml } from "yaml";
|
|
31
|
+
import { z } from "zod";
|
|
32
|
+
import { getLogger } from "./util/logger.js";
|
|
33
|
+
const log = getLogger("aegis.policy");
|
|
34
|
+
// ── Schema ────────────────────────────────────────────────────────────────
|
|
35
|
+
const CweOrRule = z.string().min(1).max(120);
|
|
36
|
+
// Accept null (YAML's "empty value" — e.g. `ignore:` with no items below)
|
|
37
|
+
// as equivalent to an empty list. Without this, `parseYaml` produces
|
|
38
|
+
// `{ignore: null}` and zod's `.default([])` doesn't fire (it only fires
|
|
39
|
+
// on `undefined`), so the whole policy is rejected and silently empty.
|
|
40
|
+
const StringList = z
|
|
41
|
+
.union([z.array(CweOrRule), z.null()])
|
|
42
|
+
.transform((v) => v ?? [])
|
|
43
|
+
.default([]);
|
|
44
|
+
export const PolicySchema = z.object({
|
|
45
|
+
block: StringList,
|
|
46
|
+
warn: StringList,
|
|
47
|
+
ignore: StringList,
|
|
48
|
+
}).strict();
|
|
49
|
+
export const EMPTY_POLICY = {
|
|
50
|
+
block: new Set(),
|
|
51
|
+
warn: new Set(),
|
|
52
|
+
ignore: new Set(),
|
|
53
|
+
sourcePath: null,
|
|
54
|
+
};
|
|
55
|
+
// ── Normalization ─────────────────────────────────────────────────────────
|
|
56
|
+
/** Canonicalise a CWE id or rule id: uppercase, strip a leading ``CWE-``
|
|
57
|
+
* so both ``"CWE-89"`` and ``"89"`` collapse to the same key. Rule ids
|
|
58
|
+
* (anything not numeric) stay as-is but lowercased for case-insensitive
|
|
59
|
+
* matching against engine rule ids. */
|
|
60
|
+
export function normalizeKey(s) {
|
|
61
|
+
const trimmed = s.trim();
|
|
62
|
+
if (/^\d+$/.test(trimmed))
|
|
63
|
+
return trimmed; // "89"
|
|
64
|
+
const m = trimmed.match(/^cwe-(\d+)$/i);
|
|
65
|
+
if (m)
|
|
66
|
+
return m[1]; // "CWE-89" → "89"
|
|
67
|
+
return trimmed.toLowerCase(); // rule id like "semgrep.python.sql-injection"
|
|
68
|
+
}
|
|
69
|
+
/** Does a finding's CWE or rule_id match any key in ``keys``?
|
|
70
|
+
*
|
|
71
|
+
* - CWE match: exact normalized equality (``"89"`` vs ``"89"``).
|
|
72
|
+
* - Rule id match: exact normalized equality OR ``keys`` entry is a
|
|
73
|
+
* prefix followed by ``.*`` (e.g. ``"semgrep.*"`` matches every
|
|
74
|
+
* semgrep rule). The ``.*`` suffix is the only wildcard form we
|
|
75
|
+
* support — we explicitly avoid full regex to keep YAML editable
|
|
76
|
+
* without escaping pitfalls.
|
|
77
|
+
*/
|
|
78
|
+
export function findingMatches(cwe, ruleId, keys) {
|
|
79
|
+
if (keys.size === 0)
|
|
80
|
+
return false;
|
|
81
|
+
if (cwe) {
|
|
82
|
+
const n = normalizeKey(cwe);
|
|
83
|
+
if (keys.has(n))
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
const ruleNorm = normalizeKey(ruleId);
|
|
87
|
+
if (keys.has(ruleNorm))
|
|
88
|
+
return true;
|
|
89
|
+
// Prefix wildcard: any key ending in ".*" matches when ruleNorm starts
|
|
90
|
+
// with the prefix (no dot stuffing — exact dotted prefix).
|
|
91
|
+
for (const k of keys) {
|
|
92
|
+
if (k.endsWith(".*")) {
|
|
93
|
+
const prefix = k.slice(0, -2);
|
|
94
|
+
if (ruleNorm === prefix || ruleNorm.startsWith(prefix + "."))
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
// ── Loading ───────────────────────────────────────────────────────────────
|
|
101
|
+
export function policyPath(projectRoot) {
|
|
102
|
+
return join(projectRoot, "aegis.policy.yml");
|
|
103
|
+
}
|
|
104
|
+
/** Load and compile the project's policy. Returns ``EMPTY_POLICY`` when:
|
|
105
|
+
* - the file doesn't exist (most projects),
|
|
106
|
+
* - the file fails to parse / validate (we log a warning and refuse to
|
|
107
|
+
* apply a partial policy — better to be uniformly default than half-on).
|
|
108
|
+
*
|
|
109
|
+
* Never throws.
|
|
110
|
+
*/
|
|
111
|
+
export function loadPolicy(projectRoot) {
|
|
112
|
+
const p = policyPath(projectRoot);
|
|
113
|
+
if (!existsSync(p))
|
|
114
|
+
return EMPTY_POLICY;
|
|
115
|
+
let raw;
|
|
116
|
+
try {
|
|
117
|
+
raw = readFileSync(p, "utf8");
|
|
118
|
+
}
|
|
119
|
+
catch (err) {
|
|
120
|
+
log.warn("policy: read failed", { path: p, err: String(err) });
|
|
121
|
+
return EMPTY_POLICY;
|
|
122
|
+
}
|
|
123
|
+
let yaml;
|
|
124
|
+
try {
|
|
125
|
+
yaml = parseYaml(raw);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
log.warn("policy: YAML parse failed", { path: p, err: String(err) });
|
|
129
|
+
return EMPTY_POLICY;
|
|
130
|
+
}
|
|
131
|
+
// Empty file → empty policy (not an error).
|
|
132
|
+
if (yaml === null || yaml === undefined)
|
|
133
|
+
return { ...EMPTY_POLICY, sourcePath: p };
|
|
134
|
+
const parsed = PolicySchema.safeParse(yaml);
|
|
135
|
+
if (!parsed.success) {
|
|
136
|
+
log.warn("policy: schema validation failed", {
|
|
137
|
+
path: p,
|
|
138
|
+
err: parsed.error.issues[0]?.message ?? "?",
|
|
139
|
+
});
|
|
140
|
+
return EMPTY_POLICY;
|
|
141
|
+
}
|
|
142
|
+
const policy = parsed.data;
|
|
143
|
+
const block = new Set(policy.block.map(normalizeKey));
|
|
144
|
+
const warn = new Set(policy.warn.map(normalizeKey));
|
|
145
|
+
const ignore = new Set(policy.ignore.map(normalizeKey));
|
|
146
|
+
// Conflict detection: a CWE in multiple lists is almost always a typo —
|
|
147
|
+
// log it and apply strictest (ignore > block > warn).
|
|
148
|
+
for (const k of block) {
|
|
149
|
+
if (ignore.has(k)) {
|
|
150
|
+
log.warn("policy: conflict — entry is both block and ignore; treating as ignore", { key: k });
|
|
151
|
+
block.delete(k);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
for (const k of warn) {
|
|
155
|
+
if (ignore.has(k)) {
|
|
156
|
+
log.warn("policy: conflict — entry is both warn and ignore; treating as ignore", { key: k });
|
|
157
|
+
warn.delete(k);
|
|
158
|
+
}
|
|
159
|
+
else if (block.has(k)) {
|
|
160
|
+
log.warn("policy: conflict — entry is both warn and block; treating as block", { key: k });
|
|
161
|
+
warn.delete(k);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
log.debug("policy loaded", {
|
|
165
|
+
path: p,
|
|
166
|
+
block: block.size,
|
|
167
|
+
warn: warn.size,
|
|
168
|
+
ignore: ignore.size,
|
|
169
|
+
});
|
|
170
|
+
return { block, warn, ignore, sourcePath: p };
|
|
171
|
+
}
|
|
172
|
+
/** Generate a starter template the user can drop into their repo. */
|
|
173
|
+
export function policyTemplate() {
|
|
174
|
+
return [
|
|
175
|
+
"# Aegis-v2 policy — per-project overrides for finding severity / blocking.",
|
|
176
|
+
"# https://aegis-v2.example/docs/policy",
|
|
177
|
+
"#",
|
|
178
|
+
"# Keys: CWE ids (CWE-89 or 89) OR rule-ids (semgrep.python.sql-injection",
|
|
179
|
+
"# OR a prefix wildcard like joern.*). Precedence: ignore > block > warn.",
|
|
180
|
+
"",
|
|
181
|
+
"block:",
|
|
182
|
+
" # SQL injection — always block, no exceptions",
|
|
183
|
+
" - CWE-89",
|
|
184
|
+
" # OS command injection",
|
|
185
|
+
" - CWE-78",
|
|
186
|
+
" # Hardcoded credentials",
|
|
187
|
+
" - CWE-798",
|
|
188
|
+
"",
|
|
189
|
+
"warn:",
|
|
190
|
+
" # Float-money rounding is real but rarely critical — warn, don't block",
|
|
191
|
+
" - CWE-704",
|
|
192
|
+
" # Division-by-zero — surface, don't block (often defensive)",
|
|
193
|
+
" - CWE-369",
|
|
194
|
+
"",
|
|
195
|
+
"ignore:",
|
|
196
|
+
" # Specific rule IDs the team has reviewed + decided to suppress",
|
|
197
|
+
" # Example: every semgrep.test-helper.* finding",
|
|
198
|
+
" # - semgrep.test-helper.*",
|
|
199
|
+
].join("\n");
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policy.js","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"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"}
|
package/dist/risk.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Risk scoring + action mapping.
|
|
3
|
+
*
|
|
4
|
+
* Inputs: a set of `Finding` (already validated by zod).
|
|
5
|
+
* Output: an `Action` — `allow` | `warn` | `block` — plus the *driving* finding
|
|
6
|
+
* (for messages/audit) and a one-line summary suitable for stderr.
|
|
7
|
+
*
|
|
8
|
+
* The mapping is intentionally simple and lives in ONE function so we can tune
|
|
9
|
+
* thresholds in A/B without touching engines.
|
|
10
|
+
*/
|
|
11
|
+
import { Finding } from "./findings.js";
|
|
12
|
+
export type Action = "allow" | "warn" | "block";
|
|
13
|
+
export interface ActionDecision {
|
|
14
|
+
action: Action;
|
|
15
|
+
driving: Finding | null;
|
|
16
|
+
summary: string;
|
|
17
|
+
blockCount: number;
|
|
18
|
+
warnCount: number;
|
|
19
|
+
totalFindings: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* `confidence × severity_weight` is the score; thresholds:
|
|
23
|
+
* ≥ 0.85 with severity ≥ high → block
|
|
24
|
+
* ≥ 0.60 with severity ≥ medium → warn
|
|
25
|
+
* else → allow
|
|
26
|
+
*/
|
|
27
|
+
export declare function scoreOne(f: Finding): Action;
|
|
28
|
+
export declare function decide(findings: ReadonlyArray<Finding>): ActionDecision;
|
|
29
|
+
/** Exit code for the Claude-Code hook protocol — 0 allow/warn, 2 block. */
|
|
30
|
+
export declare function exitCodeFor(action: Action): 0 | 2;
|
|
31
|
+
//# sourceMappingURL=risk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk.d.ts","sourceRoot":"","sources":["../src/risk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,OAAO,EAAgB,MAAM,eAAe,CAAC;AAEtD,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,OAAO,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAkBD;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAO3C;AAED,wBAAgB,MAAM,CAAC,QAAQ,EAAE,aAAa,CAAC,OAAO,CAAC,GAAG,cAAc,CAgCvE;AAwBD,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,CAAC,GAAG,CAAC,CAEjD"}
|
package/dist/risk.js
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Risk scoring + action mapping.
|
|
3
|
+
*
|
|
4
|
+
* Inputs: a set of `Finding` (already validated by zod).
|
|
5
|
+
* Output: an `Action` — `allow` | `warn` | `block` — plus the *driving* finding
|
|
6
|
+
* (for messages/audit) and a one-line summary suitable for stderr.
|
|
7
|
+
*
|
|
8
|
+
* The mapping is intentionally simple and lives in ONE function so we can tune
|
|
9
|
+
* thresholds in A/B without touching engines.
|
|
10
|
+
*/
|
|
11
|
+
import { severityRank } from "./findings.js";
|
|
12
|
+
/** Single critical rules that *always* block, regardless of confidence. */
|
|
13
|
+
const ALWAYS_BLOCK_ENGINES_RULES = [
|
|
14
|
+
// any secret detection at any confidence
|
|
15
|
+
["secret-scan", /.*/],
|
|
16
|
+
// confirmed taint-sink reachability from Pysa
|
|
17
|
+
["pysa", /.*reach.*/i],
|
|
18
|
+
];
|
|
19
|
+
function shouldAlwaysBlock(f) {
|
|
20
|
+
if (f.severity === "critical" && f.confidence >= 0.7)
|
|
21
|
+
return true;
|
|
22
|
+
for (const [engine, rule] of ALWAYS_BLOCK_ENGINES_RULES) {
|
|
23
|
+
if (f.engine === engine && rule.test(f.rule_id))
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* `confidence × severity_weight` is the score; thresholds:
|
|
30
|
+
* ≥ 0.85 with severity ≥ high → block
|
|
31
|
+
* ≥ 0.60 with severity ≥ medium → warn
|
|
32
|
+
* else → allow
|
|
33
|
+
*/
|
|
34
|
+
export function scoreOne(f) {
|
|
35
|
+
if (shouldAlwaysBlock(f))
|
|
36
|
+
return "block";
|
|
37
|
+
const sev = severityRank(f.severity);
|
|
38
|
+
// sev: 0=info 1=low 2=medium 3=high 4=critical
|
|
39
|
+
if (sev >= 3 && f.confidence >= 0.85)
|
|
40
|
+
return "block";
|
|
41
|
+
if (sev >= 2 && f.confidence >= 0.6)
|
|
42
|
+
return "warn";
|
|
43
|
+
return "allow";
|
|
44
|
+
}
|
|
45
|
+
export function decide(findings) {
|
|
46
|
+
let action = "allow";
|
|
47
|
+
let driving = null;
|
|
48
|
+
let blockCount = 0;
|
|
49
|
+
let warnCount = 0;
|
|
50
|
+
// Highest-severity findings first so `driving` carries the most relevant one.
|
|
51
|
+
const sorted = [...findings].sort((a, b) => severityRank(b.severity) - severityRank(a.severity) ||
|
|
52
|
+
b.confidence - a.confidence);
|
|
53
|
+
for (const f of sorted) {
|
|
54
|
+
const per = scoreOne(f);
|
|
55
|
+
if (per === "block") {
|
|
56
|
+
blockCount++;
|
|
57
|
+
if (action !== "block") {
|
|
58
|
+
action = "block";
|
|
59
|
+
driving = f;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else if (per === "warn") {
|
|
63
|
+
warnCount++;
|
|
64
|
+
if (action === "allow") {
|
|
65
|
+
action = "warn";
|
|
66
|
+
driving = f;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const summary = formatSummary(action, driving, blockCount, warnCount, findings.length);
|
|
71
|
+
return { action, driving, summary, blockCount, warnCount, totalFindings: findings.length };
|
|
72
|
+
}
|
|
73
|
+
function formatSummary(action, driving, blockCount, warnCount, total) {
|
|
74
|
+
if (action === "allow") {
|
|
75
|
+
return total === 0
|
|
76
|
+
? "ALLOW — no findings."
|
|
77
|
+
: `ALLOW — ${total} low-confidence finding(s), none meet block/warn threshold.`;
|
|
78
|
+
}
|
|
79
|
+
if (action === "warn") {
|
|
80
|
+
const ref = driving ? `${driving.engine}:${driving.rule_id}` : "n/a";
|
|
81
|
+
return `WARN — ${warnCount} warning(s); top: ${ref} (${driving?.severity}, conf=${driving?.confidence.toFixed(2)})`;
|
|
82
|
+
}
|
|
83
|
+
// block
|
|
84
|
+
const ref = driving ? `${driving.engine}:${driving.rule_id}` : "n/a";
|
|
85
|
+
const cwe = driving?.cwe ? ` [${driving.cwe}]` : "";
|
|
86
|
+
return `BLOCK — ${blockCount} blocking finding(s); top: ${ref}${cwe} (${driving?.severity}, conf=${driving?.confidence.toFixed(2)})`;
|
|
87
|
+
}
|
|
88
|
+
/** Exit code for the Claude-Code hook protocol — 0 allow/warn, 2 block. */
|
|
89
|
+
export function exitCodeFor(action) {
|
|
90
|
+
return action === "block" ? 2 : 0;
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=risk.js.map
|
package/dist/risk.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"risk.js","sourceRoot":"","sources":["../src/risk.ts"],"names":[],"mappings":"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"}
|
package/dist/stats.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export type Verdict = "allow" | "warn" | "block";
|
|
2
|
+
/** Shape we parse out of each audit row — matches what ``appendAudit``
|
|
3
|
+
* writes in src/orchestrator.ts. Tolerate extra fields. */
|
|
4
|
+
export interface AuditRow {
|
|
5
|
+
ts: string;
|
|
6
|
+
file: string;
|
|
7
|
+
lang?: string;
|
|
8
|
+
action: Verdict;
|
|
9
|
+
duration_ms: number;
|
|
10
|
+
truncated?: boolean;
|
|
11
|
+
n_findings?: number;
|
|
12
|
+
n_block?: number;
|
|
13
|
+
n_warn?: number;
|
|
14
|
+
driving?: {
|
|
15
|
+
engine?: string;
|
|
16
|
+
rule_id?: string;
|
|
17
|
+
severity?: string;
|
|
18
|
+
confidence?: number;
|
|
19
|
+
cwe?: string;
|
|
20
|
+
} | null;
|
|
21
|
+
}
|
|
22
|
+
export interface StatsReport {
|
|
23
|
+
source: string;
|
|
24
|
+
total_runs: number;
|
|
25
|
+
since: string | null;
|
|
26
|
+
until: string | null;
|
|
27
|
+
verdict_distribution: Record<Verdict, {
|
|
28
|
+
count: number;
|
|
29
|
+
pct: number;
|
|
30
|
+
}>;
|
|
31
|
+
latency_ms: {
|
|
32
|
+
p50: number;
|
|
33
|
+
p95: number;
|
|
34
|
+
p99: number;
|
|
35
|
+
max: number;
|
|
36
|
+
mean: number;
|
|
37
|
+
};
|
|
38
|
+
truncated_count: number;
|
|
39
|
+
truncated_pct: number;
|
|
40
|
+
findings_per_run: {
|
|
41
|
+
mean: number;
|
|
42
|
+
max: number;
|
|
43
|
+
};
|
|
44
|
+
top_engines: Array<{
|
|
45
|
+
engine: string;
|
|
46
|
+
count: number;
|
|
47
|
+
}>;
|
|
48
|
+
top_rules: Array<{
|
|
49
|
+
rule_id: string;
|
|
50
|
+
count: number;
|
|
51
|
+
}>;
|
|
52
|
+
top_files: Array<{
|
|
53
|
+
file: string;
|
|
54
|
+
blocks: number;
|
|
55
|
+
runs: number;
|
|
56
|
+
}>;
|
|
57
|
+
}
|
|
58
|
+
export declare function auditPath(projectRoot: string): string;
|
|
59
|
+
/** Read all audit rows. Skips malformed lines silently. Never throws. */
|
|
60
|
+
export declare function loadAuditRows(projectRoot: string): AuditRow[];
|
|
61
|
+
/** Parse a `--since` value: ``N{d|h|m}`` (relative) or an ISO 8601
|
|
62
|
+
* timestamp (absolute). Returns the epoch ms cutoff, or null when the
|
|
63
|
+
* value is unparseable (caller treats null as "all-time"). */
|
|
64
|
+
export declare function parseSince(since: string | undefined | null): number | null;
|
|
65
|
+
interface ComputeOpts {
|
|
66
|
+
sinceMs?: number | null;
|
|
67
|
+
topN?: number;
|
|
68
|
+
}
|
|
69
|
+
export declare function computeStats(rows: AuditRow[], opts?: ComputeOpts): StatsReport;
|
|
70
|
+
export declare function formatHuman(s: StatsReport): string;
|
|
71
|
+
export {};
|
|
72
|
+
//# sourceMappingURL=stats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../src/stats.ts"],"names":[],"mappings":"AAkCA,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AAEjD;2DAC2D;AAC3D,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,IAAI,CAAC;CACV;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,oBAAoB,EAAE,MAAM,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtE,UAAU,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACjF,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAChD,WAAW,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACtD,SAAS,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrD,SAAS,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAClE;AAID,wBAAgB,SAAS,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,yEAAyE;AACzE,wBAAgB,aAAa,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ,EAAE,CA8B7D;AAID;;8DAE8D;AAC9D,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAa1E;AAID,UAAU,WAAW;IACnB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,EAAE,WAAW,GAAG,WAAW,CAqF9E;AAQD,wBAAgB,WAAW,CAAC,CAAC,EAAE,WAAW,GAAG,MAAM,CA2ClD"}
|