@panguard-ai/atr 1.4.3 → 1.5.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.
Files changed (274) hide show
  1. package/dist/action-executor.d.ts +44 -0
  2. package/dist/action-executor.d.ts.map +1 -0
  3. package/dist/action-executor.js +130 -0
  4. package/dist/action-executor.js.map +1 -0
  5. package/dist/adapters/default-adapter.d.ts +24 -0
  6. package/dist/adapters/default-adapter.d.ts.map +1 -0
  7. package/dist/adapters/default-adapter.js +51 -0
  8. package/dist/adapters/default-adapter.js.map +1 -0
  9. package/dist/adapters/stdio-adapter.d.ts +30 -0
  10. package/dist/adapters/stdio-adapter.d.ts.map +1 -0
  11. package/dist/adapters/stdio-adapter.js +128 -0
  12. package/dist/adapters/stdio-adapter.js.map +1 -0
  13. package/dist/badge.d.ts +42 -0
  14. package/dist/badge.d.ts.map +1 -0
  15. package/dist/badge.js +163 -0
  16. package/dist/badge.js.map +1 -0
  17. package/dist/capability-extractor.d.ts +35 -0
  18. package/dist/capability-extractor.d.ts.map +1 -0
  19. package/dist/capability-extractor.js +91 -0
  20. package/dist/capability-extractor.js.map +1 -0
  21. package/dist/cli/scan-handler.d.ts +21 -0
  22. package/dist/cli/scan-handler.d.ts.map +1 -0
  23. package/dist/cli/scan-handler.js +276 -0
  24. package/dist/cli/scan-handler.js.map +1 -0
  25. package/dist/cli/tc-pipeline.d.ts +18 -0
  26. package/dist/cli/tc-pipeline.d.ts.map +1 -0
  27. package/dist/cli/tc-pipeline.js +295 -0
  28. package/dist/cli/tc-pipeline.js.map +1 -0
  29. package/dist/cli.d.ts +12 -0
  30. package/dist/cli.d.ts.map +1 -0
  31. package/dist/cli.js +894 -0
  32. package/dist/cli.js.map +1 -0
  33. package/dist/content-hash.d.ts +7 -0
  34. package/dist/content-hash.d.ts.map +1 -0
  35. package/dist/content-hash.js +10 -0
  36. package/dist/content-hash.js.map +1 -0
  37. package/dist/converters/elastic.d.ts +36 -0
  38. package/dist/converters/elastic.d.ts.map +1 -0
  39. package/dist/converters/elastic.js +125 -0
  40. package/dist/converters/elastic.js.map +1 -0
  41. package/dist/converters/generic-regex.d.ts +37 -0
  42. package/dist/converters/generic-regex.d.ts.map +1 -0
  43. package/dist/converters/generic-regex.js +59 -0
  44. package/dist/converters/generic-regex.js.map +1 -0
  45. package/dist/converters/index.d.ts +32 -0
  46. package/dist/converters/index.d.ts.map +1 -0
  47. package/dist/converters/index.js +38 -0
  48. package/dist/converters/index.js.map +1 -0
  49. package/dist/converters/sarif.d.ts +18 -0
  50. package/dist/converters/sarif.d.ts.map +1 -0
  51. package/dist/converters/sarif.js +142 -0
  52. package/dist/converters/sarif.js.map +1 -0
  53. package/dist/converters/splunk.d.ts +19 -0
  54. package/dist/converters/splunk.d.ts.map +1 -0
  55. package/dist/converters/splunk.js +148 -0
  56. package/dist/converters/splunk.js.map +1 -0
  57. package/dist/coverage-analyzer.d.ts +43 -0
  58. package/dist/coverage-analyzer.d.ts.map +1 -0
  59. package/dist/coverage-analyzer.js +329 -0
  60. package/dist/coverage-analyzer.js.map +1 -0
  61. package/dist/embedding/build-corpus.d.ts +15 -0
  62. package/dist/embedding/build-corpus.d.ts.map +1 -0
  63. package/dist/embedding/build-corpus.js +105 -0
  64. package/dist/embedding/build-corpus.js.map +1 -0
  65. package/dist/embedding/model-loader.d.ts +41 -0
  66. package/dist/embedding/model-loader.d.ts.map +1 -0
  67. package/dist/embedding/model-loader.js +90 -0
  68. package/dist/embedding/model-loader.js.map +1 -0
  69. package/dist/embedding/vector-store.d.ts +41 -0
  70. package/dist/embedding/vector-store.d.ts.map +1 -0
  71. package/dist/embedding/vector-store.js +70 -0
  72. package/dist/embedding/vector-store.js.map +1 -0
  73. package/dist/engine.d.ts +222 -0
  74. package/dist/engine.d.ts.map +1 -0
  75. package/dist/engine.js +1185 -0
  76. package/dist/engine.js.map +1 -0
  77. package/dist/eval/corpus.d.ts +42 -0
  78. package/dist/eval/corpus.d.ts.map +1 -0
  79. package/dist/eval/corpus.js +427 -0
  80. package/dist/eval/corpus.js.map +1 -0
  81. package/dist/eval/eval-harness.d.ts +44 -0
  82. package/dist/eval/eval-harness.d.ts.map +1 -0
  83. package/dist/eval/eval-harness.js +296 -0
  84. package/dist/eval/eval-harness.js.map +1 -0
  85. package/dist/eval/index.d.ts +13 -0
  86. package/dist/eval/index.d.ts.map +1 -0
  87. package/dist/eval/index.js +9 -0
  88. package/dist/eval/index.js.map +1 -0
  89. package/dist/eval/metrics.d.ts +74 -0
  90. package/dist/eval/metrics.d.ts.map +1 -0
  91. package/dist/eval/metrics.js +108 -0
  92. package/dist/eval/metrics.js.map +1 -0
  93. package/dist/eval/pint-corpus.d.ts +34 -0
  94. package/dist/eval/pint-corpus.d.ts.map +1 -0
  95. package/dist/eval/pint-corpus.js +113 -0
  96. package/dist/eval/pint-corpus.js.map +1 -0
  97. package/dist/eval/rule-corpus.d.ts +9 -0
  98. package/dist/eval/rule-corpus.d.ts.map +1 -0
  99. package/dist/eval/rule-corpus.js +4780 -0
  100. package/dist/eval/rule-corpus.js.map +1 -0
  101. package/dist/eval/rule-metrics.d.ts +34 -0
  102. package/dist/eval/rule-metrics.d.ts.map +1 -0
  103. package/dist/eval/rule-metrics.js +92 -0
  104. package/dist/eval/rule-metrics.js.map +1 -0
  105. package/dist/eval/run-eval.d.ts +7 -0
  106. package/dist/eval/run-eval.d.ts.map +1 -0
  107. package/dist/eval/run-eval.js +11 -0
  108. package/dist/eval/run-eval.js.map +1 -0
  109. package/dist/eval/run-pint-benchmark.d.ts +18 -0
  110. package/dist/eval/run-pint-benchmark.d.ts.map +1 -0
  111. package/dist/eval/run-pint-benchmark.js +159 -0
  112. package/dist/eval/run-pint-benchmark.js.map +1 -0
  113. package/dist/eval/skill-benchmark.d.ts +66 -0
  114. package/dist/eval/skill-benchmark.d.ts.map +1 -0
  115. package/dist/eval/skill-benchmark.js +194 -0
  116. package/dist/eval/skill-benchmark.js.map +1 -0
  117. package/dist/flywheel.d.ts +54 -0
  118. package/dist/flywheel.d.ts.map +1 -0
  119. package/dist/flywheel.js +121 -0
  120. package/dist/flywheel.js.map +1 -0
  121. package/dist/hook-handler.d.ts +61 -0
  122. package/dist/hook-handler.d.ts.map +1 -0
  123. package/dist/hook-handler.js +178 -0
  124. package/dist/hook-handler.js.map +1 -0
  125. package/dist/index.d.ts +8 -0
  126. package/dist/index.d.ts.map +1 -0
  127. package/{src/index.ts → dist/index.js} +1 -0
  128. package/dist/index.js.map +1 -0
  129. package/dist/layer-integration.d.ts +55 -0
  130. package/dist/layer-integration.d.ts.map +1 -0
  131. package/dist/layer-integration.js +187 -0
  132. package/dist/layer-integration.js.map +1 -0
  133. package/dist/loader.d.ts +18 -0
  134. package/dist/loader.d.ts.map +1 -0
  135. package/dist/loader.js +129 -0
  136. package/dist/loader.js.map +1 -0
  137. package/dist/mcp-server.d.ts +13 -0
  138. package/dist/mcp-server.d.ts.map +1 -0
  139. package/dist/mcp-server.js +246 -0
  140. package/dist/mcp-server.js.map +1 -0
  141. package/dist/mcp-tools/coverage-gaps.d.ts +13 -0
  142. package/dist/mcp-tools/coverage-gaps.d.ts.map +1 -0
  143. package/dist/mcp-tools/coverage-gaps.js +55 -0
  144. package/dist/mcp-tools/coverage-gaps.js.map +1 -0
  145. package/dist/mcp-tools/list-rules.d.ts +17 -0
  146. package/dist/mcp-tools/list-rules.d.ts.map +1 -0
  147. package/dist/mcp-tools/list-rules.js +45 -0
  148. package/dist/mcp-tools/list-rules.js.map +1 -0
  149. package/dist/mcp-tools/scan-skill.d.ts +17 -0
  150. package/dist/mcp-tools/scan-skill.d.ts.map +1 -0
  151. package/dist/mcp-tools/scan-skill.js +65 -0
  152. package/dist/mcp-tools/scan-skill.js.map +1 -0
  153. package/dist/mcp-tools/scan.d.ts +24 -0
  154. package/dist/mcp-tools/scan.d.ts.map +1 -0
  155. package/dist/mcp-tools/scan.js +94 -0
  156. package/dist/mcp-tools/scan.js.map +1 -0
  157. package/dist/mcp-tools/submit-proposal.d.ts +12 -0
  158. package/dist/mcp-tools/submit-proposal.d.ts.map +1 -0
  159. package/dist/mcp-tools/submit-proposal.js +103 -0
  160. package/dist/mcp-tools/submit-proposal.js.map +1 -0
  161. package/dist/mcp-tools/threat-summary.d.ts +12 -0
  162. package/dist/mcp-tools/threat-summary.d.ts.map +1 -0
  163. package/dist/mcp-tools/threat-summary.js +74 -0
  164. package/dist/mcp-tools/threat-summary.js.map +1 -0
  165. package/dist/mcp-tools/validate.d.ts +15 -0
  166. package/dist/mcp-tools/validate.d.ts.map +1 -0
  167. package/dist/mcp-tools/validate.js +51 -0
  168. package/dist/mcp-tools/validate.js.map +1 -0
  169. package/dist/modules/embedding.d.ts +71 -0
  170. package/dist/modules/embedding.d.ts.map +1 -0
  171. package/dist/modules/embedding.js +141 -0
  172. package/dist/modules/embedding.js.map +1 -0
  173. package/dist/modules/index.d.ts +144 -0
  174. package/dist/modules/index.d.ts.map +1 -0
  175. package/dist/modules/index.js +82 -0
  176. package/dist/modules/index.js.map +1 -0
  177. package/dist/modules/semantic.d.ts +106 -0
  178. package/dist/modules/semantic.d.ts.map +1 -0
  179. package/dist/modules/semantic.js +359 -0
  180. package/dist/modules/semantic.js.map +1 -0
  181. package/dist/modules/session.d.ts +70 -0
  182. package/dist/modules/session.d.ts.map +1 -0
  183. package/dist/modules/session.js +128 -0
  184. package/dist/modules/session.js.map +1 -0
  185. package/dist/quality/adapters/atr.d.ts +65 -0
  186. package/dist/quality/adapters/atr.d.ts.map +1 -0
  187. package/dist/quality/adapters/atr.js +154 -0
  188. package/dist/quality/adapters/atr.js.map +1 -0
  189. package/dist/quality/adapters/index.d.ts +10 -0
  190. package/dist/quality/adapters/index.d.ts.map +1 -0
  191. package/dist/quality/adapters/index.js +10 -0
  192. package/dist/quality/adapters/index.js.map +1 -0
  193. package/dist/quality/compute-confidence.d.ts +45 -0
  194. package/dist/quality/compute-confidence.d.ts.map +1 -0
  195. package/dist/quality/compute-confidence.js +133 -0
  196. package/dist/quality/compute-confidence.js.map +1 -0
  197. package/dist/quality/index.d.ts +36 -0
  198. package/dist/quality/index.d.ts.map +1 -0
  199. package/dist/quality/index.js +39 -0
  200. package/dist/quality/index.js.map +1 -0
  201. package/dist/quality/quality-gate.d.ts +86 -0
  202. package/dist/quality/quality-gate.d.ts.map +1 -0
  203. package/dist/quality/quality-gate.js +187 -0
  204. package/dist/quality/quality-gate.js.map +1 -0
  205. package/dist/quality/types.d.ts +129 -0
  206. package/dist/quality/types.d.ts.map +1 -0
  207. package/dist/quality/types.js +10 -0
  208. package/dist/quality/types.js.map +1 -0
  209. package/dist/quality/validate-maturity.d.ts +51 -0
  210. package/dist/quality/validate-maturity.d.ts.map +1 -0
  211. package/dist/quality/validate-maturity.js +134 -0
  212. package/dist/quality/validate-maturity.js.map +1 -0
  213. package/dist/quality.d.ts +8 -0
  214. package/dist/quality.d.ts.map +1 -0
  215. package/dist/quality.js +8 -0
  216. package/dist/quality.js.map +1 -0
  217. package/dist/rule-scaffolder.d.ts +53 -0
  218. package/dist/rule-scaffolder.d.ts.map +1 -0
  219. package/dist/rule-scaffolder.js +301 -0
  220. package/dist/rule-scaffolder.js.map +1 -0
  221. package/dist/session-tracker.d.ts +58 -0
  222. package/dist/session-tracker.d.ts.map +1 -0
  223. package/dist/session-tracker.js +176 -0
  224. package/dist/session-tracker.js.map +1 -0
  225. package/dist/shadow-evaluator.d.ts +48 -0
  226. package/dist/shadow-evaluator.d.ts.map +1 -0
  227. package/dist/shadow-evaluator.js +129 -0
  228. package/dist/shadow-evaluator.js.map +1 -0
  229. package/dist/skill-fingerprint.d.ts +85 -0
  230. package/dist/skill-fingerprint.d.ts.map +1 -0
  231. package/dist/skill-fingerprint.js +284 -0
  232. package/dist/skill-fingerprint.js.map +1 -0
  233. package/dist/tc-reporter.d.ts +50 -0
  234. package/dist/tc-reporter.d.ts.map +1 -0
  235. package/dist/tc-reporter.js +164 -0
  236. package/dist/tc-reporter.js.map +1 -0
  237. package/dist/tier0-invariant.d.ts +49 -0
  238. package/dist/tier0-invariant.d.ts.map +1 -0
  239. package/dist/tier0-invariant.js +185 -0
  240. package/dist/tier0-invariant.js.map +1 -0
  241. package/dist/tier1-blacklist.d.ts +48 -0
  242. package/dist/tier1-blacklist.d.ts.map +1 -0
  243. package/dist/tier1-blacklist.js +92 -0
  244. package/dist/tier1-blacklist.js.map +1 -0
  245. package/dist/types.d.ts +232 -0
  246. package/dist/types.d.ts.map +1 -0
  247. package/dist/types.js +6 -0
  248. package/dist/types.js.map +1 -0
  249. package/dist/verdict.d.ts +26 -0
  250. package/dist/verdict.d.ts.map +1 -0
  251. package/dist/verdict.js +127 -0
  252. package/dist/verdict.js.map +1 -0
  253. package/package.json +16 -4
  254. package/.github/ISSUE_TEMPLATE/evasion-report.yml +0 -75
  255. package/.github/ISSUE_TEMPLATE/false-positive.yml +0 -31
  256. package/.github/ISSUE_TEMPLATE/mirofish-prediction.yml +0 -128
  257. package/.github/ISSUE_TEMPLATE/new-rule.yml +0 -37
  258. package/.github/PULL_REQUEST_TEMPLATE.md +0 -23
  259. package/.github/workflows/rule-quality.yml +0 -203
  260. package/.github/workflows/validate.yml +0 -42
  261. package/CHANGELOG.md +0 -30
  262. package/CONTRIBUTING.md +0 -168
  263. package/CONTRIBUTORS.md +0 -28
  264. package/COVERAGE.md +0 -135
  265. package/LIMITATIONS.md +0 -154
  266. package/SECURITY.md +0 -48
  267. package/THREAT-MODEL.md +0 -243
  268. package/docs/contribution-paths.md +0 -202
  269. package/docs/mirofish-prediction-guide.md +0 -304
  270. package/docs/quick-start.md +0 -245
  271. package/docs/rule-writing-guide.md +0 -647
  272. package/docs/schema-spec.md +0 -594
  273. package/examples/how-to-write-a-rule.md +0 -251
  274. package/tsconfig.json +0 -17
