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.
Files changed (208) hide show
  1. package/.claude/settings.example.json +30 -0
  2. package/ARCHITECTURE.md +410 -0
  3. package/LICENSE +21 -0
  4. package/README.md +153 -0
  5. package/ROADMAP.md +117 -0
  6. package/data/vulnkb.json +666 -0
  7. package/dist/bin/aegis.d.ts +3 -0
  8. package/dist/bin/aegis.d.ts.map +1 -0
  9. package/dist/bin/aegis.js +489 -0
  10. package/dist/bin/aegis.js.map +1 -0
  11. package/dist/cache.d.ts +9 -0
  12. package/dist/cache.d.ts.map +1 -0
  13. package/dist/cache.js +146 -0
  14. package/dist/cache.js.map +1 -0
  15. package/dist/engines/ai-sinks.d.ts +52 -0
  16. package/dist/engines/ai-sinks.d.ts.map +1 -0
  17. package/dist/engines/ai-sinks.js +204 -0
  18. package/dist/engines/ai-sinks.js.map +1 -0
  19. package/dist/engines/eslint.d.ts +9 -0
  20. package/dist/engines/eslint.d.ts.map +1 -0
  21. package/dist/engines/eslint.js +245 -0
  22. package/dist/engines/eslint.js.map +1 -0
  23. package/dist/engines/joern.d.ts +3 -0
  24. package/dist/engines/joern.d.ts.map +1 -0
  25. package/dist/engines/joern.js +98 -0
  26. package/dist/engines/joern.js.map +1 -0
  27. package/dist/engines/js-sinks.d.ts +70 -0
  28. package/dist/engines/js-sinks.d.ts.map +1 -0
  29. package/dist/engines/js-sinks.js +370 -0
  30. package/dist/engines/js-sinks.js.map +1 -0
  31. package/dist/engines/llm-critic.d.ts +130 -0
  32. package/dist/engines/llm-critic.d.ts.map +1 -0
  33. package/dist/engines/llm-critic.js +551 -0
  34. package/dist/engines/llm-critic.js.map +1 -0
  35. package/dist/engines/pragma.d.ts +20 -0
  36. package/dist/engines/pragma.d.ts.map +1 -0
  37. package/dist/engines/pragma.js +83 -0
  38. package/dist/engines/pragma.js.map +1 -0
  39. package/dist/engines/property-test.d.ts +3 -0
  40. package/dist/engines/property-test.d.ts.map +1 -0
  41. package/dist/engines/property-test.js +134 -0
  42. package/dist/engines/property-test.js.map +1 -0
  43. package/dist/engines/pyright.d.ts +10 -0
  44. package/dist/engines/pyright.d.ts.map +1 -0
  45. package/dist/engines/pyright.js +143 -0
  46. package/dist/engines/pyright.js.map +1 -0
  47. package/dist/engines/pysa.d.ts +3 -0
  48. package/dist/engines/pysa.d.ts.map +1 -0
  49. package/dist/engines/pysa.js +83 -0
  50. package/dist/engines/pysa.js.map +1 -0
  51. package/dist/engines/python-sinks.d.ts +82 -0
  52. package/dist/engines/python-sinks.d.ts.map +1 -0
  53. package/dist/engines/python-sinks.js +459 -0
  54. package/dist/engines/python-sinks.js.map +1 -0
  55. package/dist/engines/registry.d.ts +26 -0
  56. package/dist/engines/registry.d.ts.map +1 -0
  57. package/dist/engines/registry.js +70 -0
  58. package/dist/engines/registry.js.map +1 -0
  59. package/dist/engines/secret-scan.d.ts +22 -0
  60. package/dist/engines/secret-scan.d.ts.map +1 -0
  61. package/dist/engines/secret-scan.js +179 -0
  62. package/dist/engines/secret-scan.js.map +1 -0
  63. package/dist/engines/semgrep.d.ts +10 -0
  64. package/dist/engines/semgrep.d.ts.map +1 -0
  65. package/dist/engines/semgrep.js +200 -0
  66. package/dist/engines/semgrep.js.map +1 -0
  67. package/dist/engines/treesitter.d.ts +18 -0
  68. package/dist/engines/treesitter.d.ts.map +1 -0
  69. package/dist/engines/treesitter.js +135 -0
  70. package/dist/engines/treesitter.js.map +1 -0
  71. package/dist/engines/tsc.d.ts +10 -0
  72. package/dist/engines/tsc.d.ts.map +1 -0
  73. package/dist/engines/tsc.js +142 -0
  74. package/dist/engines/tsc.js.map +1 -0
  75. package/dist/engines/types.d.ts +47 -0
  76. package/dist/engines/types.d.ts.map +1 -0
  77. package/dist/engines/types.js +27 -0
  78. package/dist/engines/types.js.map +1 -0
  79. package/dist/findings.d.ts +121 -0
  80. package/dist/findings.d.ts.map +1 -0
  81. package/dist/findings.js +98 -0
  82. package/dist/findings.js.map +1 -0
  83. package/dist/hooks/claude-code.d.ts +3 -0
  84. package/dist/hooks/claude-code.d.ts.map +1 -0
  85. package/dist/hooks/claude-code.js +187 -0
  86. package/dist/hooks/claude-code.js.map +1 -0
  87. package/dist/index/context.d.ts +127 -0
  88. package/dist/index/context.d.ts.map +1 -0
  89. package/dist/index/context.js +267 -0
  90. package/dist/index/context.js.map +1 -0
  91. package/dist/index/embeddings.d.ts +68 -0
  92. package/dist/index/embeddings.d.ts.map +1 -0
  93. package/dist/index/embeddings.js +570 -0
  94. package/dist/index/embeddings.js.map +1 -0
  95. package/dist/index/graph_routing.d.ts +36 -0
  96. package/dist/index/graph_routing.d.ts.map +1 -0
  97. package/dist/index/graph_routing.js +170 -0
  98. package/dist/index/graph_routing.js.map +1 -0
  99. package/dist/index/joern.d.ts +76 -0
  100. package/dist/index/joern.d.ts.map +1 -0
  101. package/dist/index/joern.js +782 -0
  102. package/dist/index/joern.js.map +1 -0
  103. package/dist/index/property-test.d.ts +88 -0
  104. package/dist/index/property-test.d.ts.map +1 -0
  105. package/dist/index/property-test.js +466 -0
  106. package/dist/index/property-test.js.map +1 -0
  107. package/dist/index/proto/scip.proto +897 -0
  108. package/dist/index/pysa.d.ts +91 -0
  109. package/dist/index/pysa.d.ts.map +1 -0
  110. package/dist/index/pysa.js +617 -0
  111. package/dist/index/pysa.js.map +1 -0
  112. package/dist/index/scip.d.ts +76 -0
  113. package/dist/index/scip.d.ts.map +1 -0
  114. package/dist/index/scip.js +541 -0
  115. package/dist/index/scip.js.map +1 -0
  116. package/dist/index/vulrag.d.ts +86 -0
  117. package/dist/index/vulrag.d.ts.map +1 -0
  118. package/dist/index/vulrag.js +242 -0
  119. package/dist/index/vulrag.js.map +1 -0
  120. package/dist/index.d.ts +9 -0
  121. package/dist/index.d.ts.map +1 -0
  122. package/dist/index.js +8 -0
  123. package/dist/index.js.map +1 -0
  124. package/dist/install/claude-code.d.ts +31 -0
  125. package/dist/install/claude-code.d.ts.map +1 -0
  126. package/dist/install/claude-code.js +447 -0
  127. package/dist/install/claude-code.js.map +1 -0
  128. package/dist/lang.d.ts +5 -0
  129. package/dist/lang.d.ts.map +1 -0
  130. package/dist/lang.js +52 -0
  131. package/dist/lang.js.map +1 -0
  132. package/dist/learning/suppressions.d.ts +70 -0
  133. package/dist/learning/suppressions.d.ts.map +1 -0
  134. package/dist/learning/suppressions.js +179 -0
  135. package/dist/learning/suppressions.js.map +1 -0
  136. package/dist/mcp/server.d.ts +2 -0
  137. package/dist/mcp/server.d.ts.map +1 -0
  138. package/dist/mcp/server.js +187 -0
  139. package/dist/mcp/server.js.map +1 -0
  140. package/dist/mcp/tools/explain.d.ts +58 -0
  141. package/dist/mcp/tools/explain.d.ts.map +1 -0
  142. package/dist/mcp/tools/explain.js +60 -0
  143. package/dist/mcp/tools/explain.js.map +1 -0
  144. package/dist/mcp/tools/precheck.d.ts +29 -0
  145. package/dist/mcp/tools/precheck.d.ts.map +1 -0
  146. package/dist/mcp/tools/precheck.js +42 -0
  147. package/dist/mcp/tools/precheck.js.map +1 -0
  148. package/dist/mcp/tools/validate.d.ts +73 -0
  149. package/dist/mcp/tools/validate.d.ts.map +1 -0
  150. package/dist/mcp/tools/validate.js +66 -0
  151. package/dist/mcp/tools/validate.js.map +1 -0
  152. package/dist/mcp/warm.d.ts +88 -0
  153. package/dist/mcp/warm.d.ts.map +1 -0
  154. package/dist/mcp/warm.js +331 -0
  155. package/dist/mcp/warm.js.map +1 -0
  156. package/dist/orchestrator.d.ts +46 -0
  157. package/dist/orchestrator.d.ts.map +1 -0
  158. package/dist/orchestrator.js +596 -0
  159. package/dist/orchestrator.js.map +1 -0
  160. package/dist/policy.d.ts +51 -0
  161. package/dist/policy.d.ts.map +1 -0
  162. package/dist/policy.js +201 -0
  163. package/dist/policy.js.map +1 -0
  164. package/dist/risk.d.ts +31 -0
  165. package/dist/risk.d.ts.map +1 -0
  166. package/dist/risk.js +92 -0
  167. package/dist/risk.js.map +1 -0
  168. package/dist/stats.d.ts +72 -0
  169. package/dist/stats.d.ts.map +1 -0
  170. package/dist/stats.js +217 -0
  171. package/dist/stats.js.map +1 -0
  172. package/dist/telemetry/collector.d.ts +10 -0
  173. package/dist/telemetry/collector.d.ts.map +1 -0
  174. package/dist/telemetry/collector.js +75 -0
  175. package/dist/telemetry/collector.js.map +1 -0
  176. package/dist/telemetry/consent.d.ts +9 -0
  177. package/dist/telemetry/consent.d.ts.map +1 -0
  178. package/dist/telemetry/consent.js +42 -0
  179. package/dist/telemetry/consent.js.map +1 -0
  180. package/dist/telemetry/installation.d.ts +2 -0
  181. package/dist/telemetry/installation.d.ts.map +1 -0
  182. package/dist/telemetry/installation.js +32 -0
  183. package/dist/telemetry/installation.js.map +1 -0
  184. package/dist/telemetry/sanitizer.d.ts +5 -0
  185. package/dist/telemetry/sanitizer.d.ts.map +1 -0
  186. package/dist/telemetry/sanitizer.js +60 -0
  187. package/dist/telemetry/sanitizer.js.map +1 -0
  188. package/dist/telemetry/types.d.ts +39 -0
  189. package/dist/telemetry/types.d.ts.map +1 -0
  190. package/dist/telemetry/types.js +4 -0
  191. package/dist/telemetry/types.js.map +1 -0
  192. package/dist/telemetry/uploader.d.ts +12 -0
  193. package/dist/telemetry/uploader.d.ts.map +1 -0
  194. package/dist/telemetry/uploader.js +92 -0
  195. package/dist/telemetry/uploader.js.map +1 -0
  196. package/dist/util/logger.d.ts +19 -0
  197. package/dist/util/logger.d.ts.map +1 -0
  198. package/dist/util/logger.js +58 -0
  199. package/dist/util/logger.js.map +1 -0
  200. package/dist/util/safe-paths.d.ts +8 -0
  201. package/dist/util/safe-paths.d.ts.map +1 -0
  202. package/dist/util/safe-paths.js +102 -0
  203. package/dist/util/safe-paths.js.map +1 -0
  204. package/dist/util/subprocess.d.ts +32 -0
  205. package/dist/util/subprocess.d.ts.map +1 -0
  206. package/dist/util/subprocess.js +137 -0
  207. package/dist/util/subprocess.js.map +1 -0
  208. package/package.json +93 -0
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"risk.js","sourceRoot":"","sources":["../src/risk.ts"],"names":[],"mappings":"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"}
@@ -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"}