@cejel/cejel 0.4.7 → 0.4.9
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/README.md +59 -24
- package/dist/calibration/llm-detector.js +5 -5
- package/dist/{chunk-UYJBSQCV.js → chunk-GKYTLWQK.js} +1 -1
- package/dist/{chunk-OIGCYULH.js → chunk-IHT7B6L7.js} +1 -1
- package/dist/{chunk-EP7YYWEP.js → chunk-IN2LPGGU.js} +2 -2
- package/dist/{chunk-XHAETB7N.js → chunk-IQ42TE5H.js} +1 -1
- package/dist/{chunk-ZNVILRHK.js → chunk-PTZU6G4E.js} +65 -20
- package/dist/{chunk-QTLLASOO.js → chunk-TUUNJP27.js} +473 -172
- package/dist/index.js +7 -5
- package/dist/mcp/index.js +5 -5
- package/dist/packs/d-series/index.js +4 -4
- package/dist/packs/decision-contracts/index.js +3 -3
- package/package.json +12 -15
package/README.md
CHANGED
|
@@ -20,12 +20,8 @@ portable, offline trust certificate that aggregates them. Pipe in SARIF-compatib
|
|
|
20
20
|
(MunaTrust, Snyk, Semgrep, CodeQL, Codex) plus OpenSSF Scorecard, and get one shareable
|
|
21
21
|
certificate + badge over all of them. See "Aggregate your scanners" below.
|
|
22
22
|
|
|
23
|
-
>
|
|
24
|
-
>
|
|
25
|
-
> 3.3/4.0 on its rubric-native certificate. That transparency snapshot opts into prospective
|
|
26
|
-
> v18; the public CLI default remains calibrated v17. On the comparative board, our code sits
|
|
27
|
-
> outside the ranked population and receives no verdict band. We score ourselves before
|
|
28
|
-
> asking you to score yourself.
|
|
23
|
+
> Cejel is used on Barg Labs’ own code. The [public board](https://cejel.dev/leaderboard/)
|
|
24
|
+
> labels publisher-owned snapshots separately from the ranked public repositories.
|
|
29
25
|
|
|
30
26
|
### Rubric calibration policy
|
|
31
27
|
|
|
@@ -93,7 +89,7 @@ if (-not $expected -or $actual -ne $expected.ToLowerInvariant()) {
|
|
|
93
89
|
```
|
|
94
90
|
|
|
95
91
|
> **Windows signing status:** `cejel-Windows-x86_64.exe` is intentionally unsigned in
|
|
96
|
-
> 0.4.
|
|
92
|
+
> 0.4.9 and may trigger Microsoft SmartScreen. The release build removes Node's inherited
|
|
97
93
|
> signature before SEA injection and fails unless Windows reports the result as `NotSigned`;
|
|
98
94
|
> it does not ship an invalid signature. Before running it, verify `SHA256SUMS` and the
|
|
99
95
|
> GitHub build-provenance attestation. Each binary also has an attached SPDX SBOM and an
|
|
@@ -116,7 +112,7 @@ docker run --rm --network=none -v "$PWD:/w" -w /w -v "$PWD/cejel:/cejel:ro" debi
|
|
|
116
112
|
npx @cejel/cejel@latest .
|
|
117
113
|
```
|
|
118
114
|
|
|
119
|
-
> **Distribution note:** Cejel `0.4.
|
|
115
|
+
> **Distribution note:** Cejel `0.4.9` is the coordinated release version for npm,
|
|
120
116
|
> standalone binaries, Docker/OCI, GitHub Action, Homebrew, and MCP Registry.
|
|
121
117
|
|
|
122
118
|
`npx` can reuse a stale cached package. Force the current npm release with the `@latest`
|
|
@@ -178,16 +174,16 @@ gh attestation verify ./cejel-Windows-x86_64.exe -R BargLabs/cejel
|
|
|
178
174
|
This is cryptographically signed provenance. It is distinct from Apple Developer ID or
|
|
179
175
|
Microsoft Authenticode code-signing.
|
|
180
176
|
|
|
181
|
-
**Docker / OCI.** The current container release is `0.4.
|
|
177
|
+
**Docker / OCI.** The current container release is `0.4.9`:
|
|
182
178
|
|
|
183
179
|
```bash
|
|
184
|
-
docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.4.
|
|
180
|
+
docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.4.9
|
|
185
181
|
```
|
|
186
182
|
|
|
187
183
|
The image defaults to `cejel-mcp` over stdio. To use the CLI instead:
|
|
188
184
|
|
|
189
185
|
```bash
|
|
190
|
-
docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.4.
|
|
186
|
+
docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.4.9 .
|
|
191
187
|
```
|
|
192
188
|
|
|
193
189
|
The OCI image carries an SBOM, maximum-mode build provenance, and a signed registry
|
|
@@ -195,17 +191,15 @@ attestation.
|
|
|
195
191
|
|
|
196
192
|
## Leaderboard
|
|
197
193
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
locations are not publicly available, so that row is not independently reproducible and is
|
|
208
|
-
not presented as a public-repository self-score.
|
|
194
|
+
The [Cejel OSS trust leaderboard](https://cejel.dev/leaderboard/) is hosted on cejel.dev,
|
|
195
|
+
which is the single current board. This repository no longer distributes a second copy of
|
|
196
|
+
its scores or certificates. The board records its producing package version, rubric,
|
|
197
|
+
run date, pinned public revisions, and reproduction instructions for that particular run.
|
|
198
|
+
The private Alfred transparency snapshot is not independently reproducible.
|
|
199
|
+
|
|
200
|
+
The site's History section preserves the **2026-08-18 withdrawal**: the earlier
|
|
201
|
+
sealed-public-scorer reproducibility claim was false. The stale prospective-rubric copy
|
|
202
|
+
previously linked here has been removed; it must not be treated as current evidence.
|
|
209
203
|
|
|
210
204
|
### Redaction policy
|
|
211
205
|
|
|
@@ -519,7 +513,7 @@ The OCI image is an alternative when Docker is the preferred execution boundary.
|
|
|
519
513
|
the host path with the repository OpenClaw should allow Cejel to read:
|
|
520
514
|
|
|
521
515
|
```bash
|
|
522
|
-
npx -y openclaw@latest mcp set cejel-oci '{"command":"docker","args":["run","--rm","-i","-v","/absolute/path/to/repo:/workspace:ro","ghcr.io/barglabs/cejel:0.4.
|
|
516
|
+
npx -y openclaw@latest mcp set cejel-oci '{"command":"docker","args":["run","--rm","-i","-v","/absolute/path/to/repo:/workspace:ro","ghcr.io/barglabs/cejel:0.4.9"]}'
|
|
523
517
|
npx -y openclaw@latest mcp doctor cejel-oci --probe
|
|
524
518
|
```
|
|
525
519
|
|
|
@@ -546,6 +540,47 @@ part of the scoring guarantee. If the tracked-file inventory fails unexpectedly,
|
|
|
546
540
|
HTML, and markdown certificates declare that the scanner used its bounded directory fallback
|
|
547
541
|
instead of silently presenting the two inventories as equivalent.
|
|
548
542
|
|
|
543
|
+
## What a certificate's scope means
|
|
544
|
+
|
|
545
|
+
A certificate scores the repository tree at one pinned revision, and only that tree. That
|
|
546
|
+
boundary is deliberate: a certificate that reached outside the pinned tree could not be
|
|
547
|
+
reproduced by whoever receives it, and reproducibility is the entire product. Scoring only the
|
|
548
|
+
pinned tree is correct — the gap was that nothing on the certificate itself told a reader which
|
|
549
|
+
kind of statement they were holding. A repository whose regression suite lives in a separate
|
|
550
|
+
repository, checked out and run by its own CI, is correctly reported as having zero test files
|
|
551
|
+
against its source files. That statement is true about the tree and false about the system, and a
|
|
552
|
+
reader with no other context cannot tell the difference.
|
|
553
|
+
|
|
554
|
+
Every certificate now carries a standing scope line, in the "How to read this certificate"
|
|
555
|
+
section on every surface (HTML, Markdown, terminal), regardless of verdict: the certificate is a
|
|
556
|
+
statement about the repository tree at the pinned revision, not about the system that tree
|
|
557
|
+
belongs to, and evidence outside that tree is neither seen nor claimed to be absent. This is
|
|
558
|
+
additive, not a hedge — a finding that says evidence was not found in this tree stays exactly as
|
|
559
|
+
stated.
|
|
560
|
+
|
|
561
|
+
Four specific situations can make the tree's own conclusion misleading about the system it
|
|
562
|
+
belongs to:
|
|
563
|
+
|
|
564
|
+
- **A test suite kept in a separate repository.** Not detectable from inside the pinned tree —
|
|
565
|
+
there is no reliable signal that a sibling repository exists. Covered by the standing scope
|
|
566
|
+
line above, not a conditional disclosure.
|
|
567
|
+
- **CI configuration that changes into a different working directory before running its checks.**
|
|
568
|
+
Also not detectable without executing the CI job itself, which the offline scanner does not do.
|
|
569
|
+
Covered by the standing scope line above.
|
|
570
|
+
- **A large implementation file that exceeds the read limit.** This one is detectable, and
|
|
571
|
+
disclosed conditionally when it happens: when a file above the size ceiling is the reason a
|
|
572
|
+
specific signal has nothing to measure, the certificate's scan-limitations section names it —
|
|
573
|
+
"declined a large implementation file that exceeded the repository content size limit" — rather
|
|
574
|
+
than folding it into the generic coverage-limit sentence used for an extension exclusion or a
|
|
575
|
+
non-regular file. Today this fires for two A3 signals (health/readiness route detection and
|
|
576
|
+
observability-marker counting); it extends to more signals as they adopt the same per-signal
|
|
577
|
+
attribution.
|
|
578
|
+
- **A recognized-but-nonfunctional package script**, such as npm's auto-generated
|
|
579
|
+
`"test": "echo \"Error: no test specified\" && exit 1"` placeholder being credited the same as a
|
|
580
|
+
real test runner. This was a detector defect, not a scope-disclosure gap — Cejel now checks the
|
|
581
|
+
`test` script's content against known test-runner invocations rather than crediting it by key
|
|
582
|
+
presence alone, so no separate disclosure line is needed for it.
|
|
583
|
+
|
|
549
584
|
## Help validate Cejel
|
|
550
585
|
|
|
551
586
|
Cejel does not collect telemetry. External validation is therefore opt-in and inspectable:
|
|
@@ -680,7 +715,7 @@ published in public.
|
|
|
680
715
|
|
|
681
716
|
**No rubric change re-scores you silently.** Every change to scoring behavior requires a
|
|
682
717
|
`WITAN_RUBRIC_VERSION` bump and a corpus-wide before/after delta published in
|
|
683
|
-
[`
|
|
718
|
+
[`leaderboard/RUBRIC_CHANGELOG.md`](./leaderboard/RUBRIC_CHANGELOG.md) — score,
|
|
684
719
|
verdict, and rank for every repository, "no repository moved" stated explicitly when that is
|
|
685
720
|
the result. A build that changes scoring without both fails; see that file's `v2` entry for
|
|
686
721
|
the home-field fix above as the first rubric change recorded this way.
|
|
@@ -5,20 +5,20 @@ import {
|
|
|
5
5
|
deriveProductIdentity,
|
|
6
6
|
runCejelScan,
|
|
7
7
|
serializeWitanReport
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-TUUNJP27.js";
|
|
9
9
|
import {
|
|
10
10
|
listCejelLlmPackFiles
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
11
|
+
} from "../chunk-IN2LPGGU.js";
|
|
12
|
+
import "../chunk-IHT7B6L7.js";
|
|
13
13
|
import {
|
|
14
14
|
external_exports
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-GKYTLWQK.js";
|
|
16
16
|
import {
|
|
17
17
|
init_esm_shims,
|
|
18
18
|
readRepoText,
|
|
19
19
|
recordContentSkip,
|
|
20
20
|
recordFilesystemSkip
|
|
21
|
-
} from "../chunk-
|
|
21
|
+
} from "../chunk-PTZU6G4E.js";
|
|
22
22
|
|
|
23
23
|
// src/calibration/llm-detector.ts
|
|
24
24
|
init_esm_shims();
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
describeGitFailure,
|
|
6
6
|
execGit,
|
|
7
7
|
isExpectedGitAbsence
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-IHT7B6L7.js";
|
|
9
9
|
import {
|
|
10
10
|
init_esm_shims
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-PTZU6G4E.js";
|
|
12
12
|
|
|
13
13
|
// src/packs/llm/files.ts
|
|
14
14
|
init_esm_shims();
|
|
@@ -62,28 +62,58 @@ var MAX_REPOSITORY_CONTENT_BYTES = 512e3;
|
|
|
62
62
|
init_esm_shims();
|
|
63
63
|
import { closeSync, lstatSync, openSync, readFileSync, readSync } from "fs";
|
|
64
64
|
import { resolve } from "path";
|
|
65
|
+
var READ_FAILURE_REASONS = /* @__PURE__ */ new Set(["unreadable", "denied_path"]);
|
|
66
|
+
function isReadFailureReason(reason) {
|
|
67
|
+
return READ_FAILURE_REASONS.has(reason);
|
|
68
|
+
}
|
|
69
|
+
function classifyAbstentionReason(reasons) {
|
|
70
|
+
if (!reasons || reasons.size === 0) return {};
|
|
71
|
+
for (const reason of reasons) {
|
|
72
|
+
if (isReadFailureReason(reason)) return {};
|
|
73
|
+
}
|
|
74
|
+
const priority = [
|
|
75
|
+
"too_large",
|
|
76
|
+
"excluded_by_extension",
|
|
77
|
+
"non_regular_file"
|
|
78
|
+
];
|
|
79
|
+
const chosen = priority.find((reason) => reasons.has(reason));
|
|
80
|
+
return chosen ? { insufficientDataReason: chosen } : {};
|
|
81
|
+
}
|
|
65
82
|
function contentReadSignalKey(criterionId, signalId) {
|
|
66
83
|
return [criterionId, signalId].join(":");
|
|
67
84
|
}
|
|
68
85
|
var activeSession;
|
|
86
|
+
function addSkipReason(map, key, reason) {
|
|
87
|
+
const existing = map.get(key);
|
|
88
|
+
if (existing) {
|
|
89
|
+
existing.add(reason);
|
|
90
|
+
} else {
|
|
91
|
+
map.set(key, /* @__PURE__ */ new Set([reason]));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
69
94
|
function errnoClass(error) {
|
|
70
95
|
if (typeof error !== "object" || error === null || !("code" in error)) return null;
|
|
71
96
|
const code = error.code;
|
|
72
97
|
return typeof code === "string" && /^E[A-Z0-9_]+$/.test(code) ? code : null;
|
|
73
98
|
}
|
|
99
|
+
function attributeSkip(session, criterion, signals, reason) {
|
|
100
|
+
session.affectedCriteria.add(criterion);
|
|
101
|
+
if (signals && signals.length > 0) {
|
|
102
|
+
for (const signal of signals) {
|
|
103
|
+
const key = contentReadSignalKey(criterion, signal);
|
|
104
|
+
session.affectedSignals.add(key);
|
|
105
|
+
addSkipReason(session.signalSkipReasons, key, reason);
|
|
106
|
+
}
|
|
107
|
+
} else {
|
|
108
|
+
session.unattributedCriteria.add(criterion);
|
|
109
|
+
addSkipReason(session.criterionSkipReasons, criterion, reason);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
74
112
|
function recordSkip(path2, reason, errno, affectsCurrentCriterion = false, deduplicate = false) {
|
|
75
113
|
const session = activeSession;
|
|
76
114
|
if (!session) return;
|
|
77
115
|
if (affectsCurrentCriterion && session.criterion) {
|
|
78
|
-
session.
|
|
79
|
-
const signals = session.signals;
|
|
80
|
-
if (signals && signals.length > 0) {
|
|
81
|
-
for (const signal of signals) {
|
|
82
|
-
session.affectedSignals.add(contentReadSignalKey(session.criterion, signal));
|
|
83
|
-
}
|
|
84
|
-
} else {
|
|
85
|
-
session.unattributedCriteria.add(session.criterion);
|
|
86
|
-
}
|
|
116
|
+
attributeSkip(session, session.criterion, session.signals, reason);
|
|
87
117
|
}
|
|
88
118
|
if (deduplicate) {
|
|
89
119
|
const key = `${resolve(path2)}\0${reason}\0${errno ?? ""}`;
|
|
@@ -121,7 +151,9 @@ function trackContentReads(_repoPath, collect) {
|
|
|
121
151
|
summary: summaryFor(existing),
|
|
122
152
|
affectedCriteria: existing.affectedCriteria,
|
|
123
153
|
affectedSignals: existing.affectedSignals,
|
|
124
|
-
unattributedCriteria: existing.unattributedCriteria
|
|
154
|
+
unattributedCriteria: existing.unattributedCriteria,
|
|
155
|
+
criterionSkipReasons: existing.criterionSkipReasons,
|
|
156
|
+
signalSkipReasons: existing.signalSkipReasons
|
|
125
157
|
};
|
|
126
158
|
}
|
|
127
159
|
const session = {
|
|
@@ -136,7 +168,10 @@ function trackContentReads(_repoPath, collect) {
|
|
|
136
168
|
deduplicatedSkips: /* @__PURE__ */ new Set(),
|
|
137
169
|
affectedCriteria: /* @__PURE__ */ new Set(),
|
|
138
170
|
affectedSignals: /* @__PURE__ */ new Set(),
|
|
139
|
-
unattributedCriteria: /* @__PURE__ */ new Set()
|
|
171
|
+
unattributedCriteria: /* @__PURE__ */ new Set(),
|
|
172
|
+
criterionSkipReasons: /* @__PURE__ */ new Map(),
|
|
173
|
+
signalSkipReasons: /* @__PURE__ */ new Map(),
|
|
174
|
+
withheldPaths: /* @__PURE__ */ new Map()
|
|
140
175
|
};
|
|
141
176
|
activeSession = session;
|
|
142
177
|
try {
|
|
@@ -146,7 +181,9 @@ function trackContentReads(_repoPath, collect) {
|
|
|
146
181
|
summary: summaryFor(session),
|
|
147
182
|
affectedCriteria: session.affectedCriteria,
|
|
148
183
|
affectedSignals: session.affectedSignals,
|
|
149
|
-
unattributedCriteria: session.unattributedCriteria
|
|
184
|
+
unattributedCriteria: session.unattributedCriteria,
|
|
185
|
+
criterionSkipReasons: session.criterionSkipReasons,
|
|
186
|
+
signalSkipReasons: session.signalSkipReasons
|
|
150
187
|
};
|
|
151
188
|
} finally {
|
|
152
189
|
activeSession = void 0;
|
|
@@ -183,15 +220,21 @@ function withContentReadSignals(criterionId, signalIds, collect) {
|
|
|
183
220
|
function recordContentSkip(path2, reason, deduplicate = false) {
|
|
184
221
|
recordSkip(path2, reason, void 0, false, deduplicate);
|
|
185
222
|
}
|
|
186
|
-
function
|
|
223
|
+
function registerWithheldRepoPath(relativePath, reason) {
|
|
187
224
|
const session = activeSession;
|
|
188
|
-
if (session)
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
225
|
+
if (!session) return;
|
|
226
|
+
addSkipReason(session.withheldPaths, relativePath, reason);
|
|
227
|
+
}
|
|
228
|
+
function abstainSignalOnWithheldPaths(criterionId, signalId, wouldHaveRead) {
|
|
229
|
+
const session = activeSession;
|
|
230
|
+
if (!session) return false;
|
|
231
|
+
let abstained = false;
|
|
232
|
+
for (const [path2, reasons] of session.withheldPaths) {
|
|
233
|
+
if (!wouldHaveRead(path2)) continue;
|
|
234
|
+
abstained = true;
|
|
235
|
+
for (const reason of reasons) attributeSkip(session, criterionId, [signalId], reason);
|
|
193
236
|
}
|
|
194
|
-
|
|
237
|
+
return abstained;
|
|
195
238
|
}
|
|
196
239
|
function recordFilesystemSkip(path2, error, deniedContext = false, deduplicate = true) {
|
|
197
240
|
const errno = errnoClass(error);
|
|
@@ -264,13 +307,15 @@ export {
|
|
|
264
307
|
__filename,
|
|
265
308
|
init_esm_shims,
|
|
266
309
|
MAX_REPOSITORY_CONTENT_BYTES,
|
|
310
|
+
classifyAbstentionReason,
|
|
267
311
|
contentReadSignalKey,
|
|
268
312
|
trackContentReads,
|
|
269
313
|
withContentReadCriterion,
|
|
270
314
|
withContentReadSignal,
|
|
271
315
|
withContentReadSignals,
|
|
272
316
|
recordContentSkip,
|
|
273
|
-
|
|
317
|
+
registerWithheldRepoPath,
|
|
318
|
+
abstainSignalOnWithheldPaths,
|
|
274
319
|
recordFilesystemSkip,
|
|
275
320
|
readRepoText,
|
|
276
321
|
readRepoTextPrefix
|