agent-threat-rules 2.2.1 → 3.0.5

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 (101) hide show
  1. package/README.md +365 -327
  2. package/dist/engine.d.ts +46 -1
  3. package/dist/engine.d.ts.map +1 -1
  4. package/dist/engine.js +242 -1
  5. package/dist/engine.js.map +1 -1
  6. package/dist/eval/eval-harness.d.ts.map +1 -1
  7. package/dist/eval/eval-harness.js +9 -0
  8. package/dist/eval/eval-harness.js.map +1 -1
  9. package/dist/eval/run-hackaprompt-benchmark.js +9 -0
  10. package/dist/eval/run-hackaprompt-benchmark.js.map +1 -1
  11. package/dist/eval/run-pint-benchmark.js +9 -0
  12. package/dist/eval/run-pint-benchmark.js.map +1 -1
  13. package/dist/eval/skill-benchmark.d.ts +11 -0
  14. package/dist/eval/skill-benchmark.d.ts.map +1 -1
  15. package/dist/eval/skill-benchmark.js +57 -0
  16. package/dist/eval/skill-benchmark.js.map +1 -1
  17. package/dist/measurement/from-eval-harness.d.ts +70 -0
  18. package/dist/measurement/from-eval-harness.d.ts.map +1 -0
  19. package/dist/measurement/from-eval-harness.js +49 -0
  20. package/dist/measurement/from-eval-harness.js.map +1 -0
  21. package/dist/measurement/schema.d.ts +152 -0
  22. package/dist/measurement/schema.d.ts.map +1 -0
  23. package/dist/measurement/schema.js +178 -0
  24. package/dist/measurement/schema.js.map +1 -0
  25. package/dist/measurement/write.d.ts +64 -0
  26. package/dist/measurement/write.d.ts.map +1 -0
  27. package/dist/measurement/write.js +163 -0
  28. package/dist/measurement/write.js.map +1 -0
  29. package/dist/semantic-evaluator.d.ts +48 -0
  30. package/dist/semantic-evaluator.d.ts.map +1 -0
  31. package/dist/semantic-evaluator.js +107 -0
  32. package/dist/semantic-evaluator.js.map +1 -0
  33. package/dist/trace-evaluator.d.ts +22 -0
  34. package/dist/trace-evaluator.d.ts.map +1 -0
  35. package/dist/trace-evaluator.js +249 -0
  36. package/dist/trace-evaluator.js.map +1 -0
  37. package/dist/types.d.ts +143 -0
  38. package/dist/types.d.ts.map +1 -1
  39. package/package.json +5 -3
  40. package/rules/agent-manipulation/ATR-2026-00552-goal-drift-after-pressure-injection.yaml +216 -0
  41. package/rules/context-exfiltration/ATR-2026-00524-claude-code-anthropic-base-url-credential-exfil.yaml +257 -0
  42. package/rules/context-exfiltration/ATR-2026-00548-cross-agent-session-context-leak.yaml +177 -0
  43. package/rules/excessive-autonomy/ATR-2026-00553-runaway-tool-loop-behavioral.yaml +174 -0
  44. package/rules/privilege-escalation/ATR-2026-00528-praisonai-auth-disabled-default.yaml +192 -0
  45. package/rules/privilege-escalation/ATR-2026-00539-crewai-codeinterpreter-sandbox-escape-rce.yaml +292 -0
  46. package/rules/privilege-escalation/ATR-2026-00546-crewai-json-loader-local-file-read.yaml +162 -0
  47. package/rules/privilege-escalation/ATR-2026-00547-crewai-rag-url-ssrf-bypass.yaml +167 -0
  48. package/rules/privilege-escalation/ATR-2026-00549-destructive-tool-without-human-approval.yaml +193 -0
  49. package/rules/privilege-escalation/ATR-2026-00551-cross-conversation-memory-write.yaml +198 -0
  50. package/rules/prompt-injection/ATR-2026-00535-windsurf-ide-zero-click-prompt-injection.yaml +199 -0
  51. package/rules/prompt-injection/ATR-2026-00550-untrusted-retrieval-to-privileged-tool.yaml +199 -0
  52. package/rules/skill-compromise/ATR-2026-00123-skill-overreach-permissions.yaml +5 -2
  53. package/rules/skill-compromise/ATR-2026-00523-claude-code-hooks-session-start-pre-trust-rce.yaml +221 -0
  54. package/rules/skill-compromise/ATR-2026-00525-mini-shai-hulud-gh-token-monitor-persistence.yaml +220 -0
  55. package/rules/skill-compromise/ATR-2026-00527-skill-silent-git-remote-mirror-exfiltration.yaml +201 -0
  56. package/rules/tool-poisoning/ATR-2026-00526-claude-code-shell-metachar-in-double-quoted-path.yaml +167 -0
  57. package/rules/tool-poisoning/ATR-2026-00529-litellm-proxy-sqli-cisa-kev.yaml +158 -0
  58. package/rules/tool-poisoning/ATR-2026-00530-ms-agent-shell-tool-unsanitized-argv-rce.yaml +184 -0
  59. package/rules/tool-poisoning/ATR-2026-00531-praisonai-unauthenticated-agent-api.yaml +174 -0
  60. package/rules/tool-poisoning/ATR-2026-00532-apache-doris-mcp-sql-injection.yaml +155 -0
  61. package/rules/tool-poisoning/ATR-2026-00533-apache-pinot-mcp-unauthenticated-takeover.yaml +151 -0
  62. package/rules/tool-poisoning/ATR-2026-00534-alibaba-rds-mcp-unauthenticated-metadata-exfil.yaml +155 -0
  63. package/rules/tool-poisoning/ATR-2026-00536-nginx-ui-mcp-unauthenticated-command-execution.yaml +199 -0
  64. package/rules/tool-poisoning/ATR-2026-00537-fastmcp-server-name-cmd-injection-windows.yaml +226 -0
  65. package/rules/tool-poisoning/ATR-2026-00538-langchain-chatchat-mcp-stdio-unauthenticated-rce.yaml +244 -0
  66. package/rules/tool-poisoning/ATR-2026-00540-praisonai-parse-mcp-command-cli-injection.yaml +186 -0
  67. package/rules/tool-poisoning/ATR-2026-00541-agent-zero-mcp-config-command-injection.yaml +183 -0
  68. package/rules/tool-poisoning/ATR-2026-00542-upsonic-mcp-command-allowlist-bypass.yaml +166 -0
  69. package/rules/tool-poisoning/ATR-2026-00543-litellm-mcp-server-argv-injection.yaml +168 -0
  70. package/rules/tool-poisoning/ATR-2026-00544-praisonai-pth-file-path-traversal-rce.yaml +172 -0
  71. package/rules/tool-poisoning/ATR-2026-00545-praisonai-tool-override-unauth-rce.yaml +170 -0
  72. package/spec/README.md +279 -0
  73. package/spec/atr-correlation-v1.0.md +281 -0
  74. package/spec/atr-event-v1.0.md +294 -0
  75. package/spec/atr-language-detection-v1.0.md +218 -0
  76. package/spec/atr-method-v1.1.md +557 -0
  77. package/spec/atr-profile-v1.0.md +307 -0
  78. package/spec/atr-schema.yaml +279 -8
  79. package/spec/category-registry/v1.0.yaml +200 -0
  80. package/spec/conformance/README.md +244 -0
  81. package/spec/conformance/SIGNING.md +191 -0
  82. package/spec/conformance/baseline/fixtures/ATR-2026-00001-tp-001/expected.json +36 -0
  83. package/spec/conformance/baseline/fixtures/ATR-2026-00001-tp-001/input.json +16 -0
  84. package/spec/conformance/baseline/fixtures/README.md +120 -0
  85. package/spec/conformance/baseline/manifest.json +56 -0
  86. package/spec/conformance/expected-results.schema.json +121 -0
  87. package/spec/external-registries/cccs-yara.md +142 -0
  88. package/spec/internet-drafts/draft-lin-atr-core-00.html +1925 -0
  89. package/spec/internet-drafts/draft-lin-atr-core-00.md +288 -0
  90. package/spec/internet-drafts/draft-lin-atr-core-00.txt +560 -0
  91. package/spec/internet-drafts/draft-lin-atr-core-00.xml +424 -0
  92. package/spec/mappings/README.md +43 -0
  93. package/spec/mappings/atr-to-nist-csf-2.0.md +234 -0
  94. package/spec/schema/correlation.schema.json +144 -0
  95. package/spec/schema/event.schema.json +233 -0
  96. package/spec/schema/profile.schema.json +196 -0
  97. package/spec/schema/rule.schema.json +224 -0
  98. package/spec/stix-extension/README.md +76 -13
  99. package/spec/stix-extension/examples/atr-rule-trace-method-example.json +85 -0
  100. package/spec/stix-extension/extension-definition.json +23 -3
  101. package/spec/stix-extension/x-atr-rule-schema.json +107 -11
