@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.
- package/dist/action-executor.d.ts +44 -0
- package/dist/action-executor.d.ts.map +1 -0
- package/dist/action-executor.js +130 -0
- package/dist/action-executor.js.map +1 -0
- package/dist/adapters/default-adapter.d.ts +24 -0
- package/dist/adapters/default-adapter.d.ts.map +1 -0
- package/dist/adapters/default-adapter.js +51 -0
- package/dist/adapters/default-adapter.js.map +1 -0
- package/dist/adapters/stdio-adapter.d.ts +30 -0
- package/dist/adapters/stdio-adapter.d.ts.map +1 -0
- package/dist/adapters/stdio-adapter.js +128 -0
- package/dist/adapters/stdio-adapter.js.map +1 -0
- package/dist/badge.d.ts +42 -0
- package/dist/badge.d.ts.map +1 -0
- package/dist/badge.js +163 -0
- package/dist/badge.js.map +1 -0
- package/dist/capability-extractor.d.ts +35 -0
- package/dist/capability-extractor.d.ts.map +1 -0
- package/dist/capability-extractor.js +91 -0
- package/dist/capability-extractor.js.map +1 -0
- package/dist/cli/scan-handler.d.ts +21 -0
- package/dist/cli/scan-handler.d.ts.map +1 -0
- package/dist/cli/scan-handler.js +276 -0
- package/dist/cli/scan-handler.js.map +1 -0
- package/dist/cli/tc-pipeline.d.ts +18 -0
- package/dist/cli/tc-pipeline.d.ts.map +1 -0
- package/dist/cli/tc-pipeline.js +295 -0
- package/dist/cli/tc-pipeline.js.map +1 -0
- package/dist/cli.d.ts +12 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +894 -0
- package/dist/cli.js.map +1 -0
- package/dist/content-hash.d.ts +7 -0
- package/dist/content-hash.d.ts.map +1 -0
- package/dist/content-hash.js +10 -0
- package/dist/content-hash.js.map +1 -0
- package/dist/converters/elastic.d.ts +36 -0
- package/dist/converters/elastic.d.ts.map +1 -0
- package/dist/converters/elastic.js +125 -0
- package/dist/converters/elastic.js.map +1 -0
- package/dist/converters/generic-regex.d.ts +37 -0
- package/dist/converters/generic-regex.d.ts.map +1 -0
- package/dist/converters/generic-regex.js +59 -0
- package/dist/converters/generic-regex.js.map +1 -0
- package/dist/converters/index.d.ts +32 -0
- package/dist/converters/index.d.ts.map +1 -0
- package/dist/converters/index.js +38 -0
- package/dist/converters/index.js.map +1 -0
- package/dist/converters/sarif.d.ts +18 -0
- package/dist/converters/sarif.d.ts.map +1 -0
- package/dist/converters/sarif.js +142 -0
- package/dist/converters/sarif.js.map +1 -0
- package/dist/converters/splunk.d.ts +19 -0
- package/dist/converters/splunk.d.ts.map +1 -0
- package/dist/converters/splunk.js +148 -0
- package/dist/converters/splunk.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/embedding/build-corpus.d.ts +15 -0
- package/dist/embedding/build-corpus.d.ts.map +1 -0
- package/dist/embedding/build-corpus.js +105 -0
- package/dist/embedding/build-corpus.js.map +1 -0
- package/dist/embedding/model-loader.d.ts +41 -0
- package/dist/embedding/model-loader.d.ts.map +1 -0
- package/dist/embedding/model-loader.js +90 -0
- package/dist/embedding/model-loader.js.map +1 -0
- package/dist/embedding/vector-store.d.ts +41 -0
- package/dist/embedding/vector-store.d.ts.map +1 -0
- package/dist/embedding/vector-store.js +70 -0
- package/dist/embedding/vector-store.js.map +1 -0
- package/dist/engine.d.ts +222 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +1185 -0
- package/dist/engine.js.map +1 -0
- package/dist/eval/corpus.d.ts +42 -0
- package/dist/eval/corpus.d.ts.map +1 -0
- package/dist/eval/corpus.js +427 -0
- package/dist/eval/corpus.js.map +1 -0
- package/dist/eval/eval-harness.d.ts +44 -0
- package/dist/eval/eval-harness.d.ts.map +1 -0
- package/dist/eval/eval-harness.js +296 -0
- package/dist/eval/eval-harness.js.map +1 -0
- package/dist/eval/index.d.ts +13 -0
- package/dist/eval/index.d.ts.map +1 -0
- package/dist/eval/index.js +9 -0
- package/dist/eval/index.js.map +1 -0
- package/dist/eval/metrics.d.ts +74 -0
- package/dist/eval/metrics.d.ts.map +1 -0
- package/dist/eval/metrics.js +108 -0
- package/dist/eval/metrics.js.map +1 -0
- package/dist/eval/pint-corpus.d.ts +34 -0
- package/dist/eval/pint-corpus.d.ts.map +1 -0
- package/dist/eval/pint-corpus.js +113 -0
- package/dist/eval/pint-corpus.js.map +1 -0
- package/dist/eval/rule-corpus.d.ts +9 -0
- package/dist/eval/rule-corpus.d.ts.map +1 -0
- package/dist/eval/rule-corpus.js +4780 -0
- package/dist/eval/rule-corpus.js.map +1 -0
- package/dist/eval/rule-metrics.d.ts +34 -0
- package/dist/eval/rule-metrics.d.ts.map +1 -0
- package/dist/eval/rule-metrics.js +92 -0
- package/dist/eval/rule-metrics.js.map +1 -0
- package/dist/eval/run-eval.d.ts +7 -0
- package/dist/eval/run-eval.d.ts.map +1 -0
- package/dist/eval/run-eval.js +11 -0
- package/dist/eval/run-eval.js.map +1 -0
- package/dist/eval/run-pint-benchmark.d.ts +18 -0
- package/dist/eval/run-pint-benchmark.d.ts.map +1 -0
- package/dist/eval/run-pint-benchmark.js +159 -0
- package/dist/eval/run-pint-benchmark.js.map +1 -0
- package/dist/eval/skill-benchmark.d.ts +66 -0
- package/dist/eval/skill-benchmark.d.ts.map +1 -0
- package/dist/eval/skill-benchmark.js +194 -0
- package/dist/eval/skill-benchmark.js.map +1 -0
- package/dist/flywheel.d.ts +54 -0
- package/dist/flywheel.d.ts.map +1 -0
- package/dist/flywheel.js +121 -0
- package/dist/flywheel.js.map +1 -0
- package/dist/hook-handler.d.ts +61 -0
- package/dist/hook-handler.d.ts.map +1 -0
- package/dist/hook-handler.js +178 -0
- package/dist/hook-handler.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/{src/index.ts → dist/index.js} +1 -0
- package/dist/index.js.map +1 -0
- package/dist/layer-integration.d.ts +55 -0
- package/dist/layer-integration.d.ts.map +1 -0
- package/dist/layer-integration.js +187 -0
- package/dist/layer-integration.js.map +1 -0
- package/dist/loader.d.ts +18 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +129 -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 +246 -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-skill.d.ts +17 -0
- package/dist/mcp-tools/scan-skill.d.ts.map +1 -0
- package/dist/mcp-tools/scan-skill.js +65 -0
- package/dist/mcp-tools/scan-skill.js.map +1 -0
- package/dist/mcp-tools/scan.d.ts +24 -0
- package/dist/mcp-tools/scan.d.ts.map +1 -0
- package/dist/mcp-tools/scan.js +94 -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 +103 -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 +51 -0
- package/dist/mcp-tools/validate.js.map +1 -0
- package/dist/modules/embedding.d.ts +71 -0
- package/dist/modules/embedding.d.ts.map +1 -0
- package/dist/modules/embedding.js +141 -0
- package/dist/modules/embedding.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 +106 -0
- package/dist/modules/semantic.d.ts.map +1 -0
- package/dist/modules/semantic.js +359 -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/quality/adapters/atr.d.ts +65 -0
- package/dist/quality/adapters/atr.d.ts.map +1 -0
- package/dist/quality/adapters/atr.js +154 -0
- package/dist/quality/adapters/atr.js.map +1 -0
- package/dist/quality/adapters/index.d.ts +10 -0
- package/dist/quality/adapters/index.d.ts.map +1 -0
- package/dist/quality/adapters/index.js +10 -0
- package/dist/quality/adapters/index.js.map +1 -0
- package/dist/quality/compute-confidence.d.ts +45 -0
- package/dist/quality/compute-confidence.d.ts.map +1 -0
- package/dist/quality/compute-confidence.js +133 -0
- package/dist/quality/compute-confidence.js.map +1 -0
- package/dist/quality/index.d.ts +36 -0
- package/dist/quality/index.d.ts.map +1 -0
- package/dist/quality/index.js +39 -0
- package/dist/quality/index.js.map +1 -0
- package/dist/quality/quality-gate.d.ts +86 -0
- package/dist/quality/quality-gate.d.ts.map +1 -0
- package/dist/quality/quality-gate.js +187 -0
- package/dist/quality/quality-gate.js.map +1 -0
- package/dist/quality/types.d.ts +129 -0
- package/dist/quality/types.d.ts.map +1 -0
- package/dist/quality/types.js +10 -0
- package/dist/quality/types.js.map +1 -0
- package/dist/quality/validate-maturity.d.ts +51 -0
- package/dist/quality/validate-maturity.d.ts.map +1 -0
- package/dist/quality/validate-maturity.js +134 -0
- package/dist/quality/validate-maturity.js.map +1 -0
- package/dist/quality.d.ts +8 -0
- package/dist/quality.d.ts.map +1 -0
- package/dist/quality.js +8 -0
- package/dist/quality.js.map +1 -0
- package/dist/rule-scaffolder.d.ts +53 -0
- package/dist/rule-scaffolder.d.ts.map +1 -0
- package/dist/rule-scaffolder.js +301 -0
- package/dist/rule-scaffolder.js.map +1 -0
- package/dist/session-tracker.d.ts +58 -0
- package/dist/session-tracker.d.ts.map +1 -0
- package/dist/session-tracker.js +176 -0
- package/dist/session-tracker.js.map +1 -0
- package/dist/shadow-evaluator.d.ts +48 -0
- package/dist/shadow-evaluator.d.ts.map +1 -0
- package/dist/shadow-evaluator.js +129 -0
- package/dist/shadow-evaluator.js.map +1 -0
- package/dist/skill-fingerprint.d.ts +85 -0
- package/dist/skill-fingerprint.d.ts.map +1 -0
- package/dist/skill-fingerprint.js +284 -0
- package/dist/skill-fingerprint.js.map +1 -0
- package/dist/tc-reporter.d.ts +50 -0
- package/dist/tc-reporter.d.ts.map +1 -0
- package/dist/tc-reporter.js +164 -0
- package/dist/tc-reporter.js.map +1 -0
- package/dist/tier0-invariant.d.ts +49 -0
- package/dist/tier0-invariant.d.ts.map +1 -0
- package/dist/tier0-invariant.js +185 -0
- package/dist/tier0-invariant.js.map +1 -0
- package/dist/tier1-blacklist.d.ts +48 -0
- package/dist/tier1-blacklist.d.ts.map +1 -0
- package/dist/tier1-blacklist.js +92 -0
- package/dist/tier1-blacklist.js.map +1 -0
- package/dist/types.d.ts +232 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/dist/verdict.d.ts +26 -0
- package/dist/verdict.d.ts.map +1 -0
- package/dist/verdict.js +127 -0
- package/dist/verdict.js.map +1 -0
- package/package.json +16 -4
- package/.github/ISSUE_TEMPLATE/evasion-report.yml +0 -75
- package/.github/ISSUE_TEMPLATE/false-positive.yml +0 -31
- package/.github/ISSUE_TEMPLATE/mirofish-prediction.yml +0 -128
- package/.github/ISSUE_TEMPLATE/new-rule.yml +0 -37
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -23
- package/.github/workflows/rule-quality.yml +0 -203
- package/.github/workflows/validate.yml +0 -42
- package/CHANGELOG.md +0 -30
- package/CONTRIBUTING.md +0 -168
- package/CONTRIBUTORS.md +0 -28
- package/COVERAGE.md +0 -135
- package/LIMITATIONS.md +0 -154
- package/SECURITY.md +0 -48
- package/THREAT-MODEL.md +0 -243
- package/docs/contribution-paths.md +0 -202
- package/docs/mirofish-prediction-guide.md +0 -304
- package/docs/quick-start.md +0 -245
- package/docs/rule-writing-guide.md +0 -647
- package/docs/schema-spec.md +0 -594
- package/examples/how-to-write-a-rule.md +0 -251
- package/tsconfig.json +0 -17
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ATR Quality Standard — Maturity Promotion and Demotion
|
|
3
|
+
*
|
|
4
|
+
* Pure functions that decide whether a rule is eligible to promote to a
|
|
5
|
+
* higher maturity level, or should be automatically demoted due to
|
|
6
|
+
* quality regression.
|
|
7
|
+
*
|
|
8
|
+
* See docs/proposals/001-atr-quality-standard-rfc.md §1 for the gate
|
|
9
|
+
* definitions.
|
|
10
|
+
*
|
|
11
|
+
* @module agent-threat-rules/quality/validate-maturity
|
|
12
|
+
*/
|
|
13
|
+
import { computeConfidence } from "./compute-confidence.js";
|
|
14
|
+
import { validateRuleMeetsStandard } from "./quality-gate.js";
|
|
15
|
+
/** Minimum days a rule must spend at experimental before promotion to stable */
|
|
16
|
+
const MIN_EXPERIMENTAL_DAYS = 14;
|
|
17
|
+
/** Minimum wild samples for stable promotion */
|
|
18
|
+
const MIN_WILD_SAMPLES_FOR_STABLE = 1000;
|
|
19
|
+
/** Maximum wild FP rate for stable promotion (percent) */
|
|
20
|
+
const MAX_WILD_FP_FOR_STABLE = 0.5;
|
|
21
|
+
/** Minimum confidence score for stable promotion */
|
|
22
|
+
const MIN_CONFIDENCE_FOR_STABLE = 80;
|
|
23
|
+
/** Wild FP rate that triggers automatic demotion from stable */
|
|
24
|
+
const DEMOTION_FP_RATE_THRESHOLD = 2.0;
|
|
25
|
+
/** Number of unresolved FP reports in the demotion window that trigger demotion */
|
|
26
|
+
const DEMOTION_FP_REPORT_COUNT = 3;
|
|
27
|
+
/** Demotion window in days */
|
|
28
|
+
const DEMOTION_WINDOW_DAYS = 30;
|
|
29
|
+
/**
|
|
30
|
+
* Determine whether a rule is eligible to promote from its current maturity
|
|
31
|
+
* to the next level.
|
|
32
|
+
*
|
|
33
|
+
* @param rule - Rule metadata
|
|
34
|
+
* @param target - Target maturity level
|
|
35
|
+
* @param now - Current timestamp (ISO string) for age calculations
|
|
36
|
+
* @returns Promotion decision with blockers listed
|
|
37
|
+
*/
|
|
38
|
+
export function canPromote(rule, target, now = new Date().toISOString()) {
|
|
39
|
+
const blockers = [];
|
|
40
|
+
// Must pass the quality gate for the target level
|
|
41
|
+
const gate = validateRuleMeetsStandard(rule, target);
|
|
42
|
+
if (!gate.passed) {
|
|
43
|
+
blockers.push(...gate.issues);
|
|
44
|
+
}
|
|
45
|
+
// Stable has additional wild validation + time-in-experimental gates
|
|
46
|
+
if (target === "stable") {
|
|
47
|
+
if (rule.maturity !== "experimental") {
|
|
48
|
+
blockers.push(`rule must be at experimental to promote to stable (current: ${rule.maturity})`);
|
|
49
|
+
}
|
|
50
|
+
if (rule.wildSamples === undefined ||
|
|
51
|
+
rule.wildSamples < MIN_WILD_SAMPLES_FOR_STABLE) {
|
|
52
|
+
blockers.push(`wild_samples ${rule.wildSamples ?? 0} below threshold ${MIN_WILD_SAMPLES_FOR_STABLE}`);
|
|
53
|
+
}
|
|
54
|
+
if (rule.wildFpRate === undefined ||
|
|
55
|
+
rule.wildFpRate > MAX_WILD_FP_FOR_STABLE) {
|
|
56
|
+
blockers.push(`wild_fp_rate ${rule.wildFpRate ?? "unmeasured"}% above threshold ${MAX_WILD_FP_FOR_STABLE}%`);
|
|
57
|
+
}
|
|
58
|
+
if (rule.wildValidatedAt) {
|
|
59
|
+
const ageMs = new Date(now).getTime() - new Date(rule.wildValidatedAt).getTime();
|
|
60
|
+
const ageDays = ageMs / (1000 * 60 * 60 * 24);
|
|
61
|
+
if (ageDays < MIN_EXPERIMENTAL_DAYS) {
|
|
62
|
+
blockers.push(`only ${Math.floor(ageDays)} days since wild validation (need ${MIN_EXPERIMENTAL_DAYS}+)`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
blockers.push("no wild_validated_at timestamp");
|
|
67
|
+
}
|
|
68
|
+
// Confidence must meet stable threshold
|
|
69
|
+
const confidence = computeConfidence(rule);
|
|
70
|
+
if (confidence.total < MIN_CONFIDENCE_FOR_STABLE) {
|
|
71
|
+
blockers.push(`confidence ${confidence.total} below stable threshold ${MIN_CONFIDENCE_FOR_STABLE}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
eligible: blockers.length === 0,
|
|
76
|
+
to: target,
|
|
77
|
+
blockers,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Determine whether a stable rule should be automatically demoted to
|
|
82
|
+
* experimental due to quality regression.
|
|
83
|
+
*
|
|
84
|
+
* Triggers:
|
|
85
|
+
* - Wild FP rate exceeds DEMOTION_FP_RATE_THRESHOLD
|
|
86
|
+
* - DEMOTION_FP_REPORT_COUNT+ unresolved FP reports in the window
|
|
87
|
+
*
|
|
88
|
+
* @param rule - Rule metadata
|
|
89
|
+
* @param recentFpReports - FP reports from the demotion window
|
|
90
|
+
* @param now - Current timestamp (ISO string)
|
|
91
|
+
* @returns Demotion decision
|
|
92
|
+
*/
|
|
93
|
+
export function shouldDemote(rule, recentFpReports, now = new Date().toISOString()) {
|
|
94
|
+
const reasons = [];
|
|
95
|
+
// Only stable rules are subject to automatic demotion
|
|
96
|
+
if (rule.maturity !== "stable") {
|
|
97
|
+
return { shouldDemote: false, reasons: [] };
|
|
98
|
+
}
|
|
99
|
+
// Reason 1: wild FP rate exceeds threshold
|
|
100
|
+
if (rule.wildFpRate !== undefined &&
|
|
101
|
+
rule.wildFpRate > DEMOTION_FP_RATE_THRESHOLD) {
|
|
102
|
+
reasons.push(`wild_fp_rate ${rule.wildFpRate}% exceeds demotion threshold ${DEMOTION_FP_RATE_THRESHOLD}%`);
|
|
103
|
+
}
|
|
104
|
+
// Reason 2: unresolved FP reports in the demotion window
|
|
105
|
+
const windowStart = new Date(now).getTime() - DEMOTION_WINDOW_DAYS * 24 * 60 * 60 * 1000;
|
|
106
|
+
const unresolvedInWindow = recentFpReports.filter((r) => {
|
|
107
|
+
if (r.resolved)
|
|
108
|
+
return false;
|
|
109
|
+
return new Date(r.reportedAt).getTime() >= windowStart;
|
|
110
|
+
});
|
|
111
|
+
if (unresolvedInWindow.length >= DEMOTION_FP_REPORT_COUNT) {
|
|
112
|
+
reasons.push(`${unresolvedInWindow.length} unresolved FP reports in last ${DEMOTION_WINDOW_DAYS} days`);
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
shouldDemote: reasons.length > 0,
|
|
116
|
+
reasons,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Public accessor for the promotion/demotion thresholds.
|
|
121
|
+
* Useful for documentation and UI that displays the gate policy.
|
|
122
|
+
*/
|
|
123
|
+
export function getMaturityThresholds() {
|
|
124
|
+
return {
|
|
125
|
+
minExperimentalDays: MIN_EXPERIMENTAL_DAYS,
|
|
126
|
+
minWildSamplesForStable: MIN_WILD_SAMPLES_FOR_STABLE,
|
|
127
|
+
maxWildFpForStable: MAX_WILD_FP_FOR_STABLE,
|
|
128
|
+
minConfidenceForStable: MIN_CONFIDENCE_FOR_STABLE,
|
|
129
|
+
demotionFpRateThreshold: DEMOTION_FP_RATE_THRESHOLD,
|
|
130
|
+
demotionFpReportCount: DEMOTION_FP_REPORT_COUNT,
|
|
131
|
+
demotionWindowDays: DEMOTION_WINDOW_DAYS,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=validate-maturity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-maturity.js","sourceRoot":"","sources":["../../src/quality/validate-maturity.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @panguard-ai/atr/quality — re-export of ATR Quality Standard library.
|
|
3
|
+
*
|
|
4
|
+
* Thin wrapper around agent-threat-rules/quality. See RFC-001 in the ATR
|
|
5
|
+
* repo for the full specification.
|
|
6
|
+
*/
|
|
7
|
+
export * from 'agent-threat-rules/quality';
|
|
8
|
+
//# sourceMappingURL=quality.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality.d.ts","sourceRoot":"","sources":["../src/quality.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,4BAA4B,CAAC"}
|
package/dist/quality.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @panguard-ai/atr/quality — re-export of ATR Quality Standard library.
|
|
3
|
+
*
|
|
4
|
+
* Thin wrapper around agent-threat-rules/quality. See RFC-001 in the ATR
|
|
5
|
+
* repo for the full specification.
|
|
6
|
+
*/
|
|
7
|
+
export * from 'agent-threat-rules/quality';
|
|
8
|
+
//# sourceMappingURL=quality.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"quality.js","sourceRoot":"","sources":["../src/quality.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,cAAc,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ATR Rule Scaffolder - Generates ATR rule YAML scaffolds from structured input
|
|
3
|
+
* @module agent-threat-rules/rule-scaffolder
|
|
4
|
+
*/
|
|
5
|
+
import type { ATRCategory, ATRSeverity, ATRSourceType } from './types.js';
|
|
6
|
+
export interface ScaffoldInput {
|
|
7
|
+
title: string;
|
|
8
|
+
category: ATRCategory;
|
|
9
|
+
severity?: ATRSeverity;
|
|
10
|
+
attackDescription: string;
|
|
11
|
+
examplePayloads: string[];
|
|
12
|
+
agentSourceType?: ATRSourceType;
|
|
13
|
+
owaspRefs?: string[];
|
|
14
|
+
mitreRefs?: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface ScaffoldResult {
|
|
17
|
+
yaml: string;
|
|
18
|
+
id: string;
|
|
19
|
+
warnings: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface ScaffoldOptions {
|
|
22
|
+
author?: string;
|
|
23
|
+
schemaVersion?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Attack pattern templates by category — reusable regex building blocks
|
|
27
|
+
* that detect BEHAVIOR, not package names.
|
|
28
|
+
*/
|
|
29
|
+
export declare const ATTACK_PATTERN_INDICATORS: ReadonlyArray<{
|
|
30
|
+
/** Regex to test if the payload contains this attack indicator */
|
|
31
|
+
readonly test: RegExp;
|
|
32
|
+
/** The detection regex to use in the rule */
|
|
33
|
+
readonly pattern: string;
|
|
34
|
+
/** Human-readable description */
|
|
35
|
+
readonly description: string;
|
|
36
|
+
/** Which categories this indicator applies to */
|
|
37
|
+
readonly categories: readonly ATRCategory[];
|
|
38
|
+
}>;
|
|
39
|
+
export declare class RuleScaffolder {
|
|
40
|
+
private readonly options;
|
|
41
|
+
constructor(options?: ScaffoldOptions);
|
|
42
|
+
/**
|
|
43
|
+
* Generate a complete ATR YAML rule from structured input.
|
|
44
|
+
* Returns a ScaffoldResult with the YAML string, generated ID, and any warnings.
|
|
45
|
+
*/
|
|
46
|
+
scaffold(input: ScaffoldInput, existingIds?: ReadonlySet<string>): ScaffoldResult;
|
|
47
|
+
/**
|
|
48
|
+
* Validate scaffold input, throwing on invalid required fields
|
|
49
|
+
* and returning warnings for non-critical issues.
|
|
50
|
+
*/
|
|
51
|
+
private validateInput;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=rule-scaffolder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-scaffolder.d.ts","sourceRoot":"","sources":["../src/rule-scaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EACV,WAAW,EACX,WAAW,EACX,aAAa,EAGd,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,WAAW,CAAC;IACtB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,eAAe,CAAC,EAAE,aAAa,CAAC;IAChC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAwCD;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,aAAa,CAAC;IACpD,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,6CAA6C;IAC7C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,iCAAiC;IACjC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,iDAAiD;IACjD,QAAQ,CAAC,UAAU,EAAE,SAAS,WAAW,EAAE,CAAC;CAC7C,CAqFA,CAAC;AAsEF,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA4B;gBAExC,OAAO,GAAE,eAAoB;IAOzC;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,aAAa,EAAE,WAAW,GAAE,WAAW,CAAC,MAAM,CAAa,GAAG,cAAc;IAwF5F;;;OAGG;IACH,OAAO,CAAC,aAAa;CAwBtB"}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ATR Rule Scaffolder - Generates ATR rule YAML scaffolds from structured input
|
|
3
|
+
* @module agent-threat-rules/rule-scaffolder
|
|
4
|
+
*/
|
|
5
|
+
import yaml from 'js-yaml';
|
|
6
|
+
const CATEGORY_TO_SOURCE_TYPE = {
|
|
7
|
+
'prompt-injection': 'llm_io',
|
|
8
|
+
'tool-poisoning': 'tool_call',
|
|
9
|
+
'context-exfiltration': 'context_window',
|
|
10
|
+
'agent-manipulation': 'multi_agent_comm',
|
|
11
|
+
'privilege-escalation': 'agent_behavior',
|
|
12
|
+
'excessive-autonomy': 'agent_behavior',
|
|
13
|
+
'data-poisoning': 'llm_io',
|
|
14
|
+
'model-abuse': 'llm_io',
|
|
15
|
+
'skill-compromise': 'skill_lifecycle',
|
|
16
|
+
};
|
|
17
|
+
const CATEGORY_TO_FIELD = {
|
|
18
|
+
'prompt-injection': 'user_input',
|
|
19
|
+
'tool-poisoning': 'tool_response',
|
|
20
|
+
'context-exfiltration': 'agent_output',
|
|
21
|
+
'agent-manipulation': 'agent_message',
|
|
22
|
+
'privilege-escalation': 'agent_action',
|
|
23
|
+
'excessive-autonomy': 'agent_action',
|
|
24
|
+
'data-poisoning': 'training_input',
|
|
25
|
+
'model-abuse': 'user_input',
|
|
26
|
+
'skill-compromise': 'skill_manifest',
|
|
27
|
+
};
|
|
28
|
+
const SEVERITY_TO_ACTIONS = {
|
|
29
|
+
critical: ['block_input', 'alert', 'escalate'],
|
|
30
|
+
high: ['block_input', 'alert'],
|
|
31
|
+
medium: ['alert', 'snapshot'],
|
|
32
|
+
low: ['alert'],
|
|
33
|
+
informational: ['alert'],
|
|
34
|
+
};
|
|
35
|
+
const REGEX_SPECIAL_CHARS = /[.*+?^${}()|[\]\\]/g;
|
|
36
|
+
function escapeRegex(str) {
|
|
37
|
+
return str.replace(REGEX_SPECIAL_CHARS, '\\$&');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Attack pattern templates by category — reusable regex building blocks
|
|
41
|
+
* that detect BEHAVIOR, not package names.
|
|
42
|
+
*/
|
|
43
|
+
export const ATTACK_PATTERN_INDICATORS = [
|
|
44
|
+
// Shell execution patterns
|
|
45
|
+
{
|
|
46
|
+
test: /exec(Sync)?|spawn|child_process|shell|subprocess|popen|os\.system/i,
|
|
47
|
+
pattern: '(execSync?|spawn|child_process|shell|subprocess|popen|os\\.system)\\s*\\(',
|
|
48
|
+
description: 'Shell/command execution',
|
|
49
|
+
categories: ['tool-poisoning', 'skill-compromise', 'privilege-escalation'],
|
|
50
|
+
},
|
|
51
|
+
// Dynamic shell with interpolation (RCE)
|
|
52
|
+
{
|
|
53
|
+
test: /exec.*\$\{|spawn.*\$\{|`.*\$\{.*`/i,
|
|
54
|
+
pattern: '(exec|spawn|shell)\\s*\\(.*\\$\\{',
|
|
55
|
+
description: 'Dynamic shell execution with variable interpolation',
|
|
56
|
+
categories: ['tool-poisoning', 'skill-compromise'],
|
|
57
|
+
},
|
|
58
|
+
// Network exfiltration
|
|
59
|
+
{
|
|
60
|
+
test: /fetch|http|request|axios|got|node-fetch|urllib|curl|wget/i,
|
|
61
|
+
pattern: '(fetch|https?://|request|axios|got|node-fetch|urllib|curl|wget)\\s*\\(?',
|
|
62
|
+
description: 'Outbound network request',
|
|
63
|
+
categories: ['context-exfiltration', 'tool-poisoning', 'data-poisoning'],
|
|
64
|
+
},
|
|
65
|
+
// Credential/secret access
|
|
66
|
+
{
|
|
67
|
+
test: /password|secret|token|credential|api[_\s]?key|auth|cookie/i,
|
|
68
|
+
pattern: '(password|secret|token|credential|api[_ ]?key|auth_token|cookie)',
|
|
69
|
+
description: 'Credential/secret access',
|
|
70
|
+
categories: ['context-exfiltration', 'privilege-escalation', 'tool-poisoning'],
|
|
71
|
+
},
|
|
72
|
+
// Environment variable exfiltration
|
|
73
|
+
{
|
|
74
|
+
test: /process\.env|os\.environ|getenv|ENV\[/i,
|
|
75
|
+
pattern: '(process\\.env|os\\.environ|getenv|ENV\\[)',
|
|
76
|
+
description: 'Environment variable access',
|
|
77
|
+
categories: ['context-exfiltration', 'tool-poisoning', 'skill-compromise'],
|
|
78
|
+
},
|
|
79
|
+
// eval / dynamic code execution
|
|
80
|
+
{
|
|
81
|
+
test: /\beval\s*\(|new\s+Function\s*\(|vm\.run/i,
|
|
82
|
+
pattern: '(\\beval\\s*\\(|new\\s+Function\\s*\\(|vm\\.run)',
|
|
83
|
+
description: 'Dynamic code execution',
|
|
84
|
+
categories: ['tool-poisoning', 'skill-compromise'],
|
|
85
|
+
},
|
|
86
|
+
// Instruction override (prompt injection)
|
|
87
|
+
{
|
|
88
|
+
test: /ignore|disregard|forget|override|overwrite/i,
|
|
89
|
+
pattern: '(override|overwrite|ignore|disregard|forget)\\s+(previous|prior|above|existing|all|any)\\s+(instructions?|rules?|constraints?|guidelines?|protocols?)',
|
|
90
|
+
description: 'Instruction override attempt',
|
|
91
|
+
categories: ['prompt-injection', 'agent-manipulation'],
|
|
92
|
+
},
|
|
93
|
+
// Role manipulation
|
|
94
|
+
{
|
|
95
|
+
test: /you are now|act as|pretend|new role|system prompt/i,
|
|
96
|
+
pattern: '(you\\s+are\\s+now|act\\s+as\\s+(a|an|if)|pretend\\s+(to|you)|new\\s+role|system\\s+prompt)',
|
|
97
|
+
description: 'Role/identity manipulation',
|
|
98
|
+
categories: ['prompt-injection', 'agent-manipulation'],
|
|
99
|
+
},
|
|
100
|
+
// File system destructive operations
|
|
101
|
+
{
|
|
102
|
+
test: /rm\s+-rf|rmdir|unlink|deleteFile|fs\.rm/i,
|
|
103
|
+
pattern: '(rm\\s+-rf|rmdir\\s|unlink\\s*\\(|deleteFile|fs\\.rm)',
|
|
104
|
+
description: 'Destructive file system operation',
|
|
105
|
+
categories: ['tool-poisoning', 'excessive-autonomy'],
|
|
106
|
+
},
|
|
107
|
+
// Base64/encoding evasion
|
|
108
|
+
{
|
|
109
|
+
test: /atob|btoa|base64|Buffer\.from.*encoding|fromCharCode/i,
|
|
110
|
+
pattern: '(atob|btoa|base64|Buffer\\.from|fromCharCode)\\s*\\(',
|
|
111
|
+
description: 'Encoding-based payload obfuscation',
|
|
112
|
+
categories: ['tool-poisoning', 'skill-compromise'],
|
|
113
|
+
},
|
|
114
|
+
// Data exfiltration combo (credential + network)
|
|
115
|
+
{
|
|
116
|
+
test: /(password|secret|token|key).*(fetch|http|send|post|upload)/i,
|
|
117
|
+
pattern: '(password|secret|token|api[_ ]?key).*(fetch|https?://|request|send|post|upload)',
|
|
118
|
+
description: 'Credential access combined with network exfiltration',
|
|
119
|
+
categories: ['context-exfiltration', 'tool-poisoning'],
|
|
120
|
+
},
|
|
121
|
+
// Download + execute combo
|
|
122
|
+
{
|
|
123
|
+
test: /(download|fetch|curl|wget).*(exec|eval|spawn)/i,
|
|
124
|
+
pattern: '(download|fetch|curl|wget).*(exec|eval|spawn|child_process)',
|
|
125
|
+
description: 'Download and execute pattern',
|
|
126
|
+
categories: ['tool-poisoning', 'skill-compromise'],
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
/**
|
|
130
|
+
* Build detection regex from a payload string, using category-aware
|
|
131
|
+
* attack pattern templates instead of naive keyword extraction.
|
|
132
|
+
*
|
|
133
|
+
* Priority:
|
|
134
|
+
* 1. Match known attack indicators in the payload -> use behavioral regex
|
|
135
|
+
* 2. Combine multiple indicators with alternation for multi-vector attacks
|
|
136
|
+
* 3. Fall back to keyword extraction only for text that has no code patterns
|
|
137
|
+
*/
|
|
138
|
+
function buildRegexPattern(payload, category) {
|
|
139
|
+
const trimmed = payload.trim();
|
|
140
|
+
// Step 1: Find all attack indicators present in this payload
|
|
141
|
+
const matched = ATTACK_PATTERN_INDICATORS.filter((ind) => {
|
|
142
|
+
const matchesPayload = ind.test.test(trimmed);
|
|
143
|
+
const matchesCategory = !category || ind.categories.includes(category);
|
|
144
|
+
return matchesPayload && matchesCategory;
|
|
145
|
+
});
|
|
146
|
+
// Step 2: If we found behavioral patterns, use them
|
|
147
|
+
if (matched.length > 0) {
|
|
148
|
+
if (matched.length === 1) {
|
|
149
|
+
return `(?i)${matched[0].pattern}`;
|
|
150
|
+
}
|
|
151
|
+
// Combine multiple indicators — detect the most specific one
|
|
152
|
+
// Sort by pattern length (longer = more specific) and take top 3
|
|
153
|
+
const sorted = [...matched].sort((a, b) => b.pattern.length - a.pattern.length);
|
|
154
|
+
const top = sorted.slice(0, 3);
|
|
155
|
+
if (top.length === 1) {
|
|
156
|
+
return `(?i)${top[0].pattern}`;
|
|
157
|
+
}
|
|
158
|
+
// Use alternation for multi-vector detection
|
|
159
|
+
return `(?i)(${top.map((t) => t.pattern).join('|')})`;
|
|
160
|
+
}
|
|
161
|
+
// Step 3: Fallback — keyword extraction for text-based payloads
|
|
162
|
+
// (e.g., prompt injection text without code patterns)
|
|
163
|
+
const words = trimmed.split(/\s+/).filter((w) => w.length > 3);
|
|
164
|
+
if (words.length === 0) {
|
|
165
|
+
return `(?i).*${escapeRegex(trimmed)}.*`;
|
|
166
|
+
}
|
|
167
|
+
const keywords = words.slice(0, 4);
|
|
168
|
+
return `(?i)${keywords.map((k) => `(?=.*${escapeRegex(k)})`).join('')}`;
|
|
169
|
+
}
|
|
170
|
+
function generateId(existingIds = new Set()) {
|
|
171
|
+
const year = new Date().getFullYear();
|
|
172
|
+
const maxAttempts = 800;
|
|
173
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
174
|
+
const seq = String(Math.floor(Math.random() * 900) + 100);
|
|
175
|
+
const id = `ATR-${year}-${seq}`;
|
|
176
|
+
if (!existingIds.has(id)) {
|
|
177
|
+
return id;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
throw new Error('Unable to generate a unique ATR rule ID after maximum attempts');
|
|
181
|
+
}
|
|
182
|
+
function getCurrentDate() {
|
|
183
|
+
const d = new Date();
|
|
184
|
+
const yyyy = d.getFullYear();
|
|
185
|
+
const mm = String(d.getMonth() + 1).padStart(2, '0');
|
|
186
|
+
const dd = String(d.getDate()).padStart(2, '0');
|
|
187
|
+
return `${yyyy}/${mm}/${dd}`;
|
|
188
|
+
}
|
|
189
|
+
export class RuleScaffolder {
|
|
190
|
+
options;
|
|
191
|
+
constructor(options = {}) {
|
|
192
|
+
this.options = {
|
|
193
|
+
author: options.author ?? 'ATR Community (auto-scaffolded)',
|
|
194
|
+
schemaVersion: options.schemaVersion ?? '0.1',
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Generate a complete ATR YAML rule from structured input.
|
|
199
|
+
* Returns a ScaffoldResult with the YAML string, generated ID, and any warnings.
|
|
200
|
+
*/
|
|
201
|
+
scaffold(input, existingIds = new Set()) {
|
|
202
|
+
const warnings = this.validateInput(input);
|
|
203
|
+
const severity = input.severity ?? 'medium';
|
|
204
|
+
const sourceType = input.agentSourceType ?? CATEGORY_TO_SOURCE_TYPE[input.category];
|
|
205
|
+
const field = CATEGORY_TO_FIELD[input.category];
|
|
206
|
+
const id = generateId(existingIds);
|
|
207
|
+
const date = getCurrentDate();
|
|
208
|
+
const conditions = input.examplePayloads.map((payload, idx) => ({
|
|
209
|
+
field,
|
|
210
|
+
operator: 'regex',
|
|
211
|
+
value: buildRegexPattern(payload, input.category),
|
|
212
|
+
description: `Pattern ${idx + 1}: detects "${payload.trim().slice(0, 80)}"`,
|
|
213
|
+
}));
|
|
214
|
+
const truePositives = input.examplePayloads.map((payload) => ({
|
|
215
|
+
input: payload.trim(),
|
|
216
|
+
expected: 'trigger',
|
|
217
|
+
}));
|
|
218
|
+
const trueNegatives = [
|
|
219
|
+
{
|
|
220
|
+
input: 'TODO: Add benign input that should not trigger this rule',
|
|
221
|
+
expected: 'no_trigger',
|
|
222
|
+
},
|
|
223
|
+
];
|
|
224
|
+
const references = {};
|
|
225
|
+
if (input.owaspRefs && input.owaspRefs.length > 0) {
|
|
226
|
+
references.owasp_llm = [...input.owaspRefs];
|
|
227
|
+
}
|
|
228
|
+
if (input.mitreRefs && input.mitreRefs.length > 0) {
|
|
229
|
+
references.mitre_atlas = [...input.mitreRefs];
|
|
230
|
+
}
|
|
231
|
+
const conditionExpr = conditions.length > 1 ? 'any' : 'all';
|
|
232
|
+
const rule = {
|
|
233
|
+
title: input.title,
|
|
234
|
+
id,
|
|
235
|
+
schema_version: this.options.schemaVersion,
|
|
236
|
+
status: 'draft',
|
|
237
|
+
description: input.attackDescription,
|
|
238
|
+
author: this.options.author,
|
|
239
|
+
date,
|
|
240
|
+
severity,
|
|
241
|
+
detection_tier: 'pattern',
|
|
242
|
+
maturity: 'draft',
|
|
243
|
+
...(Object.keys(references).length > 0 ? { references } : {}),
|
|
244
|
+
tags: {
|
|
245
|
+
category: input.category,
|
|
246
|
+
confidence: severity === 'critical' || severity === 'high' ? 'high' : 'medium',
|
|
247
|
+
},
|
|
248
|
+
agent_source: {
|
|
249
|
+
type: sourceType,
|
|
250
|
+
},
|
|
251
|
+
detection: {
|
|
252
|
+
conditions,
|
|
253
|
+
condition: conditionExpr,
|
|
254
|
+
false_positives: [
|
|
255
|
+
'TODO: Document known false positive scenarios',
|
|
256
|
+
],
|
|
257
|
+
},
|
|
258
|
+
response: {
|
|
259
|
+
actions: [...SEVERITY_TO_ACTIONS[severity]],
|
|
260
|
+
message_template: `Potential ${input.category} detected: {{matched_patterns}}`,
|
|
261
|
+
},
|
|
262
|
+
test_cases: {
|
|
263
|
+
true_positives: truePositives,
|
|
264
|
+
true_negatives: trueNegatives,
|
|
265
|
+
},
|
|
266
|
+
};
|
|
267
|
+
const yamlStr = yaml.dump(rule, {
|
|
268
|
+
indent: 2,
|
|
269
|
+
lineWidth: 120,
|
|
270
|
+
noRefs: true,
|
|
271
|
+
sortKeys: false,
|
|
272
|
+
quotingType: '"',
|
|
273
|
+
forceQuotes: false,
|
|
274
|
+
});
|
|
275
|
+
return { yaml: yamlStr, id, warnings };
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Validate scaffold input, throwing on invalid required fields
|
|
279
|
+
* and returning warnings for non-critical issues.
|
|
280
|
+
*/
|
|
281
|
+
validateInput(input) {
|
|
282
|
+
const warnings = [];
|
|
283
|
+
if (!input.title || input.title.trim().length === 0) {
|
|
284
|
+
throw new Error('ScaffoldInput.title is required and must be non-empty');
|
|
285
|
+
}
|
|
286
|
+
if (!input.category) {
|
|
287
|
+
throw new Error('ScaffoldInput.category is required');
|
|
288
|
+
}
|
|
289
|
+
if (!input.attackDescription || input.attackDescription.trim().length === 0) {
|
|
290
|
+
throw new Error('ScaffoldInput.attackDescription is required and must be non-empty');
|
|
291
|
+
}
|
|
292
|
+
if (!input.examplePayloads || input.examplePayloads.length === 0) {
|
|
293
|
+
throw new Error('ScaffoldInput.examplePayloads must contain at least one payload');
|
|
294
|
+
}
|
|
295
|
+
if (input.examplePayloads.length < 3) {
|
|
296
|
+
warnings.push('Fewer than 3 example payloads - consider adding more for better pattern coverage.');
|
|
297
|
+
}
|
|
298
|
+
return warnings;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=rule-scaffolder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule-scaffolder.js","sourceRoot":"","sources":["../src/rule-scaffolder.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,IAAI,MAAM,SAAS,CAAC;AA+B3B,MAAM,uBAAuB,GAAiD;IAC5E,kBAAkB,EAAE,QAAQ;IAC5B,gBAAgB,EAAE,WAAW;IAC7B,sBAAsB,EAAE,gBAAgB;IACxC,oBAAoB,EAAE,kBAAkB;IACxC,sBAAsB,EAAE,gBAAgB;IACxC,oBAAoB,EAAE,gBAAgB;IACtC,gBAAgB,EAAE,QAAQ;IAC1B,aAAa,EAAE,QAAQ;IACvB,kBAAkB,EAAE,iBAAiB;CACtC,CAAC;AAEF,MAAM,iBAAiB,GAA0C;IAC/D,kBAAkB,EAAE,YAAY;IAChC,gBAAgB,EAAE,eAAe;IACjC,sBAAsB,EAAE,cAAc;IACtC,oBAAoB,EAAE,eAAe;IACrC,sBAAsB,EAAE,cAAc;IACtC,oBAAoB,EAAE,cAAc;IACpC,gBAAgB,EAAE,gBAAgB;IAClC,aAAa,EAAE,YAAY;IAC3B,kBAAkB,EAAE,gBAAgB;CACrC,CAAC;AAEF,MAAM,mBAAmB,GAAwD;IAC/E,QAAQ,EAAE,CAAC,aAAa,EAAE,OAAO,EAAE,UAAU,CAAC;IAC9C,IAAI,EAAE,CAAC,aAAa,EAAE,OAAO,CAAC;IAC9B,MAAM,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC;IAC7B,GAAG,EAAE,CAAC,OAAO,CAAC;IACd,aAAa,EAAE,CAAC,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,mBAAmB,GAAG,qBAAqB,CAAC;AAElD,SAAS,WAAW,CAAC,GAAW;IAC9B,OAAO,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GASjC;IACH,2BAA2B;IAC3B;QACE,IAAI,EAAE,oEAAoE;QAC1E,OAAO,EAAE,2EAA2E;QACpF,WAAW,EAAE,yBAAyB;QACtC,UAAU,EAAE,CAAC,gBAAgB,EAAE,kBAAkB,EAAE,sBAAsB,CAAC;KAC3E;IACD,yCAAyC;IACzC;QACE,IAAI,EAAE,oCAAoC;QAC1C,OAAO,EAAE,mCAAmC;QAC5C,WAAW,EAAE,qDAAqD;QAClE,UAAU,EAAE,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;KACnD;IACD,uBAAuB;IACvB;QACE,IAAI,EAAE,2DAA2D;QACjE,OAAO,EAAE,yEAAyE;QAClF,WAAW,EAAE,0BAA0B;QACvC,UAAU,EAAE,CAAC,sBAAsB,EAAE,gBAAgB,EAAE,gBAAgB,CAAC;KACzE;IACD,2BAA2B;IAC3B;QACE,IAAI,EAAE,4DAA4D;QAClE,OAAO,EAAE,kEAAkE;QAC3E,WAAW,EAAE,0BAA0B;QACvC,UAAU,EAAE,CAAC,sBAAsB,EAAE,sBAAsB,EAAE,gBAAgB,CAAC;KAC/E;IACD,oCAAoC;IACpC;QACE,IAAI,EAAE,wCAAwC;QAC9C,OAAO,EAAE,4CAA4C;QACrD,WAAW,EAAE,6BAA6B;QAC1C,UAAU,EAAE,CAAC,sBAAsB,EAAE,gBAAgB,EAAE,kBAAkB,CAAC;KAC3E;IACD,gCAAgC;IAChC;QACE,IAAI,EAAE,0CAA0C;QAChD,OAAO,EAAE,kDAAkD;QAC3D,WAAW,EAAE,wBAAwB;QACrC,UAAU,EAAE,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;KACnD;IACD,0CAA0C;IAC1C;QACE,IAAI,EAAE,6CAA6C;QACnD,OAAO,EAAE,uJAAuJ;QAChK,WAAW,EAAE,8BAA8B;QAC3C,UAAU,EAAE,CAAC,kBAAkB,EAAE,oBAAoB,CAAC;KACvD;IACD,oBAAoB;IACpB;QACE,IAAI,EAAE,oDAAoD;QAC1D,OAAO,EAAE,6FAA6F;QACtG,WAAW,EAAE,4BAA4B;QACzC,UAAU,EAAE,CAAC,kBAAkB,EAAE,oBAAoB,CAAC;KACvD;IACD,qCAAqC;IACrC;QACE,IAAI,EAAE,0CAA0C;QAChD,OAAO,EAAE,uDAAuD;QAChE,WAAW,EAAE,mCAAmC;QAChD,UAAU,EAAE,CAAC,gBAAgB,EAAE,oBAAoB,CAAC;KACrD;IACD,0BAA0B;IAC1B;QACE,IAAI,EAAE,uDAAuD;QAC7D,OAAO,EAAE,sDAAsD;QAC/D,WAAW,EAAE,oCAAoC;QACjD,UAAU,EAAE,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;KACnD;IACD,iDAAiD;IACjD;QACE,IAAI,EAAE,6DAA6D;QACnE,OAAO,EAAE,iFAAiF;QAC1F,WAAW,EAAE,sDAAsD;QACnE,UAAU,EAAE,CAAC,sBAAsB,EAAE,gBAAgB,CAAC;KACvD;IACD,2BAA2B;IAC3B;QACE,IAAI,EAAE,gDAAgD;QACtD,OAAO,EAAE,6DAA6D;QACtE,WAAW,EAAE,8BAA8B;QAC3C,UAAU,EAAE,CAAC,gBAAgB,EAAE,kBAAkB,CAAC;KACnD;CACF,CAAC;AAEF;;;;;;;;GAQG;AACH,SAAS,iBAAiB,CAAC,OAAe,EAAE,QAAsB;IAChE,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAE/B,6DAA6D;IAC7D,MAAM,OAAO,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE;QACvD,MAAM,cAAc,GAAG,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9C,MAAM,eAAe,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACvE,OAAO,cAAc,IAAI,eAAe,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,oDAAoD;IACpD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,OAAO,OAAO,CAAC,CAAC,CAAE,CAAC,OAAO,EAAE,CAAC;QACtC,CAAC;QACD,6DAA6D;QAC7D,iEAAiE;QACjE,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAChF,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAC/B,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACrB,OAAO,OAAO,GAAG,CAAC,CAAC,CAAE,CAAC,OAAO,EAAE,CAAC;QAClC,CAAC;QACD,6CAA6C;QAC7C,OAAO,QAAQ,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IACxD,CAAC;IAED,gEAAgE;IAChE,sDAAsD;IACtD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE/D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3C,CAAC;IAED,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACnC,OAAO,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;AAC1E,CAAC;AAED,SAAS,UAAU,CAAC,cAAmC,IAAI,GAAG,EAAE;IAC9D,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACtC,MAAM,WAAW,GAAG,GAAG,CAAC;IACxB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACvD,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC;QAC1D,MAAM,EAAE,GAAG,OAAO,IAAI,IAAI,GAAG,EAAE,CAAC;QAChC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACzB,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAC;AACpF,CAAC;AAED,SAAS,cAAc;IACrB,MAAM,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;IACrB,MAAM,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;IAC7B,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IACrD,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAChD,OAAO,GAAG,IAAI,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC;AAC/B,CAAC;AAED,MAAM,OAAO,cAAc;IACR,OAAO,CAA4B;IAEpD,YAAY,UAA2B,EAAE;QACvC,IAAI,CAAC,OAAO,GAAG;YACb,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,iCAAiC;YAC3D,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,KAAK;SAC9C,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,QAAQ,CAAC,KAAoB,EAAE,cAAmC,IAAI,GAAG,EAAE;QACzE,MAAM,QAAQ,GAAG,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAE3C,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,QAAQ,CAAC;QAC5C,MAAM,UAAU,GAAG,KAAK,CAAC,eAAe,IAAI,uBAAuB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACpF,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAChD,MAAM,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;QAE9B,MAAM,UAAU,GAAwB,KAAK,CAAC,eAAe,CAAC,GAAG,CAC/D,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;YACjB,KAAK;YACL,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,iBAAiB,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC;YACjD,WAAW,EAAE,WAAW,GAAG,GAAG,CAAC,cAAc,OAAO,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG;SAC5E,CAAC,CACH,CAAC;QAEF,MAAM,aAAa,GAAG,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;YAC5D,KAAK,EAAE,OAAO,CAAC,IAAI,EAAE;YACrB,QAAQ,EAAE,SAAkB;SAC7B,CAAC,CAAC,CAAC;QAEJ,MAAM,aAAa,GAAG;YACpB;gBACE,KAAK,EAAE,0DAA0D;gBACjE,QAAQ,EAAE,YAAqB;aAChC;SACF,CAAC;QAEF,MAAM,UAAU,GAA6B,EAAE,CAAC;QAChD,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClD,UAAU,CAAC,SAAS,GAAG,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClD,UAAU,CAAC,WAAW,GAAG,CAAC,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC;QAChD,CAAC;QAED,MAAM,aAAa,GAAG,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC;QAE5D,MAAM,IAAI,GAA4B;YACpC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,EAAE;YACF,cAAc,EAAE,IAAI,CAAC,OAAO,CAAC,aAAa;YAC1C,MAAM,EAAE,OAAO;YACf,WAAW,EAAE,KAAK,CAAC,iBAAiB;YACpC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;YAC3B,IAAI;YACJ,QAAQ;YACR,cAAc,EAAE,SAAS;YACzB,QAAQ,EAAE,OAAO;YACjB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC7D,IAAI,EAAE;gBACJ,QAAQ,EAAE,KAAK,CAAC,QAAQ;gBACxB,UAAU,EAAE,QAAQ,KAAK,UAAU,IAAI,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ;aAC/E;YACD,YAAY,EAAE;gBACZ,IAAI,EAAE,UAAU;aACjB;YACD,SAAS,EAAE;gBACT,UAAU;gBACV,SAAS,EAAE,aAAa;gBACxB,eAAe,EAAE;oBACf,+CAA+C;iBAChD;aACF;YACD,QAAQ,EAAE;gBACR,OAAO,EAAE,CAAC,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;gBAC3C,gBAAgB,EAAE,aAAa,KAAK,CAAC,QAAQ,iCAAiC;aAC/E;YACD,UAAU,EAAE;gBACV,cAAc,EAAE,aAAa;gBAC7B,cAAc,EAAE,aAAa;aAC9B;SACF,CAAC;QAEF,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAC9B,MAAM,EAAE,CAAC;YACT,SAAS,EAAE,GAAG;YACd,MAAM,EAAE,IAAI;YACZ,QAAQ,EAAE,KAAK;YACf,WAAW,EAAE,GAAG;YAChB,WAAW,EAAE,KAAK;SACnB,CAAC,CAAC;QAEH,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;IACzC,CAAC;IAED;;;OAGG;IACK,aAAa,CAAC,KAAoB;QACxC,MAAM,QAAQ,GAAa,EAAE,CAAC;QAE9B,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACpD,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC3E,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACxD,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,iBAAiB,IAAI,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5E,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;QACvF,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,eAAe,IAAI,KAAK,CAAC,eAAe,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACjE,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC;QACrF,CAAC;QAED,IAAI,KAAK,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrC,QAAQ,CAAC,IAAI,CACX,mFAAmF,CACpF,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SessionTracker - Tracks per-session state for behavioral detection operators.
|
|
3
|
+
*
|
|
4
|
+
* Enables multi-turn injection detection, call frequency tracking,
|
|
5
|
+
* and pattern repetition counting. All state is internal; public methods
|
|
6
|
+
* return copies to preserve immutability.
|
|
7
|
+
*
|
|
8
|
+
* @module agent-threat-rules/session-tracker
|
|
9
|
+
*/
|
|
10
|
+
import type { AgentEvent } from './types.js';
|
|
11
|
+
/** Snapshot of session state returned to callers (immutable copy) */
|
|
12
|
+
export interface SessionStateSnapshot {
|
|
13
|
+
readonly sessionId: string;
|
|
14
|
+
readonly eventCount: number;
|
|
15
|
+
readonly oldestEventTimestamp: number | undefined;
|
|
16
|
+
readonly newestEventTimestamp: number | undefined;
|
|
17
|
+
/** Event history for sequence detection (immutable copies) */
|
|
18
|
+
readonly events: readonly Readonly<AgentEvent>[];
|
|
19
|
+
}
|
|
20
|
+
export declare class SessionTracker {
|
|
21
|
+
private readonly sessions;
|
|
22
|
+
/**
|
|
23
|
+
* Record an agent event for the given session.
|
|
24
|
+
* Extracts tool name and patterns from event fields/content.
|
|
25
|
+
*/
|
|
26
|
+
recordEvent(sessionId: string, event: AgentEvent, patterns?: readonly string[]): void;
|
|
27
|
+
/**
|
|
28
|
+
* Get the number of calls to a specific tool within a time window.
|
|
29
|
+
*/
|
|
30
|
+
getCallFrequency(sessionId: string, toolName: string, windowMs: number): number;
|
|
31
|
+
/**
|
|
32
|
+
* Get the number of times a pattern has been observed within a time window.
|
|
33
|
+
*/
|
|
34
|
+
getPatternFrequency(sessionId: string, pattern: string, windowMs: number): number;
|
|
35
|
+
/**
|
|
36
|
+
* Get total event count for a session, optionally within a time window.
|
|
37
|
+
*/
|
|
38
|
+
getEventCount(sessionId: string, windowMs?: number): number;
|
|
39
|
+
/**
|
|
40
|
+
* Get an immutable snapshot of session state. Returns undefined if session does not exist.
|
|
41
|
+
*/
|
|
42
|
+
getSessionSnapshot(sessionId: string): SessionStateSnapshot | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Evict sessions that have been inactive longer than maxAgeMs.
|
|
45
|
+
* Returns the number of sessions evicted.
|
|
46
|
+
*/
|
|
47
|
+
cleanup(maxAgeMs: number): number;
|
|
48
|
+
/** Get the number of tracked sessions */
|
|
49
|
+
getSessionCount(): number;
|
|
50
|
+
/**
|
|
51
|
+
* Ensure we don't exceed the maximum session count.
|
|
52
|
+
* Evicts the oldest session if at capacity.
|
|
53
|
+
*/
|
|
54
|
+
private ensureCapacity;
|
|
55
|
+
private getOrCreateSession;
|
|
56
|
+
private extractToolName;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=session-tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-tracker.d.ts","sourceRoot":"","sources":["../src/session-tracker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAgB7C,qEAAqE;AACrE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IAClD,8DAA8D;IAC9D,QAAQ,CAAC,MAAM,EAAE,SAAS,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;CAClD;AAWD,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmC;IAE5D;;;OAGG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,GAAE,SAAS,MAAM,EAAO,GAAG,IAAI;IAkCzF;;OAEG;IACH,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAc/E;;OAEG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAcjF;;OAEG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM;IAkB3D;;OAEG;IACH,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS;IAgBvE;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAcjC,yCAAyC;IACzC,eAAe,IAAI,MAAM;IAIzB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAkBtB,OAAO,CAAC,kBAAkB;IAgB1B,OAAO,CAAC,eAAe;CAMxB"}
|