@@ -0,0 +1,128 @@
1
+ /**
2
+ * ATR Session Module - Built-in behavioral detection module
3
+ *
4
+ * Provides cross-event analysis using SessionTracker.
5
+ * This is the reference implementation for ATR modules.
6
+ *
7
+ * Functions:
8
+ * - call_frequency: Count tool calls within a time window
9
+ * - pattern_frequency: Count pattern occurrences within a window
10
+ * - event_count: Total events in a session within a window
11
+ * - session_age: Time since first event in session (seconds)
12
+ *
13
+ * @module agent-threat-rules/modules/session
14
+ */
15
+ import { SessionTracker } from '../session-tracker.js';
16
+ export class SessionModule {
17
+ name = 'session';
18
+ description = 'Cross-event behavioral analysis using session state tracking';
19
+ version = '0.1.0';
20
+ functions = [
21
+ {
22
+ name: 'call_frequency',
23
+ description: 'Count how many times a specific tool was called within a time window',
24
+ args: [
25
+ { name: 'tool_name', type: 'string', required: true, description: 'Tool name to count' },
26
+ { name: 'window', type: 'string', required: false, description: 'Time window (e.g., "5m", "1h"). Default: 5m' },
27
+ ],
28
+ },
29
+ {
30
+ name: 'pattern_frequency',
31
+ description: 'Count how many times a pattern was matched within a time window',
32
+ args: [
33
+ { name: 'pattern', type: 'string', required: true, description: 'Pattern string to count' },
34
+ { name: 'window', type: 'string', required: false, description: 'Time window. Default: 5m' },
35
+ ],
36
+ },
37
+ {
38
+ name: 'event_count',
39
+ description: 'Total number of events in the current session within a time window',
40
+ args: [
41
+ { name: 'window', type: 'string', required: false, description: 'Time window. Default: 5m' },
42
+ ],
43
+ },
44
+ {
45
+ name: 'session_age',
46
+ description: 'Time in seconds since the first event in this session',
47
+ args: [],
48
+ },
49
+ ];
50
+ tracker;
51
+ constructor(tracker) {
52
+ this.tracker = tracker ?? new SessionTracker();
53
+ }
54
+ async initialize() {
55
+ // SessionTracker is ready immediately, no async setup needed
56
+ }
57
+ async evaluate(event, condition) {
58
+ const sessionId = event.sessionId ?? 'default';
59
+ const fn = condition.function;
60
+ const args = condition.args;
61
+ let value = 0;
62
+ let description = '';
63
+ switch (fn) {
64
+ case 'call_frequency': {
65
+ const toolName = String(args['tool_name'] ?? '');
66
+ const window = String(args['window'] ?? '5m');
67
+ const windowMs = parseWindow(window);
68
+ value = this.tracker.getCallFrequency(sessionId, toolName, windowMs);
69
+ description = `Tool "${toolName}" called ${value} times in ${window}`;
70
+ break;
71
+ }
72
+ case 'pattern_frequency': {
73
+ const pattern = String(args['pattern'] ?? '');
74
+ const window = String(args['window'] ?? '5m');
75
+ const windowMs = parseWindow(window);
76
+ value = this.tracker.getPatternFrequency(sessionId, pattern, windowMs);
77
+ description = `Pattern "${pattern}" seen ${value} times in ${window}`;
78
+ break;
79
+ }
80
+ case 'event_count': {
81
+ const window = String(args['window'] ?? '5m');
82
+ const windowMs = parseWindow(window);
83
+ value = this.tracker.getEventCount(sessionId, windowMs);
84
+ description = `${value} events in session within ${window}`;
85
+ break;
86
+ }
87
+ case 'session_age': {
88
+ const snapshot = this.tracker.getSessionSnapshot(sessionId);
89
+ if (snapshot && snapshot.oldestEventTimestamp) {
90
+ value = Math.floor((Date.now() - snapshot.oldestEventTimestamp) / 1000);
91
+ }
92
+ description = `Session age: ${value} seconds`;
93
+ break;
94
+ }
95
+ default:
96
+ return { matched: false, value: 0, description: `Unknown function: ${fn}` };
97
+ }
98
+ const matched = compare(value, condition.operator, condition.threshold);
99
+ return { matched, value, description };
100
+ }
101
+ async destroy() {
102
+ // No cleanup needed
103
+ }
104
+ }
105
+ function compare(value, operator, threshold) {
106
+ switch (operator) {
107
+ case 'gt': return value > threshold;
108
+ case 'lt': return value < threshold;
109
+ case 'eq': return value === threshold;
110
+ case 'gte': return value >= threshold;
111
+ case 'lte': return value <= threshold;
112
+ default: return false;
113
+ }
114
+ }
115
+ function parseWindow(window) {
116
+ const match = window.match(/^(\d+)(s|m|h)$/);
117
+ if (!match)
118
+ return 300_000; // default 5m
119
+ const [, num, unit] = match;
120
+ const n = parseInt(num, 10);
121
+ switch (unit) {
122
+ case 's': return n * 1000;
123
+ case 'm': return n * 60_000;
124
+ case 'h': return n * 3_600_000;
125
+ default: return 300_000;
126
+ }
127
+ }
128
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/modules/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * ATR Quality Standard — ATR YAML Adapter
3
+ *
4
+ * Parses an ATR YAML rule (either as raw string or pre-parsed object) and
5
+ * produces RuleMetadata that the quality gate and scoring functions
6
+ * understand.
7
+ *
8
+ * @module agent-threat-rules/quality/adapters/atr
9
+ */
10
+ import type { RuleMetadata } from "../types.js";
11
+ /**
12
+ * Loose shape of an ATR rule file — matches what actually appears in
13
+ * rules/**\/*.yaml, not the strict type. This lets us adapt rules even if
14
+ * they're missing optional fields.
15
+ */
16
+ interface RawATRRule {
17
+ id?: string;
18
+ title?: string;
19
+ status?: string;
20
+ maturity?: string;
21
+ detection?: {
22
+ conditions?: unknown;
23
+ false_positives?: unknown[];
24
+ };
25
+ test_cases?: {
26
+ true_positives?: unknown[];
27
+ true_negatives?: unknown[];
28
+ };
29
+ evasion_tests?: unknown[];
30
+ references?: {
31
+ owasp_llm?: unknown[];
32
+ owasp_agentic?: unknown[];
33
+ mitre_atlas?: unknown[];
34
+ mitre_attack?: unknown[];
35
+ };
36
+ author?: string;
37
+ wild_samples?: number;
38
+ wild_fp_rate?: number;
39
+ wild_validated?: string;
40
+ metadata_provenance?: {
41
+ mitre_atlas?: string;
42
+ mitre_attack?: string;
43
+ owasp_llm?: string;
44
+ owasp_agentic?: string;
45
+ test_cases?: string;
46
+ evasion_tests?: string;
47
+ false_positives?: string;
48
+ };
49
+ }
50
+ /**
51
+ * Parse an ATR YAML rule string into RuleMetadata.
52
+ *
53
+ * @param yamlContent - Raw YAML content
54
+ * @returns RuleMetadata (throws if YAML is invalid or missing required fields)
55
+ */
56
+ export declare function parseATRRule(yamlContent: string): RuleMetadata;
57
+ /**
58
+ * Convert a parsed ATR rule object into RuleMetadata.
59
+ *
60
+ * Accepts the loose shape returned by yaml.load() so callers that already
61
+ * have a parsed object don't need to re-serialize.
62
+ */
63
+ export declare function atrRuleToMetadata(rule: RawATRRule): RuleMetadata;
64
+ export {};
65
+ //# sourceMappingURL=atr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atr.d.ts","sourceRoot":"","sources":["../../../src/quality/adapters/atr.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAIV,YAAY,EACb,MAAM,aAAa,CAAC;AAErB;;;;GAIG;AACH,UAAU,UAAU;IAClB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE;QACV,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,eAAe,CAAC,EAAE,OAAO,EAAE,CAAC;KAC7B,CAAC;IACF,UAAU,CAAC,EAAE;QACX,cAAc,CAAC,EAAE,OAAO,EAAE,CAAC;QAC3B,cAAc,CAAC,EAAE,OAAO,EAAE,CAAC;KAC5B,CAAC;IACF,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC;IAC1B,UAAU,CAAC,EAAE;QACX,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;QACtB,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC;QAC1B,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;QACxB,YAAY,CAAC,EAAE,OAAO,EAAE,CAAC;KAC1B,CAAC;IACF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,mBAAmB,CAAC,EAAE;QACpB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,eAAe,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,YAAY,CAM9D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,YAAY,CA2DhE"}
@@ -0,0 +1,154 @@
1
+ /**
2
+ * ATR Quality Standard — ATR YAML Adapter
3
+ *
4
+ * Parses an ATR YAML rule (either as raw string or pre-parsed object) and
5
+ * produces RuleMetadata that the quality gate and scoring functions
6
+ * understand.
7
+ *
8
+ * @module agent-threat-rules/quality/adapters/atr
9
+ */
10
+ import { load as parseYaml } from "js-yaml";
11
+ /**
12
+ * Parse an ATR YAML rule string into RuleMetadata.
13
+ *
14
+ * @param yamlContent - Raw YAML content
15
+ * @returns RuleMetadata (throws if YAML is invalid or missing required fields)
16
+ */
17
+ export function parseATRRule(yamlContent) {
18
+ const parsed = parseYaml(yamlContent);
19
+ if (!parsed || typeof parsed !== "object") {
20
+ throw new Error("Invalid YAML: not an object");
21
+ }
22
+ return atrRuleToMetadata(parsed);
23
+ }
24
+ /**
25
+ * Convert a parsed ATR rule object into RuleMetadata.
26
+ *
27
+ * Accepts the loose shape returned by yaml.load() so callers that already
28
+ * have a parsed object don't need to re-serialize.
29
+ */
30
+ export function atrRuleToMetadata(rule) {
31
+ const id = rule.id ?? "<unknown>";
32
+ const title = rule.title ?? "<untitled>";
33
+ // Prefer `maturity` field; fall back to `status` if maturity is absent.
34
+ // Normalize common aliases: `test` -> `experimental`, anything unknown -> `draft`.
35
+ const rawMaturity = (rule.maturity ?? rule.status ?? "draft").toLowerCase();
36
+ const maturity = normalizeMaturity(rawMaturity);
37
+ const conditions = countConditions(rule.detection?.conditions);
38
+ const truePositives = Array.isArray(rule.test_cases?.true_positives)
39
+ ? rule.test_cases.true_positives.length
40
+ : 0;
41
+ const trueNegatives = Array.isArray(rule.test_cases?.true_negatives)
42
+ ? rule.test_cases.true_negatives.length
43
+ : 0;
44
+ const evasionTests = Array.isArray(rule.evasion_tests)
45
+ ? rule.evasion_tests.length
46
+ : 0;
47
+ const hasOwaspRef = hasAnyArrayItem(rule.references?.owasp_llm) ||
48
+ hasAnyArrayItem(rule.references?.owasp_agentic);
49
+ const hasMitreRef = hasAnyArrayItem(rule.references?.mitre_atlas) ||
50
+ hasAnyArrayItem(rule.references?.mitre_attack);
51
+ const hasFalsePositiveDocs = Array.isArray(rule.detection?.false_positives) &&
52
+ rule.detection.false_positives.length > 0;
53
+ // LLM-generated detection: author contains "Crystallization" or "LLM"
54
+ const author = (rule.author ?? "").toLowerCase();
55
+ const llmGenerated = author.includes("crystallization") ||
56
+ author.includes("llm") ||
57
+ author.includes("mirofish");
58
+ const provenance = extractProvenance(rule.metadata_provenance);
59
+ return {
60
+ id,
61
+ title,
62
+ maturity,
63
+ conditions,
64
+ truePositives,
65
+ trueNegatives,
66
+ evasionTests,
67
+ hasOwaspRef,
68
+ hasMitreRef,
69
+ hasFalsePositiveDocs,
70
+ ...(rule.wild_samples !== undefined
71
+ ? { wildSamples: rule.wild_samples }
72
+ : {}),
73
+ ...(rule.wild_fp_rate !== undefined
74
+ ? { wildFpRate: rule.wild_fp_rate }
75
+ : {}),
76
+ ...(rule.wild_validated ? { wildValidatedAt: rule.wild_validated } : {}),
77
+ ...(llmGenerated ? { llmGenerated: true } : {}),
78
+ ...(provenance ? { provenance } : {}),
79
+ };
80
+ }
81
+ /** Parse metadata_provenance field and normalize values to Provenance enum */
82
+ function extractProvenance(raw) {
83
+ if (!raw || typeof raw !== "object")
84
+ return undefined;
85
+ const result = {
86
+ ...(raw.mitre_atlas
87
+ ? { mitre_atlas: normalizeProvenance(raw.mitre_atlas) }
88
+ : {}),
89
+ ...(raw.mitre_attack
90
+ ? { mitre_attack: normalizeProvenance(raw.mitre_attack) }
91
+ : {}),
92
+ ...(raw.owasp_llm ? { owasp_llm: normalizeProvenance(raw.owasp_llm) } : {}),
93
+ ...(raw.owasp_agentic
94
+ ? { owasp_agentic: normalizeProvenance(raw.owasp_agentic) }
95
+ : {}),
96
+ ...(raw.test_cases
97
+ ? { test_cases: normalizeProvenance(raw.test_cases) }
98
+ : {}),
99
+ ...(raw.evasion_tests
100
+ ? { evasion_tests: normalizeProvenance(raw.evasion_tests) }
101
+ : {}),
102
+ ...(raw.false_positives
103
+ ? { false_positives: normalizeProvenance(raw.false_positives) }
104
+ : {}),
105
+ };
106
+ return Object.keys(result).length > 0 ? result : undefined;
107
+ }
108
+ function normalizeProvenance(raw) {
109
+ const v = raw.toLowerCase().trim();
110
+ if (v === "human-reviewed" || v === "human")
111
+ return "human-reviewed";
112
+ if (v === "community-contributed" || v === "community")
113
+ return "community-contributed";
114
+ if (v === "auto-generated" || v === "auto")
115
+ return "auto-generated";
116
+ if (v === "llm-generated" || v === "llm")
117
+ return "llm-generated";
118
+ // Unknown value — treat as auto-generated (conservative)
119
+ return "auto-generated";
120
+ }
121
+ /**
122
+ * ATR rules use two different condition formats:
123
+ * - Array: `conditions: [{ field, operator, value }, ...]`
124
+ * - Named map: `conditions: { name1: {...}, name2: {...} }`
125
+ *
126
+ * Count layers in either format.
127
+ */
128
+ function countConditions(conditions) {
129
+ if (Array.isArray(conditions))
130
+ return conditions.length;
131
+ if (conditions !== null && typeof conditions === "object") {
132
+ return Object.keys(conditions).length;
133
+ }
134
+ return 0;
135
+ }
136
+ function hasAnyArrayItem(value) {
137
+ return Array.isArray(value) && value.length > 0;
138
+ }
139
+ function normalizeMaturity(raw) {
140
+ switch (raw) {
141
+ case "draft":
142
+ return "draft";
143
+ case "experimental":
144
+ case "test": // ATR legacy alias
145
+ return "experimental";
146
+ case "stable":
147
+ return "stable";
148
+ case "deprecated":
149
+ return "deprecated";
150
+ default:
151
+ return "draft";
152
+ }
153
+ }
154
+ //# sourceMappingURL=atr.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"atr.js","sourceRoot":"","sources":["../../../src/quality/adapters/atr.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * ATR Quality Standard — Rule Format Adapters
3
+ *
4
+ * Adapters convert vendor-specific rule formats into the canonical
5
+ * RuleMetadata interface that the scoring and validation functions consume.
6
+ *
7
+ * @module agent-threat-rules/quality/adapters
8
+ */
9
+ export { parseATRRule, atrRuleToMetadata } from "./atr.js";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/quality/adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * ATR Quality Standard — Rule Format Adapters
3
+ *
4
+ * Adapters convert vendor-specific rule formats into the canonical
5
+ * RuleMetadata interface that the scoring and validation functions consume.
6
+ *
7
+ * @module agent-threat-rules/quality/adapters
8
+ */
9
+ export { parseATRRule, atrRuleToMetadata } from "./atr.js";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/quality/adapters/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * ATR Quality Standard — Confidence Scoring
3
+ *
4
+ * Pure function implementing the RFC-001 §2 confidence formula:
5
+ *
6
+ * confidence = round(
7
+ * precision_score * 0.40
8
+ * + wild_validation * 0.30
9
+ * + coverage_score * 0.20
10
+ * + evasion_docs * 0.10
11
+ * )
12
+ *
13
+ * @module agent-threat-rules/quality/compute-confidence
14
+ */
15
+ import type { ConfidenceScore, DeploymentRecommendation, RuleMetadata } from "./types.js";
16
+ /**
17
+ * Compute the confidence score for a rule.
18
+ *
19
+ * Score is in [0, 100]. Higher is more trustworthy.
20
+ *
21
+ * @param rule - Rule metadata (vendor-agnostic)
22
+ * @returns Score breakdown and total
23
+ */
24
+ export declare function computeConfidence(rule: RuleMetadata): ConfidenceScore;
25
+ /**
26
+ * Map a confidence score to a deployment recommendation.
27
+ *
28
+ * This is the consumer-facing signal: "should I deploy this rule in
29
+ * blocking mode, alert mode, or not at all?"
30
+ */
31
+ export declare function deploymentFor(score: number): DeploymentRecommendation;
32
+ /**
33
+ * Apply the cross-context penalty to a match's contribution.
34
+ *
35
+ * When a rule designed for one scan context (e.g. MCP runtime) fires in
36
+ * a different context (e.g. SKILL.md static scan), the match's contribution
37
+ * is downweighted by 0.7. This prevents cross-context noise from inflating
38
+ * overall detection confidence.
39
+ *
40
+ * @param score - The base confidence score of the rule
41
+ * @param isCrossContext - True if the match is outside the rule's native context
42
+ * @returns Adjusted score
43
+ */
44
+ export declare function applyCrossContextPenalty(score: number, isCrossContext: boolean): number;
45
+ //# sourceMappingURL=compute-confidence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute-confidence.d.ts","sourceRoot":"","sources":["../../src/quality/compute-confidence.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,wBAAwB,EACxB,YAAY,EACb,MAAM,YAAY,CAAC;AAKpB;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,GAAG,eAAe,CAiCrE;AAuDD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,wBAAwB,CAMrE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,cAAc,EAAE,OAAO,GACtB,MAAM,CAER"}
@@ -0,0 +1,133 @@
1
+ /**
2
+ * ATR Quality Standard — Confidence Scoring
3
+ *
4
+ * Pure function implementing the RFC-001 §2 confidence formula:
5
+ *
6
+ * confidence = round(
7
+ * precision_score * 0.40
8
+ * + wild_validation * 0.30
9
+ * + coverage_score * 0.20
10
+ * + evasion_docs * 0.10
11
+ * )
12
+ *
13
+ * @module agent-threat-rules/quality/compute-confidence
14
+ */
15
+ /** Max confidence an LLM-generated rule can reach without human review */
16
+ const LLM_CAP_WITHOUT_REVIEW = 70;
17
+ /**
18
+ * Compute the confidence score for a rule.
19
+ *
20
+ * Score is in [0, 100]. Higher is more trustworthy.
21
+ *
22
+ * @param rule - Rule metadata (vendor-agnostic)
23
+ * @returns Score breakdown and total
24
+ */
25
+ export function computeConfidence(rule) {
26
+ const precisionScore = computePrecisionScore(rule);
27
+ const wildValidationScore = computeWildValidationScore(rule);
28
+ const coverageScore = computeCoverageScore(rule);
29
+ const evasionScore = computeEvasionScore(rule);
30
+ const rawTotal = precisionScore * 0.4 +
31
+ wildValidationScore * 0.3 +
32
+ coverageScore * 0.2 +
33
+ evasionScore * 0.1;
34
+ let total = Math.round(rawTotal);
35
+ let capped = false;
36
+ // LLM-generated rules are capped at LLM_CAP_WITHOUT_REVIEW until a human reviews them.
37
+ // Rationale: LLMs can produce subtly wrong rules that pass static validation
38
+ // but fail in the wild. Human review is the only reliable backstop.
39
+ if (rule.llmGenerated === true && rule.humanReviewed !== true) {
40
+ if (total > LLM_CAP_WITHOUT_REVIEW) {
41
+ total = LLM_CAP_WITHOUT_REVIEW;
42
+ capped = true;
43
+ }
44
+ }
45
+ return {
46
+ total,
47
+ precisionScore: Math.round(precisionScore),
48
+ wildValidationScore: Math.round(wildValidationScore),
49
+ coverageScore: Math.round(coverageScore),
50
+ evasionScore: Math.round(evasionScore),
51
+ capped,
52
+ };
53
+ }
54
+ /**
55
+ * Precision component (weight 0.40).
56
+ *
57
+ * If wild FP rate is measured, use it directly: (1 - fpRate/100) * 100.
58
+ * Otherwise, estimate from test case coverage: more test cases = higher
59
+ * confidence in precision (max at 10 total).
60
+ */
61
+ function computePrecisionScore(rule) {
62
+ if (rule.wildFpRate !== undefined &&
63
+ rule.wildSamples !== undefined &&
64
+ rule.wildSamples > 0) {
65
+ const fpRate = Math.max(0, Math.min(100, rule.wildFpRate));
66
+ return 100 - fpRate;
67
+ }
68
+ // Fallback: estimate from test case depth
69
+ const testCaseCount = rule.truePositives + rule.trueNegatives;
70
+ return Math.min(testCaseCount / 10, 1) * 100;
71
+ }
72
+ /**
73
+ * Wild validation component (weight 0.30).
74
+ *
75
+ * Scales with sample size up to 10,000 samples. More real-world data
76
+ * = higher score. A rule tested on 0 samples gets 0. A rule tested on
77
+ * 10,000+ samples gets 100.
78
+ */
79
+ function computeWildValidationScore(rule) {
80
+ const samples = rule.wildSamples ?? 0;
81
+ return Math.min(samples / 10000, 1) * 100;
82
+ }
83
+ /**
84
+ * Coverage component (weight 0.20).
85
+ *
86
+ * Scales with number of detection conditions (layers). A single-condition
87
+ * rule gets 20. A 5+ condition rule gets 100. Defense in depth matters.
88
+ */
89
+ function computeCoverageScore(rule) {
90
+ return Math.min(rule.conditions / 5, 1) * 100;
91
+ }
92
+ /**
93
+ * Evasion documentation component (weight 0.10).
94
+ *
95
+ * Rewards honest acknowledgment of known bypasses. A rule with 0 evasion
96
+ * tests gets 0. A rule with 5+ evasion tests gets 100.
97
+ */
98
+ function computeEvasionScore(rule) {
99
+ return Math.min(rule.evasionTests / 5, 1) * 100;
100
+ }
101
+ /**
102
+ * Map a confidence score to a deployment recommendation.
103
+ *
104
+ * This is the consumer-facing signal: "should I deploy this rule in
105
+ * blocking mode, alert mode, or not at all?"
106
+ */
107
+ export function deploymentFor(score) {
108
+ if (score >= 90)
109
+ return "block-in-production";
110
+ if (score >= 80)
111
+ return "block-with-monitoring";
112
+ if (score >= 60)
113
+ return "alert-only";
114
+ if (score >= 40)
115
+ return "evaluation-only";
116
+ return "do-not-deploy";
117
+ }
118
+ /**
119
+ * Apply the cross-context penalty to a match's contribution.
120
+ *
121
+ * When a rule designed for one scan context (e.g. MCP runtime) fires in
122
+ * a different context (e.g. SKILL.md static scan), the match's contribution
123
+ * is downweighted by 0.7. This prevents cross-context noise from inflating
124
+ * overall detection confidence.
125
+ *
126
+ * @param score - The base confidence score of the rule
127
+ * @param isCrossContext - True if the match is outside the rule's native context
128
+ * @returns Adjusted score
129
+ */
130
+ export function applyCrossContextPenalty(score, isCrossContext) {
131
+ return isCrossContext ? Math.round(score * 0.7) : score;
132
+ }
133
+ //# sourceMappingURL=compute-confidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute-confidence.js","sourceRoot":"","sources":["../../src/quality/compute-confidence.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * ATR Quality Standard — Public API
3
+ *
4
+ * Vendor-neutral library for scoring and validating AI agent threat detection
5
+ * rules. See docs/proposals/001-atr-quality-standard-rfc.md for the RFC.
6
+ *
7
+ * @example Compute a confidence score for an ATR rule
8
+ * ```typescript
9
+ * import { parseATRRule, computeConfidence } from 'agent-threat-rules/quality';
10
+ * import { readFileSync } from 'node:fs';
11
+ *
12
+ * const yaml = readFileSync('rules/prompt-injection/ATR-2026-00001.yaml', 'utf-8');
13
+ * const rule = parseATRRule(yaml);
14
+ * const score = computeConfidence(rule);
15
+ * console.log(`Confidence: ${score.total}/100`);
16
+ * ```
17
+ *
18
+ * @example Run a rule through the quality gate
19
+ * ```typescript
20
+ * import { parseATRRule, validateRuleMeetsStandard } from 'agent-threat-rules/quality';
21
+ *
22
+ * const rule = parseATRRule(yamlContent);
23
+ * const gate = validateRuleMeetsStandard(rule, 'experimental');
24
+ * if (!gate.passed) {
25
+ * console.error('Rule rejected:', gate.issues);
26
+ * }
27
+ * ```
28
+ *
29
+ * @module agent-threat-rules/quality
30
+ */
31
+ export type { Maturity, RuleMetadata, ConfidenceScore, QualityGateResult, PromotionDecision, DemotionDecision, FpReport, DeploymentRecommendation, } from "./types.js";
32
+ export { computeConfidence, deploymentFor, applyCrossContextPenalty, } from "./compute-confidence.js";
33
+ export { validateRuleMeetsStandard, getRequirements } from "./quality-gate.js";
34
+ export { canPromote, shouldDemote, getMaturityThresholds, } from "./validate-maturity.js";
35
+ export { parseATRRule, atrRuleToMetadata } from "./adapters/atr.js";
36
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/quality/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,QAAQ,EACR,wBAAwB,GACzB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,yBAAyB,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAG/E,OAAO,EACL,UAAU,EACV,YAAY,EACZ,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAGhC,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}