@@ -0,0 +1,178 @@
1
+ /**
2
+ * src/measurement/schema.ts
3
+ *
4
+ * Schema for ATR benchmark measurement files.
5
+ *
6
+ * Every public ATR recall / precision / FP-rate claim must reference a
7
+ * measurement file conforming to this schema. The contract is documented in
8
+ * `data/measurements/README.md`.
9
+ *
10
+ * Design constraints:
11
+ * - No external dependencies (no zod, no ajv). Schemas evolve slowly; the
12
+ * dependency surface should not.
13
+ * - Strict at the boundary. `parseMeasurement()` throws on any deviation;
14
+ * it does not silently coerce, drop fields, or accept missing required
15
+ * fields.
16
+ * - Forward-compatible. `schema_version` is mandatory. Future readers can
17
+ * decide how to handle older versions.
18
+ */
19
+ // ─── Schema version ─────────────────────────────────────────────────────────
20
+ /** Bump this when the schema breaks backward compatibility. */
21
+ export const CURRENT_SCHEMA_VERSION = "1";
22
+ // ─── Validation ─────────────────────────────────────────────────────────────
23
+ /**
24
+ * Error thrown when a measurement file fails schema validation.
25
+ * Includes the field path and reason for fast debugging.
26
+ */
27
+ export class MeasurementSchemaError extends Error {
28
+ path;
29
+ reason;
30
+ constructor(path, reason) {
31
+ super(`measurement schema: ${path}: ${reason}`);
32
+ this.path = path;
33
+ this.reason = reason;
34
+ this.name = "MeasurementSchemaError";
35
+ }
36
+ }
37
+ function assertString(v, path, opts) {
38
+ if (typeof v !== "string") {
39
+ throw new MeasurementSchemaError(path, `expected string, got ${typeof v}`);
40
+ }
41
+ if (opts?.nonEmpty && v.length === 0) {
42
+ throw new MeasurementSchemaError(path, "expected non-empty string");
43
+ }
44
+ return v;
45
+ }
46
+ function assertNumber(v, path, opts) {
47
+ if (typeof v !== "number" || Number.isNaN(v) || !Number.isFinite(v)) {
48
+ throw new MeasurementSchemaError(path, `expected finite number, got ${JSON.stringify(v)}`);
49
+ }
50
+ if (opts?.integer && !Number.isInteger(v)) {
51
+ throw new MeasurementSchemaError(path, `expected integer, got ${v}`);
52
+ }
53
+ if (opts?.min !== undefined && v < opts.min) {
54
+ throw new MeasurementSchemaError(path, `expected >= ${opts.min}, got ${v}`);
55
+ }
56
+ if (opts?.max !== undefined && v > opts.max) {
57
+ throw new MeasurementSchemaError(path, `expected <= ${opts.max}, got ${v}`);
58
+ }
59
+ return v;
60
+ }
61
+ function assertObject(v, path) {
62
+ if (v === null || typeof v !== "object" || Array.isArray(v)) {
63
+ throw new MeasurementSchemaError(path, `expected object, got ${Array.isArray(v) ? "array" : typeof v}`);
64
+ }
65
+ return v;
66
+ }
67
+ function parseMetrics(raw, path) {
68
+ const obj = assertObject(raw, path);
69
+ return {
70
+ recall: assertNumber(obj.recall, `${path}.recall`, { min: 0, max: 1 }),
71
+ precision: assertNumber(obj.precision, `${path}.precision`, { min: 0, max: 1 }),
72
+ f1: assertNumber(obj.f1, `${path}.f1`, { min: 0, max: 1 }),
73
+ fp_rate: assertNumber(obj.fp_rate, `${path}.fp_rate`, { min: 0, max: 1 }),
74
+ };
75
+ }
76
+ function parseConfusion(raw, path) {
77
+ const obj = assertObject(raw, path);
78
+ return {
79
+ tp: assertNumber(obj.tp, `${path}.tp`, { min: 0, integer: true }),
80
+ fp: assertNumber(obj.fp, `${path}.fp`, { min: 0, integer: true }),
81
+ tn: assertNumber(obj.tn, `${path}.tn`, { min: 0, integer: true }),
82
+ fn: assertNumber(obj.fn, `${path}.fn`, { min: 0, integer: true }),
83
+ };
84
+ }
85
+ function parseLatency(raw, path) {
86
+ const obj = assertObject(raw, path);
87
+ return {
88
+ p50: assertNumber(obj.p50, `${path}.p50`, { min: 0 }),
89
+ p95: assertNumber(obj.p95, `${path}.p95`, { min: 0 }),
90
+ p99: assertNumber(obj.p99, `${path}.p99`, { min: 0 }),
91
+ mean: assertNumber(obj.mean, `${path}.mean`, { min: 0 }),
92
+ max: assertNumber(obj.max, `${path}.max`, { min: 0 }),
93
+ };
94
+ }
95
+ const ISO8601_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
96
+ const SOURCE_RE = /^[a-z0-9][a-z0-9-]*$/;
97
+ /**
98
+ * Parse a `Measurement` from an arbitrary value. Throws `MeasurementSchemaError`
99
+ * on any deviation from the schema. Returns a strongly-typed `Measurement`.
100
+ *
101
+ * Unknown extra top-level keys are allowed but ignored (forward-compat); they
102
+ * are NOT preserved in the returned object.
103
+ */
104
+ export function parseMeasurement(raw) {
105
+ const obj = assertObject(raw, "$");
106
+ const schema_version = assertString(obj.schema_version, "$.schema_version", { nonEmpty: true });
107
+ if (schema_version !== CURRENT_SCHEMA_VERSION) {
108
+ throw new MeasurementSchemaError("$.schema_version", `expected "${CURRENT_SCHEMA_VERSION}", got "${schema_version}" — older formats need migration`);
109
+ }
110
+ const source = assertString(obj.source, "$.source", { nonEmpty: true });
111
+ if (!SOURCE_RE.test(source)) {
112
+ throw new MeasurementSchemaError("$.source", `must match /^[a-z0-9][a-z0-9-]*$/; got "${source}"`);
113
+ }
114
+ const measured_at = assertString(obj.measured_at, "$.measured_at", { nonEmpty: true });
115
+ if (!ISO8601_RE.test(measured_at)) {
116
+ throw new MeasurementSchemaError("$.measured_at", `must be ISO 8601 UTC (e.g. "2026-05-23T03:57:58Z"); got "${measured_at}"`);
117
+ }
118
+ const m = {
119
+ schema_version: CURRENT_SCHEMA_VERSION,
120
+ source,
121
+ source_version: assertString(obj.source_version, "$.source_version", { nonEmpty: true }),
122
+ atr_version: assertString(obj.atr_version, "$.atr_version", { nonEmpty: true }),
123
+ atr_commit: assertString(obj.atr_commit, "$.atr_commit", { nonEmpty: true }),
124
+ rules_loaded: assertNumber(obj.rules_loaded, "$.rules_loaded", { min: 1, integer: true }),
125
+ measured_at,
126
+ samples: assertNumber(obj.samples, "$.samples", { min: 0, integer: true }),
127
+ metrics: parseMetrics(obj.metrics, "$.metrics"),
128
+ };
129
+ if (obj.source_url !== undefined)
130
+ m.source_url = assertString(obj.source_url, "$.source_url", { nonEmpty: true });
131
+ if (obj.source_commit !== undefined)
132
+ m.source_commit = assertString(obj.source_commit, "$.source_commit", { nonEmpty: true });
133
+ if (obj.confusion !== undefined)
134
+ m.confusion = parseConfusion(obj.confusion, "$.confusion");
135
+ if (obj.latency_ms !== undefined)
136
+ m.latency_ms = parseLatency(obj.latency_ms, "$.latency_ms");
137
+ if (obj.breakdown !== undefined)
138
+ m.breakdown = assertObject(obj.breakdown, "$.breakdown");
139
+ if (obj.notes !== undefined)
140
+ m.notes = assertString(obj.notes, "$.notes");
141
+ return m;
142
+ }
143
+ /** Parse a `LatestPointer`. Throws on schema violation. */
144
+ export function parseLatestPointer(raw) {
145
+ const obj = assertObject(raw, "$");
146
+ return {
147
+ source: assertString(obj.source, "$.source", { nonEmpty: true }),
148
+ file: assertString(obj.file, "$.file", { nonEmpty: true }),
149
+ measured_at: assertString(obj.measured_at, "$.measured_at", { nonEmpty: true }),
150
+ metrics: parseMetrics(obj.metrics, "$.metrics"),
151
+ source_version: assertString(obj.source_version, "$.source_version", { nonEmpty: true }),
152
+ atr_version: assertString(obj.atr_version, "$.atr_version", { nonEmpty: true }),
153
+ samples: assertNumber(obj.samples, "$.samples", { min: 0, integer: true }),
154
+ };
155
+ }
156
+ /**
157
+ * Compute the canonical filename for a measurement.
158
+ *
159
+ * Format: `<YYYY-MM-DD>_<source>-<source_version>_atr-<atr_version>.json`
160
+ *
161
+ * `source_version` and `atr_version` are slugified (lowercase, non-alphanumeric
162
+ * → `-`, leading/trailing `-` removed, collapsed runs of `-`).
163
+ */
164
+ export function measurementFilename(m) {
165
+ const date = m.measured_at.slice(0, 10);
166
+ const sourceSlug = slugify(m.source);
167
+ const sourceVerSlug = slugify(m.source_version);
168
+ const atrVerSlug = slugify(m.atr_version);
169
+ return `${date}_${sourceSlug}-${sourceVerSlug}_atr-${atrVerSlug}.json`;
170
+ }
171
+ function slugify(s) {
172
+ return s
173
+ .toLowerCase()
174
+ .replace(/[^a-z0-9]+/g, "-")
175
+ .replace(/^-+|-+$/g, "")
176
+ .replace(/-{2,}/g, "-");
177
+ }
178
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/measurement/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * src/measurement/write.ts
3
+ *
4
+ * Atomic writer + helpers for ATR benchmark measurement files.
5
+ *
6
+ * Used by every eval script. Guarantees:
7
+ * - Schema-valid output (calls `parseMeasurement` before write).
8
+ * - Atomic write (tmp file + fsync + rename — no half-written files).
9
+ * - `latest.json` is updated only after the underlying file is durable on disk.
10
+ * - Caller-supplied measurements receive `schema_version`, `measured_at`,
11
+ * `atr_version`, `atr_commit`, and `rules_loaded` autofills if omitted.
12
+ */
13
+ import { type Measurement } from "./schema.js";
14
+ /** Read the ATR version from `package.json`. */
15
+ export declare function readATRVersion(): string;
16
+ /** Read the current short git SHA. Falls back to `"unknown"` outside a git repo. */
17
+ export declare function readATRCommit(): string;
18
+ /** Best-effort: count `ATR-*.yaml` rule files under `rules/`. */
19
+ export declare function countRules(rulesDir?: string): number;
20
+ /**
21
+ * Caller-friendly subset of `Measurement`. The fields the eval script must
22
+ * provide; the rest (`schema_version`, `atr_version`, `atr_commit`,
23
+ * `rules_loaded`, `measured_at`) are autofilled by `writeMeasurement()`.
24
+ *
25
+ * Callers MAY override any autofill by setting the field explicitly.
26
+ */
27
+ export type MeasurementInput = Omit<Measurement, "schema_version" | "measured_at" | "atr_version" | "atr_commit" | "rules_loaded"> & {
28
+ measured_at?: string;
29
+ atr_version?: string;
30
+ atr_commit?: string;
31
+ rules_loaded?: number;
32
+ };
33
+ /**
34
+ * Write a measurement file and update the source's `latest.json`.
35
+ *
36
+ * Returns the absolute path of the measurement file that was written.
37
+ *
38
+ * Behavior:
39
+ * 1. Autofill `schema_version`, `measured_at` (now, ISO UTC), `atr_version`,
40
+ * `atr_commit`, `rules_loaded` if not provided.
41
+ * 2. Validate via `parseMeasurement()`. Throws on any schema violation.
42
+ * 3. Compute the canonical filename.
43
+ * 4. Refuse to overwrite an existing file unless `opts.force` is true. (We
44
+ * maintain the append-only invariant by default.)
45
+ * 5. Atomic write the measurement file.
46
+ * 6. Update `latest.json` only if the new measurement is strictly newer.
47
+ *
48
+ * @param input Measurement minus the autofilled fields.
49
+ * @param opts Options. `force: true` allows overwriting an existing file
50
+ * with the same filename (use with caution; breaks append-only).
51
+ */
52
+ export declare function writeMeasurement(input: MeasurementInput, opts?: {
53
+ force?: boolean;
54
+ rulesDir?: string;
55
+ }): {
56
+ measurementPath: string;
57
+ latestPath: string;
58
+ measurement: Measurement;
59
+ };
60
+ /** Resolve the absolute path of a source's `latest.json`. */
61
+ export declare function latestPath(source: string): string;
62
+ /** Absolute path of the measurements root directory. */
63
+ export declare function measurementsDir(): string;
64
+ //# sourceMappingURL=write.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.d.ts","sourceRoot":"","sources":["../../src/measurement/write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,EAGL,KAAK,WAAW,EAIjB,MAAM,aAAa,CAAC;AASrB,gDAAgD;AAChD,wBAAgB,cAAc,IAAI,MAAM,CAMvC;AAED,oFAAoF;AACpF,wBAAgB,aAAa,IAAI,MAAM,CAStC;AAED,iEAAiE;AACjE,wBAAgB,UAAU,CAAC,QAAQ,SAA8B,GAAG,MAAM,CAKzE;AAoDD;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,IAAI,CACjC,WAAW,EACX,gBAAgB,GAAG,aAAa,GAAG,aAAa,GAAG,YAAY,GAAG,cAAc,CACjF,GAAG;IACF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,gBAAgB,EACvB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAChD;IAAE,eAAe,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,WAAW,CAAA;CAAE,CAgD3E;AAED,6DAA6D;AAC7D,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,wDAAwD;AACxD,wBAAgB,eAAe,IAAI,MAAM,CAExC"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * src/measurement/write.ts
3
+ *
4
+ * Atomic writer + helpers for ATR benchmark measurement files.
5
+ *
6
+ * Used by every eval script. Guarantees:
7
+ * - Schema-valid output (calls `parseMeasurement` before write).
8
+ * - Atomic write (tmp file + fsync + rename — no half-written files).
9
+ * - `latest.json` is updated only after the underlying file is durable on disk.
10
+ * - Caller-supplied measurements receive `schema_version`, `measured_at`,
11
+ * `atr_version`, `atr_commit`, and `rules_loaded` autofills if omitted.
12
+ */
13
+ import { closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, renameSync, writeSync } from "node:fs";
14
+ import { dirname, join, resolve } from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+ import { execFileSync } from "node:child_process";
17
+ import { CURRENT_SCHEMA_VERSION, measurementFilename, parseLatestPointer, parseMeasurement, } from "./schema.js";
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = dirname(__filename);
20
+ const REPO_ROOT = resolve(__dirname, "..", "..");
21
+ const MEASUREMENTS_DIR = resolve(REPO_ROOT, "data", "measurements");
22
+ // ─── Environment auto-detection ─────────────────────────────────────────────
23
+ /** Read the ATR version from `package.json`. */
24
+ export function readATRVersion() {
25
+ const pkg = JSON.parse(readFileSync(resolve(REPO_ROOT, "package.json"), "utf-8"));
26
+ if (typeof pkg.version !== "string" || pkg.version.length === 0) {
27
+ throw new Error("package.json: missing or non-string `version`");
28
+ }
29
+ return pkg.version;
30
+ }
31
+ /** Read the current short git SHA. Falls back to `"unknown"` outside a git repo. */
32
+ export function readATRCommit() {
33
+ try {
34
+ return execFileSync("git", ["rev-parse", "--short", "HEAD"], {
35
+ cwd: REPO_ROOT,
36
+ stdio: ["ignore", "pipe", "ignore"],
37
+ }).toString().trim();
38
+ }
39
+ catch {
40
+ return "unknown";
41
+ }
42
+ }
43
+ /** Best-effort: count `ATR-*.yaml` rule files under `rules/`. */
44
+ export function countRules(rulesDir = resolve(REPO_ROOT, "rules")) {
45
+ const out = execFileSync("find", [rulesDir, "-name", "ATR-*.yaml"], {
46
+ stdio: ["ignore", "pipe", "ignore"],
47
+ }).toString();
48
+ return out.split("\n").filter((l) => l.trim().length > 0).length;
49
+ }
50
+ // ─── Atomic write primitives ────────────────────────────────────────────────
51
+ /**
52
+ * Write `content` to `targetPath` atomically.
53
+ *
54
+ * Implementation: write to `<targetPath>.<pid>.<nonce>.tmp`, `fsync()` the file
55
+ * descriptor, then `rename()` over the target. POSIX `rename(2)` is atomic; if
56
+ * the process dies between write and rename, the target is untouched and the
57
+ * tmp file can be cleaned up safely.
58
+ *
59
+ * If `fs.renameSync` fails (cross-device EXDEV, permissions), throws.
60
+ */
61
+ function writeFileAtomic(targetPath, content) {
62
+ mkdirSync(dirname(targetPath), { recursive: true });
63
+ const nonce = Math.random().toString(36).slice(2, 10);
64
+ const tmpPath = `${targetPath}.${process.pid}.${nonce}.tmp`;
65
+ const fd = openSync(tmpPath, "w");
66
+ try {
67
+ writeSync(fd, content);
68
+ fsyncSync(fd);
69
+ }
70
+ finally {
71
+ closeSync(fd);
72
+ }
73
+ renameSync(tmpPath, targetPath);
74
+ }
75
+ // ─── Latest pointer ─────────────────────────────────────────────────────────
76
+ function deriveLatestPointer(m, filename) {
77
+ return {
78
+ source: m.source,
79
+ file: filename,
80
+ measured_at: m.measured_at,
81
+ metrics: m.metrics,
82
+ source_version: m.source_version,
83
+ atr_version: m.atr_version,
84
+ samples: m.samples,
85
+ };
86
+ }
87
+ /**
88
+ * Decide whether `candidate` is more recent than the existing `latest.json`.
89
+ * Pure function (no I/O); given two pointer-shaped objects, returns boolean.
90
+ */
91
+ function isStrictlyNewer(candidate, existing) {
92
+ return candidate.measured_at > existing.measured_at;
93
+ }
94
+ /**
95
+ * Write a measurement file and update the source's `latest.json`.
96
+ *
97
+ * Returns the absolute path of the measurement file that was written.
98
+ *
99
+ * Behavior:
100
+ * 1. Autofill `schema_version`, `measured_at` (now, ISO UTC), `atr_version`,
101
+ * `atr_commit`, `rules_loaded` if not provided.
102
+ * 2. Validate via `parseMeasurement()`. Throws on any schema violation.
103
+ * 3. Compute the canonical filename.
104
+ * 4. Refuse to overwrite an existing file unless `opts.force` is true. (We
105
+ * maintain the append-only invariant by default.)
106
+ * 5. Atomic write the measurement file.
107
+ * 6. Update `latest.json` only if the new measurement is strictly newer.
108
+ *
109
+ * @param input Measurement minus the autofilled fields.
110
+ * @param opts Options. `force: true` allows overwriting an existing file
111
+ * with the same filename (use with caution; breaks append-only).
112
+ */
113
+ export function writeMeasurement(input, opts = {}) {
114
+ const measured_at = input.measured_at ?? new Date().toISOString();
115
+ const atr_version = input.atr_version ?? readATRVersion();
116
+ const atr_commit = input.atr_commit ?? readATRCommit();
117
+ const rules_loaded = input.rules_loaded ?? countRules(opts.rulesDir);
118
+ const measurement = parseMeasurement({
119
+ schema_version: CURRENT_SCHEMA_VERSION,
120
+ ...input,
121
+ measured_at,
122
+ atr_version,
123
+ atr_commit,
124
+ rules_loaded,
125
+ });
126
+ const sourceDir = join(MEASUREMENTS_DIR, measurement.source);
127
+ const filename = measurementFilename(measurement);
128
+ const measurementPath = join(sourceDir, filename);
129
+ const latestPath = join(sourceDir, "latest.json");
130
+ if (existsSync(measurementPath) && !opts.force) {
131
+ throw new Error(`measurement already exists: ${measurementPath}\n` +
132
+ `Re-running the same (source, source_version, atr_version) on the same day produces the same filename.\n` +
133
+ `Pass { force: true } to overwrite, or change one of the inputs.`);
134
+ }
135
+ const measurementJson = JSON.stringify(measurement, null, 2) + "\n";
136
+ writeFileAtomic(measurementPath, measurementJson);
137
+ // Update latest.json only if strictly newer than the existing pointer.
138
+ const newPointer = deriveLatestPointer(measurement, filename);
139
+ let shouldWriteLatest = true;
140
+ if (existsSync(latestPath)) {
141
+ try {
142
+ const existing = parseLatestPointer(JSON.parse(readFileSync(latestPath, "utf-8")));
143
+ shouldWriteLatest = isStrictlyNewer(newPointer, existing);
144
+ }
145
+ catch {
146
+ // Corrupt or missing latest.json — overwrite it.
147
+ shouldWriteLatest = true;
148
+ }
149
+ }
150
+ if (shouldWriteLatest) {
151
+ writeFileAtomic(latestPath, JSON.stringify(newPointer, null, 2) + "\n");
152
+ }
153
+ return { measurementPath, latestPath, measurement };
154
+ }
155
+ /** Resolve the absolute path of a source's `latest.json`. */
156
+ export function latestPath(source) {
157
+ return join(MEASUREMENTS_DIR, source, "latest.json");
158
+ }
159
+ /** Absolute path of the measurements root directory. */
160
+ export function measurementsDir() {
161
+ return MEASUREMENTS_DIR;
162
+ }
163
+ //# sourceMappingURL=write.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"write.js","sourceRoot":"","sources":["../../src/measurement/write.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Semantic-method rule evaluator (LLM-as-judge).
3
+ *
4
+ * Implements atr-method-v1.1.md §6.4 evaluation semantics. The judge
5
+ * itself is passed in via dependency injection — the reference engine
6
+ * does NOT bundle a vendor SDK. Operators wire in OpenAI, Anthropic,
7
+ * or a local model at deployment time.
8
+ *
9
+ * Capability: atr/method/semantic (per atr-method-v1.1.md §9).
10
+ *
11
+ * Fallback behavior per spec §6.4:
12
+ * - If judge is unavailable AND rule.semantic.fallback_method === 'pattern',
13
+ * the engine falls back to pattern evaluation on the same input.
14
+ * - If fallback_method === 'none' or absent, the engine returns a
15
+ * graceful_error (matched: false, error: <reason>).
16
+ */
17
+ import type { ATRRule, ATRSemanticJudge } from "./types.js";
18
+ export interface SemanticEvaluationResult {
19
+ matched: boolean;
20
+ /** Judge response confidence (0.0-1.0) if judge was called */
21
+ confidence?: number;
22
+ /** Judge response category if returned */
23
+ category?: string;
24
+ /** Why the rule did not evaluate via judge (cache hit / fallback / error) */
25
+ reason?: string;
26
+ /** Set when judge unavailable AND fallback_method !== 'pattern' */
27
+ error?: string;
28
+ }
29
+ interface JudgeCache {
30
+ get(key: string): {
31
+ confidence: number;
32
+ category: string;
33
+ } | undefined;
34
+ set(key: string, value: {
35
+ confidence: number;
36
+ category: string;
37
+ expires_at: number;
38
+ }): void;
39
+ }
40
+ export interface SemanticEvaluatorOptions {
41
+ /** Caller-supplied judge function. If absent, fallback path is taken. */
42
+ judge?: ATRSemanticJudge;
43
+ /** Caller-supplied cache. Defaults to an in-process Map cache. */
44
+ cache?: JudgeCache;
45
+ }
46
+ export declare function evaluateSemanticRule(rule: ATRRule, input: string, options?: SemanticEvaluatorOptions): Promise<SemanticEvaluationResult>;
47
+ export {};
48
+ //# sourceMappingURL=semantic-evaluator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-evaluator.d.ts","sourceRoot":"","sources":["../src/semantic-evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EACV,OAAO,EAEP,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,UAAU;IAClB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,SAAS,CAAC;IACvE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAC7F;AA+BD,MAAM,WAAW,wBAAwB;IACvC,yEAAyE;IACzE,KAAK,CAAC,EAAE,gBAAgB,CAAC;IACzB,kEAAkE;IAClE,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB;AAED,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAAC,wBAAwB,CAAC,CAmEnC"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Semantic-method rule evaluator (LLM-as-judge).
3
+ *
4
+ * Implements atr-method-v1.1.md §6.4 evaluation semantics. The judge
5
+ * itself is passed in via dependency injection — the reference engine
6
+ * does NOT bundle a vendor SDK. Operators wire in OpenAI, Anthropic,
7
+ * or a local model at deployment time.
8
+ *
9
+ * Capability: atr/method/semantic (per atr-method-v1.1.md §9).
10
+ *
11
+ * Fallback behavior per spec §6.4:
12
+ * - If judge is unavailable AND rule.semantic.fallback_method === 'pattern',
13
+ * the engine falls back to pattern evaluation on the same input.
14
+ * - If fallback_method === 'none' or absent, the engine returns a
15
+ * graceful_error (matched: false, error: <reason>).
16
+ */
17
+ class InMemoryJudgeCache {
18
+ store = new Map();
19
+ get(key) {
20
+ const entry = this.store.get(key);
21
+ if (!entry)
22
+ return undefined;
23
+ if (entry.expires_at < Date.now()) {
24
+ this.store.delete(key);
25
+ return undefined;
26
+ }
27
+ return { confidence: entry.confidence, category: entry.category };
28
+ }
29
+ set(key, value) {
30
+ this.store.set(key, value);
31
+ }
32
+ }
33
+ const DEFAULT_CACHE = new InMemoryJudgeCache();
34
+ /** Render a prompt template by substituting `{{input}}` with the actual input. */
35
+ function renderPrompt(template, input) {
36
+ return template.replace(/\{\{\s*input\s*\}\}/g, input);
37
+ }
38
+ /** Compute a stable cache key from (judge prompt hash, input). */
39
+ function cacheKey(promptHash, input) {
40
+ // Caller should hash; we just concatenate. For reference, prefer pre-hashed input.
41
+ return `${promptHash ?? "no-hash"}:${input}`;
42
+ }
43
+ export async function evaluateSemanticRule(rule, input, options = {}) {
44
+ const sem = rule.detection.semantic;
45
+ if (!sem) {
46
+ return { matched: false, error: "rule has method=semantic but no detection.semantic block" };
47
+ }
48
+ // Cache check
49
+ const cache = options.cache ?? DEFAULT_CACHE;
50
+ const key = cacheKey(sem.judge_prompt_hash, input);
51
+ const cached = cache.get(key);
52
+ if (cached) {
53
+ return {
54
+ matched: cached.confidence >= sem.threshold,
55
+ confidence: cached.confidence,
56
+ category: cached.category,
57
+ reason: "cache_hit",
58
+ };
59
+ }
60
+ // Judge unavailable → fallback path
61
+ if (!options.judge) {
62
+ if (sem.fallback_method === "pattern") {
63
+ return {
64
+ matched: false,
65
+ reason: "judge_unavailable_fallback_pattern",
66
+ };
67
+ }
68
+ return {
69
+ matched: false,
70
+ error: "judge_unavailable_no_fallback",
71
+ };
72
+ }
73
+ // Call judge
74
+ const prompt = renderPrompt(sem.prompt_template, input);
75
+ let response;
76
+ try {
77
+ response = await options.judge({
78
+ prompt,
79
+ input,
80
+ judge_model_class: sem.judge_model_class,
81
+ });
82
+ }
83
+ catch (err) {
84
+ if (sem.fallback_method === "pattern") {
85
+ return {
86
+ matched: false,
87
+ reason: `judge_error_fallback_pattern: ${err.message}`,
88
+ };
89
+ }
90
+ return { matched: false, error: `judge_error: ${err.message}` };
91
+ }
92
+ // Cache the response if cache_ttl set
93
+ if (sem.cache_ttl && sem.cache_ttl > 0) {
94
+ cache.set(key, {
95
+ confidence: response.confidence,
96
+ category: response.category,
97
+ expires_at: Date.now() + sem.cache_ttl * 1000,
98
+ });
99
+ }
100
+ return {
101
+ matched: response.confidence >= sem.threshold,
102
+ confidence: response.confidence,
103
+ category: response.category,
104
+ reason: "judge_evaluated",
105
+ };
106
+ }
107
+ //# sourceMappingURL=semantic-evaluator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"semantic-evaluator.js","sourceRoot":"","sources":["../src/semantic-evaluator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Trace-method rule evaluator.
3
+ *
4
+ * Implements the formal semantics in atr-method-v1.1.md §8 for the three
5
+ * trace primitives: forbid, require, invariant. Operates on a Trace (DAG
6
+ * of spans, OpenInference / OTel GenAI format).
7
+ *
8
+ * Capability: atr/method/trace (per atr-method-v1.1.md §9).
9
+ *
10
+ * Pure function; no I/O. Engine wires this in via evaluateRule dispatch
11
+ * when detection.method === 'trace'.
12
+ */
13
+ import type { ATRRule, ATRTrace } from "./types.js";
14
+ export interface TraceEvaluationResult {
15
+ matched: boolean;
16
+ violations: string[];
17
+ matchedPrimitives: ("forbid" | "require" | "invariant")[];
18
+ }
19
+ /** Top-level trace rule evaluator. Returns matched=true if ANY declared
20
+ * primitive evaluates to violation. */
21
+ export declare function evaluateTraceRule(rule: ATRRule, trace: ATRTrace): TraceEvaluationResult;
22
+ //# sourceMappingURL=trace-evaluator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-evaluator.d.ts","sourceRoot":"","sources":["../src/trace-evaluator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EACV,OAAO,EACP,QAAQ,EAMT,MAAM,YAAY,CAAC;AAqMpB,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,iBAAiB,EAAE,CAAC,QAAQ,GAAG,SAAS,GAAG,WAAW,CAAC,EAAE,CAAC;CAC3D;AAED;wCACwC;AACxC,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,GAAG,qBAAqB,CAmCvF"}