@cejel/cejel 0.4.8 → 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-J6R5OHN7.js → chunk-GKYTLWQK.js} +1 -1
- package/dist/{chunk-KNQBI3IX.js → chunk-IHT7B6L7.js} +1 -1
- package/dist/{chunk-ERNYMFH4.js → chunk-IN2LPGGU.js} +2 -2
- package/dist/{chunk-ZPQOZLB7.js → chunk-IQ42TE5H.js} +1 -1
- package/dist/{chunk-V3B2V4WA.js → chunk-PTZU6G4E.js} +34 -13
- package/dist/{chunk-6R3VJGJ2.js → chunk-TUUNJP27.js} +224 -84
- package/dist/index.js +5 -4
- package/dist/mcp/index.js +4 -4
- 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();
|
|
@@ -96,22 +96,24 @@ function errnoClass(error) {
|
|
|
96
96
|
const code = error.code;
|
|
97
97
|
return typeof code === "string" && /^E[A-Z0-9_]+$/.test(code) ? code : null;
|
|
98
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
|
+
}
|
|
99
112
|
function recordSkip(path2, reason, errno, affectsCurrentCriterion = false, deduplicate = false) {
|
|
100
113
|
const session = activeSession;
|
|
101
114
|
if (!session) return;
|
|
102
115
|
if (affectsCurrentCriterion && session.criterion) {
|
|
103
|
-
session.
|
|
104
|
-
const signals = session.signals;
|
|
105
|
-
if (signals && signals.length > 0) {
|
|
106
|
-
for (const signal of signals) {
|
|
107
|
-
const key = contentReadSignalKey(session.criterion, signal);
|
|
108
|
-
session.affectedSignals.add(key);
|
|
109
|
-
addSkipReason(session.signalSkipReasons, key, reason);
|
|
110
|
-
}
|
|
111
|
-
} else {
|
|
112
|
-
session.unattributedCriteria.add(session.criterion);
|
|
113
|
-
addSkipReason(session.criterionSkipReasons, session.criterion, reason);
|
|
114
|
-
}
|
|
116
|
+
attributeSkip(session, session.criterion, session.signals, reason);
|
|
115
117
|
}
|
|
116
118
|
if (deduplicate) {
|
|
117
119
|
const key = `${resolve(path2)}\0${reason}\0${errno ?? ""}`;
|
|
@@ -168,7 +170,8 @@ function trackContentReads(_repoPath, collect) {
|
|
|
168
170
|
affectedSignals: /* @__PURE__ */ new Set(),
|
|
169
171
|
unattributedCriteria: /* @__PURE__ */ new Set(),
|
|
170
172
|
criterionSkipReasons: /* @__PURE__ */ new Map(),
|
|
171
|
-
signalSkipReasons: /* @__PURE__ */ new Map()
|
|
173
|
+
signalSkipReasons: /* @__PURE__ */ new Map(),
|
|
174
|
+
withheldPaths: /* @__PURE__ */ new Map()
|
|
172
175
|
};
|
|
173
176
|
activeSession = session;
|
|
174
177
|
try {
|
|
@@ -217,6 +220,22 @@ function withContentReadSignals(criterionId, signalIds, collect) {
|
|
|
217
220
|
function recordContentSkip(path2, reason, deduplicate = false) {
|
|
218
221
|
recordSkip(path2, reason, void 0, false, deduplicate);
|
|
219
222
|
}
|
|
223
|
+
function registerWithheldRepoPath(relativePath, reason) {
|
|
224
|
+
const session = activeSession;
|
|
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);
|
|
236
|
+
}
|
|
237
|
+
return abstained;
|
|
238
|
+
}
|
|
220
239
|
function recordFilesystemSkip(path2, error, deniedContext = false, deduplicate = true) {
|
|
221
240
|
const errno = errnoClass(error);
|
|
222
241
|
if (!errno) throw error;
|
|
@@ -295,6 +314,8 @@ export {
|
|
|
295
314
|
withContentReadSignal,
|
|
296
315
|
withContentReadSignals,
|
|
297
316
|
recordContentSkip,
|
|
317
|
+
registerWithheldRepoPath,
|
|
318
|
+
abstainSignalOnWithheldPaths,
|
|
298
319
|
recordFilesystemSkip,
|
|
299
320
|
readRepoText,
|
|
300
321
|
readRepoTextPrefix
|
|
@@ -5,12 +5,13 @@ import {
|
|
|
5
5
|
describeGitFailure,
|
|
6
6
|
execGit,
|
|
7
7
|
isExpectedGitAbsence
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-IHT7B6L7.js";
|
|
9
9
|
import {
|
|
10
10
|
external_exports
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-GKYTLWQK.js";
|
|
12
12
|
import {
|
|
13
13
|
MAX_REPOSITORY_CONTENT_BYTES,
|
|
14
|
+
abstainSignalOnWithheldPaths,
|
|
14
15
|
classifyAbstentionReason,
|
|
15
16
|
contentReadSignalKey,
|
|
16
17
|
init_esm_shims,
|
|
@@ -18,11 +19,12 @@ import {
|
|
|
18
19
|
readRepoTextPrefix,
|
|
19
20
|
recordContentSkip,
|
|
20
21
|
recordFilesystemSkip,
|
|
22
|
+
registerWithheldRepoPath,
|
|
21
23
|
trackContentReads,
|
|
22
24
|
withContentReadCriterion,
|
|
23
25
|
withContentReadSignal,
|
|
24
26
|
withContentReadSignals
|
|
25
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-PTZU6G4E.js";
|
|
26
28
|
|
|
27
29
|
// src/witan/schemas.ts
|
|
28
30
|
init_esm_shims();
|
|
@@ -313,6 +315,16 @@ var WitanReportCommonSchema = external_exports.object({
|
|
|
313
315
|
productDisplayName: external_exports.string().min(1).max(120),
|
|
314
316
|
repo: WitanRepoRefSchema,
|
|
315
317
|
rubricVersion: external_exports.string().min(1).max(120),
|
|
318
|
+
// The BEHAVIOURAL identity of the rubric named above, beside its NAME. `rubricVersion` is an
|
|
319
|
+
// identifier the tool's author controls and can leave unchanged across a scoring change (this
|
|
320
|
+
// happened under witan-rubric-v17-2026-07-24 in 0.4.9 — see leaderboard/RUBRIC_CHANGELOG.md).
|
|
321
|
+
// This field is the sha256 of the scoring-relevant output of a fixed committed fixture corpus
|
|
322
|
+
// under that rubric, so two certificates naming the same rubric can be checked for behavioural
|
|
323
|
+
// agreement rather than assumed into it. See src/witan/rubric-fingerprint.ts for exactly what
|
|
324
|
+
// the digest covers, what it excludes, and what it does not claim. Optional and absent —
|
|
325
|
+
// never fabricated — for any rubric this build has no measurement for, and absent on every
|
|
326
|
+
// report emitted before report format 1.2; those artifacts' attestations remain valid.
|
|
327
|
+
rubricBehaviourFingerprint: external_exports.string().regex(/^sha256:[a-f0-9]{64}$/).optional(),
|
|
316
328
|
// Rubric-driven: length matches whatever rubric produced this report, not a fixed enum.
|
|
317
329
|
criteria: external_exports.array(WitanCriterionScoreSchema).min(1),
|
|
318
330
|
consumedSignals: external_exports.array(WitanConsumedSignalSummarySchema).optional(),
|
|
@@ -366,7 +378,7 @@ var WitanReportSchema = external_exports.preprocess((value) => {
|
|
|
366
378
|
}, StrictWitanReportSchema);
|
|
367
379
|
var WITAN_ATTESTATION_STATEMENT_TYPE = "https://in-toto.io/Statement/v1";
|
|
368
380
|
var WITAN_ATTESTATION_PREDICATE_TYPE = "https://cejel.dev/attestations/scan/v1";
|
|
369
|
-
var WITAN_REPORT_FORMAT_VERSION = "1.
|
|
381
|
+
var WITAN_REPORT_FORMAT_VERSION = "1.2";
|
|
370
382
|
var WitanAttestationOutcomeSchema = external_exports.discriminatedUnion("status", [
|
|
371
383
|
external_exports.object({
|
|
372
384
|
status: external_exports.literal("scored"),
|
|
@@ -584,6 +596,7 @@ init_esm_shims();
|
|
|
584
596
|
// src/witan/certificate-presentation.ts
|
|
585
597
|
init_esm_shims();
|
|
586
598
|
var CALLER_CONTEXT_PRODUCT_IDENTITY_NOTICE = "Product name and slug are caller context and are excluded from certificate byte-comparison claims.";
|
|
599
|
+
var CERTIFICATE_SCOPE_NOTICE = "This certificate is a statement about the repository tree at the revision pinned above, not about the system that tree is part of. Evidence outside that tree \u2014 for example, a test suite kept in a separate repository, or CI configuration that changes into a different working directory before running its checks \u2014 is neither seen by this scan nor claimed to be absent.";
|
|
587
600
|
var CERTIFICATE_METRIC_REGISTRY = {
|
|
588
601
|
test_to_source_ratio: { displayLabel: "Test-to-source file ratio" },
|
|
589
602
|
coverage_percent: { displayLabel: "Static coverage percentage" },
|
|
@@ -1097,6 +1110,7 @@ function buildRelyingPartySummary(report) {
|
|
|
1097
1110
|
"Anything absent from the measured evidence was not established: no measurement and no finding are not clearance."
|
|
1098
1111
|
);
|
|
1099
1112
|
return {
|
|
1113
|
+
scope: CERTIFICATE_SCOPE_NOTICE,
|
|
1100
1114
|
examined: `Cejel examined the repository evidence recorded for ${report.productDisplayName}${revision} under ${report.rubricVersion}.`,
|
|
1101
1115
|
established: `The report established measured results for ${measured.length} of ${applicable.length} applicable rubric dimensions and recorded ${findings} evidence-backed finding${findings === 1 ? "" : "s"}.`,
|
|
1102
1116
|
notEstablished: gaps.join(" "),
|
|
@@ -1309,6 +1323,7 @@ function renderRelyingPartySummary(summary) {
|
|
|
1309
1323
|
return `<section class="relying-party-summary" aria-labelledby="relying-party-heading">
|
|
1310
1324
|
<h2 id="relying-party-heading">How to read this certificate</h2>
|
|
1311
1325
|
<dl>
|
|
1326
|
+
<div><dt>Scope</dt><dd>${escapeHtml(summary.scope)}</dd></div>
|
|
1312
1327
|
<div><dt>What was examined</dt><dd>${escapeHtml(summary.examined)}</dd></div>
|
|
1313
1328
|
<div><dt>What was established</dt><dd>${escapeHtml(summary.established)}</dd></div>
|
|
1314
1329
|
<div><dt>What was not established</dt><dd>${escapeHtml(summary.notEstablished)}</dd></div>
|
|
@@ -2093,13 +2108,14 @@ function buildWitanInputFromRepo(options) {
|
|
|
2093
2108
|
const wholesaleAbstainedReadFailureCriteria = [];
|
|
2094
2109
|
const wholesaleAbstainedCoverageLimitedCriteria = [];
|
|
2095
2110
|
const partiallyAbstainedReadFailureSignals = [];
|
|
2096
|
-
const
|
|
2111
|
+
const partiallyAbstainedLargeFileSignals = [];
|
|
2112
|
+
const partiallyAbstainedOtherCoverageLimitedSignals = [];
|
|
2097
2113
|
const signals = (tracked.value.signals ?? []).map((signal) => {
|
|
2098
2114
|
if (!affectedCriteria.has(signal.criterionId)) return signal;
|
|
2099
2115
|
if (tracked.unattributedCriteria.has(signal.criterionId)) {
|
|
2100
2116
|
const reasons = tracked.criterionSkipReasons.get(signal.criterionId);
|
|
2101
|
-
const { insufficientDataReason
|
|
2102
|
-
(
|
|
2117
|
+
const { insufficientDataReason } = classifyAbstentionReason(reasons);
|
|
2118
|
+
(insufficientDataReason !== void 0 ? wholesaleAbstainedCoverageLimitedCriteria : wholesaleAbstainedReadFailureCriteria).push(signal.criterionId);
|
|
2103
2119
|
return wholesaleCriterionAbstention(signal, reasons);
|
|
2104
2120
|
}
|
|
2105
2121
|
const prefix = contentReadSignalKey(signal.criterionId, "");
|
|
@@ -2118,40 +2134,63 @@ function buildWitanInputFromRepo(options) {
|
|
|
2118
2134
|
}
|
|
2119
2135
|
}
|
|
2120
2136
|
if (!anythingSurvives) {
|
|
2121
|
-
const { insufficientDataReason
|
|
2122
|
-
(
|
|
2137
|
+
const { insufficientDataReason } = classifyAbstentionReason(droppedReasons);
|
|
2138
|
+
(insufficientDataReason !== void 0 ? wholesaleAbstainedCoverageLimitedCriteria : wholesaleAbstainedReadFailureCriteria).push(signal.criterionId);
|
|
2123
2139
|
return wholesaleCriterionAbstention(signal, droppedReasons);
|
|
2124
2140
|
}
|
|
2125
|
-
const
|
|
2126
|
-
const isReadFailure = insufficientDataReason === void 0;
|
|
2141
|
+
const nameBuckets = /* @__PURE__ */ new Map();
|
|
2127
2142
|
for (const name of affectedNames) {
|
|
2128
|
-
|
|
2129
|
-
|
|
2143
|
+
const nameReasons = skipReasonsForSignal(signal.criterionId, name, tracked);
|
|
2144
|
+
const { insufficientDataReason: nameReason } = classifyAbstentionReason(nameReasons);
|
|
2145
|
+
const bucket = nameReason === void 0 ? "read-failure" : nameReason === "too_large" ? "too-large" : "other-coverage";
|
|
2146
|
+
nameBuckets.set(name, bucket);
|
|
2147
|
+
(bucket === "read-failure" ? partiallyAbstainedReadFailureSignals : bucket === "too-large" ? partiallyAbstainedLargeFileSignals : partiallyAbstainedOtherCoverageLimitedSignals).push(`${signal.criterionId}.${name}`);
|
|
2148
|
+
}
|
|
2149
|
+
const distinctBuckets = new Set(nameBuckets.values());
|
|
2150
|
+
const uniformBucket = distinctBuckets.size === 1 ? [...distinctBuckets][0] : void 0;
|
|
2151
|
+
const affectedList = [...affectedNames].sort().join(", ");
|
|
2152
|
+
const notes = uniformBucket === "read-failure" ? `Cejel abstained on ${affectedList} in this criterion because that content could not be read; other signals in this criterion were computed from readable files and are unaffected.` : uniformBucket === "too-large" ? `Cejel declined ${affectedList} in this criterion under the repository content size limit; other signals in this criterion were computed from readable files and are unaffected. This is a disclosed coverage limit, not a read failure.` : uniformBucket === "other-coverage" ? `Cejel declined ${affectedList} in this criterion under an extension exclusion or a non-regular-file skip; other signals in this criterion were computed from readable files and are unaffected. This is a disclosed coverage limit, not a read failure.` : `Cejel abstained on ${affectedList} in this criterion for a mix of reasons \u2014 some content could not be read, some was declined under the repository content size limit or an extension exclusion; other signals in this criterion were computed from readable files and are unaffected.`;
|
|
2130
2153
|
return {
|
|
2131
2154
|
...signal,
|
|
2132
2155
|
metrics,
|
|
2133
|
-
notes
|
|
2156
|
+
notes
|
|
2134
2157
|
};
|
|
2135
2158
|
});
|
|
2136
2159
|
const scanLimitations = [...tracked.value.scanLimitations ?? []];
|
|
2137
|
-
|
|
2138
|
-
|
|
2160
|
+
const candidateScanLimitations = [];
|
|
2161
|
+
if (wholesaleAbstainedReadFailureCriteria.length > 0) {
|
|
2162
|
+
candidateScanLimitations.push(
|
|
2139
2163
|
`${wholesaleAbstainedReadFailureCriteria.length} ${wholesaleAbstainedReadFailureCriteria.length === 1 ? "criterion" : "criteria"} abstained because relevant repository content could not be read and the affected signal could not be isolated. Counts and errno classes are recorded in contentReadSummary; file paths are intentionally omitted.`
|
|
2140
2164
|
);
|
|
2141
2165
|
}
|
|
2142
|
-
if (wholesaleAbstainedCoverageLimitedCriteria.length > 0
|
|
2143
|
-
|
|
2166
|
+
if (wholesaleAbstainedCoverageLimitedCriteria.length > 0) {
|
|
2167
|
+
candidateScanLimitations.push(
|
|
2144
2168
|
`${wholesaleAbstainedCoverageLimitedCriteria.length} ${wholesaleAbstainedCoverageLimitedCriteria.length === 1 ? "criterion" : "criteria"} abstained because relevant repository content was declined under the repository content size limit or excluded from scanning by policy, and the affected signal could not be isolated. This is a disclosed coverage limit, not a read failure, and does not affect the composite score.`
|
|
2145
2169
|
);
|
|
2146
2170
|
}
|
|
2147
|
-
if (partiallyAbstainedReadFailureSignals.length > 0
|
|
2148
|
-
|
|
2171
|
+
if (partiallyAbstainedReadFailureSignals.length > 0) {
|
|
2172
|
+
candidateScanLimitations.push(
|
|
2149
2173
|
`${partiallyAbstainedReadFailureSignals.length} ${partiallyAbstainedReadFailureSignals.length === 1 ? "signal" : "signals"} abstained because its own repository content could not be read, while other signals in the same criterion were unaffected: ${[...partiallyAbstainedReadFailureSignals].sort().join(", ")}.`
|
|
2150
2174
|
);
|
|
2151
2175
|
}
|
|
2152
|
-
if (
|
|
2176
|
+
if (partiallyAbstainedLargeFileSignals.length > 0) {
|
|
2177
|
+
candidateScanLimitations.push(
|
|
2178
|
+
`${partiallyAbstainedLargeFileSignals.length} ${partiallyAbstainedLargeFileSignals.length === 1 ? "signal" : "signals"} declined a large implementation file that exceeded the repository content size limit, while other signals in the same criterion were unaffected: ${[...partiallyAbstainedLargeFileSignals].sort().join(", ")}. That file is undercounted, not scored as clean or absent \u2014 this is a disclosed coverage limit, not a read failure.`
|
|
2179
|
+
);
|
|
2180
|
+
}
|
|
2181
|
+
if (partiallyAbstainedOtherCoverageLimitedSignals.length > 0) {
|
|
2182
|
+
candidateScanLimitations.push(
|
|
2183
|
+
`${partiallyAbstainedOtherCoverageLimitedSignals.length} ${partiallyAbstainedOtherCoverageLimitedSignals.length === 1 ? "signal" : "signals"} declined under an extension exclusion or a non-regular-file skip, while other signals in the same criterion were unaffected: ${[...partiallyAbstainedOtherCoverageLimitedSignals].sort().join(", ")}. This is a disclosed coverage limit, not a read failure.`
|
|
2184
|
+
);
|
|
2185
|
+
}
|
|
2186
|
+
const availableSlots = Math.max(0, 16 - scanLimitations.length);
|
|
2187
|
+
if (candidateScanLimitations.length <= availableSlots) {
|
|
2188
|
+
scanLimitations.push(...candidateScanLimitations);
|
|
2189
|
+
} else if (availableSlots > 0) {
|
|
2190
|
+
const keep = availableSlots - 1;
|
|
2191
|
+
scanLimitations.push(...candidateScanLimitations.slice(0, keep));
|
|
2153
2192
|
scanLimitations.push(
|
|
2154
|
-
`${
|
|
2193
|
+
`${candidateScanLimitations.length - keep} additional disclosed scan limitation(s) omitted at the 16-entry cap \u2014 see contentReadSummary for full counts.`
|
|
2155
2194
|
);
|
|
2156
2195
|
}
|
|
2157
2196
|
return {
|
|
@@ -2182,6 +2221,7 @@ function buildWitanInputFromRepoUntracked(options) {
|
|
|
2182
2221
|
const usesV22PackageStartEntrypoint = rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23;
|
|
2183
2222
|
const usesV23CommandCoverage = rubricVersion === WITAN_RUBRIC_VERSION_V23;
|
|
2184
2223
|
const usesV23PemPrivateKeyGrammar = rubricVersion === WITAN_RUBRIC_VERSION_V23;
|
|
2224
|
+
const usesV23WithheldPathAbstention = rubricVersion === WITAN_RUBRIC_VERSION_V23;
|
|
2185
2225
|
const structuralArchetype = classifyRepoArchetype(inventoryFiles, rubricVersion);
|
|
2186
2226
|
const readableArchetype = rubricVersion === WITAN_RUBRIC_VERSION_V13 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure(rubricVersion) ? applyReadableSourceRepresentationGate(
|
|
2187
2227
|
options.repoPath,
|
|
@@ -2219,6 +2259,7 @@ function buildWitanInputFromRepoUntracked(options) {
|
|
|
2219
2259
|
usesV22PackageStartEntrypoint,
|
|
2220
2260
|
usesV23CommandCoverage,
|
|
2221
2261
|
usesV23PemPrivateKeyGrammar,
|
|
2262
|
+
usesV23WithheldPathAbstention,
|
|
2222
2263
|
reviewableSourceProof,
|
|
2223
2264
|
inventoryAbsenceContext,
|
|
2224
2265
|
scanLimitations
|
|
@@ -2830,7 +2871,7 @@ function buildNotApplicableSignal(criterionId, reason) {
|
|
|
2830
2871
|
notApplicable: true
|
|
2831
2872
|
};
|
|
2832
2873
|
}
|
|
2833
|
-
function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, useV18NativeRls, useV19CommitYear, useV20A3ExplicitGaps, useV21ExecutedEscalations, useV22PackageStartEntrypoint, useV23CommandCoverage, useV23PemPrivateKeyGrammar, reviewableSourceProof, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT, scanLimitations = /* @__PURE__ */ new Set()) {
|
|
2874
|
+
function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, useV18NativeRls, useV19CommitYear, useV20A3ExplicitGaps, useV21ExecutedEscalations, useV22PackageStartEntrypoint, useV23CommandCoverage, useV23PemPrivateKeyGrammar, useV23WithheldPathAbstention, reviewableSourceProof, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT, scanLimitations = /* @__PURE__ */ new Set()) {
|
|
2834
2875
|
const signals = [];
|
|
2835
2876
|
const mono = resolveMonorepoContext(repoPath, scanLimitations);
|
|
2836
2877
|
const collectCriterion = (criterionId, collect) => withContentReadCriterion(criterionId, collect);
|
|
@@ -2871,6 +2912,7 @@ function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, u
|
|
|
2871
2912
|
useV27Detectors,
|
|
2872
2913
|
useV20A3ExplicitGaps,
|
|
2873
2914
|
useV22PackageStartEntrypoint,
|
|
2915
|
+
useV23WithheldPathAbstention,
|
|
2874
2916
|
inventoryAbsenceContext
|
|
2875
2917
|
)
|
|
2876
2918
|
);
|
|
@@ -2891,6 +2933,7 @@ function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, u
|
|
|
2891
2933
|
repoPath,
|
|
2892
2934
|
repoFiles,
|
|
2893
2935
|
useV27Detectors,
|
|
2936
|
+
useV23WithheldPathAbstention,
|
|
2894
2937
|
inventoryAbsenceContext
|
|
2895
2938
|
)
|
|
2896
2939
|
);
|
|
@@ -2993,12 +3036,16 @@ function collectA1TestIntegrityEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
2993
3036
|
const ciHasTypecheckCommand = ciWorkflows.some(
|
|
2994
3037
|
(file) => fileContains(repoPath, file, CI_TYPECHECK_COMMAND_PATTERN)
|
|
2995
3038
|
);
|
|
2996
|
-
const
|
|
2997
|
-
|
|
2998
|
-
coverageAnalysis.hasCoverageCommand,
|
|
2999
|
-
packageScripts.has("lint") || ciHasLintCommand,
|
|
3000
|
-
|
|
3001
|
-
|
|
3039
|
+
const verificationScriptComponents = [
|
|
3040
|
+
{ label: "test command", count: hasCredibleTestScript(packageScripts) || Boolean(ciTestWorkflow) ? 1 : 0 },
|
|
3041
|
+
{ label: "coverage command", count: coverageAnalysis.hasCoverageCommand ? 1 : 0 },
|
|
3042
|
+
{ label: "lint command", count: packageScripts.has("lint") || ciHasLintCommand ? 1 : 0 },
|
|
3043
|
+
{
|
|
3044
|
+
label: "type-check command",
|
|
3045
|
+
count: packageScripts.has("typecheck") || ciHasTypecheckCommand ? 1 : 0
|
|
3046
|
+
}
|
|
3047
|
+
];
|
|
3048
|
+
const verificationScriptCount = verificationScriptComponents.filter((c) => c.count > 0).length;
|
|
3002
3049
|
const usesLeanBuiltInTestRunner = packageJson != null && [...packageScripts.values()].some(
|
|
3003
3050
|
(script) => LEAN_TEST_RUNNER_SCRIPT_PATTERN.test(script)
|
|
3004
3051
|
) || testFiles.some((file) => fileContains(repoPath, file, LEAN_TEST_RUNNER_IMPORT_PATTERN));
|
|
@@ -3062,7 +3109,9 @@ function collectA1TestIntegrityEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
3062
3109
|
repoPath,
|
|
3063
3110
|
reviewableSourceProof,
|
|
3064
3111
|
repoFiles.length,
|
|
3065
|
-
inventoryAbsenceContext
|
|
3112
|
+
inventoryAbsenceContext,
|
|
3113
|
+
verificationScriptComponents,
|
|
3114
|
+
runnerFiles.length
|
|
3066
3115
|
) : null;
|
|
3067
3116
|
}
|
|
3068
3117
|
if (testFiles.length === 0) {
|
|
@@ -3162,19 +3211,7 @@ function collectA1TestIntegrityEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
3162
3211
|
"saturating_count",
|
|
3163
3212
|
{
|
|
3164
3213
|
components: [
|
|
3165
|
-
|
|
3166
|
-
label: "test command",
|
|
3167
|
-
count: packageScripts.has("test") || Boolean(ciTestWorkflow) ? 1 : 0
|
|
3168
|
-
},
|
|
3169
|
-
{ label: "coverage command", count: coverageAnalysis.hasCoverageCommand ? 1 : 0 },
|
|
3170
|
-
{
|
|
3171
|
-
label: "lint command",
|
|
3172
|
-
count: packageScripts.has("lint") || ciHasLintCommand ? 1 : 0
|
|
3173
|
-
},
|
|
3174
|
-
{
|
|
3175
|
-
label: "type-check command",
|
|
3176
|
-
count: packageScripts.has("typecheck") || ciHasTypecheckCommand ? 1 : 0
|
|
3177
|
-
},
|
|
3214
|
+
...verificationScriptComponents,
|
|
3178
3215
|
{ label: "test-runner configuration", count: runnerFiles.length }
|
|
3179
3216
|
]
|
|
3180
3217
|
}
|
|
@@ -3192,7 +3229,7 @@ function collectA1TestIntegrityEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
3192
3229
|
notes: coverageFiles.length === 0 && coverageAnalysis.unresolvedFiles.length > 0 ? `A1 is detected from real test files, test runner configuration, and optional coverage configuration. Coverage command reachability or flag ownership was unresolved in ${coverageAnalysis.unresolvedFiles.slice(0, 4).join(", ")}; the no-coverage absence claim was withheld.` : "A1 is detected from real test files, test runner configuration, and optional coverage configuration."
|
|
3193
3230
|
};
|
|
3194
3231
|
}
|
|
3195
|
-
function buildA1AuthenticatedAbsenceSignal(repoPath, proof, inventoryCount, inventoryAbsenceContext) {
|
|
3232
|
+
function buildA1AuthenticatedAbsenceSignal(repoPath, proof, inventoryCount, inventoryAbsenceContext, verificationScriptComponents, runnerFileCount) {
|
|
3196
3233
|
const sourcePath = proof.firstReadablePath;
|
|
3197
3234
|
if (!sourcePath) {
|
|
3198
3235
|
throw new Error("Cejel invariant: a passing reviewable-source proof must have a readable path");
|
|
@@ -3244,7 +3281,12 @@ function buildA1AuthenticatedAbsenceSignal(repoPath, proof, inventoryCount, inve
|
|
|
3244
3281
|
metric(
|
|
3245
3282
|
"verification_script_ratio",
|
|
3246
3283
|
"Verification script ratio",
|
|
3247
|
-
|
|
3284
|
+
// Zero test FILES does not mean zero verification signal: a lint/typecheck/coverage
|
|
3285
|
+
// script or CI command is a real, independently-observable fact from package.json/CI
|
|
3286
|
+
// content and must be credited here the same way B3 credits it, or A1 flatly
|
|
3287
|
+
// contradicts B3 on the same repository fact (goal_cejel_detector_false_assertions_
|
|
3288
|
+
// 0_4_9_2026-09-14 finding 3).
|
|
3289
|
+
verificationScriptComponents.filter((c) => c.count > 0).length + runnerFileCount,
|
|
3248
3290
|
4,
|
|
3249
3291
|
0.25,
|
|
3250
3292
|
"ratio",
|
|
@@ -3252,11 +3294,8 @@ function buildA1AuthenticatedAbsenceSignal(repoPath, proof, inventoryCount, inve
|
|
|
3252
3294
|
"saturating_count",
|
|
3253
3295
|
{
|
|
3254
3296
|
components: [
|
|
3255
|
-
|
|
3256
|
-
{ label: "
|
|
3257
|
-
{ label: "lint command", count: 0 },
|
|
3258
|
-
{ label: "type-check command", count: 0 },
|
|
3259
|
-
{ label: "test-runner configuration", count: 0 }
|
|
3297
|
+
...verificationScriptComponents,
|
|
3298
|
+
{ label: "test-runner configuration", count: runnerFileCount }
|
|
3260
3299
|
]
|
|
3261
3300
|
}
|
|
3262
3301
|
),
|
|
@@ -3270,7 +3309,7 @@ function buildA1AuthenticatedAbsenceSignal(repoPath, proof, inventoryCount, inve
|
|
|
3270
3309
|
"No concrete test files were present to establish non-hollow test behavior."
|
|
3271
3310
|
)
|
|
3272
3311
|
],
|
|
3273
|
-
notes: `V17 authenticated absence: ${proof.eligibleSourceFileCount} criterion-ratable of ${proof.sourceShapedFileCount} source-shaped files; sampled ${proof.sampledFileCount}; ${proof.readableSampledFileCount} representative-text files.`
|
|
3312
|
+
notes: `V17 authenticated absence: ${proof.eligibleSourceFileCount} criterion-ratable of ${proof.sourceShapedFileCount} source-shaped files; sampled ${proof.sampledFileCount}; ${proof.readableSampledFileCount} representative-text files. Verification-script signals (lint/typecheck/coverage/CI commands) are independent of test-file presence and are still credited above where detected.`
|
|
3274
3313
|
};
|
|
3275
3314
|
}
|
|
3276
3315
|
function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, useV23PemPrivateKeyGrammar, useV18NativeRls, inventoryAbsenceContext, scanLimitations) {
|
|
@@ -3730,7 +3769,7 @@ function collectCryptoHygieneEvidence(repoPath, implFiles, useV39Detectors = fal
|
|
|
3730
3769
|
}
|
|
3731
3770
|
return { evidence, findings, hasSurface, clean: hasSurface && !insecureFound };
|
|
3732
3771
|
}
|
|
3733
|
-
function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, useV20ExplicitGaps = false, useV22PackageStartEntrypoint = false, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT) {
|
|
3772
|
+
function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, useV20ExplicitGaps = false, useV22PackageStartEntrypoint = false, useV23WithheldPathAbstention = false, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT) {
|
|
3734
3773
|
const v20DirectHttpEntrypoint = useV20ExplicitGaps ? findV20DirectHttpServerEntrypointFile(repoPath, repoFiles) : null;
|
|
3735
3774
|
const v22PackageStartHttpEntrypoint = useV22PackageStartEntrypoint ? findV22PackageStartHttpServerEntrypointFile(repoPath, repoFiles) : null;
|
|
3736
3775
|
const v20RuntimeContainer = useV20ExplicitGaps ? findRuntimeContainerEntrypointFile(repoPath, repoFiles, true) : null;
|
|
@@ -3768,9 +3807,11 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
3768
3807
|
)
|
|
3769
3808
|
);
|
|
3770
3809
|
const healthCheck = healthChecks[0];
|
|
3810
|
+
const healthReadinessRouteReads = (file) => isAuthoredProductionPath(file) && isImplementationFile(file);
|
|
3811
|
+
const observabilityDepthReads = (file) => (!useV27Detectors || isAuthoredProductionPath(file)) && isImplementationFile(file);
|
|
3771
3812
|
const { hasV20HealthOrReadinessRoute, hasV22PackageStartHealthOrReadinessRoute } = withContentReadSignal("A3", "health_readiness_route", () => ({
|
|
3772
3813
|
hasV20HealthOrReadinessRoute: useV20ExplicitGaps && repoFiles.some(
|
|
3773
|
-
(file) =>
|
|
3814
|
+
(file) => healthReadinessRouteReads(file) && fileContains(repoPath, file, V20_HEALTH_OR_READINESS_ROUTE_PATTERN)
|
|
3774
3815
|
),
|
|
3775
3816
|
hasV22PackageStartHealthOrReadinessRoute: v22PackageStartHttpEntrypoint !== null && fileContains(
|
|
3776
3817
|
repoPath,
|
|
@@ -3778,23 +3819,34 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
3778
3819
|
V20_HEALTH_OR_READINESS_ROUTE_PATTERN
|
|
3779
3820
|
)
|
|
3780
3821
|
}));
|
|
3822
|
+
const healthReadinessRouteWithheld = useV23WithheldPathAbstention && useV20ExplicitGaps && abstainSignalOnWithheldPaths("A3", "health_readiness_route", healthReadinessRouteReads);
|
|
3781
3823
|
const serverEntrypoint = v22PackageStartHttpEntrypoint ?? findServerEntrypointFile(repoPath, repoFiles, useV27Detectors) ?? v20DirectHttpEntrypoint ?? null;
|
|
3782
3824
|
const runtimeContainer = useV27Detectors ? findRuntimeContainerEntrypointFile(repoPath, repoFiles, useV20ExplicitGaps) : null;
|
|
3783
3825
|
const errorBoundaries = repoFiles.filter(
|
|
3784
3826
|
(file) => (!useV27Detectors || isAuthoredProductionPath(file)) && /error-boundary|error\.(tsx|jsx|ts|js)$/.test(file)
|
|
3785
3827
|
);
|
|
3786
|
-
const
|
|
3828
|
+
const expressErrorMiddlewareFile = errorBoundaries.length > 0 ? void 0 : withContentReadSignal(
|
|
3829
|
+
"A3",
|
|
3830
|
+
"prod_readiness_primitives",
|
|
3831
|
+
() => repoFiles.find(
|
|
3832
|
+
(file) => observabilityDepthReads(file) && fileContains(repoPath, file, EXPRESS_ERROR_MIDDLEWARE_PATTERN) && fileContains(repoPath, file, EXPRESS_MIDDLEWARE_REACHABLE_PATTERN)
|
|
3833
|
+
)
|
|
3834
|
+
);
|
|
3835
|
+
const errorBoundary = errorBoundaries[0] ?? expressErrorMiddlewareFile;
|
|
3836
|
+
if (useV23WithheldPathAbstention && errorBoundaries.length === 0) {
|
|
3837
|
+
abstainSignalOnWithheldPaths("A3", "prod_readiness_primitives", observabilityDepthReads);
|
|
3838
|
+
}
|
|
3787
3839
|
const observabilityCount = withContentReadSignal(
|
|
3788
3840
|
"A3",
|
|
3789
3841
|
"observability_depth",
|
|
3790
|
-
() =>
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
),
|
|
3795
|
-
/sentry|otel|opentelemetry|datadog|prometheus|metrics|logger|logtail/i
|
|
3796
|
-
)
|
|
3842
|
+
() => countFilesMatchingAny(repoPath, repoFiles.filter(observabilityDepthReads), [
|
|
3843
|
+
/sentry|otel|opentelemetry|datadog|prometheus|metrics|logger|logtail|\b(?:correlation|request|trace)[-_]?id\b|\basynclocalstorage\b/i,
|
|
3844
|
+
/\b(?:pino|winston|bunyan|morgan)\b/
|
|
3845
|
+
])
|
|
3797
3846
|
);
|
|
3847
|
+
if (useV23WithheldPathAbstention) {
|
|
3848
|
+
abstainSignalOnWithheldPaths("A3", "observability_depth", observabilityDepthReads);
|
|
3849
|
+
}
|
|
3798
3850
|
const rollbackSafetyCount = withContentReadSignal(
|
|
3799
3851
|
"A3",
|
|
3800
3852
|
"rollback_safety_depth",
|
|
@@ -3841,8 +3893,17 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
3841
3893
|
)
|
|
3842
3894
|
);
|
|
3843
3895
|
}
|
|
3844
|
-
if (errorBoundary)
|
|
3845
|
-
evidence.push(
|
|
3896
|
+
if (errorBoundary) {
|
|
3897
|
+
evidence.push(
|
|
3898
|
+
errorBoundary === expressErrorMiddlewareFile ? evidenceForRelativeAtLine(
|
|
3899
|
+
repoPath,
|
|
3900
|
+
errorBoundary,
|
|
3901
|
+
"prod_check",
|
|
3902
|
+
"Error boundary",
|
|
3903
|
+
findFirstMatchingLine(repoPath, errorBoundary, EXPRESS_ERROR_MIDDLEWARE_PATTERN)
|
|
3904
|
+
) : evidenceForRelative(repoPath, errorBoundary, "prod_check", "Error boundary")
|
|
3905
|
+
);
|
|
3906
|
+
}
|
|
3846
3907
|
if (evidence.length === 0) {
|
|
3847
3908
|
if (serverEntrypoint) {
|
|
3848
3909
|
evidence.push(
|
|
@@ -3896,7 +3957,12 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
3896
3957
|
)
|
|
3897
3958
|
});
|
|
3898
3959
|
}
|
|
3899
|
-
} else if (serverEntrypoint &&
|
|
3960
|
+
} else if (serverEntrypoint && // An absence finding is an assertion that Cejel looked and found nothing. When a file this
|
|
3961
|
+
// signal would have read was withheld, Cejel did not look at everything it selected, so the
|
|
3962
|
+
// honest output is the recorded abstention above and no finding — never "declares no health
|
|
3963
|
+
// or readiness route". This is the whole defect: insufficient_data must not be emitted as a
|
|
3964
|
+
// finding of absence.
|
|
3965
|
+
!healthReadinessRouteWithheld && withContentReadSignal(
|
|
3900
3966
|
"A3",
|
|
3901
3967
|
"health_readiness_route",
|
|
3902
3968
|
() => fileContains(
|
|
@@ -3950,7 +4016,7 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
3950
4016
|
deployConfigs.length > 0,
|
|
3951
4017
|
envTemplate,
|
|
3952
4018
|
healthChecks.length > 0,
|
|
3953
|
-
|
|
4019
|
+
errorBoundary !== void 0
|
|
3954
4020
|
].filter(Boolean).length,
|
|
3955
4021
|
6,
|
|
3956
4022
|
0.55,
|
|
@@ -3967,7 +4033,7 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
3967
4033
|
{ label: "deployment configuration", count: deployConfigs.length > 0 ? 1 : 0 },
|
|
3968
4034
|
{ label: "environment template", count: envTemplate ? 1 : 0 },
|
|
3969
4035
|
{ label: "health or readiness signal", count: healthChecks.length > 0 ? 1 : 0 },
|
|
3970
|
-
{ label: "error boundary", count:
|
|
4036
|
+
{ label: "error boundary", count: errorBoundary !== void 0 ? 1 : 0 }
|
|
3971
4037
|
]
|
|
3972
4038
|
}
|
|
3973
4039
|
),
|
|
@@ -4211,7 +4277,26 @@ function hasDeclaredVersionConstraint(dependency) {
|
|
|
4211
4277
|
if (/[~^<>=!]/.test(trimmed)) return true;
|
|
4212
4278
|
return /^v?\d/.test(trimmed);
|
|
4213
4279
|
}
|
|
4214
|
-
function collectA5ClaimRealityEvidence(repoPath, repoFiles, useV27Detectors, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT) {
|
|
4280
|
+
function collectA5ClaimRealityEvidence(repoPath, repoFiles, useV27Detectors, useV23WithheldPathAbstention, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT) {
|
|
4281
|
+
const claimImplementationReads = claimImplementationFileReads(useV27Detectors);
|
|
4282
|
+
if (useV23WithheldPathAbstention) {
|
|
4283
|
+
abstainSignalOnWithheldPaths(
|
|
4284
|
+
"A5",
|
|
4285
|
+
"claim_match_rate",
|
|
4286
|
+
(file) => claimImplementationReads(file) || isClaimSourceFile(file)
|
|
4287
|
+
);
|
|
4288
|
+
abstainSignalOnWithheldPaths("A5", "claim_source_depth", isClaimSourceFile);
|
|
4289
|
+
abstainSignalOnWithheldPaths(
|
|
4290
|
+
"A5",
|
|
4291
|
+
"reconciliation_artifact_depth",
|
|
4292
|
+
isClaimRealityReconciliationPath
|
|
4293
|
+
);
|
|
4294
|
+
abstainSignalOnWithheldPaths(
|
|
4295
|
+
"A5",
|
|
4296
|
+
"negative_space_documentation",
|
|
4297
|
+
isNegativeSpaceDocCandidate
|
|
4298
|
+
);
|
|
4299
|
+
}
|
|
4215
4300
|
const reconciliationArtifacts = useV27Detectors ? findClaimRealityReconciliationArtifacts(repoPath, repoFiles) : [];
|
|
4216
4301
|
const claimSourceFiles = useV27Detectors ? findClaimSourceFiles(repoFiles) : repoFiles.filter(
|
|
4217
4302
|
(file) => /^(?:README|readme)\.md$/.test(file) || /^docs\/[^/]+\.(?:md|mdx)$/.test(file)
|
|
@@ -4257,7 +4342,7 @@ function collectA5ClaimRealityEvidence(repoPath, repoFiles, useV27Detectors, inv
|
|
|
4257
4342
|
const negativeSpaceCandidates = /* @__PURE__ */ new Set([
|
|
4258
4343
|
claimDoc,
|
|
4259
4344
|
...allDocFiles,
|
|
4260
|
-
...repoFiles.filter(
|
|
4345
|
+
...repoFiles.filter(isSecurityOrThreatModelDoc)
|
|
4261
4346
|
]);
|
|
4262
4347
|
const negativeSpaceDoc = withContentReadSignal(
|
|
4263
4348
|
"A5",
|
|
@@ -4345,7 +4430,7 @@ function collectA5ClaimRealityEvidence(repoPath, repoFiles, useV27Detectors, inv
|
|
|
4345
4430
|
function collectB2PrTraceEvidence(repoPath, repoFiles) {
|
|
4346
4431
|
const workflows = repoFiles.filter(isCiWorkflow);
|
|
4347
4432
|
const prTemplate = repoFiles.find(
|
|
4348
|
-
(file) => /(^|\/)(pull_request_template|PULL_REQUEST_TEMPLATE)\.md
|
|
4433
|
+
(file) => /(^|\/)(pull_request_template|PULL_REQUEST_TEMPLATE)(\.md$|\/[^/]+\.md$)/.test(file)
|
|
4349
4434
|
);
|
|
4350
4435
|
const branchProtectionDoc = repoFiles.find(
|
|
4351
4436
|
(file) => /branch.*protection|review.*gate|CODEOWNERS/i.test(file)
|
|
@@ -4448,7 +4533,9 @@ function collectB3CiDisciplineEvidence(repoPath, repoFiles, mono) {
|
|
|
4448
4533
|
CI_TYPECHECK_COMMAND_PATTERN,
|
|
4449
4534
|
CI_BUILD_COMMAND_PATTERN
|
|
4450
4535
|
];
|
|
4451
|
-
const scriptDepth = ["test", "lint", "typecheck", "build"].filter(
|
|
4536
|
+
const scriptDepth = ["test", "lint", "typecheck", "build"].filter(
|
|
4537
|
+
(s) => s === "test" ? hasCredibleTestScript(scripts) : scripts.has(s)
|
|
4538
|
+
).length;
|
|
4452
4539
|
const { repoCategoryHits, rootCategoryHits } = withContentReadSignal(
|
|
4453
4540
|
"B3",
|
|
4454
4541
|
"ci_script_depth",
|
|
@@ -4481,7 +4568,7 @@ function collectB3CiDisciplineEvidence(repoPath, repoFiles, mono) {
|
|
|
4481
4568
|
components: [
|
|
4482
4569
|
...["test", "lint", "typecheck", "build"].map((name) => ({
|
|
4483
4570
|
label: `package script: ${name === "typecheck" ? "type-check" : name}`,
|
|
4484
|
-
count: scripts.has(name) ? 1 : 0
|
|
4571
|
+
count: (name === "test" ? hasCredibleTestScript(scripts) : scripts.has(name)) ? 1 : 0
|
|
4485
4572
|
})),
|
|
4486
4573
|
...CI_COMMAND_CATEGORIES.map((_pattern, index) => ({
|
|
4487
4574
|
label: `repository CI command: ${["test", "lint", "type-check", "build"][index]}`,
|
|
@@ -4840,6 +4927,10 @@ function isTestFile(file, rubricVersion = WITAN_RUBRIC_VERSION) {
|
|
|
4840
4927
|
var NAME_SHAPED_TEST_FILE_PATTERN = /^test(?:-[^/]+)?\.[cm]?[jt]sx?$|\.(test|spec)\.[cm]?[jt]sx?$|(^|\/)__tests__\/|(^|\/)test_[^/]*\.py$|(^|\/)tests?\.py$|_test\.go$|(^|\/)test_[^/]*\.(cpp|cc|cxx)$|_(test|tests)\.(cpp|cc|cxx)$|Tests?\.(java|kt)$|(_test|_spec)\.(rs|rb|php|swift|kt)$/;
|
|
4841
4928
|
var NAME_SHAPED_TEST_FILE_PATTERN_V17 = /\.tftest\.hcl$|\.bats$|(^|\/)test[^/]*\.m$|_test\.m$/i;
|
|
4842
4929
|
var TEST_RUNNER_PATTERN = /\b(vitest|jest|mocha|ava|tap|pytest|go test|cargo test|rspec|phpunit|gradle test|mvn test|node\s+--test|node:test)\b/i;
|
|
4930
|
+
function hasCredibleTestScript(scripts) {
|
|
4931
|
+
const script = scripts.get("test");
|
|
4932
|
+
return script != null && TEST_RUNNER_PATTERN.test(script);
|
|
4933
|
+
}
|
|
4843
4934
|
var CI_TEST_COMMAND_PATTERN = /\b(pytest|go\s+test|cargo\s+test|mvn\s+test|gradle\s+test|dotnet\s+test|ctest|make\s+test|jest|vitest|mocha|rspec|phpunit|pnpm\s+(?:run\s+)?test|npm\s+(?:run\s+)?test|yarn\s+(?:run\s+)?test|node\s+--test|node:test)\b|--target[=\s]+test\b/i;
|
|
4844
4935
|
var CI_LINT_COMMAND_PATTERN = /\b(eslint|pylint|flake8|black|ruff)\b/i;
|
|
4845
4936
|
var CI_TYPECHECK_COMMAND_PATTERN = /\b(tsc|mypy|pyright)\b/i;
|
|
@@ -5013,8 +5104,8 @@ function looksLikeSecretValue(value) {
|
|
|
5013
5104
|
return SECRET_VALUE_BRANDED_PATTERN.test(value) || isGenericSecretValue(value);
|
|
5014
5105
|
}
|
|
5015
5106
|
var PLACEHOLDER_SECRET_PATTERN = /(?:^|[-_])(?:your|example|sample|placeholder|dummy|changeme|replace(?:-?me)?|redacted)(?:$|[-_])|^x{3,}$|^\.\.\.|^\$\{[^}]+}$|^<[^>]+>$/i;
|
|
5016
|
-
var ENV_TEMPLATE_PATTERN = /(^|\/)\.env(?:\.[^/]+)
|
|
5017
|
-
var ENV_TEMPLATE_PATTERN_V47 = /(^|\/)\.env(?:\.[^/]+)
|
|
5107
|
+
var ENV_TEMPLATE_PATTERN = /(^|\/)\.env(?:\.[^/]+)?\.(?:example|sample|template|dist)$/i;
|
|
5108
|
+
var ENV_TEMPLATE_PATTERN_V47 = /(^|\/)\.env(?:\.[^/]+)?\.(?:example|sample|template|dist|exemplo|ejemplo|exemple|esempio|beispiel|voorbeeld)$/i;
|
|
5018
5109
|
function isEnvTemplatePath(path, useV47Detectors = false) {
|
|
5019
5110
|
return (useV47Detectors ? ENV_TEMPLATE_PATTERN_V47 : ENV_TEMPLATE_PATTERN).test(path);
|
|
5020
5111
|
}
|
|
@@ -5031,27 +5122,34 @@ function readGitTrackedFileOutput(repoPath) {
|
|
|
5031
5122
|
if (workTree.stdout.trim() !== "true") return { ok: false, reason: "not_a_repo" };
|
|
5032
5123
|
return execGit(["ls-files", "--cached"], { cwd: repoPath });
|
|
5033
5124
|
}
|
|
5034
|
-
function parseGitTrackedFiles(repoPath, output, includeHardExcluded) {
|
|
5125
|
+
function parseGitTrackedFiles(repoPath, output, includeHardExcluded, registerWithheld = false) {
|
|
5035
5126
|
const files = [];
|
|
5127
|
+
const withhold = (file, reason) => {
|
|
5128
|
+
if (registerWithheld) registerWithheldRepoPath(file, reason);
|
|
5129
|
+
};
|
|
5036
5130
|
for (const file of output.trim().split("\n")) {
|
|
5037
5131
|
if (file.length === 0) continue;
|
|
5038
5132
|
const fullPath = join(repoPath, file);
|
|
5039
5133
|
if (!includeHardExcluded && isHardExcludedPath(file)) {
|
|
5040
5134
|
recordContentSkip(fullPath, "denied_path", true);
|
|
5135
|
+
withhold(file, "denied_path");
|
|
5041
5136
|
continue;
|
|
5042
5137
|
}
|
|
5043
5138
|
try {
|
|
5044
5139
|
const stat = lstatSync(fullPath);
|
|
5045
5140
|
if (!stat.isFile()) {
|
|
5046
5141
|
recordContentSkip(fullPath, "non_regular_file", true);
|
|
5142
|
+
withhold(file, "non_regular_file");
|
|
5047
5143
|
continue;
|
|
5048
5144
|
}
|
|
5049
5145
|
if (stat.size > MAX_REPOSITORY_CONTENT_BYTES) {
|
|
5050
5146
|
recordContentSkip(fullPath, "too_large", true);
|
|
5147
|
+
withhold(file, "too_large");
|
|
5051
5148
|
continue;
|
|
5052
5149
|
}
|
|
5053
5150
|
} catch (error) {
|
|
5054
5151
|
recordFilesystemSkip(fullPath, error, false, true);
|
|
5152
|
+
withhold(file, "unreadable");
|
|
5055
5153
|
continue;
|
|
5056
5154
|
}
|
|
5057
5155
|
if (!isPotentialContentPath(file)) {
|
|
@@ -5071,7 +5169,7 @@ function collectRepoFileInventory(repoPath) {
|
|
|
5071
5169
|
const tracked = readGitTrackedFileOutput(repoPath);
|
|
5072
5170
|
if (tracked.ok) {
|
|
5073
5171
|
return {
|
|
5074
|
-
repoFiles: parseGitTrackedFiles(repoPath, tracked.stdout, false),
|
|
5172
|
+
repoFiles: parseGitTrackedFiles(repoPath, tracked.stdout, false, true),
|
|
5075
5173
|
inventoryFiles: parseGitTrackedFiles(repoPath, tracked.stdout, true),
|
|
5076
5174
|
repoFileInventoryScope: "tracked-scan-eligible",
|
|
5077
5175
|
scanLimitations: []
|
|
@@ -5169,8 +5267,10 @@ function visitRepoDir(repoPath, dirPath, files, rootDevice) {
|
|
|
5169
5267
|
visitRepoDir(repoPath, fullPath, files, rootDevice);
|
|
5170
5268
|
continue;
|
|
5171
5269
|
}
|
|
5270
|
+
const repoRelativePath = relative(repoPath, fullPath);
|
|
5172
5271
|
if (!entry.isFile()) {
|
|
5173
5272
|
recordContentSkip(fullPath, "non_regular_file");
|
|
5273
|
+
registerWithheldRepoPath(repoRelativePath, "non_regular_file");
|
|
5174
5274
|
continue;
|
|
5175
5275
|
}
|
|
5176
5276
|
let size;
|
|
@@ -5178,11 +5278,12 @@ function visitRepoDir(repoPath, dirPath, files, rootDevice) {
|
|
|
5178
5278
|
size = statSync(fullPath).size;
|
|
5179
5279
|
} catch (error) {
|
|
5180
5280
|
recordFilesystemSkip(fullPath, error);
|
|
5281
|
+
registerWithheldRepoPath(repoRelativePath, "unreadable");
|
|
5181
5282
|
continue;
|
|
5182
5283
|
}
|
|
5183
|
-
const repoRelativePath = relative(repoPath, fullPath);
|
|
5184
5284
|
if (size > MAX_REPOSITORY_CONTENT_BYTES) {
|
|
5185
5285
|
recordContentSkip(fullPath, "too_large");
|
|
5286
|
+
registerWithheldRepoPath(repoRelativePath, "too_large");
|
|
5186
5287
|
continue;
|
|
5187
5288
|
}
|
|
5188
5289
|
if (!isPotentialContentPath(repoRelativePath)) {
|
|
@@ -5306,6 +5407,9 @@ function measureNonHollowTestShare(repoPath, files, useV17Detectors = false) {
|
|
|
5306
5407
|
function countFilesContaining(repoPath, files, pattern) {
|
|
5307
5408
|
return files.filter((file) => fileContains(repoPath, file, pattern)).length;
|
|
5308
5409
|
}
|
|
5410
|
+
function countFilesMatchingAny(repoPath, files, patterns) {
|
|
5411
|
+
return files.filter((file) => patterns.some((pattern) => fileContains(repoPath, file, pattern))).length;
|
|
5412
|
+
}
|
|
5309
5413
|
function countPatternMatches(repoPath, files, pattern) {
|
|
5310
5414
|
const flags = pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`;
|
|
5311
5415
|
const matcher = new RegExp(pattern.source, flags);
|
|
@@ -5845,22 +5949,33 @@ function isDocumentationOnlyDeployWorkflow(repoPath, file) {
|
|
|
5845
5949
|
function findPackagedApplicationPremiseFiles(repoPath, repoFiles) {
|
|
5846
5950
|
return repoFiles.filter((file) => /(^|\/)package\.json$/.test(file) && isAuthoredProductionPath(file)).filter((file) => packageJsonDescribesPackagedApplication(repoPath, file, repoFiles));
|
|
5847
5951
|
}
|
|
5952
|
+
function isClaimSourceFile(file) {
|
|
5953
|
+
return /^(?:README|readme)\.md$/.test(file) || /^docs\/[^/]+\.(?:md|mdx)$/.test(file);
|
|
5954
|
+
}
|
|
5955
|
+
function isClaimRealityReconciliationPath(file) {
|
|
5956
|
+
return /(^|\/)claim[-_]reality[-_]reconciliation\.(?:md|mdx|json)$/i.test(file);
|
|
5957
|
+
}
|
|
5958
|
+
function isSecurityOrThreatModelDoc(file) {
|
|
5959
|
+
return /(^|\/)(SECURITY|THREAT[_-]?MODEL)\.md$/i.test(file);
|
|
5960
|
+
}
|
|
5961
|
+
function isNegativeSpaceDocCandidate(file) {
|
|
5962
|
+
return isClaimSourceFile(file) || isSecurityOrThreatModelDoc(file);
|
|
5963
|
+
}
|
|
5964
|
+
function claimImplementationFileReads(authoredOnly) {
|
|
5965
|
+
return (file) => isImplementationFile(file) && (!authoredOnly || isAuthoredProductionPath(file));
|
|
5966
|
+
}
|
|
5848
5967
|
function findClaimSourceFiles(repoFiles) {
|
|
5849
|
-
return repoFiles.filter(
|
|
5850
|
-
(file) => /^(?:README|readme)\.md$/.test(file) || /^docs\/[^/]+\.(?:md|mdx)$/.test(file)
|
|
5851
|
-
).sort((left, right) => {
|
|
5968
|
+
return repoFiles.filter(isClaimSourceFile).sort((left, right) => {
|
|
5852
5969
|
const leftRootReadme = /^(?:README|readme)\.md$/.test(left);
|
|
5853
5970
|
const rightRootReadme = /^(?:README|readme)\.md$/.test(right);
|
|
5854
5971
|
return Number(rightRootReadme) - Number(leftRootReadme) || left.localeCompare(right);
|
|
5855
5972
|
});
|
|
5856
5973
|
}
|
|
5857
5974
|
function findClaimImplementationFiles(repoFiles, authoredOnly = false) {
|
|
5858
|
-
return repoFiles.filter(
|
|
5859
|
-
(file) => isImplementationFile(file) && (!authoredOnly || isAuthoredProductionPath(file))
|
|
5860
|
-
);
|
|
5975
|
+
return repoFiles.filter(claimImplementationFileReads(authoredOnly));
|
|
5861
5976
|
}
|
|
5862
5977
|
function findClaimRealityReconciliationArtifacts(repoPath, repoFiles) {
|
|
5863
|
-
return repoFiles.filter(
|
|
5978
|
+
return repoFiles.filter(isClaimRealityReconciliationPath).filter((file) => isAuthenticatedClaimRealityArtifact(repoPath, file));
|
|
5864
5979
|
}
|
|
5865
5980
|
function isAuthenticatedClaimRealityArtifact(repoPath, file) {
|
|
5866
5981
|
const fullPath = join(repoPath, file);
|
|
@@ -6916,7 +7031,9 @@ var MAIN_ENTRYPOINT_FILE_PATTERN = /(^|\/)(main|server|app|wsgi|asgi|index|entry
|
|
|
6916
7031
|
var RACK_ENTRYPOINT_FILE_PATTERN = /(^|\/)(?:config\.ru|(?:main|server|app|start|run)\.rb)$/i;
|
|
6917
7032
|
var SERVER_ENTRYPOINT_PATTERN = /\bapp\.listen\s*\(|\bserver\.listen\s*\(\s*(?:PORT|port|\d+)|http\.ListenAndServe\s*\(|http\.ListenAndServeTLS\s*\(|axum::Server(?:::|\.)|actix_web::HttpServer(?:::|\.)|uvicorn\.run\s*\(/;
|
|
6918
7033
|
var V20_DIRECT_HTTP_SERVER_PATTERN = /\b(?:http|https)\.createServer\s*\([\s\S]{0,1500}?\)\.listen\s*\(\s*(?:PORT|port|\d+)/;
|
|
6919
|
-
var V20_HEALTH_OR_READINESS_ROUTE_PATTERN = /["'`]\/(?:health|ready|readiness|
|
|
7034
|
+
var V20_HEALTH_OR_READINESS_ROUTE_PATTERN = /["'`][\w${}./-]{0,60}\/(?:(?:health|ready|live)z?|readiness|liveness)(?=["'`/])/i;
|
|
7035
|
+
var EXPRESS_ERROR_MIDDLEWARE_PATTERN = /\(\s*(?:err|error)(?:\s*:\s*(?:[^,()<]|<[^<>]*>)*)?\s*,\s*(?:req|request)(?:\s*:\s*(?:[^,()<]|<[^<>]*>)*)?\s*,\s*(?:res|response)(?:\s*:\s*(?:[^,()<]|<[^<>]*>)*)?\s*,\s*next(?:\s*:\s*(?:[^,()<]|<[^<>]*>)*)?\s*\)\s*(?:=>|\{)/i;
|
|
7036
|
+
var EXPRESS_MIDDLEWARE_REACHABLE_PATTERN = /\.use\s*\(|\bmodule\.exports\b|\bexport\s+(?:default\b|function\b|const\b)/;
|
|
6920
7037
|
var RACK_SERVER_ENTRYPOINT_PATTERN = /Rack::(?:Server|Handler(?:::\w+)?)\.(?:start|run)\s*\(/;
|
|
6921
7038
|
var RACK_CONFIG_RUN_PATTERN = /^\s*run\s+(?:(?:[A-Z]\w*(?:::\w+)*(?:\.new)?|lambda)\b|->)/m;
|
|
6922
7039
|
var RUNTIME_CONTAINER_COMMAND_PATTERN = /^\s*(?:CMD|ENTRYPOINT)\s+.*(?:\b(?:start|serve|server|qgis|nginx|apache|gunicorn|uvicorn)\b|manage\.py\s+runserver).*$/im;
|
|
@@ -8377,6 +8494,22 @@ function discoverIngestInputs(repoPath, maxMatches = Number.POSITIVE_INFINITY) {
|
|
|
8377
8494
|
// src/witan/scoring.ts
|
|
8378
8495
|
init_esm_shims();
|
|
8379
8496
|
|
|
8497
|
+
// src/witan/rubric-fingerprint.ts
|
|
8498
|
+
init_esm_shims();
|
|
8499
|
+
import { createHash as createHash3 } from "crypto";
|
|
8500
|
+
var WITAN_RUBRIC_BEHAVIOUR_FINGERPRINTS = Object.freeze({
|
|
8501
|
+
[WITAN_RUBRIC_VERSION_V17]: "sha256:ff0f01abe8c12daa60375d0e18c1aca4a1135a55ab2a80b15f4c037bfc18b4b1",
|
|
8502
|
+
[WITAN_RUBRIC_VERSION_V18]: "sha256:abc35df0fdc0749aa941f47b295059d06c96dd9800af7f79cfef2bc8dae917da",
|
|
8503
|
+
[WITAN_RUBRIC_VERSION_V19]: "sha256:f670fa2cc44beef066fa38767bd587e1a16fb28b03bc904756daaea5a6465e96",
|
|
8504
|
+
[WITAN_RUBRIC_VERSION_V20]: "sha256:9276ce2ce865c2d50c52882ee45bbf1df5fe3c8b6038858b4a147f7a4cedfa98",
|
|
8505
|
+
[WITAN_RUBRIC_VERSION_V21]: "sha256:d86411a7fe108bba4d2b8fe7ff9d4f7f69a60f11ca0c5c3fef8e88f66a9af53a",
|
|
8506
|
+
[WITAN_RUBRIC_VERSION_V22]: "sha256:1bb57dd98d29b43b170f3a4f1c8b3b379b433a2aa9df0821ab9d5115f48cfb2f",
|
|
8507
|
+
[WITAN_RUBRIC_VERSION_V23]: "sha256:b558c0aa4b2f85b734bed2e077298fd55851a1086234d678f10a71cf913ec3cf"
|
|
8508
|
+
});
|
|
8509
|
+
function rubricBehaviourFingerprint(rubricVersion) {
|
|
8510
|
+
return WITAN_RUBRIC_BEHAVIOUR_FINGERPRINTS[rubricVersion];
|
|
8511
|
+
}
|
|
8512
|
+
|
|
8380
8513
|
// src/witan/rubric.ts
|
|
8381
8514
|
init_esm_shims();
|
|
8382
8515
|
var WITAN_RUBRIC = [
|
|
@@ -8536,6 +8669,13 @@ function createWitanReport(input, inputSignals, rubric = WITAN_RUBRIC, toolVersi
|
|
|
8536
8669
|
productDisplayName: parsedInput.productDisplayName,
|
|
8537
8670
|
repo: parsedInput.repo,
|
|
8538
8671
|
rubricVersion: parsedInput.rubricVersion,
|
|
8672
|
+
// Behavioural identity beside the rubric's name, so a reader holding two certificates can
|
|
8673
|
+
// check whether the scoring that produced them agrees instead of inferring it from a string
|
|
8674
|
+
// the tool's author controls. Derived only from parsedInput.rubricVersion, so it is a
|
|
8675
|
+
// property of the (build, rubric) pair and not of this invocation: two runs of the same
|
|
8676
|
+
// installed version at the same revision stay byte-identical. Absent, never fabricated, for
|
|
8677
|
+
// a rubric this build carries no measurement for.
|
|
8678
|
+
...rubricBehaviourFingerprint(parsedInput.rubricVersion) ? { rubricBehaviourFingerprint: rubricBehaviourFingerprint(parsedInput.rubricVersion) } : {},
|
|
8539
8679
|
verdict: abstained ? "insufficient_source" : witanVerdictForScore(overallScore),
|
|
8540
8680
|
codeTrustScore: abstained ? null : codeTrustScore,
|
|
8541
8681
|
processTrustScore: abstained ? null : processTrustScore,
|
package/dist/index.js
CHANGED
|
@@ -21,12 +21,12 @@ import {
|
|
|
21
21
|
runCejelScan,
|
|
22
22
|
serializeWitanReport,
|
|
23
23
|
verifyWitanAttestationBinding
|
|
24
|
-
} from "./chunk-
|
|
25
|
-
import "./chunk-
|
|
26
|
-
import "./chunk-
|
|
24
|
+
} from "./chunk-TUUNJP27.js";
|
|
25
|
+
import "./chunk-IHT7B6L7.js";
|
|
26
|
+
import "./chunk-GKYTLWQK.js";
|
|
27
27
|
import {
|
|
28
28
|
init_esm_shims
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-PTZU6G4E.js";
|
|
30
30
|
|
|
31
31
|
// src/index.ts
|
|
32
32
|
init_esm_shims();
|
|
@@ -76,6 +76,7 @@ function renderTerminalCertificate(summary, report) {
|
|
|
76
76
|
lines.splice(
|
|
77
77
|
3,
|
|
78
78
|
0,
|
|
79
|
+
`Scope: ${relyingPartySummary.scope}`,
|
|
79
80
|
`What was examined: ${relyingPartySummary.examined}`,
|
|
80
81
|
`What was established: ${relyingPartySummary.established}`,
|
|
81
82
|
`What was not established: ${relyingPartySummary.notEstablished}`,
|
package/dist/mcp/index.js
CHANGED
|
@@ -5,20 +5,20 @@ import {
|
|
|
5
5
|
renderWitanBadgeSvg,
|
|
6
6
|
renderWitanHtmlReport,
|
|
7
7
|
runCejelScan
|
|
8
|
-
} from "../chunk-
|
|
9
|
-
import "../chunk-
|
|
8
|
+
} from "../chunk-TUUNJP27.js";
|
|
9
|
+
import "../chunk-IHT7B6L7.js";
|
|
10
10
|
import {
|
|
11
11
|
ZodFirstPartyTypeKind,
|
|
12
12
|
ZodOptional,
|
|
13
13
|
external_exports,
|
|
14
14
|
objectType
|
|
15
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-GKYTLWQK.js";
|
|
16
16
|
import {
|
|
17
17
|
__commonJS,
|
|
18
18
|
__export,
|
|
19
19
|
__toESM,
|
|
20
20
|
init_esm_shims
|
|
21
|
-
} from "../chunk-
|
|
21
|
+
} from "../chunk-PTZU6G4E.js";
|
|
22
22
|
|
|
23
23
|
// node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/codegen/code.js
|
|
24
24
|
var require_code = __commonJS({
|
|
@@ -3,18 +3,18 @@ import { createRequire as __cejelCreateRequire } from 'node:module';
|
|
|
3
3
|
const require = __cejelCreateRequire(import.meta.url);
|
|
4
4
|
import {
|
|
5
5
|
listCejelLlmPackFiles
|
|
6
|
-
} from "../../chunk-
|
|
6
|
+
} from "../../chunk-IN2LPGGU.js";
|
|
7
7
|
import {
|
|
8
8
|
execGit
|
|
9
|
-
} from "../../chunk-
|
|
9
|
+
} from "../../chunk-IHT7B6L7.js";
|
|
10
10
|
import {
|
|
11
11
|
require_typescript
|
|
12
|
-
} from "../../chunk-
|
|
12
|
+
} from "../../chunk-IQ42TE5H.js";
|
|
13
13
|
import {
|
|
14
14
|
__toESM,
|
|
15
15
|
init_esm_shims,
|
|
16
16
|
readRepoText
|
|
17
|
-
} from "../../chunk-
|
|
17
|
+
} from "../../chunk-PTZU6G4E.js";
|
|
18
18
|
|
|
19
19
|
// src/packs/d-series/index.ts
|
|
20
20
|
init_esm_shims();
|
|
@@ -3,15 +3,15 @@ import { createRequire as __cejelCreateRequire } from 'node:module';
|
|
|
3
3
|
const require = __cejelCreateRequire(import.meta.url);
|
|
4
4
|
import {
|
|
5
5
|
external_exports
|
|
6
|
-
} from "../../chunk-
|
|
6
|
+
} from "../../chunk-GKYTLWQK.js";
|
|
7
7
|
import {
|
|
8
8
|
require_typescript
|
|
9
|
-
} from "../../chunk-
|
|
9
|
+
} from "../../chunk-IQ42TE5H.js";
|
|
10
10
|
import {
|
|
11
11
|
__toESM,
|
|
12
12
|
init_esm_shims,
|
|
13
13
|
readRepoText
|
|
14
|
-
} from "../../chunk-
|
|
14
|
+
} from "../../chunk-PTZU6G4E.js";
|
|
15
15
|
|
|
16
16
|
// src/packs/decision-contracts/index.ts
|
|
17
17
|
init_esm_shims();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cejel/cejel",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.9",
|
|
4
4
|
"mcpName": "io.github.BargLabs/cejel",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
|
@@ -31,7 +31,6 @@
|
|
|
31
31
|
"type": "git",
|
|
32
32
|
"url": "git+https://github.com/BargLabs/cejel.git"
|
|
33
33
|
},
|
|
34
|
-
"packageManager": "pnpm@9.0.0",
|
|
35
34
|
"type": "module",
|
|
36
35
|
"bin": {
|
|
37
36
|
"cejel": "dist/index.js",
|
|
@@ -49,6 +48,16 @@
|
|
|
49
48
|
"engines": {
|
|
50
49
|
"node": ">=18"
|
|
51
50
|
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
53
|
+
"@types/node": "^25.9.1",
|
|
54
|
+
"postject": "^1.0.0-alpha.6",
|
|
55
|
+
"tsup": "^8.0.0",
|
|
56
|
+
"tsx": "^4.0.0",
|
|
57
|
+
"typescript": "^5.5.0",
|
|
58
|
+
"vitest": "^2.0.0",
|
|
59
|
+
"zod": "^3.23.0"
|
|
60
|
+
},
|
|
52
61
|
"scripts": {
|
|
53
62
|
"build": "tsup",
|
|
54
63
|
"build:sea-js": "tsup --config tsup.public-sea.config.ts",
|
|
@@ -62,21 +71,9 @@
|
|
|
62
71
|
"gate:d6": "pnpm run build && node scripts/d6-precision-gate.mjs",
|
|
63
72
|
"validate:distribution": "node scripts/validate-distribution-metadata.mjs",
|
|
64
73
|
"pnpm:devPreinstall": "node scripts/assert-dev-environment.mjs --phase=preinstall",
|
|
65
|
-
"prepublishOnly": "pnpm run build",
|
|
66
|
-
"prepack": "pnpm run build",
|
|
67
74
|
"pretest": "node scripts/assert-dev-environment.mjs --phase=verify",
|
|
68
75
|
"dev": "tsx src/index.ts",
|
|
69
76
|
"typecheck": "tsc --noEmit -p tsconfig.json",
|
|
70
77
|
"test": "vitest run"
|
|
71
|
-
},
|
|
72
|
-
"devDependencies": {
|
|
73
|
-
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
74
|
-
"@types/node": "^25.9.1",
|
|
75
|
-
"postject": "^1.0.0-alpha.6",
|
|
76
|
-
"tsup": "^8.0.0",
|
|
77
|
-
"tsx": "^4.0.0",
|
|
78
|
-
"typescript": "^5.5.0",
|
|
79
|
-
"vitest": "^2.0.0",
|
|
80
|
-
"zod": "^3.23.0"
|
|
81
78
|
}
|
|
82
|
-
}
|
|
79
|
+
}
|