@panguard-ai/atr 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +299 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +720 -0
- package/dist/cli.js.map +1 -0
- package/dist/coverage-analyzer.d.ts +43 -0
- package/dist/coverage-analyzer.d.ts.map +1 -0
- package/dist/coverage-analyzer.js +329 -0
- package/dist/coverage-analyzer.js.map +1 -0
- package/dist/engine.d.ts +127 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +636 -0
- package/dist/engine.js.map +1 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +21 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +124 -0
- package/dist/loader.js.map +1 -0
- package/dist/mcp-server.d.ts +13 -0
- package/dist/mcp-server.d.ts.map +1 -0
- package/dist/mcp-server.js +220 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/mcp-tools/coverage-gaps.d.ts +13 -0
- package/dist/mcp-tools/coverage-gaps.d.ts.map +1 -0
- package/dist/mcp-tools/coverage-gaps.js +55 -0
- package/dist/mcp-tools/coverage-gaps.js.map +1 -0
- package/dist/mcp-tools/list-rules.d.ts +17 -0
- package/dist/mcp-tools/list-rules.d.ts.map +1 -0
- package/dist/mcp-tools/list-rules.js +45 -0
- package/dist/mcp-tools/list-rules.js.map +1 -0
- package/dist/mcp-tools/scan.d.ts +18 -0
- package/dist/mcp-tools/scan.d.ts.map +1 -0
- package/dist/mcp-tools/scan.js +75 -0
- package/dist/mcp-tools/scan.js.map +1 -0
- package/dist/mcp-tools/submit-proposal.d.ts +12 -0
- package/dist/mcp-tools/submit-proposal.d.ts.map +1 -0
- package/dist/mcp-tools/submit-proposal.js +95 -0
- package/dist/mcp-tools/submit-proposal.js.map +1 -0
- package/dist/mcp-tools/threat-summary.d.ts +12 -0
- package/dist/mcp-tools/threat-summary.d.ts.map +1 -0
- package/dist/mcp-tools/threat-summary.js +74 -0
- package/dist/mcp-tools/threat-summary.js.map +1 -0
- package/dist/mcp-tools/validate.d.ts +15 -0
- package/dist/mcp-tools/validate.d.ts.map +1 -0
- package/dist/mcp-tools/validate.js +45 -0
- package/dist/mcp-tools/validate.js.map +1 -0
- package/dist/modules/index.d.ts +144 -0
- package/dist/modules/index.d.ts.map +1 -0
- package/dist/modules/index.js +82 -0
- package/dist/modules/index.js.map +1 -0
- package/dist/modules/semantic.d.ts +105 -0
- package/dist/modules/semantic.d.ts.map +1 -0
- package/dist/modules/semantic.js +283 -0
- package/dist/modules/semantic.js.map +1 -0
- package/dist/modules/session.d.ts +70 -0
- package/dist/modules/session.d.ts.map +1 -0
- package/dist/modules/session.js +128 -0
- package/dist/modules/session.js.map +1 -0
- package/dist/rule-scaffolder.d.ts +39 -0
- package/dist/rule-scaffolder.d.ts.map +1 -0
- package/dist/rule-scaffolder.js +173 -0
- package/dist/rule-scaffolder.js.map +1 -0
- package/dist/session-tracker.d.ts +56 -0
- package/dist/session-tracker.d.ts.map +1 -0
- package/dist/session-tracker.js +175 -0
- package/dist/session-tracker.js.map +1 -0
- package/dist/skill-fingerprint.d.ts +96 -0
- package/dist/skill-fingerprint.d.ts.map +1 -0
- package/dist/skill-fingerprint.js +337 -0
- package/dist/skill-fingerprint.js.map +1 -0
- package/dist/types.d.ts +129 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +75 -0
- package/rules/agent-manipulation/ATR-2026-030-cross-agent-attack.yaml +175 -0
- package/rules/agent-manipulation/ATR-2026-032-goal-hijacking.yaml +135 -0
- package/rules/agent-manipulation/ATR-2026-074-cross-agent-privilege-escalation.yaml +115 -0
- package/rules/agent-manipulation/ATR-2026-076-inter-agent-message-spoofing.yaml +165 -0
- package/rules/agent-manipulation/ATR-2026-077-human-trust-exploitation.yaml +144 -0
- package/rules/context-exfiltration/ATR-2026-020-system-prompt-leak.yaml +175 -0
- package/rules/context-exfiltration/ATR-2026-021-api-key-exposure.yaml +176 -0
- package/rules/context-exfiltration/ATR-2026-075-agent-memory-manipulation.yaml +115 -0
- package/rules/data-poisoning/ATR-2026-070-data-poisoning.yaml +160 -0
- package/rules/excessive-autonomy/ATR-2026-050-runaway-agent-loop.yaml +134 -0
- package/rules/excessive-autonomy/ATR-2026-051-resource-exhaustion.yaml +137 -0
- package/rules/excessive-autonomy/ATR-2026-052-cascading-failure.yaml +153 -0
- package/rules/model-security/ATR-2026-072-model-behavior-extraction.yaml +115 -0
- package/rules/model-security/ATR-2026-073-malicious-finetuning-data.yaml +108 -0
- package/rules/privilege-escalation/ATR-2026-040-privilege-escalation.yaml +175 -0
- package/rules/privilege-escalation/ATR-2026-041-scope-creep.yaml +124 -0
- package/rules/prompt-injection/ATR-2026-001-direct-prompt-injection.yaml +265 -0
- package/rules/prompt-injection/ATR-2026-002-indirect-prompt-injection.yaml +214 -0
- package/rules/prompt-injection/ATR-2026-003-jailbreak-attempt.yaml +250 -0
- package/rules/prompt-injection/ATR-2026-004-system-prompt-override.yaml +204 -0
- package/rules/prompt-injection/ATR-2026-005-multi-turn-injection.yaml +181 -0
- package/rules/prompt-injection/ATR-PRED-2026-001.yaml +61 -0
- package/rules/prompt-injection/ATR-PRED-2026-002.yaml +58 -0
- package/rules/prompt-injection/ATR-PRED-2026-003.yaml +61 -0
- package/rules/prompt-injection/ATR-PRED-2026-005.yaml +55 -0
- package/rules/prompt-injection/ATR-PRED-2026-006.yaml +51 -0
- package/rules/prompt-injection/ATR-PRED-2026-007.yaml +57 -0
- package/rules/prompt-injection/ATR-PRED-2026-008.yaml +57 -0
- package/rules/prompt-injection/ATR-PRED-2026-009.yaml +51 -0
- package/rules/prompt-injection/ATR-PRED-2026-010.yaml +57 -0
- package/rules/prompt-injection/ATR-PRED-2026-011.yaml +53 -0
- package/rules/prompt-injection/ATR-PRED-2026-012.yaml +57 -0
- package/rules/prompt-injection/ATR-PRED-2026-023.yaml +56 -0
- package/rules/prompt-injection/ATR-PRED-2026-025.yaml +68 -0
- package/rules/prompt-injection/ATR-PRED-2026-026.yaml +66 -0
- package/rules/prompt-injection/ATR-PRED-2026-027.yaml +62 -0
- package/rules/skill-compromise/ATR-2026-060-skill-impersonation.yaml +153 -0
- package/rules/skill-compromise/ATR-2026-061-description-behavior-mismatch.yaml +98 -0
- package/rules/skill-compromise/ATR-2026-062-hidden-capability.yaml +96 -0
- package/rules/skill-compromise/ATR-2026-063-skill-chain-attack.yaml +96 -0
- package/rules/skill-compromise/ATR-2026-064-over-permissioned-skill.yaml +115 -0
- package/rules/skill-compromise/ATR-2026-065-skill-update-attack.yaml +93 -0
- package/rules/skill-compromise/ATR-2026-066-parameter-injection.yaml +106 -0
- package/rules/tool-poisoning/ATR-2026-010-mcp-malicious-response.yaml +237 -0
- package/rules/tool-poisoning/ATR-2026-011-tool-output-injection.yaml +185 -0
- package/rules/tool-poisoning/ATR-2026-012-unauthorized-tool-call.yaml +190 -0
- package/rules/tool-poisoning/ATR-2026-013-tool-ssrf.yaml +208 -0
- package/rules/tool-poisoning/ATR-PRED-2026-004.yaml +54 -0
- package/rules/tool-poisoning/ATR-PRED-2026-024.yaml +68 -0
- package/spec/atr-schema.yaml +375 -0
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Behavioral Fingerprint
|
|
3
|
+
* Skill 行為指紋追蹤器
|
|
4
|
+
*
|
|
5
|
+
* Tracks what each skill "normally does" across invocations, then detects
|
|
6
|
+
* behavioral drift when a previously-trusted skill starts acting differently.
|
|
7
|
+
*
|
|
8
|
+
* Solves the "installed then turns malicious" scenario:
|
|
9
|
+
* - First N invocations: build fingerprint (what APIs, what patterns, what scope)
|
|
10
|
+
* - After fingerprint stabilizes: flag any deviation as anomaly
|
|
11
|
+
*
|
|
12
|
+
* 追蹤每個 skill 的「正常行為」,然後在行為偏移時偵測:
|
|
13
|
+
* - 前 N 次呼叫:建立指紋
|
|
14
|
+
* - 指紋穩定後:任何偏離都標記為異常
|
|
15
|
+
*
|
|
16
|
+
* @module agent-threat-rules/skill-fingerprint
|
|
17
|
+
*/
|
|
18
|
+
import { createHash } from 'node:crypto';
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Pattern detectors (regex-based, no LLM needed)
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
const FS_WRITE_PATTERN = /(?:write(?:File)?|appendFile|fs\.write|truncate|mkdir|rmdir|unlink|rm\s+-)/i;
|
|
23
|
+
const FS_READ_PATTERN = /(?:read(?:File)?|readdir|stat|access|exists|glob|find\s)/i;
|
|
24
|
+
const FS_DELETE_PATTERN = /(?:unlink|rm\s+-rf|delete(?:File)?|removeDir|rmdir)/i;
|
|
25
|
+
const NETWORK_PATTERN = /(?:https?:\/\/|fetch|curl|wget|axios|http\.request|net\.connect|socket)[\s('"]*([a-zA-Z0-9.-]+(?:\.[a-zA-Z]{2,}))/i;
|
|
26
|
+
const ENV_PATTERN = /(?:process\.env|os\.environ|getenv|System\.getenv)\[?['"(]?([A-Z_][A-Z0-9_]*)/i;
|
|
27
|
+
const ENV_INLINE_PATTERN = /\$\{?([A-Z_][A-Z0-9_]{2,})\}?/g;
|
|
28
|
+
const EXEC_PATTERN = /(?:child_process|spawn|exec(?:File)?|system\(|popen|subprocess|shell_exec|os\.system)\s*\(\s*['"(]?([^\s'")\]]{1,80})/i;
|
|
29
|
+
const EXFIL_PATTERN = /(?:base64|btoa|encode|compress|deflate|gzip).*(?:http|fetch|curl|send|post|upload)/i;
|
|
30
|
+
const REDIRECT_PATTERN = /(?:redirect|forward|proxy|tunnel)\s+(?:to\s+)?(?:https?:\/\/)/i;
|
|
31
|
+
/** Classify a text content into behavioral capabilities */
|
|
32
|
+
function extractCapabilities(text) {
|
|
33
|
+
const result = {
|
|
34
|
+
filesystemOps: [],
|
|
35
|
+
networkTargets: [],
|
|
36
|
+
envAccesses: [],
|
|
37
|
+
processExecs: [],
|
|
38
|
+
outputPatterns: [],
|
|
39
|
+
};
|
|
40
|
+
if (!text || text.length === 0)
|
|
41
|
+
return result;
|
|
42
|
+
// Limit analysis to first 10KB to prevent ReDoS
|
|
43
|
+
const safeText = text.slice(0, 10_240);
|
|
44
|
+
// Filesystem
|
|
45
|
+
if (FS_WRITE_PATTERN.test(safeText))
|
|
46
|
+
result.filesystemOps.push('write');
|
|
47
|
+
if (FS_READ_PATTERN.test(safeText))
|
|
48
|
+
result.filesystemOps.push('read');
|
|
49
|
+
if (FS_DELETE_PATTERN.test(safeText))
|
|
50
|
+
result.filesystemOps.push('delete');
|
|
51
|
+
// Network targets
|
|
52
|
+
const netMatch = safeText.match(NETWORK_PATTERN);
|
|
53
|
+
if (netMatch?.[1])
|
|
54
|
+
result.networkTargets.push(netMatch[1]);
|
|
55
|
+
// Environment variable accesses
|
|
56
|
+
const envMatch = safeText.match(ENV_PATTERN);
|
|
57
|
+
if (envMatch?.[1])
|
|
58
|
+
result.envAccesses.push(envMatch[1]);
|
|
59
|
+
// Also check inline env vars like $HOME, ${API_KEY}
|
|
60
|
+
for (const m of safeText.matchAll(ENV_INLINE_PATTERN)) {
|
|
61
|
+
if (m[1] && !result.envAccesses.includes(m[1])) {
|
|
62
|
+
result.envAccesses.push(m[1]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Process executions
|
|
66
|
+
const execMatch = safeText.match(EXEC_PATTERN);
|
|
67
|
+
if (execMatch?.[1])
|
|
68
|
+
result.processExecs.push(execMatch[1]);
|
|
69
|
+
// Output patterns
|
|
70
|
+
if (EXFIL_PATTERN.test(safeText))
|
|
71
|
+
result.outputPatterns.push('exfiltration');
|
|
72
|
+
if (REDIRECT_PATTERN.test(safeText))
|
|
73
|
+
result.outputPatterns.push('redirect');
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// Fingerprint Store
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
/** Default invocations needed before fingerprint is considered stable */
|
|
80
|
+
const DEFAULT_STABILITY_THRESHOLD = 10;
|
|
81
|
+
/** Consecutive invocations with no new capabilities to mark stable */
|
|
82
|
+
const DEFAULT_STABLE_STREAK = 5;
|
|
83
|
+
/** Maximum number of skills to track */
|
|
84
|
+
const MAX_SKILLS = 5_000;
|
|
85
|
+
export class SkillFingerprintStore {
|
|
86
|
+
fingerprints = new Map();
|
|
87
|
+
stabilityThreshold;
|
|
88
|
+
stableStreak;
|
|
89
|
+
constructor(config) {
|
|
90
|
+
this.stabilityThreshold = config?.stabilityThreshold ?? DEFAULT_STABILITY_THRESHOLD;
|
|
91
|
+
this.stableStreak = config?.stableStreak ?? DEFAULT_STABLE_STREAK;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Record a skill invocation and detect behavioral anomalies.
|
|
95
|
+
* Returns anomalies if the fingerprint was stable and new capabilities appeared.
|
|
96
|
+
*
|
|
97
|
+
* 記錄 skill 呼叫並偵測行為異常。
|
|
98
|
+
* 如果指紋已穩定且出現新能力,回傳異常列表。
|
|
99
|
+
*/
|
|
100
|
+
recordInvocation(skillName, event) {
|
|
101
|
+
const now = Date.now();
|
|
102
|
+
const fp = this.getOrCreate(skillName, now);
|
|
103
|
+
fp.invocationCount++;
|
|
104
|
+
fp.lastSeen = now;
|
|
105
|
+
// Extract capabilities from event content + fields
|
|
106
|
+
const content = [
|
|
107
|
+
event.content ?? '',
|
|
108
|
+
event.fields?.['tool_args'] ?? '',
|
|
109
|
+
event.fields?.['tool_response'] ?? '',
|
|
110
|
+
].join('\n');
|
|
111
|
+
const caps = extractCapabilities(content);
|
|
112
|
+
// Check for anomalies (only if fingerprint is stable)
|
|
113
|
+
const anomalies = [];
|
|
114
|
+
const isStable = fp.stableHash !== null;
|
|
115
|
+
if (isStable) {
|
|
116
|
+
// Detect NEW capabilities not in the stable fingerprint
|
|
117
|
+
for (const op of caps.filesystemOps) {
|
|
118
|
+
if (!fp.filesystemOps.has(op)) {
|
|
119
|
+
anomalies.push({
|
|
120
|
+
skillName,
|
|
121
|
+
anomalyType: 'new_filesystem_op',
|
|
122
|
+
description: `Skill "${skillName}" performing new filesystem operation: ${op} (not in baseline)`,
|
|
123
|
+
severity: op === 'delete' ? 'critical' : op === 'write' ? 'high' : 'medium',
|
|
124
|
+
newValue: op,
|
|
125
|
+
timestamp: now,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
for (const target of caps.networkTargets) {
|
|
130
|
+
if (!fp.networkTargets.has(target)) {
|
|
131
|
+
anomalies.push({
|
|
132
|
+
skillName,
|
|
133
|
+
anomalyType: 'new_network_target',
|
|
134
|
+
description: `Skill "${skillName}" contacting new network target: ${target}`,
|
|
135
|
+
severity: 'high',
|
|
136
|
+
newValue: target,
|
|
137
|
+
timestamp: now,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
for (const env of caps.envAccesses) {
|
|
142
|
+
if (!fp.envAccesses.has(env)) {
|
|
143
|
+
const isSensitive = /(?:KEY|SECRET|TOKEN|PASSWORD|CREDENTIAL)/i.test(env);
|
|
144
|
+
anomalies.push({
|
|
145
|
+
skillName,
|
|
146
|
+
anomalyType: 'new_env_access',
|
|
147
|
+
description: `Skill "${skillName}" accessing new env var: ${env}`,
|
|
148
|
+
severity: isSensitive ? 'critical' : 'medium',
|
|
149
|
+
newValue: env,
|
|
150
|
+
timestamp: now,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
for (const proc of caps.processExecs) {
|
|
155
|
+
if (!fp.processExecs.has(proc)) {
|
|
156
|
+
anomalies.push({
|
|
157
|
+
skillName,
|
|
158
|
+
anomalyType: 'new_process_exec',
|
|
159
|
+
description: `Skill "${skillName}" executing new process: ${proc}`,
|
|
160
|
+
severity: 'critical',
|
|
161
|
+
newValue: proc,
|
|
162
|
+
timestamp: now,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
for (const pat of caps.outputPatterns) {
|
|
167
|
+
if (!fp.outputPatterns.has(pat)) {
|
|
168
|
+
anomalies.push({
|
|
169
|
+
skillName,
|
|
170
|
+
anomalyType: 'new_output_pattern',
|
|
171
|
+
description: `Skill "${skillName}" exhibiting new pattern: ${pat}`,
|
|
172
|
+
severity: pat === 'exfiltration' ? 'critical' : 'high',
|
|
173
|
+
newValue: pat,
|
|
174
|
+
timestamp: now,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
// Update fingerprint with observed capabilities
|
|
180
|
+
let newCapsSeen = false;
|
|
181
|
+
for (const op of caps.filesystemOps) {
|
|
182
|
+
if (!fp.filesystemOps.has(op)) {
|
|
183
|
+
fp.filesystemOps.add(op);
|
|
184
|
+
newCapsSeen = true;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
for (const t of caps.networkTargets) {
|
|
188
|
+
if (!fp.networkTargets.has(t)) {
|
|
189
|
+
fp.networkTargets.add(t);
|
|
190
|
+
newCapsSeen = true;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
for (const e of caps.envAccesses) {
|
|
194
|
+
if (!fp.envAccesses.has(e)) {
|
|
195
|
+
fp.envAccesses.add(e);
|
|
196
|
+
newCapsSeen = true;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
for (const p of caps.processExecs) {
|
|
200
|
+
if (!fp.processExecs.has(p)) {
|
|
201
|
+
fp.processExecs.add(p);
|
|
202
|
+
newCapsSeen = true;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
for (const o of caps.outputPatterns) {
|
|
206
|
+
if (!fp.outputPatterns.has(o)) {
|
|
207
|
+
fp.outputPatterns.add(o);
|
|
208
|
+
newCapsSeen = true;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
// Track stability
|
|
212
|
+
if (!isStable) {
|
|
213
|
+
if (newCapsSeen) {
|
|
214
|
+
fp.stableStreak = 0;
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
fp.stableStreak++;
|
|
218
|
+
}
|
|
219
|
+
// Mark stable when threshold met
|
|
220
|
+
if (fp.invocationCount >= this.stabilityThreshold &&
|
|
221
|
+
fp.stableStreak >= this.stableStreak) {
|
|
222
|
+
fp.stableHash = this.computeCapabilityHash(fp);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return anomalies;
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Get an immutable fingerprint snapshot for a skill.
|
|
229
|
+
* 取得某 skill 的不可變指紋快照。
|
|
230
|
+
*/
|
|
231
|
+
getFingerprint(skillName) {
|
|
232
|
+
const fp = this.fingerprints.get(skillName);
|
|
233
|
+
if (!fp)
|
|
234
|
+
return undefined;
|
|
235
|
+
return {
|
|
236
|
+
skillName: fp.skillName,
|
|
237
|
+
invocationCount: fp.invocationCount,
|
|
238
|
+
firstSeen: fp.firstSeen,
|
|
239
|
+
lastSeen: fp.lastSeen,
|
|
240
|
+
isStable: fp.stableHash !== null,
|
|
241
|
+
capabilities: {
|
|
242
|
+
filesystemOps: new Set(fp.filesystemOps),
|
|
243
|
+
networkTargets: new Set(fp.networkTargets),
|
|
244
|
+
envAccesses: new Set(fp.envAccesses),
|
|
245
|
+
processExecs: new Set(fp.processExecs),
|
|
246
|
+
outputPatterns: new Set(fp.outputPatterns),
|
|
247
|
+
},
|
|
248
|
+
capabilityHash: fp.stableHash ?? this.computeCapabilityHash(fp),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
/** Get all tracked skill names */
|
|
252
|
+
getTrackedSkills() {
|
|
253
|
+
return [...this.fingerprints.keys()];
|
|
254
|
+
}
|
|
255
|
+
/** Get count of stable fingerprints */
|
|
256
|
+
getStableCount() {
|
|
257
|
+
let count = 0;
|
|
258
|
+
for (const fp of this.fingerprints.values()) {
|
|
259
|
+
if (fp.stableHash !== null)
|
|
260
|
+
count++;
|
|
261
|
+
}
|
|
262
|
+
return count;
|
|
263
|
+
}
|
|
264
|
+
/** Get total tracked skills */
|
|
265
|
+
getTrackedCount() {
|
|
266
|
+
return this.fingerprints.size;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Reset a skill's fingerprint (e.g., after a legitimate update).
|
|
270
|
+
* 重置 skill 指紋(例如合法更新後)。
|
|
271
|
+
*/
|
|
272
|
+
resetFingerprint(skillName) {
|
|
273
|
+
this.fingerprints.delete(skillName);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Evict fingerprints not seen since cutoffMs ago.
|
|
277
|
+
* 清除超過 cutoffMs 未活動的指紋。
|
|
278
|
+
*/
|
|
279
|
+
cleanup(cutoffMs) {
|
|
280
|
+
const cutoff = Date.now() - cutoffMs;
|
|
281
|
+
let evicted = 0;
|
|
282
|
+
for (const [name, fp] of this.fingerprints) {
|
|
283
|
+
if (fp.lastSeen < cutoff) {
|
|
284
|
+
this.fingerprints.delete(name);
|
|
285
|
+
evicted++;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return evicted;
|
|
289
|
+
}
|
|
290
|
+
// -----------------------------------------------------------------------
|
|
291
|
+
// Private
|
|
292
|
+
// -----------------------------------------------------------------------
|
|
293
|
+
getOrCreate(skillName, now) {
|
|
294
|
+
const existing = this.fingerprints.get(skillName);
|
|
295
|
+
if (existing)
|
|
296
|
+
return existing;
|
|
297
|
+
// Evict oldest if at capacity
|
|
298
|
+
if (this.fingerprints.size >= MAX_SKILLS) {
|
|
299
|
+
let oldestName;
|
|
300
|
+
let oldestTime = Infinity;
|
|
301
|
+
for (const [name, fp] of this.fingerprints) {
|
|
302
|
+
if (fp.lastSeen < oldestTime) {
|
|
303
|
+
oldestTime = fp.lastSeen;
|
|
304
|
+
oldestName = name;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
if (oldestName)
|
|
308
|
+
this.fingerprints.delete(oldestName);
|
|
309
|
+
}
|
|
310
|
+
const fp = {
|
|
311
|
+
skillName,
|
|
312
|
+
invocationCount: 0,
|
|
313
|
+
firstSeen: now,
|
|
314
|
+
lastSeen: now,
|
|
315
|
+
filesystemOps: new Set(),
|
|
316
|
+
networkTargets: new Set(),
|
|
317
|
+
envAccesses: new Set(),
|
|
318
|
+
processExecs: new Set(),
|
|
319
|
+
outputPatterns: new Set(),
|
|
320
|
+
stableHash: null,
|
|
321
|
+
stableStreak: 0,
|
|
322
|
+
};
|
|
323
|
+
this.fingerprints.set(skillName, fp);
|
|
324
|
+
return fp;
|
|
325
|
+
}
|
|
326
|
+
computeCapabilityHash(fp) {
|
|
327
|
+
const parts = [
|
|
328
|
+
[...fp.filesystemOps].sort().join(','),
|
|
329
|
+
[...fp.networkTargets].sort().join(','),
|
|
330
|
+
[...fp.envAccesses].sort().join(','),
|
|
331
|
+
[...fp.processExecs].sort().join(','),
|
|
332
|
+
[...fp.outputPatterns].sort().join(','),
|
|
333
|
+
];
|
|
334
|
+
return createHash('sha256').update(parts.join('|')).digest('hex').slice(0, 16);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
//# sourceMappingURL=skill-fingerprint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-fingerprint.js","sourceRoot":"","sources":["../src/skill-fingerprint.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ATR (Agent Threat Rules) type definitions
|
|
3
|
+
* @module agent-threat-rules/types
|
|
4
|
+
*/
|
|
5
|
+
export type ATRStatus = 'draft' | 'experimental' | 'stable' | 'deprecated';
|
|
6
|
+
export type ATRSeverity = 'critical' | 'high' | 'medium' | 'low' | 'informational';
|
|
7
|
+
export type ATRCategory = 'prompt-injection' | 'tool-poisoning' | 'context-exfiltration' | 'agent-manipulation' | 'privilege-escalation' | 'excessive-autonomy' | 'data-poisoning' | 'model-abuse' | 'skill-compromise';
|
|
8
|
+
export type ATRConfidence = 'high' | 'medium' | 'low';
|
|
9
|
+
export type ATRSourceType = 'llm_io' | 'tool_call' | 'mcp_exchange' | 'agent_behavior' | 'multi_agent_comm' | 'context_window' | 'memory_access' | 'skill_lifecycle' | 'skill_permission' | 'skill_chain';
|
|
10
|
+
export type ATRMatchType = 'contains' | 'regex' | 'exact' | 'starts_with';
|
|
11
|
+
export type ATROperator = 'gt' | 'lt' | 'eq' | 'gte' | 'lte' | 'deviation_from_baseline';
|
|
12
|
+
export type ATRAction = 'block_input' | 'block_output' | 'block_tool' | 'quarantine_session' | 'reset_context' | 'alert' | 'snapshot' | 'escalate' | 'reduce_permissions' | 'kill_agent';
|
|
13
|
+
export interface ATRReferences {
|
|
14
|
+
owasp_llm?: string[];
|
|
15
|
+
mitre_atlas?: string[];
|
|
16
|
+
mitre_attack?: string[];
|
|
17
|
+
cve?: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface ATRTags {
|
|
20
|
+
category: ATRCategory;
|
|
21
|
+
subcategory?: string;
|
|
22
|
+
confidence?: ATRConfidence;
|
|
23
|
+
}
|
|
24
|
+
export interface ATRAgentSource {
|
|
25
|
+
type: ATRSourceType;
|
|
26
|
+
framework?: string[];
|
|
27
|
+
provider?: string[];
|
|
28
|
+
}
|
|
29
|
+
export interface ATRPatternCondition {
|
|
30
|
+
field: string;
|
|
31
|
+
patterns: string[];
|
|
32
|
+
match_type: ATRMatchType;
|
|
33
|
+
case_sensitive?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface ATRBehavioralCondition {
|
|
36
|
+
metric: string;
|
|
37
|
+
operator: ATROperator;
|
|
38
|
+
threshold: number;
|
|
39
|
+
window?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface ATRSequenceStep {
|
|
42
|
+
field?: string;
|
|
43
|
+
patterns?: string[];
|
|
44
|
+
match_type?: ATRMatchType;
|
|
45
|
+
metric?: string;
|
|
46
|
+
operator?: ATROperator;
|
|
47
|
+
threshold?: number;
|
|
48
|
+
}
|
|
49
|
+
export interface ATRSequenceCondition {
|
|
50
|
+
ordered: boolean;
|
|
51
|
+
within: string;
|
|
52
|
+
steps: ATRSequenceStep[];
|
|
53
|
+
}
|
|
54
|
+
/** Array-format condition: {field, operator, value} used by most rules */
|
|
55
|
+
export interface ATRArrayCondition {
|
|
56
|
+
field: string;
|
|
57
|
+
operator: string;
|
|
58
|
+
value: string;
|
|
59
|
+
description?: string;
|
|
60
|
+
}
|
|
61
|
+
/** Named-map conditions or array conditions */
|
|
62
|
+
export type ATRConditions = ATRArrayCondition[] | Record<string, ATRPatternCondition | ATRBehavioralCondition | ATRSequenceCondition>;
|
|
63
|
+
export interface ATRDetection {
|
|
64
|
+
conditions: ATRConditions;
|
|
65
|
+
/** "any" = OR across all conditions, "all" = AND. For named format: boolean expression string. */
|
|
66
|
+
condition: string;
|
|
67
|
+
false_positives?: string[];
|
|
68
|
+
}
|
|
69
|
+
export interface ATRResponse {
|
|
70
|
+
actions: ATRAction[];
|
|
71
|
+
auto_response_threshold?: string;
|
|
72
|
+
message_template?: string;
|
|
73
|
+
}
|
|
74
|
+
export interface ATRTestCase {
|
|
75
|
+
input?: string;
|
|
76
|
+
tool_response?: string;
|
|
77
|
+
agent_output?: string;
|
|
78
|
+
tool_name?: string;
|
|
79
|
+
tool_args?: string;
|
|
80
|
+
expected: 'trigger' | 'no_trigger' | 'triggered' | 'not_triggered';
|
|
81
|
+
}
|
|
82
|
+
export interface ATRTestCases {
|
|
83
|
+
true_positives: ATRTestCase[];
|
|
84
|
+
true_negatives: ATRTestCase[];
|
|
85
|
+
}
|
|
86
|
+
export interface ATRRule {
|
|
87
|
+
title: string;
|
|
88
|
+
id: string;
|
|
89
|
+
status: ATRStatus;
|
|
90
|
+
description: string;
|
|
91
|
+
author: string;
|
|
92
|
+
date: string;
|
|
93
|
+
modified?: string;
|
|
94
|
+
severity: ATRSeverity;
|
|
95
|
+
references?: ATRReferences;
|
|
96
|
+
tags: ATRTags;
|
|
97
|
+
agent_source: ATRAgentSource;
|
|
98
|
+
detection: ATRDetection;
|
|
99
|
+
response: ATRResponse;
|
|
100
|
+
test_cases?: ATRTestCases;
|
|
101
|
+
}
|
|
102
|
+
/** Event types that the ATR engine can evaluate */
|
|
103
|
+
export type AgentEventType = 'llm_input' | 'llm_output' | 'tool_call' | 'tool_response' | 'agent_behavior' | 'multi_agent_message';
|
|
104
|
+
/** An agent event to evaluate against ATR rules */
|
|
105
|
+
export interface AgentEvent {
|
|
106
|
+
type: AgentEventType;
|
|
107
|
+
timestamp: string;
|
|
108
|
+
/** The text content to analyze */
|
|
109
|
+
content: string;
|
|
110
|
+
/** Specific field values for pattern matching */
|
|
111
|
+
fields?: Record<string, string>;
|
|
112
|
+
/** Behavioral metrics for threshold-based detection */
|
|
113
|
+
metrics?: Record<string, number>;
|
|
114
|
+
/** Session identifier for correlation */
|
|
115
|
+
sessionId?: string;
|
|
116
|
+
/** Source agent identifier */
|
|
117
|
+
agentId?: string;
|
|
118
|
+
/** Additional metadata */
|
|
119
|
+
metadata?: Record<string, unknown>;
|
|
120
|
+
}
|
|
121
|
+
/** Result when an ATR rule matches an event */
|
|
122
|
+
export interface ATRMatch {
|
|
123
|
+
rule: ATRRule;
|
|
124
|
+
matchedConditions: string[];
|
|
125
|
+
matchedPatterns: string[];
|
|
126
|
+
confidence: number;
|
|
127
|
+
timestamp: string;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,cAAc,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE3E,MAAM,MAAM,WAAW,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,eAAe,CAAC;AAEnF,MAAM,MAAM,WAAW,GACnB,kBAAkB,GAClB,gBAAgB,GAChB,sBAAsB,GACtB,oBAAoB,GACpB,sBAAsB,GACtB,oBAAoB,GACpB,gBAAgB,GAChB,aAAa,GACb,kBAAkB,CAAC;AAEvB,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;AAEtD,MAAM,MAAM,aAAa,GACrB,QAAQ,GACR,WAAW,GACX,cAAc,GACd,gBAAgB,GAChB,kBAAkB,GAClB,gBAAgB,GAChB,eAAe,GACf,iBAAiB,GACjB,kBAAkB,GAClB,aAAa,CAAC;AAElB,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,aAAa,CAAC;AAE1E,MAAM,MAAM,WAAW,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,yBAAyB,CAAC;AAEzF,MAAM,MAAM,SAAS,GACjB,aAAa,GACb,cAAc,GACd,YAAY,GACZ,oBAAoB,GACpB,eAAe,GACf,OAAO,GACP,UAAU,GACV,UAAU,GACV,oBAAoB,GACpB,YAAY,CAAC;AAEjB,MAAM,WAAW,aAAa;IAC5B,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,OAAO;IACtB,QAAQ,EAAE,WAAW,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,aAAa,CAAC;CAC5B;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,aAAa,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,UAAU,EAAE,YAAY,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,WAAW,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,+CAA+C;AAC/C,MAAM,MAAM,aAAa,GACrB,iBAAiB,EAAE,GACnB,MAAM,CAAC,MAAM,EAAE,mBAAmB,GAAG,sBAAsB,GAAG,oBAAoB,CAAC,CAAC;AAExF,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,aAAa,CAAC;IAC1B,kGAAkG;IAClG,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,uBAAuB,CAAC,EAAE,MAAM,CAAC;IACjC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,eAAe,CAAC;CACpE;AAED,MAAM,WAAW,YAAY;IAC3B,cAAc,EAAE,WAAW,EAAE,CAAC;IAC9B,cAAc,EAAE,WAAW,EAAE,CAAC;CAC/B;AAED,MAAM,WAAW,OAAO;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,SAAS,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,YAAY,EAAE,cAAc,CAAC;IAC7B,SAAS,EAAE,YAAY,CAAC;IACxB,QAAQ,EAAE,WAAW,CAAC;IACtB,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B;AAED,mDAAmD;AACnD,MAAM,MAAM,cAAc,GACtB,WAAW,GACX,YAAY,GACZ,WAAW,GACX,eAAe,GACf,gBAAgB,GAChB,qBAAqB,CAAC;AAE1B,mDAAmD;AACnD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,cAAc,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,kCAAkC;IAClC,OAAO,EAAE,MAAM,CAAC;IAChB,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,yCAAyC;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,+CAA+C;AAC/C,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,OAAO,CAAC;IACd,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@panguard-ai/atr",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Open detection rules for AI agent threats. Like Sigma, but for prompt injection, tool poisoning, and agent manipulation.",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"atr": "./dist/cli.js",
|
|
10
|
+
"agent-threat-rules": "./dist/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"types": "./dist/index.d.ts"
|
|
16
|
+
},
|
|
17
|
+
"./mcp": {
|
|
18
|
+
"import": "./dist/mcp-server.js",
|
|
19
|
+
"types": "./dist/mcp-server.d.ts"
|
|
20
|
+
},
|
|
21
|
+
"./rules": "./rules",
|
|
22
|
+
"./spec": "./spec/atr-schema.yaml"
|
|
23
|
+
},
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18.0.0"
|
|
26
|
+
},
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/Agent-Threat-Rule/agent-threat-rules.git"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/Agent-Threat-Rule/agent-threat-rules",
|
|
33
|
+
"bugs": {
|
|
34
|
+
"url": "https://github.com/Agent-Threat-Rule/agent-threat-rules/issues"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"ai-security",
|
|
38
|
+
"agent-security",
|
|
39
|
+
"prompt-injection",
|
|
40
|
+
"sigma-rules",
|
|
41
|
+
"threat-detection",
|
|
42
|
+
"mcp-security",
|
|
43
|
+
"llm-security",
|
|
44
|
+
"atr"
|
|
45
|
+
],
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"files": [
|
|
50
|
+
"dist",
|
|
51
|
+
"spec",
|
|
52
|
+
"rules",
|
|
53
|
+
"package.json",
|
|
54
|
+
"README.md"
|
|
55
|
+
],
|
|
56
|
+
"dependencies": {
|
|
57
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
58
|
+
"js-yaml": "^4.1.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@types/js-yaml": "^4.0.9",
|
|
62
|
+
"@types/node": "^22.14.0",
|
|
63
|
+
"tsx": "^4.7.0",
|
|
64
|
+
"typescript": "~5.7.3",
|
|
65
|
+
"vitest": "^3.0.0"
|
|
66
|
+
},
|
|
67
|
+
"scripts": {
|
|
68
|
+
"build": "tsc --build",
|
|
69
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
70
|
+
"typecheck": "tsc --noEmit",
|
|
71
|
+
"test": "vitest run",
|
|
72
|
+
"dev": "tsc --build --watch",
|
|
73
|
+
"validate": "tsx tests/validate-rules.ts"
|
|
74
|
+
}
|
|
75
|
+
}
|