circle-ir-ai 2.34.0 → 2.36.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/CHANGELOG.md +253 -0
- package/dist/analysis/entry-point-detection.d.ts +5 -0
- package/dist/analysis/entry-point-detection.d.ts.map +1 -1
- package/dist/analysis/entry-point-detection.js +95 -2
- package/dist/analysis/entry-point-detection.js.map +1 -1
- package/dist/cache/backend.d.ts +39 -7
- package/dist/cache/backend.d.ts.map +1 -1
- package/dist/cache/backend.js +18 -6
- package/dist/cache/backend.js.map +1 -1
- package/dist/cache/backends/index.d.ts +12 -7
- package/dist/cache/backends/index.d.ts.map +1 -1
- package/dist/cache/backends/index.js +12 -7
- package/dist/cache/backends/index.js.map +1 -1
- package/dist/cache/backends/layout.d.ts +13 -4
- package/dist/cache/backends/layout.d.ts.map +1 -1
- package/dist/cache/backends/layout.js +20 -5
- package/dist/cache/backends/layout.js.map +1 -1
- package/dist/cache/backends/local-fs.d.ts +9 -5
- package/dist/cache/backends/local-fs.d.ts.map +1 -1
- package/dist/cache/backends/local-fs.js +9 -5
- package/dist/cache/backends/local-fs.js.map +1 -1
- package/dist/cache/backends/r2.d.ts +14 -9
- package/dist/cache/backends/r2.d.ts.map +1 -1
- package/dist/cache/backends/r2.js +14 -9
- package/dist/cache/backends/r2.js.map +1 -1
- package/dist/cache/classification-cache.d.ts +22 -4
- package/dist/cache/classification-cache.d.ts.map +1 -1
- package/dist/cache/classification-cache.js +32 -4
- package/dist/cache/classification-cache.js.map +1 -1
- package/dist/llm/verification.d.ts.map +1 -1
- package/dist/llm/verification.js +25 -7
- package/dist/llm/verification.js.map +1 -1
- package/dist/security-scan/sink-filters.d.ts +11 -0
- package/dist/security-scan/sink-filters.d.ts.map +1 -1
- package/dist/security-scan/sink-filters.js +64 -0
- package/dist/security-scan/sink-filters.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,259 @@ 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
|
+
## [2.36.0] - 2026-07-03
|
|
9
|
+
|
|
10
|
+
Cache Round 3 (`cognium-ai#189`) — model-in-path defense-in-depth.
|
|
11
|
+
Motivated by the 2026-07-03 `zai-org/glm-5.2` and `minimax/minimax-m3`
|
|
12
|
+
CWE-Bench-Java runs, which both produced byte-identical 65/120
|
|
13
|
+
results with **zero** `llm-discovery:` attribution markers in either
|
|
14
|
+
log. Investigation confirmed the real root cause is a silent LLM-
|
|
15
|
+
error swallow in `src/llm/discovery.ts:524-531` (returns
|
|
16
|
+
`{vulnerabilityFound: false}` for any exception → LLM failures show
|
|
17
|
+
up as "no vulnerability found"). The cache-key composition IS
|
|
18
|
+
correctly model-fingerprinted, so this patch does NOT fix the
|
|
19
|
+
identical-result bug — it makes future model-cross-contamination
|
|
20
|
+
visible in R2 dashboards and impossible under a targeted `s3 rm`.
|
|
21
|
+
|
|
22
|
+
### Changed — R2/local-fs layout: `<model-slug>` path segment
|
|
23
|
+
|
|
24
|
+
`CacheKey` gains a new optional `modelSlug?: string` field
|
|
25
|
+
(`src/cache/backend.ts`). `renderObjectPath()` in
|
|
26
|
+
`src/cache/backends/layout.ts` injects the slug between the
|
|
27
|
+
namespace root and the sharded digest for the three model-dependent
|
|
28
|
+
namespaces:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
verify/<model-slug>/<4hex>/<sha>.json (was: verify/<4hex>/<sha>.json)
|
|
32
|
+
discovery/<model-slug>/<4hex>/<sha>.json (was: discovery/<4hex>/<sha>.json)
|
|
33
|
+
classifier/<model-slug>/<4hex>/<sha>.json (was: classifier/<4hex>/<sha>.json)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`tree/` and `cluster/` layouts are unchanged (both are model-
|
|
37
|
+
independent). When `modelSlug` is empty (no LLM configured, e.g.
|
|
38
|
+
pure-static scans), the flat 2.28.x path shape is preserved for
|
|
39
|
+
back-compat.
|
|
40
|
+
|
|
41
|
+
`ClassificationCache.toCacheKey()` populates `modelSlug` from the
|
|
42
|
+
per-phase `modelFingerprint` (already threaded through since
|
|
43
|
+
2.28.0/`cognium-ai#151`) sanitized via the new exported helper
|
|
44
|
+
`sanitizeModelSlug()` (replaces `=` with `-` so
|
|
45
|
+
`disc=zai-org_glm-5.2` renders as `disc-zai-org_glm-5.2`).
|
|
46
|
+
|
|
47
|
+
### Changed — SCHEMA_VER bumped `cic:v2` → `cic:v3`
|
|
48
|
+
|
|
49
|
+
All warm entries under both local-fs and R2 backends are invalidated
|
|
50
|
+
so operators re-populate under the Round-3 layout. Rollback path:
|
|
51
|
+
downgrade to `2.35.x` and old entries still miss (their `cic:v2`
|
|
52
|
+
envelope fails the `isValid()` schema check under the new version;
|
|
53
|
+
new writes go under `cic:v2` again). No breaking API change.
|
|
54
|
+
|
|
55
|
+
### Rationale
|
|
56
|
+
|
|
57
|
+
Even though the digest composition already folds
|
|
58
|
+
`modelFingerprint` into the SHA-256 (so `verify=opus` and
|
|
59
|
+
`verify=gpt-4o-mini` land in different files), the flat 2.28.x
|
|
60
|
+
layout made model-cross-contamination invisible in the R2 dashboard.
|
|
61
|
+
Round 3 surfaces the model dimension as a top-level segment so:
|
|
62
|
+
|
|
63
|
+
1. Operators see per-model cache footprint at a glance.
|
|
64
|
+
2. Per-model eviction is a single `s3 rm --recursive s3://cognium-cache/v2/discovery/disc-gemma3-12b/`.
|
|
65
|
+
3. Future digest-composition regressions (e.g. a stray refactor that
|
|
66
|
+
drops `modelFingerprint` from `computeDigest`) become visible as
|
|
67
|
+
an entry hitting under the wrong model prefix.
|
|
68
|
+
|
|
69
|
+
### Tests
|
|
70
|
+
|
|
71
|
+
- `tests/cache-model-in-path.test.ts` — 12 new tests covering the
|
|
72
|
+
layout renderer, `sanitizeModelSlug`, `ClassificationCache`
|
|
73
|
+
round-trip under two different discovery models, tree/cluster
|
|
74
|
+
slug-independence, and the empty-fingerprint back-compat path.
|
|
75
|
+
- `tests/cache-key-shape.test.ts` — SCHEMA_VER assertion updated to
|
|
76
|
+
`'cic:v3'`.
|
|
77
|
+
|
|
78
|
+
Full suite: 1340 pass + 3 skipped (was 1328 + 3), typecheck clean.
|
|
79
|
+
|
|
80
|
+
### Follow-up (out of scope for this release)
|
|
81
|
+
|
|
82
|
+
The silent LLM-error swallow at `src/llm/discovery.ts:524-531` is
|
|
83
|
+
the actual root cause of the "identical 65/120" observation from
|
|
84
|
+
the glm-5.2 + minimax-m3 runs. A separate ticket should:
|
|
85
|
+
|
|
86
|
+
- Surface LLM errors on the runner side (bubble up rate rather than
|
|
87
|
+
return fake `{vulnerabilityFound: false}`)
|
|
88
|
+
- Add a `llm.failureCount` metric to the CWE-Bench-Java runner's
|
|
89
|
+
summary output so a run that lost 100% of LLM calls doesn't look
|
|
90
|
+
like a legitimate static-baseline number.
|
|
91
|
+
|
|
92
|
+
## [2.35.0] - 2026-07-03
|
|
93
|
+
|
|
94
|
+
Sprint P2 Batch 4 — wide precision pass. Three shipping tickets
|
|
95
|
+
(`cognium-ai#173`, `#127` + wide extension, `#169`) plus the
|
|
96
|
+
close-out on `#172` (already-shipped, no code delta). Upstream
|
|
97
|
+
resource-leak FPs (`cognium-ai#170`, `#171`) escalated to
|
|
98
|
+
`cognium-dev` as tracked issues; no engine-source edits in this
|
|
99
|
+
release per workspace-boundary policy.
|
|
100
|
+
|
|
101
|
+
### Added — build / CI script path suppression gate (cognium-ai#173)
|
|
102
|
+
|
|
103
|
+
New `isBuildOrCiScriptPath(sinkFile)` predicate in
|
|
104
|
+
`src/security-scan/sink-filters.ts` wired into the
|
|
105
|
+
`isSuppressedSinkShape` cascade after `isCryptoLibraryInternal` and
|
|
106
|
+
before `isRequireOrImportSink`. Suppresses findings whose sink lives
|
|
107
|
+
under a well-known build / documentation / example directory:
|
|
108
|
+
|
|
109
|
+
- Path regex tokens (case-insensitive, anchored to a `/` boundary):
|
|
110
|
+
`docs?`, `dev`, `scripts?`, `tools`, `examples`, `samples`, `demos`,
|
|
111
|
+
`benchmarks?`. Ambiguous tokens (`example`, `sample`, `demo`) require
|
|
112
|
+
plural to avoid Java `com/example/...` package-name collisions —
|
|
113
|
+
verified by the "does NOT suppress `src/main/java/com/example/Foo.java`"
|
|
114
|
+
test case.
|
|
115
|
+
- File regex (basename anywhere in tree): `conf.py`, `noxfile.py`,
|
|
116
|
+
`conftest.py`, `setup.py`, `_config.py`. These historically travel
|
|
117
|
+
standalone (Sphinx conf at repo root, per-package conftest).
|
|
118
|
+
- Windows path separators normalised (`.replace(/\\/g, '/')`).
|
|
119
|
+
- `test/` + `tests/` deliberately NOT included — unit tests carry
|
|
120
|
+
real sinks (integration setup that resembles prod).
|
|
121
|
+
|
|
122
|
+
Complementary to `scanner.ts` file-walker exclusions: those drop the
|
|
123
|
+
file entirely; this gate handles the case where a partial `--include`
|
|
124
|
+
pattern or looser exclude re-admits build / CI files but the user
|
|
125
|
+
still doesn't want the findings.
|
|
126
|
+
|
|
127
|
+
**Tests.** 14 cases in `tests/sink-filters.test.ts`:
|
|
128
|
+
|
|
129
|
+
- Positive: `docs/conf.py`, `docs/source/conf.py`, `scripts/deploy.py`,
|
|
130
|
+
`tools/generate_report.py`, `dev/lint.py`, plural
|
|
131
|
+
`examples/samples/demos/`, `benchmarks/`, standalone build files,
|
|
132
|
+
case-insensitive tokens, Windows separators.
|
|
133
|
+
- Negative: substring FP guards (`docstore`, `sampler`, `toolkit`),
|
|
134
|
+
singular `example`, `sample`, `demo` (Java-package collision),
|
|
135
|
+
production `src/main/`, `lib/`, `app/`, `com/example/`, test dirs,
|
|
136
|
+
nullish inputs.
|
|
137
|
+
- Integration: `isSuppressedSinkShape` returns true when sink lives
|
|
138
|
+
under a build path even if all other gates would pass through.
|
|
139
|
+
|
|
140
|
+
### Added — wide TIER_1 supertype extension (cognium-ai#127 + wide)
|
|
141
|
+
|
|
142
|
+
`TIER_1_BY_SUPERTYPE` in `src/analysis/entry-point-detection.ts`
|
|
143
|
+
extends to five new framework families. Every entry below is an
|
|
144
|
+
accepted external trust boundary — the JVM invokes the method with
|
|
145
|
+
attacker-controlled data from a network / transport surface:
|
|
146
|
+
|
|
147
|
+
- **Netty** — `ChannelInboundHandler.channelRead[/Complete]`,
|
|
148
|
+
`SimpleChannelInboundHandler.channelRead0`,
|
|
149
|
+
`ChannelInboundHandlerAdapter.channelRead`,
|
|
150
|
+
`exceptionCaught`, `userEventTriggered`.
|
|
151
|
+
- **Vert.x** — `Handler.handle`, gated on a Vert.x-shaped parameter
|
|
152
|
+
type (`RoutingContext`, `HttpServerRequest`, `Message`, `Buffer`,
|
|
153
|
+
`AsyncResult`, `Promise`, etc.). `Handler` alone is a common name
|
|
154
|
+
(SLF4J, `java.util.logging`), so the raw supertype hit is
|
|
155
|
+
disambiguated via `matchesVertxHandlerParam(method)`. Non-matching
|
|
156
|
+
Handler.handle hits fall through with a one-time `console.warn`
|
|
157
|
+
keyed on `cognium-ai#127` so we can tune `VERTX_HANDLER_PARAM_TYPES`
|
|
158
|
+
from real corpus signal. A test-only `resetHandlerWarnState()`
|
|
159
|
+
export drops the once-latch so tests can spy on the warning.
|
|
160
|
+
- **gRPC** — `ServerCallHandler.startCall`, `ServerCall.Listener.{onMessage,
|
|
161
|
+
onHalfClose, onCancel, onComplete, onReady}`, `BindableService.bindService`.
|
|
162
|
+
- **Spring WebFlux** — `HandlerFunction.handle`, `WebFilter.filter`.
|
|
163
|
+
- **JAX-WS** — `Provider.invoke`.
|
|
164
|
+
|
|
165
|
+
Complementary to shipped `#128` (verifier reachability tags) and the
|
|
166
|
+
`interprocedural_param` gate in `runMerge`: this batch's additions flip
|
|
167
|
+
previously-uncaught taint flows into detected findings when the
|
|
168
|
+
enclosing class extends / implements one of these supertypes.
|
|
169
|
+
|
|
170
|
+
**Semver.** This is the reason `2.34.0` → `2.35.0` (minor bump, not
|
|
171
|
+
patch): behavioral additive change flips previously-uncaught sinks
|
|
172
|
+
into TP, not pure FP suppression.
|
|
173
|
+
|
|
174
|
+
**Tests.** 16 cases in `tests/analysis/entry-point-detection.test.ts`:
|
|
175
|
+
|
|
176
|
+
- 13 supertype coverage tests (Netty inbound handlers x3 + non-lifecycle
|
|
177
|
+
helper control, Vert.x with 3 param-type variants incl. package-qualified,
|
|
178
|
+
gRPC ServerCallHandler / Listener / BindableService, WebFlux
|
|
179
|
+
HandlerFunction / WebFilter, JAX-WS Provider).
|
|
180
|
+
- 3 Vert.x disambiguation tests (`java.util.logging.Handler` with
|
|
181
|
+
`LogRecord` param falls through to TIER_3, warn emitted only once
|
|
182
|
+
across multiple non-Vert.x hits, warn NOT emitted on genuine Vert.x
|
|
183
|
+
bindings).
|
|
184
|
+
|
|
185
|
+
### Changed — verifier prompt directive hardening for gemma3:12b (cognium-ai#169)
|
|
186
|
+
|
|
187
|
+
`BATCH_VERIFICATION_PROMPT` in `src/llm/verification.ts` rewrites the
|
|
188
|
+
`Entry-point tier` block from advisory language into explicit
|
|
189
|
+
directives. Root cause: on the 2026-06-24 top-100 Java baseline
|
|
190
|
+
gemma3:12b passed 495/496 CRIT+HIGH through as `exploitable: true`
|
|
191
|
+
because it treated "requires a Tier-1 call chain" as guidance rather
|
|
192
|
+
than a rule.
|
|
193
|
+
|
|
194
|
+
Prompt changes:
|
|
195
|
+
|
|
196
|
+
- Prefaces the tier block with *"These are DIRECTIVES — treat them as
|
|
197
|
+
reachability facts, not hints, unless the code clearly contradicts
|
|
198
|
+
them (cognium-ai#169)"*.
|
|
199
|
+
- **TIER_1_ENTRY_POINT** — affirmative directive: *"Sources here ARE
|
|
200
|
+
attacker-reachable. Do NOT downgrade to UNCERTAIN or FALSE_POSITIVE
|
|
201
|
+
just because you can't trace the full network path — the classifier
|
|
202
|
+
already did that."* Enumerates Batch 4's new supertype set (Netty,
|
|
203
|
+
Vert.x, gRPC, WebFlux, JAX-WS) so the LLM knows the classifier
|
|
204
|
+
scope matches.
|
|
205
|
+
- **TIER_3_LIBRARY_API** — hard rule: *"You MUST answer FALSE_POSITIVE
|
|
206
|
+
unless BOTH conditions hold: (1) the sink writes to a public-facing
|
|
207
|
+
target, AND (2) the code shows the tainted value reaches that target
|
|
208
|
+
unmodified."* Pins the short-reasoning template
|
|
209
|
+
`"TIER_3_LIBRARY_API: no external entry"` for grouping.
|
|
210
|
+
- Explicit ban on hypothetical-caller invention: *"Do NOT invent a
|
|
211
|
+
hypothetical Tier-1 caller."*
|
|
212
|
+
|
|
213
|
+
**Tests.** New `tests/regression/verifier-tier-directive.test.ts`
|
|
214
|
+
snapshots the five prompt substrings so accidental drift is caught
|
|
215
|
+
in `npm test` (~seconds) instead of showing up as an under-filter
|
|
216
|
+
regression on the next sweep. Same-model gemma3:12b sweep is the
|
|
217
|
+
ground-truth verification, tracked post-2.35.0.
|
|
218
|
+
|
|
219
|
+
### Closed — cognium-ai#172 (JSON content-type in scope suppresses XSS)
|
|
220
|
+
|
|
221
|
+
Already implemented in `hasJsonContentTypeInScope()` at
|
|
222
|
+
`sink-filters.ts:819-854`. Suppresses `xss` / `reflected_xss` /
|
|
223
|
+
`dom_xss` findings when `setContentType("application/json...")` fires
|
|
224
|
+
in the same method scope before the sink. Uses
|
|
225
|
+
`TypeShape.methods[].{start_line,end_line}` for method bounds. Called
|
|
226
|
+
from `runReport` at `workflow.ts:846` via `isSuppressedSinkShape()`.
|
|
227
|
+
Landed silently in earlier work; ticket closed with pointer.
|
|
228
|
+
|
|
229
|
+
### Escalated — cognium-dev issues for resource-leak FPs (cognium-ai#170, #171)
|
|
230
|
+
|
|
231
|
+
Filed as tracked issues on `cognium-dev` per workspace-boundary policy
|
|
232
|
+
(no engine-source edits in this repo):
|
|
233
|
+
|
|
234
|
+
- **#170** — calcite-avatica `AvaticaConnection#createStatement` — the
|
|
235
|
+
try/finally sits inside a lambda passed to `SecureUtils.doAs()`.
|
|
236
|
+
circle-ir's resource-leak pass doesn't see the finally-close because
|
|
237
|
+
the lambda body isn't inlined into the outer scope.
|
|
238
|
+
- **#171** — angus-mail `MailHandler#send` opens
|
|
239
|
+
`FileInputStream → BufferedInputStream → wrap()` — the outer wrap is
|
|
240
|
+
closed but circle-ir tracks the inner `FileInputStream` as leaked.
|
|
241
|
+
|
|
242
|
+
Both cross-referenced from the cognium-ai tickets. Retire the
|
|
243
|
+
cognium-ai tickets after the upstream engine ships the fix and we
|
|
244
|
+
bump the `circle-ir` dep range.
|
|
245
|
+
|
|
246
|
+
### Impact
|
|
247
|
+
|
|
248
|
+
Projected against the 2.34.0 → 2.35.0 top-10 Java re-sweep (post-ship
|
|
249
|
+
validation):
|
|
250
|
+
|
|
251
|
+
- CRIT ≤ 185 (vs 200 baseline; ≥ −15 from `#173` build-script gate +
|
|
252
|
+
Netty proper-shape).
|
|
253
|
+
- HIGH ≤ 20 (vs 24 baseline).
|
|
254
|
+
- jedis TLS-verify-disabled known-TP must remain flagged — verifier
|
|
255
|
+
hardening must not over-filter genuine external entry points.
|
|
256
|
+
- `verifyBatch` call volume expected near-flat at 627, possibly
|
|
257
|
+
slightly lower if `#173` gate suppresses pre-verify.
|
|
258
|
+
|
|
259
|
+
Sweep evidence lands as `testharness/java/results-top10-2.35.0-<date>/`.
|
|
260
|
+
|
|
8
261
|
## [2.34.0] - 2026-07-02
|
|
9
262
|
|
|
10
263
|
### Added — XPath / XXE / crypto library-internal FP gates (cognium-ai#167)
|
|
@@ -77,6 +77,11 @@ export interface EntryPointContext {
|
|
|
77
77
|
*/
|
|
78
78
|
callGraph?: unknown;
|
|
79
79
|
}
|
|
80
|
+
/**
|
|
81
|
+
* Test-only reset for the Handler WARN once-latch.
|
|
82
|
+
* @internal
|
|
83
|
+
*/
|
|
84
|
+
export declare function resetHandlerWarnState(): void;
|
|
80
85
|
/**
|
|
81
86
|
* Classify a method's entry-point tier.
|
|
82
87
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-point-detection.d.ts","sourceRoot":"","sources":["../../src/analysis/entry-point-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EAEZ,MAAM,uCAAuC,CAAC;AAM/C,MAAM,MAAM,cAAc,GACtB,oBAAoB,GACpB,kBAAkB,GAClB,oBAAoB,GACpB,cAAc,CAAC;AAEnB,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,KAAK,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IACxC,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"entry-point-detection.d.ts","sourceRoot":"","sources":["../../src/analysis/entry-point-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,WAAW,EAEZ,MAAM,uCAAuC,CAAC;AAM/C,MAAM,MAAM,cAAc,GACtB,oBAAoB,GACpB,kBAAkB,GAClB,oBAAoB,GACpB,cAAc,CAAC;AAEnB,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,KAAK,CAAC,EAAE,aAAa,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;IACxC,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AA6ID;;;GAGG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAoGD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,aAAa,EAAE,SAAS,GAAG,SAAS,EACpC,GAAG,EAAE,iBAAiB,GACrB,cAAc,CAgChB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,8BAA8B,CAC5C,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACrC,eAAe,EAAE,WAAW,GAAG,SAAS,EACxC,aAAa,EAAE,SAAS,GAAG,SAAS,EACpC,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAKT"}
|
|
@@ -140,7 +140,82 @@ const TIER_1_BY_SUPERTYPE = new Map([
|
|
|
140
140
|
// Spring boot CLI entry points
|
|
141
141
|
['CommandLineRunner', new Set(['run'])],
|
|
142
142
|
['ApplicationRunner', new Set(['run'])],
|
|
143
|
+
// ---------------------------------------------------------------------
|
|
144
|
+
// cognium-ai#127 + Batch 4 wide supertype extension.
|
|
145
|
+
//
|
|
146
|
+
// Every entry below is an accepted external trust boundary: the JVM
|
|
147
|
+
// invokes the method with attacker-controlled data from a network /
|
|
148
|
+
// transport surface. Users of this map should treat any hit as a
|
|
149
|
+
// hard TIER_1 signal.
|
|
150
|
+
// ---------------------------------------------------------------------
|
|
151
|
+
// Netty — inbound handlers see raw network bytes on the pipeline
|
|
152
|
+
['ChannelInboundHandler', new Set(['channelRead', 'channelReadComplete', 'exceptionCaught', 'userEventTriggered'])],
|
|
153
|
+
['SimpleChannelInboundHandler', new Set(['channelRead0', 'channelReadComplete', 'exceptionCaught'])],
|
|
154
|
+
['ChannelInboundHandlerAdapter', new Set(['channelRead', 'channelReadComplete', 'exceptionCaught'])],
|
|
155
|
+
// Vert.x — Handler<T>.handle(T) is the universal Vert.x callback shape.
|
|
156
|
+
// `Handler` is a common short name (java.util.logging.Handler etc.), so
|
|
157
|
+
// the raw map hit is validated against a Vert.x-looking parameter type
|
|
158
|
+
// in `matchesVertxHandlerParam` before we classify as TIER_1.
|
|
159
|
+
['Handler', new Set(['handle'])],
|
|
160
|
+
// gRPC — server-side callback surfaces
|
|
161
|
+
['ServerCallHandler', new Set(['startCall'])],
|
|
162
|
+
['ServerCall.Listener', new Set(['onMessage', 'onHalfClose', 'onCancel', 'onComplete', 'onReady'])],
|
|
163
|
+
['BindableService', new Set(['bindService'])],
|
|
164
|
+
// Spring WebFlux reactive server-side entry points
|
|
165
|
+
['HandlerFunction', new Set(['handle'])],
|
|
166
|
+
['WebFilter', new Set(['filter'])],
|
|
167
|
+
// JAX-WS provider-style endpoint
|
|
168
|
+
['Provider', new Set(['invoke'])],
|
|
143
169
|
]);
|
|
170
|
+
/**
|
|
171
|
+
* Simple-name substrings of parameter types that indicate a Vert.x
|
|
172
|
+
* `Handler<T>.handle(T)` binding. Used to disambiguate the generic
|
|
173
|
+
* `Handler` supertype match from unrelated `Handler` names in the JDK
|
|
174
|
+
* or SLF4J. If none match, `methodIsSupertypeLifecycleEntryPoint`
|
|
175
|
+
* falls through and emits a one-time WARN so we can tune the list.
|
|
176
|
+
*/
|
|
177
|
+
const VERTX_HANDLER_PARAM_TYPES = new Set([
|
|
178
|
+
'RoutingContext',
|
|
179
|
+
'HttpServerRequest',
|
|
180
|
+
'HttpServerResponse',
|
|
181
|
+
'HttpClientRequest',
|
|
182
|
+
'HttpClientResponse',
|
|
183
|
+
'ServerWebSocket',
|
|
184
|
+
'WebSocket',
|
|
185
|
+
'Message',
|
|
186
|
+
'NetSocket',
|
|
187
|
+
'Buffer',
|
|
188
|
+
'AsyncResult',
|
|
189
|
+
'Promise',
|
|
190
|
+
'Future',
|
|
191
|
+
'Event',
|
|
192
|
+
]);
|
|
193
|
+
/**
|
|
194
|
+
* One-time WARN gate for `Handler.handle` hits that do NOT look like
|
|
195
|
+
* Vert.x. Emitted via `console.warn` so hosts (including tests via a
|
|
196
|
+
* spy) can observe without pulling in a full logger dep. Reset by
|
|
197
|
+
* calling `resetHandlerWarnState()` from tests.
|
|
198
|
+
*/
|
|
199
|
+
let handlerWarnedOnce = false;
|
|
200
|
+
/**
|
|
201
|
+
* Test-only reset for the Handler WARN once-latch.
|
|
202
|
+
* @internal
|
|
203
|
+
*/
|
|
204
|
+
export function resetHandlerWarnState() {
|
|
205
|
+
handlerWarnedOnce = false;
|
|
206
|
+
}
|
|
207
|
+
function matchesVertxHandlerParam(method) {
|
|
208
|
+
const params = method.parameters ?? [];
|
|
209
|
+
if (params.length !== 1)
|
|
210
|
+
return false;
|
|
211
|
+
const paramType = simpleTypeName(params[0].type ?? '');
|
|
212
|
+
if (!paramType)
|
|
213
|
+
return false;
|
|
214
|
+
// The simple-name may be qualified (`io.vertx.ext.web.RoutingContext`)
|
|
215
|
+
// — strip package prefix before comparing.
|
|
216
|
+
const bare = paramType.split('.').pop() ?? paramType;
|
|
217
|
+
return VERTX_HANDLER_PARAM_TYPES.has(bare);
|
|
218
|
+
}
|
|
144
219
|
// ---------------------------------------------------------------------------
|
|
145
220
|
// Helpers
|
|
146
221
|
// ---------------------------------------------------------------------------
|
|
@@ -198,8 +273,26 @@ function methodIsSupertypeLifecycleEntryPoint(method, enclosingType) {
|
|
|
198
273
|
candidates.push(simpleTypeName(i));
|
|
199
274
|
for (const supertype of candidates) {
|
|
200
275
|
const lifecycleMethods = TIER_1_BY_SUPERTYPE.get(supertype);
|
|
201
|
-
if (lifecycleMethods?.has(method.name))
|
|
202
|
-
|
|
276
|
+
if (!lifecycleMethods?.has(method.name))
|
|
277
|
+
continue;
|
|
278
|
+
// Batch 4 disambiguation gate for Vert.x `Handler.handle`. The bare
|
|
279
|
+
// supertype name `Handler` collides with unrelated JDK / SLF4J
|
|
280
|
+
// interfaces; only treat as TIER_1 when the parameter shape looks
|
|
281
|
+
// Vert.x. Falls through with a one-time WARN otherwise so we can
|
|
282
|
+
// tune the param-type list from real corpus signal.
|
|
283
|
+
if (supertype === 'Handler') {
|
|
284
|
+
if (matchesVertxHandlerParam(method))
|
|
285
|
+
return true;
|
|
286
|
+
if (!handlerWarnedOnce) {
|
|
287
|
+
handlerWarnedOnce = true;
|
|
288
|
+
// eslint-disable-next-line no-console
|
|
289
|
+
console.warn(`[entry-point-detection] cognium-ai#127: Handler.handle hit ` +
|
|
290
|
+
`with non-Vert.x param shape on ${enclosingType.name}. ` +
|
|
291
|
+
`First occurrence only; extend VERTX_HANDLER_PARAM_TYPES if this is a real Vert.x binding.`);
|
|
292
|
+
}
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
return true;
|
|
203
296
|
}
|
|
204
297
|
return false;
|
|
205
298
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entry-point-detection.js","sourceRoot":"","sources":["../../src/analysis/entry-point-detection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiEG;AA8BH,8EAA8E;AAC9E,0CAA0C;AAC1C,8EAA8E;AAE9E;;;GAGG;AACH,MAAM,yBAAyB,GAAG,IAAI,GAAG,CAAC;IACxC,aAAa;IACb,gBAAgB;IAChB,YAAY;IACZ,aAAa;IACb,YAAY;IACZ,eAAe;IACf,cAAc;IACd,+BAA+B;IAC/B,gBAAgB;IAChB,kBAAkB;IAClB,6BAA6B;IAC7B,eAAe;IACf,cAAc;IACd,gBAAgB;IAChB,eAAe;IACf,aAAa;IACb,gBAAgB;IAChB,mBAAmB;IACnB,aAAa;IACb,YAAY;IACZ,+DAA+D;IAC/D,eAAe;IACf,mBAAmB;IACnB,WAAW;IACX,SAAS;IACT,MAAM;IACN,KAAK;IACL,MAAM;IACN,KAAK;IACL,QAAQ;IACR,OAAO;IACP,MAAM;IACN,SAAS;CACV,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,wBAAwB,GAAG,IAAI,GAAG,CAAC;IACvC,aAAa;IACb,gBAAgB;IAChB,YAAY;IACZ,wBAAwB;IACxB,MAAM;IACN,uCAAuC;IACvC,YAAY;IACZ,6BAA6B;IAC7B,gBAAgB;IAChB,8EAA8E;IAC9E,6DAA6D;IAC7D,aAAa;CACd,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,mBAAmB,GAA6C,IAAI,GAAG,CAAC;IAC5E,cAAc;IACd,CAAC,aAAa,EAAE,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IAC/G,CAAC,gBAAgB,EAAE,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;IACxC,CAAC,QAAQ,EAAE,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IACjC,aAAa;IACb,CAAC,oBAAoB,EAAE,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,YAAY,EAAE,iBAAiB,CAAC,CAAC,CAAC;IAC/E,CAAC,yBAAyB,EAAE,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,YAAY,EAAE,iBAAiB,EAAE,gCAAgC,CAAC,CAAC,CAAC;IACtH,+BAA+B;IAC/B,CAAC,mBAAmB,EAAE,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;IACvC,CAAC,mBAAmB,EAAE,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"entry-point-detection.js","sourceRoot":"","sources":["../../src/analysis/entry-point-detection.ts"],"names":[],"mappings":"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"}
|
package/dist/cache/backend.d.ts
CHANGED
|
@@ -12,22 +12,34 @@
|
|
|
12
12
|
* fingerprint composition stays in `ClassificationCache` so a backend
|
|
13
13
|
* swap doesn't change observable cache semantics.
|
|
14
14
|
*
|
|
15
|
-
* # CacheKey shape (Round
|
|
15
|
+
* # CacheKey shape (Round 3 — 2.36.0, cognium-ai#189)
|
|
16
16
|
*
|
|
17
17
|
* The Round-1 interface (`get(key: string)`) wasn't enough to express
|
|
18
18
|
* the per-namespace package-coordinate layout the R2 backend needs to
|
|
19
19
|
* surface in dashboards. We now pass a structured `{ namespace, digest,
|
|
20
|
-
* coordinate? }` so backends can render the path however
|
|
20
|
+
* coordinate?, modelSlug? }` so backends can render the path however
|
|
21
|
+
* they want:
|
|
21
22
|
*
|
|
22
|
-
* tree
|
|
23
|
-
*
|
|
24
|
-
* verify
|
|
25
|
-
*
|
|
23
|
+
* tree → `<prefix>/tree/<eco>/<name>@<ver>/<4hex>/<sha>.json` (coord)
|
|
24
|
+
* → `<prefix>/tree/_unowned/<4hex>/<sha>.json` (no coord)
|
|
25
|
+
* verify → `<prefix>/verify/<model-slug>/<4hex>/<sha>.json` (slug present)
|
|
26
|
+
* → `<prefix>/verify/<4hex>/<sha>.json` (no slug)
|
|
27
|
+
* discovery → `<prefix>/discovery/<model-slug>/<4hex>/<sha>.json` (slug present)
|
|
28
|
+
* → `<prefix>/discovery/<4hex>/<sha>.json` (no slug)
|
|
29
|
+
* classifier → analogous to verify/discovery
|
|
30
|
+
* cluster → `<prefix>/cluster/<4hex>/<sha>.json` (model-independent)
|
|
26
31
|
*
|
|
27
32
|
* Coordinate is intentionally tree-only: discovery and verify are
|
|
28
33
|
* keyed on method/batch content + model fingerprint, which already
|
|
29
34
|
* collide-correctly across packages without a coordinate prefix.
|
|
30
35
|
*
|
|
36
|
+
* `modelSlug` is intentionally non-tree: the tree cache is pattern-
|
|
37
|
+
* match (SAST) output that doesn't depend on any LLM. Splitting it by
|
|
38
|
+
* model would just fragment the cache. verify/discovery/classifier
|
|
39
|
+
* results are model-dependent and MUST NOT be shared between different
|
|
40
|
+
* discovery/verify models — a defense-in-depth against the digest-
|
|
41
|
+
* composition regressions that motivated Round 3 (cognium-ai#189).
|
|
42
|
+
*
|
|
31
43
|
* Selection: `LLM_CACHE_BACKEND` env (`local` | `memory` | `r2`).
|
|
32
44
|
* Default = `local` (back-compat). See `./backends/index.ts` factory.
|
|
33
45
|
*/
|
|
@@ -66,9 +78,29 @@ export interface CacheKey {
|
|
|
66
78
|
/**
|
|
67
79
|
* Optional package coordinate. Only consulted by tree-namespace keys;
|
|
68
80
|
* verify/discovery backends ignore it. When absent or `_unowned`,
|
|
69
|
-
* tree falls back to `_unowned/<
|
|
81
|
+
* tree falls back to `_unowned/<4hex>/<sha>` layout.
|
|
70
82
|
*/
|
|
71
83
|
coordinate?: PackageCoordinate;
|
|
84
|
+
/**
|
|
85
|
+
* Optional filesystem/URL-safe model identity for the cache path
|
|
86
|
+
* (cognium-ai#189, Round 3). Only consulted by non-tree namespaces
|
|
87
|
+
* (verify / discovery / classifier). When present, injected between
|
|
88
|
+
* the namespace root and the sharded digest:
|
|
89
|
+
* `<namespace>/<modelSlug>/<4hex>/<sha>.json`
|
|
90
|
+
* When absent (unset in the caller or empty string), the layout is
|
|
91
|
+
* flat `<namespace>/<4hex>/<sha>.json` (2.28.x back-compat).
|
|
92
|
+
*
|
|
93
|
+
* Motivation: even though `digest` is already model-fingerprinted
|
|
94
|
+
* (see classification-cache.ts `computeDigest`), surfacing the model
|
|
95
|
+
* segment in the path makes model-cross-contamination visible in R2
|
|
96
|
+
* dashboards, protects against future digest-composition regressions,
|
|
97
|
+
* and makes per-model cache eviction a `s3 rm` on a single prefix.
|
|
98
|
+
*
|
|
99
|
+
* Populated by `ClassificationCache.toCacheKey()` from the per-phase
|
|
100
|
+
* `modelFingerprint` (which is the same value already folded into the
|
|
101
|
+
* digest). MUST be URL/path-safe: the caller sanitizes `=` → `-`.
|
|
102
|
+
*/
|
|
103
|
+
modelSlug?: string;
|
|
72
104
|
}
|
|
73
105
|
export interface CacheBackend {
|
|
74
106
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/cache/backend.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/cache/backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,YAAY,GAAG,SAAS,CAAC;AAExF,MAAM,WAAW,QAAQ;IACvB;;;OAGG;IACH,SAAS,EAAE,cAAc,CAAC;IAC1B;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B;;;;;;;;;;;;;;;;;;OAkBG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B;;;;;;OAMG;IACH,GAAG,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAE3C;;;;;;OAMG;IACH,GAAG,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjD,4EAA4E;IAC5E,GAAG,CAAC,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEtC,6DAA6D;IAC7D,MAAM,CAAC,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtC;;;;OAIG;IACH,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAE1B;;;OAGG;IACH,KAAK,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAExB,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB"}
|
package/dist/cache/backend.js
CHANGED
|
@@ -12,22 +12,34 @@
|
|
|
12
12
|
* fingerprint composition stays in `ClassificationCache` so a backend
|
|
13
13
|
* swap doesn't change observable cache semantics.
|
|
14
14
|
*
|
|
15
|
-
* # CacheKey shape (Round
|
|
15
|
+
* # CacheKey shape (Round 3 — 2.36.0, cognium-ai#189)
|
|
16
16
|
*
|
|
17
17
|
* The Round-1 interface (`get(key: string)`) wasn't enough to express
|
|
18
18
|
* the per-namespace package-coordinate layout the R2 backend needs to
|
|
19
19
|
* surface in dashboards. We now pass a structured `{ namespace, digest,
|
|
20
|
-
* coordinate? }` so backends can render the path however
|
|
20
|
+
* coordinate?, modelSlug? }` so backends can render the path however
|
|
21
|
+
* they want:
|
|
21
22
|
*
|
|
22
|
-
* tree
|
|
23
|
-
*
|
|
24
|
-
* verify
|
|
25
|
-
*
|
|
23
|
+
* tree → `<prefix>/tree/<eco>/<name>@<ver>/<4hex>/<sha>.json` (coord)
|
|
24
|
+
* → `<prefix>/tree/_unowned/<4hex>/<sha>.json` (no coord)
|
|
25
|
+
* verify → `<prefix>/verify/<model-slug>/<4hex>/<sha>.json` (slug present)
|
|
26
|
+
* → `<prefix>/verify/<4hex>/<sha>.json` (no slug)
|
|
27
|
+
* discovery → `<prefix>/discovery/<model-slug>/<4hex>/<sha>.json` (slug present)
|
|
28
|
+
* → `<prefix>/discovery/<4hex>/<sha>.json` (no slug)
|
|
29
|
+
* classifier → analogous to verify/discovery
|
|
30
|
+
* cluster → `<prefix>/cluster/<4hex>/<sha>.json` (model-independent)
|
|
26
31
|
*
|
|
27
32
|
* Coordinate is intentionally tree-only: discovery and verify are
|
|
28
33
|
* keyed on method/batch content + model fingerprint, which already
|
|
29
34
|
* collide-correctly across packages without a coordinate prefix.
|
|
30
35
|
*
|
|
36
|
+
* `modelSlug` is intentionally non-tree: the tree cache is pattern-
|
|
37
|
+
* match (SAST) output that doesn't depend on any LLM. Splitting it by
|
|
38
|
+
* model would just fragment the cache. verify/discovery/classifier
|
|
39
|
+
* results are model-dependent and MUST NOT be shared between different
|
|
40
|
+
* discovery/verify models — a defense-in-depth against the digest-
|
|
41
|
+
* composition regressions that motivated Round 3 (cognium-ai#189).
|
|
42
|
+
*
|
|
31
43
|
* Selection: `LLM_CACHE_BACKEND` env (`local` | `memory` | `r2`).
|
|
32
44
|
* Default = `local` (back-compat). See `./backends/index.ts` factory.
|
|
33
45
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../../src/cache/backend.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["../../src/cache/backend.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG"}
|
|
@@ -11,14 +11,19 @@
|
|
|
11
11
|
* the backend, the structured `CacheKey` is rendered to a path via
|
|
12
12
|
* `renderObjectPath()`:
|
|
13
13
|
*
|
|
14
|
-
* tree+coord
|
|
15
|
-
* tree+nocoord
|
|
16
|
-
* verify
|
|
17
|
-
*
|
|
14
|
+
* tree+coord → `<eco>/<name>@<ver>/<4hex>/<sha>.json`
|
|
15
|
+
* tree+nocoord → `_unowned/<4hex>/<sha>.json`
|
|
16
|
+
* verify+slug → `<model-slug>/<4hex>/<sha>.json`
|
|
17
|
+
* verify+no slug → `<4hex>/<sha>.json`
|
|
18
|
+
* discovery+slug → `<model-slug>/<4hex>/<sha>.json`
|
|
19
|
+
* discovery+no slug → `<4hex>/<sha>.json`
|
|
20
|
+
* classifier+slug → `<model-slug>/<4hex>/<sha>.json`
|
|
21
|
+
* cluster (flat) → `<4hex>/<sha>.json`
|
|
18
22
|
*
|
|
19
|
-
* `R2_PREFIX` default
|
|
20
|
-
*
|
|
21
|
-
*
|
|
23
|
+
* `R2_PREFIX` default kept at `v2` for the Round 3 layout. The path-
|
|
24
|
+
* shape change is additive — flat 2.28.x entries stay readable, they
|
|
25
|
+
* just miss against Round-3 writes because `SCHEMA_VER` bumped v2→v3.
|
|
26
|
+
* Operators who want the pre-2.28 keys back can pin `R2_PREFIX=v1`.
|
|
22
27
|
*/
|
|
23
28
|
import type { CacheBackend, CacheNamespace } from '../backend.js';
|
|
24
29
|
import { LocalFSBackend } from './local-fs.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cache/backends/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cache/backends/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,SAAS,EAAE,CAAC;AAEpD,wBAAgB,cAAc,IAAI,OAAO,GAAG,QAAQ,GAAG,IAAI,CAK1D;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,GAAG,YAAY,CAoCrF"}
|
|
@@ -11,14 +11,19 @@
|
|
|
11
11
|
* the backend, the structured `CacheKey` is rendered to a path via
|
|
12
12
|
* `renderObjectPath()`:
|
|
13
13
|
*
|
|
14
|
-
* tree+coord
|
|
15
|
-
* tree+nocoord
|
|
16
|
-
* verify
|
|
17
|
-
*
|
|
14
|
+
* tree+coord → `<eco>/<name>@<ver>/<4hex>/<sha>.json`
|
|
15
|
+
* tree+nocoord → `_unowned/<4hex>/<sha>.json`
|
|
16
|
+
* verify+slug → `<model-slug>/<4hex>/<sha>.json`
|
|
17
|
+
* verify+no slug → `<4hex>/<sha>.json`
|
|
18
|
+
* discovery+slug → `<model-slug>/<4hex>/<sha>.json`
|
|
19
|
+
* discovery+no slug → `<4hex>/<sha>.json`
|
|
20
|
+
* classifier+slug → `<model-slug>/<4hex>/<sha>.json`
|
|
21
|
+
* cluster (flat) → `<4hex>/<sha>.json`
|
|
18
22
|
*
|
|
19
|
-
* `R2_PREFIX` default
|
|
20
|
-
*
|
|
21
|
-
*
|
|
23
|
+
* `R2_PREFIX` default kept at `v2` for the Round 3 layout. The path-
|
|
24
|
+
* shape change is additive — flat 2.28.x entries stay readable, they
|
|
25
|
+
* just miss against Round-3 writes because `SCHEMA_VER` bumped v2→v3.
|
|
26
|
+
* Operators who want the pre-2.28 keys back can pin `R2_PREFIX=v1`.
|
|
22
27
|
*/
|
|
23
28
|
import * as path from 'path';
|
|
24
29
|
import { LocalFSBackend } from './local-fs.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cache/backends/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cache/backends/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,SAAS,EAAE,CAAC;AAEpD,MAAM,UAAU,cAAc;IAC5B,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IACvE,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC9B,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IACtC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB,EAAE,SAAyB;IACrE,MAAM,IAAI,GAAG,cAAc,EAAE,CAAC;IAC9B,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,aAAa,EAAE,CAAC;IAElD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;QACzC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC;QACrC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;QACjD,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;QACzD,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,WAAW,IAAI,CAAC,eAAe,EAAE,CAAC;YAC7D,uDAAuD;YACvD,sCAAsC;YACtC,OAAO,CAAC,IAAI,CACV,6DAA6D;gBAC7D,wDAAwD;gBACxD,yCAAyC,CAC1C,CAAC;YACF,OAAO,IAAI,cAAc,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC1C,CAAC;QACD,MAAM,UAAU,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;QAC7E,OAAO,IAAI,SAAS,CAAC;YACnB,QAAQ;YACR,MAAM;YACN,WAAW;YACX,eAAe;YACf,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;YACvC,MAAM,EAAE,GAAG,UAAU,IAAI,SAAS,EAAE;SACrC,CAAC,CAAC;IACL,CAAC;IAED,oEAAoE;IACpE,+DAA+D;IAC/D,mCAAmC;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC;IACnD,MAAM,MAAM,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IAC9E,OAAO,IAAI,cAAc,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;AAClD,CAAC"}
|