circle-ir-ai 4.0.6 → 4.0.7
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/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [4.0.7] - 2026-08-16
|
|
9
|
+
|
|
10
|
+
### Changed — bump circle-ir 4.7.0 → 4.7.1
|
|
11
|
+
|
|
12
|
+
Engine pin bump to latest 4.x. No source changes. Single copy verified; typecheck
|
|
13
|
+
clean, 1808 tests pass. Static regression spot-check clean: OWASP 100%, Rust 92.3%,
|
|
14
|
+
Bash 100%, HTML 100%, Go 78.9% (all match baseline).
|
|
15
|
+
|
|
8
16
|
## [4.0.6] - 2026-08-14
|
|
9
17
|
|
|
10
18
|
### Added — export the parse-isolation pool helpers (cognium-ai#58 completeness)
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared skill-scan precision layer (cognium-ai#68).
|
|
3
|
+
*
|
|
4
|
+
* ## Why this exists
|
|
5
|
+
*
|
|
6
|
+
* The skill-scan false-positive fixes (skillsregistry #52/#53/#55/#57/#59/#63/#66)
|
|
7
|
+
* originally shipped inside `circle-pack/src/api/analysis/skill-runner.ts` — the
|
|
8
|
+
* HTTP handler for `POST /api/analyze/skill`. But the CLI (`cognium-ai
|
|
9
|
+
* analyze-skill`), the MCP tools, and the skills-validation gate adapter all go
|
|
10
|
+
* through `analyzeSkillBundle` in this package, which never had any of them. So
|
|
11
|
+
* two entry points returned two different verdicts for the same skill on the
|
|
12
|
+
* same engine (#68), and the validation gate scored a path with none of the
|
|
13
|
+
* precision work.
|
|
14
|
+
*
|
|
15
|
+
* The fix belongs in the inner layer: CLI / HTTP / MCP are just interfaces.
|
|
16
|
+
* These passes operate on `SkillFinding` (this package's model) so every
|
|
17
|
+
* interface inherits the same precision + verdict by construction.
|
|
18
|
+
*
|
|
19
|
+
* ## The two FP definitions
|
|
20
|
+
*
|
|
21
|
+
* - **Verdict FP** (product API): a skill is `VULNERABLE`. Severity caps fix
|
|
22
|
+
* this — capped-to-`low` findings fold into `trust_score` and never flip the
|
|
23
|
+
* verdict.
|
|
24
|
+
* - **Presence FP** (validation gate): a finding of a threat type *appears* on a
|
|
25
|
+
* safe fixture. Caps don't help (the finding still exists); only the
|
|
26
|
+
* suppressors (which DROP the finding) and genuine detector precision do.
|
|
27
|
+
*
|
|
28
|
+
* `finalizeSkillAnalysis` returns both the capped/suppressed `findings` and a
|
|
29
|
+
* `verdict` + `trust_score`, so a presence-based consumer can switch to the
|
|
30
|
+
* verdict (the cognium-ai-owned contract, skillsregistry#64) and a
|
|
31
|
+
* verdict-based consumer works directly.
|
|
32
|
+
*/
|
|
33
|
+
import type { SkillFinding } from './types.js';
|
|
34
|
+
type Severity = SkillFinding['severity'];
|
|
35
|
+
/**
|
|
36
|
+
* skillsregistry#52 — CWE-117 (log injection) is emitted for any user input
|
|
37
|
+
* reaching a logger; on a stdio skill server it's low real-world risk but was
|
|
38
|
+
* the biggest single driver of false VULNERABLE verdicts. Cap to `low`. Opt out
|
|
39
|
+
* with SKILL_KEEP_LOG_INJECTION_SEVERITY=1. Mutates in place.
|
|
40
|
+
*/
|
|
41
|
+
export declare function capLogInjectionSeverity(findings: SkillFinding[]): void;
|
|
42
|
+
/**
|
|
43
|
+
* skillsregistry#66 — the biggest FP driver. circle-ir's taint analyzer marks an
|
|
44
|
+
* MCP tool's OWN parameters as untrusted attacker input, so a tool acting on its
|
|
45
|
+
* declared arguments (a shell tool running its command arg, a DB tool querying
|
|
46
|
+
* its arg) is flagged as injection. In a skill/MCP scan EVERY taint finding is
|
|
47
|
+
* the tool acting on its declared parameter — declared capability, not an
|
|
48
|
+
* attacker flow — so cap the whole taint population to `low`. Genuine
|
|
49
|
+
* *undeclared* over-reach is the job of the capability-mismatch finding, and
|
|
50
|
+
* behavioral-malware findings (`ransomware`, `fetch_and_execute`, …) carry their
|
|
51
|
+
* own type and are untouched. `SkillFindingType 'vulnerability'` is exactly the
|
|
52
|
+
* SAST taint set. Opt out with SKILL_KEEP_PARAM_SOURCE_SEVERITY=1. Mutates.
|
|
53
|
+
*/
|
|
54
|
+
export declare function capTaintCapabilitySeverity(findings: SkillFinding[]): void;
|
|
55
|
+
export declare function suppressPlaceholderSecrets(findings: SkillFinding[]): SkillFinding[];
|
|
56
|
+
/**
|
|
57
|
+
* skillsregistry#55 — CWE-601 open-redirect is a code-flow vuln (user URL → a
|
|
58
|
+
* redirect/`Location` sink); it can't be established from instruction TEXT. The
|
|
59
|
+
* instruction-safety phase was emitting it for a SKILL.md that merely NAMES a
|
|
60
|
+
* data-source URL. Drop CWE-601 findings that don't come from a real code sink
|
|
61
|
+
* (no code `location.line`). Opt out with SKILL_KEEP_INSTRUCTION_OPEN_REDIRECT=1.
|
|
62
|
+
*/
|
|
63
|
+
export declare function suppressInstructionOpenRedirect(findings: SkillFinding[]): SkillFinding[];
|
|
64
|
+
/**
|
|
65
|
+
* skillsregistry#63 — collapse duplicate finding rows, keeping the
|
|
66
|
+
* highest-confidence instance. Identity: (type, cwe, normalized artifact, line).
|
|
67
|
+
*/
|
|
68
|
+
export declare function dedupFindings(findings: SkillFinding[]): SkillFinding[];
|
|
69
|
+
/** Coverage / mode inputs the verdict needs, supplied by the pipeline. */
|
|
70
|
+
export interface SkillVerdictContext {
|
|
71
|
+
/** Code files that actually produced a SAST result (not merely queued). */
|
|
72
|
+
codeFilesAnalyzed: number;
|
|
73
|
+
/** True only if the instruction-safety phase actually ran on a real SKILL.md. */
|
|
74
|
+
instructionAnalyzed: boolean;
|
|
75
|
+
/** True when the analyzed SKILL.md is the caller's description echo, not fetched content. */
|
|
76
|
+
skillMdIsDescriptionEcho?: boolean;
|
|
77
|
+
/** Severity floor for a finding to be "substantive" (default medium). */
|
|
78
|
+
verdictMinSeverity?: Severity;
|
|
79
|
+
}
|
|
80
|
+
export type SkillVerdict = 'SAFE' | 'VULNERABLE' | 'UNKNOWN';
|
|
81
|
+
export interface SkillFinalizeResult {
|
|
82
|
+
findings: SkillFinding[];
|
|
83
|
+
verdict: SkillVerdict;
|
|
84
|
+
trustScore: number;
|
|
85
|
+
scanCoverage: 'none' | 'partial' | 'full';
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Run the full precision layer + compute the cognium-ai-owned verdict/trust from
|
|
89
|
+
* a raw `SkillFinding[]`. Order: dedup → caps → suppressors → verdict.
|
|
90
|
+
*
|
|
91
|
+
* - skillsregistry#57: at trust ≥ 0.9 only HIGH/CRITICAL flips the verdict.
|
|
92
|
+
* - skillsregistry#59: no analyzed code AND no real instruction analysis ⇒
|
|
93
|
+
* UNKNOWN / trust 0 (unscannable content is not "scanned clean").
|
|
94
|
+
*/
|
|
95
|
+
export declare function finalizeSkillAnalysis(raw: SkillFinding[], ctx: SkillVerdictContext): SkillFinalizeResult;
|
|
96
|
+
export {};
|
|
97
|
+
//# sourceMappingURL=precision.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"precision.d.ts","sourceRoot":"","sources":["../../src/skills/precision.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,KAAK,QAAQ,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;AAWzC;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI,CAQtE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI,CASzE;AAaD,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CAYnF;AAED;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CAQxF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,YAAY,EAAE,CAetE;AAED,0EAA0E;AAC1E,MAAM,WAAW,mBAAmB;IAClC,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,CAAC;IAC1B,iFAAiF;IACjF,mBAAmB,EAAE,OAAO,CAAC;IAC7B,6FAA6F;IAC7F,wBAAwB,CAAC,EAAE,OAAO,CAAC;IACnC,yEAAyE;IACzE,kBAAkB,CAAC,EAAE,QAAQ,CAAC;CAC/B;AAED,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,YAAY,GAAG,SAAS,CAAC;AAE7D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;CAC3C;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,YAAY,EAAE,EACnB,GAAG,EAAE,mBAAmB,GACvB,mBAAmB,CAmCrB"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared skill-scan precision layer (cognium-ai#68).
|
|
3
|
+
*
|
|
4
|
+
* ## Why this exists
|
|
5
|
+
*
|
|
6
|
+
* The skill-scan false-positive fixes (skillsregistry #52/#53/#55/#57/#59/#63/#66)
|
|
7
|
+
* originally shipped inside `circle-pack/src/api/analysis/skill-runner.ts` — the
|
|
8
|
+
* HTTP handler for `POST /api/analyze/skill`. But the CLI (`cognium-ai
|
|
9
|
+
* analyze-skill`), the MCP tools, and the skills-validation gate adapter all go
|
|
10
|
+
* through `analyzeSkillBundle` in this package, which never had any of them. So
|
|
11
|
+
* two entry points returned two different verdicts for the same skill on the
|
|
12
|
+
* same engine (#68), and the validation gate scored a path with none of the
|
|
13
|
+
* precision work.
|
|
14
|
+
*
|
|
15
|
+
* The fix belongs in the inner layer: CLI / HTTP / MCP are just interfaces.
|
|
16
|
+
* These passes operate on `SkillFinding` (this package's model) so every
|
|
17
|
+
* interface inherits the same precision + verdict by construction.
|
|
18
|
+
*
|
|
19
|
+
* ## The two FP definitions
|
|
20
|
+
*
|
|
21
|
+
* - **Verdict FP** (product API): a skill is `VULNERABLE`. Severity caps fix
|
|
22
|
+
* this — capped-to-`low` findings fold into `trust_score` and never flip the
|
|
23
|
+
* verdict.
|
|
24
|
+
* - **Presence FP** (validation gate): a finding of a threat type *appears* on a
|
|
25
|
+
* safe fixture. Caps don't help (the finding still exists); only the
|
|
26
|
+
* suppressors (which DROP the finding) and genuine detector precision do.
|
|
27
|
+
*
|
|
28
|
+
* `finalizeSkillAnalysis` returns both the capped/suppressed `findings` and a
|
|
29
|
+
* `verdict` + `trust_score`, so a presence-based consumer can switch to the
|
|
30
|
+
* verdict (the cognium-ai-owned contract, skillsregistry#64) and a
|
|
31
|
+
* verdict-based consumer works directly.
|
|
32
|
+
*/
|
|
33
|
+
const SEVERITY_RANK = { info: 0, low: 1, medium: 2, high: 3, critical: 4 };
|
|
34
|
+
/** Normalize a CWE id to the `CWE-<n>` form used by the sets below. */
|
|
35
|
+
function cweId(f) {
|
|
36
|
+
const c = f.cwe;
|
|
37
|
+
if (!c)
|
|
38
|
+
return undefined;
|
|
39
|
+
return /^cwe-/i.test(c) ? c.toUpperCase() : `CWE-${c}`;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* skillsregistry#52 — CWE-117 (log injection) is emitted for any user input
|
|
43
|
+
* reaching a logger; on a stdio skill server it's low real-world risk but was
|
|
44
|
+
* the biggest single driver of false VULNERABLE verdicts. Cap to `low`. Opt out
|
|
45
|
+
* with SKILL_KEEP_LOG_INJECTION_SEVERITY=1. Mutates in place.
|
|
46
|
+
*/
|
|
47
|
+
export function capLogInjectionSeverity(findings) {
|
|
48
|
+
if (process.env.SKILL_KEEP_LOG_INJECTION_SEVERITY === '1')
|
|
49
|
+
return;
|
|
50
|
+
for (const f of findings) {
|
|
51
|
+
if (cweId(f) === 'CWE-117' && f.severity !== 'low') {
|
|
52
|
+
(f.evidence ??= {}).originalSeverity = f.severity;
|
|
53
|
+
f.severity = 'low';
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* skillsregistry#66 — the biggest FP driver. circle-ir's taint analyzer marks an
|
|
59
|
+
* MCP tool's OWN parameters as untrusted attacker input, so a tool acting on its
|
|
60
|
+
* declared arguments (a shell tool running its command arg, a DB tool querying
|
|
61
|
+
* its arg) is flagged as injection. In a skill/MCP scan EVERY taint finding is
|
|
62
|
+
* the tool acting on its declared parameter — declared capability, not an
|
|
63
|
+
* attacker flow — so cap the whole taint population to `low`. Genuine
|
|
64
|
+
* *undeclared* over-reach is the job of the capability-mismatch finding, and
|
|
65
|
+
* behavioral-malware findings (`ransomware`, `fetch_and_execute`, …) carry their
|
|
66
|
+
* own type and are untouched. `SkillFindingType 'vulnerability'` is exactly the
|
|
67
|
+
* SAST taint set. Opt out with SKILL_KEEP_PARAM_SOURCE_SEVERITY=1. Mutates.
|
|
68
|
+
*/
|
|
69
|
+
export function capTaintCapabilitySeverity(findings) {
|
|
70
|
+
if (process.env.SKILL_KEEP_PARAM_SOURCE_SEVERITY === '1')
|
|
71
|
+
return;
|
|
72
|
+
for (const f of findings) {
|
|
73
|
+
if (f.type === 'vulnerability' && f.severity !== 'low') {
|
|
74
|
+
(f.evidence ??= {}).originalSeverity = f.severity;
|
|
75
|
+
(f.evidence).capability_declared = true;
|
|
76
|
+
f.severity = 'low';
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* skillsregistry#53 — hardcoded-secret (CWE-798) false-positives on placeholder
|
|
82
|
+
* strings (`YOUR_API_KEY`, `sk_live_xxxxx`, `<your-key>`, `process.env.X`) in
|
|
83
|
+
* READMEs / help text / .env.example. A real embedded credential (PEM key, a
|
|
84
|
+
* live-shaped literal) still fires. Drop placeholder-shaped / doc-file findings.
|
|
85
|
+
* Opt out with SKILL_KEEP_PLACEHOLDER_SECRETS=1.
|
|
86
|
+
*/
|
|
87
|
+
const PLACEHOLDER_SECRET_RE = /YOUR[_-]?[A-Z0-9]|your[_-]?(?:api|token|key|secret|pass)|x{5,}|<[^>]{0,40}(?:key|token|secret|password|api|pat)[^>]{0,40}>|\$\{[^}]+\}|process\.env\.|import\.meta\.env|os\.environ|changeme|placeholder|redacted/i;
|
|
88
|
+
const DOC_OR_EXAMPLE_FILE_RE = /(?:^|\/)(?:readme|changelog)|\.md$|\.env\.example$|\.example(?:\.[a-z0-9]+)?$|example\.env$/i;
|
|
89
|
+
export function suppressPlaceholderSecrets(findings) {
|
|
90
|
+
if (process.env.SKILL_KEEP_PLACEHOLDER_SECRETS === '1')
|
|
91
|
+
return findings;
|
|
92
|
+
return findings.filter((f) => {
|
|
93
|
+
if (cweId(f) !== 'CWE-798' && f.type !== 'hardcoded_secret')
|
|
94
|
+
return true;
|
|
95
|
+
if (DOC_OR_EXAMPLE_FILE_RE.test(f.artifact || ''))
|
|
96
|
+
return false;
|
|
97
|
+
const snippet = f.location?.snippet ||
|
|
98
|
+
f.evidence?.quote ||
|
|
99
|
+
f.description ||
|
|
100
|
+
'';
|
|
101
|
+
return !PLACEHOLDER_SECRET_RE.test(snippet);
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* skillsregistry#55 — CWE-601 open-redirect is a code-flow vuln (user URL → a
|
|
106
|
+
* redirect/`Location` sink); it can't be established from instruction TEXT. The
|
|
107
|
+
* instruction-safety phase was emitting it for a SKILL.md that merely NAMES a
|
|
108
|
+
* data-source URL. Drop CWE-601 findings that don't come from a real code sink
|
|
109
|
+
* (no code `location.line`). Opt out with SKILL_KEEP_INSTRUCTION_OPEN_REDIRECT=1.
|
|
110
|
+
*/
|
|
111
|
+
export function suppressInstructionOpenRedirect(findings) {
|
|
112
|
+
if (process.env.SKILL_KEEP_INSTRUCTION_OPEN_REDIRECT === '1')
|
|
113
|
+
return findings;
|
|
114
|
+
return findings.filter((f) => {
|
|
115
|
+
if (cweId(f) !== 'CWE-601')
|
|
116
|
+
return true;
|
|
117
|
+
// A real open-redirect comes from a code sink (has a code artifact + line).
|
|
118
|
+
const fromCodeSink = !!f.location?.line && !/skill\.md$/i.test(f.artifact || '');
|
|
119
|
+
return fromCodeSink;
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* skillsregistry#63 — collapse duplicate finding rows, keeping the
|
|
124
|
+
* highest-confidence instance. Identity: (type, cwe, normalized artifact, line).
|
|
125
|
+
*/
|
|
126
|
+
export function dedupFindings(findings) {
|
|
127
|
+
const norm = (p) => (p || '').replace(/\\/g, '/').replace(/^\.\//, '').toLowerCase();
|
|
128
|
+
const ordered = findings
|
|
129
|
+
.map((f, i) => ({ f, i }))
|
|
130
|
+
.sort((a, b) => (b.f.confidence ?? 0) - (a.f.confidence ?? 0) || a.i - b.i);
|
|
131
|
+
const seen = new Set();
|
|
132
|
+
const kept = new Set();
|
|
133
|
+
for (const { f } of ordered) {
|
|
134
|
+
const key = `${f.type}|${cweId(f) ?? ''}|${norm(f.artifact)}|${f.location?.line ?? ''}`;
|
|
135
|
+
if (seen.has(key))
|
|
136
|
+
continue;
|
|
137
|
+
seen.add(key);
|
|
138
|
+
kept.add(f);
|
|
139
|
+
}
|
|
140
|
+
return findings.filter((f) => kept.has(f));
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Run the full precision layer + compute the cognium-ai-owned verdict/trust from
|
|
144
|
+
* a raw `SkillFinding[]`. Order: dedup → caps → suppressors → verdict.
|
|
145
|
+
*
|
|
146
|
+
* - skillsregistry#57: at trust ≥ 0.9 only HIGH/CRITICAL flips the verdict.
|
|
147
|
+
* - skillsregistry#59: no analyzed code AND no real instruction analysis ⇒
|
|
148
|
+
* UNKNOWN / trust 0 (unscannable content is not "scanned clean").
|
|
149
|
+
*/
|
|
150
|
+
export function finalizeSkillAnalysis(raw, ctx) {
|
|
151
|
+
let findings = dedupFindings(raw);
|
|
152
|
+
capLogInjectionSeverity(findings);
|
|
153
|
+
capTaintCapabilitySeverity(findings);
|
|
154
|
+
findings = suppressPlaceholderSecrets(findings);
|
|
155
|
+
findings = suppressInstructionOpenRedirect(findings);
|
|
156
|
+
// Trust score — weighted severity penalty (mirrors the historical formula).
|
|
157
|
+
const weights = { critical: 1.0, high: 0.7, medium: 0.4, low: 0.2, info: 0.1 };
|
|
158
|
+
let penalty = 0;
|
|
159
|
+
for (const f of findings)
|
|
160
|
+
penalty += (weights[f.severity] ?? 0.2) * (f.confidence ?? 0.7);
|
|
161
|
+
const trustScore = Math.round(Math.max(0, 1 - penalty / 10) * 100) / 100;
|
|
162
|
+
// Coverage (skillsregistry#59) — fail-closed when nothing was actually analyzed.
|
|
163
|
+
const hasCodeCoverage = ctx.codeFilesAnalyzed > 0;
|
|
164
|
+
const hasInstructionCoverage = ctx.instructionAnalyzed && !ctx.skillMdIsDescriptionEcho;
|
|
165
|
+
const hasAnyCoverage = hasCodeCoverage || hasInstructionCoverage;
|
|
166
|
+
// Verdict (skillsregistry#57) — near-clean trust only flips on HIGH/CRITICAL.
|
|
167
|
+
const floor = ctx.verdictMinSeverity ?? 'medium';
|
|
168
|
+
const floorRank = SEVERITY_RANK[floor] ?? 2;
|
|
169
|
+
const substantive = findings.filter((f) => (SEVERITY_RANK[f.severity] ?? 1) >= floorRank);
|
|
170
|
+
const hasHighCrit = findings.some((f) => f.severity === 'high' || f.severity === 'critical');
|
|
171
|
+
const NEAR_CLEAN = 0.9;
|
|
172
|
+
const substantiveEnough = hasHighCrit || (trustScore < NEAR_CLEAN && substantive.length >= 1);
|
|
173
|
+
const verdict = !hasAnyCoverage ? 'UNKNOWN' : substantiveEnough ? 'VULNERABLE' : 'SAFE';
|
|
174
|
+
const effectiveTrust = hasAnyCoverage ? trustScore : 0;
|
|
175
|
+
const scanCoverage = !hasAnyCoverage
|
|
176
|
+
? 'none'
|
|
177
|
+
: hasCodeCoverage && hasInstructionCoverage
|
|
178
|
+
? 'full'
|
|
179
|
+
: 'partial';
|
|
180
|
+
return { findings, verdict, trustScore: effectiveTrust, scanCoverage };
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=precision.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"precision.js","sourceRoot":"","sources":["../../src/skills/precision.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAMH,MAAM,aAAa,GAA2B,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AAEnG,uEAAuE;AACvE,SAAS,KAAK,CAAC,CAAe;IAC5B,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC;IAChB,IAAI,CAAC,CAAC;QAAE,OAAO,SAAS,CAAC;IACzB,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;AACzD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,QAAwB;IAC9D,IAAI,OAAO,CAAC,GAAG,CAAC,iCAAiC,KAAK,GAAG;QAAE,OAAO;IAClE,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;YACnD,CAAC,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,gBAAgB,GAAG,CAAC,CAAC,QAAQ,CAAC;YAClD,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC;QACrB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,0BAA0B,CAAC,QAAwB;IACjE,IAAI,OAAO,CAAC,GAAG,CAAC,gCAAgC,KAAK,GAAG;QAAE,OAAO;IACjE,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,IAAI,KAAK,eAAe,IAAI,CAAC,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;YACvD,CAAC,CAAC,CAAC,QAAQ,KAAK,EAAE,CAAC,CAAC,gBAAgB,GAAG,CAAC,CAAC,QAAQ,CAAC;YAClD,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,mBAAmB,GAAG,IAAI,CAAC;YACxC,CAAC,CAAC,QAAQ,GAAG,KAAK,CAAC;QACrB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,qBAAqB,GACzB,oNAAoN,CAAC;AACvN,MAAM,sBAAsB,GAC1B,8FAA8F,CAAC;AACjG,MAAM,UAAU,0BAA0B,CAAC,QAAwB;IACjE,IAAI,OAAO,CAAC,GAAG,CAAC,8BAA8B,KAAK,GAAG;QAAE,OAAO,QAAQ,CAAC;IACxE,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAC3B,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,KAAK,kBAAkB;YAAE,OAAO,IAAI,CAAC;QACzE,IAAI,sBAAsB,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC;YAAE,OAAO,KAAK,CAAC;QAChE,MAAM,OAAO,GACV,CAAC,CAAC,QAAQ,EAAE,OAA8B;YAC1C,CAAC,CAAC,QAAQ,EAAE,KAA4B;YACzC,CAAC,CAAC,WAAW;YACb,EAAE,CAAC;QACL,OAAO,CAAC,qBAAqB,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,+BAA+B,CAAC,QAAwB;IACtE,IAAI,OAAO,CAAC,GAAG,CAAC,oCAAoC,KAAK,GAAG;QAAE,OAAO,QAAQ,CAAC;IAC9E,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE;QAC3B,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS;YAAE,OAAO,IAAI,CAAC;QACxC,4EAA4E;QAC5E,MAAM,YAAY,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;QACjF,OAAO,YAAY,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,QAAwB;IACpD,MAAM,IAAI,GAAG,CAAC,CAAqB,EAAE,EAAE,CACrC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IACnE,MAAM,OAAO,GAAG,QAAQ;SACrB,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;SACzB,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAgB,CAAC;IACrC,KAAK,MAAM,EAAE,CAAC,EAAE,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,IAAI,IAAI,EAAE,EAAE,CAAC;QACxF,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACd,CAAC;IACD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AAC7C,CAAC;AAuBD;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CACnC,GAAmB,EACnB,GAAwB;IAExB,IAAI,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAClC,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAClC,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IACrC,QAAQ,GAAG,0BAA0B,CAAC,QAAQ,CAAC,CAAC;IAChD,QAAQ,GAAG,+BAA+B,CAAC,QAAQ,CAAC,CAAC;IAErD,4EAA4E;IAC5E,MAAM,OAAO,GAA2B,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IACvG,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,KAAK,MAAM,CAAC,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,UAAU,IAAI,GAAG,CAAC,CAAC;IAC1F,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,OAAO,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;IAEzE,iFAAiF;IACjF,MAAM,eAAe,GAAG,GAAG,CAAC,iBAAiB,GAAG,CAAC,CAAC;IAClD,MAAM,sBAAsB,GAAG,GAAG,CAAC,mBAAmB,IAAI,CAAC,GAAG,CAAC,wBAAwB,CAAC;IACxF,MAAM,cAAc,GAAG,eAAe,IAAI,sBAAsB,CAAC;IAEjE,8EAA8E;IAC9E,MAAM,KAAK,GAAG,GAAG,CAAC,kBAAkB,IAAI,QAAQ,CAAC;IACjD,MAAM,SAAS,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC;IAC1F,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,IAAI,CAAC,CAAC,QAAQ,KAAK,UAAU,CAAC,CAAC;IAC7F,MAAM,UAAU,GAAG,GAAG,CAAC;IACvB,MAAM,iBAAiB,GAAG,WAAW,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,WAAW,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IAE9F,MAAM,OAAO,GAAiB,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC;IACtG,MAAM,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,MAAM,YAAY,GAAgC,CAAC,cAAc;QAC/D,CAAC,CAAC,MAAM;QACR,CAAC,CAAC,eAAe,IAAI,sBAAsB;YACzC,CAAC,CAAC,MAAM;YACR,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,YAAY,EAAE,CAAC;AACzE,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "circle-ir-ai",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.7",
|
|
4
4
|
"description": "LLM-enhanced SAST analysis built on circle-ir",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
"@ax-llm/ax": "^20.0.0",
|
|
101
101
|
"@cognium/project-profile-detect": "^1.1.0",
|
|
102
102
|
"@mastra/core": "^1.18.0",
|
|
103
|
-
"circle-ir": "4.7.
|
|
103
|
+
"circle-ir": "4.7.1",
|
|
104
104
|
"minimatch": "^10.2.5",
|
|
105
105
|
"p-queue": "^9.1.0"
|
|
106
106
|
},
|