@cejel/cejel 0.6.2 → 0.6.4
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
CHANGED
|
@@ -92,7 +92,7 @@ if (-not $expected -or $actual -ne $expected.ToLowerInvariant()) {
|
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
> **Windows signing status:** `cejel-Windows-x86_64.exe` is intentionally unsigned in
|
|
95
|
-
> 0.6.
|
|
95
|
+
> 0.6.4 and may trigger Microsoft SmartScreen. The release build removes Node's inherited
|
|
96
96
|
> signature before SEA injection and fails unless Windows reports the result as `NotSigned`;
|
|
97
97
|
> it does not ship an invalid signature. Before running it, verify `SHA256SUMS` and the
|
|
98
98
|
> GitHub build-provenance attestation. Each binary also has an attached SPDX SBOM (the packages
|
|
@@ -116,7 +116,7 @@ docker run --rm --network=none -v "$PWD:/w" -w /w -v "$PWD/cejel:/cejel:ro" debi
|
|
|
116
116
|
npx @cejel/cejel@latest .
|
|
117
117
|
```
|
|
118
118
|
|
|
119
|
-
> **Distribution note:** Cejel `0.6.
|
|
119
|
+
> **Distribution note:** Cejel `0.6.4` is the coordinated release version for npm,
|
|
120
120
|
> standalone binaries, Docker/OCI, GitHub Action, Homebrew, and MCP Registry. A GitLab CI
|
|
121
121
|
> template and Code Quality export live in [`docs/gitlab-ci.md`](./docs/gitlab-ci.md).
|
|
122
122
|
|
|
@@ -187,16 +187,16 @@ gh attestation verify ./cejel-Windows-x86_64.exe -R BargLabs/cejel
|
|
|
187
187
|
This is cryptographically signed provenance. It is distinct from Apple Developer ID or
|
|
188
188
|
Microsoft Authenticode code-signing.
|
|
189
189
|
|
|
190
|
-
**Docker / OCI.** The current container release is `0.6.
|
|
190
|
+
**Docker / OCI.** The current container release is `0.6.4`:
|
|
191
191
|
|
|
192
192
|
```bash
|
|
193
|
-
docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.6.
|
|
193
|
+
docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.6.4
|
|
194
194
|
```
|
|
195
195
|
|
|
196
196
|
The image defaults to `cejel-mcp` over stdio. To use the CLI instead:
|
|
197
197
|
|
|
198
198
|
```bash
|
|
199
|
-
docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.6.
|
|
199
|
+
docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.6.4 .
|
|
200
200
|
```
|
|
201
201
|
|
|
202
202
|
The OCI image carries an SBOM of its base-image packages, maximum-mode build provenance, and a
|
|
@@ -299,8 +299,10 @@ prints that boundary on every successful verification.
|
|
|
299
299
|
- `--rubric-pin <version>` — Explicit opt-in only: pin an alternate rubric instead of the
|
|
300
300
|
calibrated public default. It
|
|
301
301
|
accepts the calibrated version or any published prospective rubric
|
|
302
|
-
(`witan-rubric-v18-prospective-*` through `
|
|
303
|
-
anything else. `
|
|
302
|
+
(`witan-rubric-v18-prospective-*` through `v25`) and fails closed, naming what was accepted, on
|
|
303
|
+
anything else. `v25` is prospective and uncalibrated: it inherits v22 and adds only credit for a
|
|
304
|
+
health or readiness route declared inline in an application file (see "What counts as a health or
|
|
305
|
+
readiness signal" below). `v23` is prospective and uncalibrated, like every rubric after v17: the public
|
|
304
306
|
default (`WITAN_LAST_CALIBRATED_RUBRIC_VERSION`) is still `witan-rubric-v17-2026-07-24`, and v23
|
|
305
307
|
inherits none of v17's precision, recall, or false-positive-rate figures. It inherits v22
|
|
306
308
|
detector/scoring behavior and adds bounded A1 coverage-flag recognition (#276) plus per-signal
|
|
@@ -567,7 +569,7 @@ The OCI image is an alternative when Docker is the preferred execution boundary.
|
|
|
567
569
|
the host path with the repository OpenClaw should allow Cejel to read:
|
|
568
570
|
|
|
569
571
|
```bash
|
|
570
|
-
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.6.
|
|
572
|
+
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.6.4"]}'
|
|
571
573
|
npx -y openclaw@latest mcp doctor cejel-oci --probe
|
|
572
574
|
```
|
|
573
575
|
|
|
@@ -635,6 +637,27 @@ belongs to:
|
|
|
635
637
|
`test` script's content against known test-runner invocations rather than crediting it by key
|
|
636
638
|
presence alone, so no separate disclosure line is needed for it.
|
|
637
639
|
|
|
640
|
+
### What counts as a health or readiness signal
|
|
641
|
+
|
|
642
|
+
The "health or readiness signal" component of A3's production-readiness checks is filename-based
|
|
643
|
+
by design under the calibrated rubric (and every prospective rubric before `v25`). It is credited
|
|
644
|
+
for exactly these forms:
|
|
645
|
+
|
|
646
|
+
- a dedicated health or readiness file, such as `health.ts`, `healthcheck.js`, `readiness.py`
|
|
647
|
+
(the file must mention health or readiness);
|
|
648
|
+
- a `HEALTHCHECK` instruction in a root `Dockerfile`;
|
|
649
|
+
- Kubernetes liveness or readiness probes in a `k8s/`, `kubernetes/` or `helm/` manifest.
|
|
650
|
+
|
|
651
|
+
**A route declared inline in an application file does not count under the calibrated rubric**,
|
|
652
|
+
whatever its content: `app.get("/health", ...)` in `server.ts` or `app.ts` earns nothing there,
|
|
653
|
+
because the component never reads route text. The certificate states this next to the component.
|
|
654
|
+
Prospective `witan-rubric-v25-prospective-2026-10-12` is the one rubric that also credits an inline
|
|
655
|
+
route, in the files the separate info-level "no health or readiness route" finding already reads
|
|
656
|
+
(under `src/`, `app/`, `lib/`, `packages/`, `functions/`, a repo-root `server`/`index`/`app`/`main`
|
|
657
|
+
file, or a `server/`, `backend/` or `api/` tree), with comments stripped and tests, docs, examples
|
|
658
|
+
and scripts excluded. It is explicit opt-in (`--rubric-pin`), carries no precision or recall claim,
|
|
659
|
+
and its public paired rescore has not run.
|
|
660
|
+
|
|
638
661
|
## Help validate Cejel
|
|
639
662
|
|
|
640
663
|
Cejel does not collect telemetry. External validation is therefore opt-in and inspectable:
|
|
@@ -532,6 +532,7 @@ var WITAN_RUBRIC_VERSION_V21 = "witan-rubric-v21-prospective-2026-08-10";
|
|
|
532
532
|
var WITAN_RUBRIC_VERSION_V22 = "witan-rubric-v22-prospective-2026-08-10";
|
|
533
533
|
var WITAN_RUBRIC_VERSION_V23 = "witan-rubric-v23-prospective-2026-09-06";
|
|
534
534
|
var WITAN_RUBRIC_VERSION_V24 = "witan-rubric-v24-prospective-2026-09-15";
|
|
535
|
+
var WITAN_RUBRIC_VERSION_V25 = "witan-rubric-v25-prospective-2026-10-12";
|
|
535
536
|
var WITAN_LAST_CALIBRATED_RUBRIC_VERSION = WITAN_RUBRIC_VERSION_V17;
|
|
536
537
|
var WITAN_PROSPECTIVE_RUBRIC_VERSIONS = Object.freeze([
|
|
537
538
|
WITAN_RUBRIC_VERSION_V18,
|
|
@@ -540,7 +541,8 @@ var WITAN_PROSPECTIVE_RUBRIC_VERSIONS = Object.freeze([
|
|
|
540
541
|
WITAN_RUBRIC_VERSION_V21,
|
|
541
542
|
WITAN_RUBRIC_VERSION_V22,
|
|
542
543
|
WITAN_RUBRIC_VERSION_V23,
|
|
543
|
-
WITAN_RUBRIC_VERSION_V24
|
|
544
|
+
WITAN_RUBRIC_VERSION_V24,
|
|
545
|
+
WITAN_RUBRIC_VERSION_V25
|
|
544
546
|
]);
|
|
545
547
|
var WITAN_SELECTABLE_RUBRIC_VERSIONS = Object.freeze([
|
|
546
548
|
WITAN_LAST_CALIBRATED_RUBRIC_VERSION,
|
|
@@ -642,14 +644,15 @@ init_esm_shims();
|
|
|
642
644
|
init_esm_shims();
|
|
643
645
|
import { createHash } from "crypto";
|
|
644
646
|
var WITAN_RUBRIC_BEHAVIOUR_FINGERPRINTS = Object.freeze({
|
|
645
|
-
[WITAN_RUBRIC_VERSION_V17]: "sha256:
|
|
646
|
-
[WITAN_RUBRIC_VERSION_V18]: "sha256:
|
|
647
|
-
[WITAN_RUBRIC_VERSION_V19]: "sha256:
|
|
648
|
-
[WITAN_RUBRIC_VERSION_V20]: "sha256:
|
|
649
|
-
[WITAN_RUBRIC_VERSION_V21]: "sha256:
|
|
650
|
-
[WITAN_RUBRIC_VERSION_V22]: "sha256:
|
|
651
|
-
[WITAN_RUBRIC_VERSION_V23]: "sha256:
|
|
652
|
-
[WITAN_RUBRIC_VERSION_V24]: "sha256:
|
|
647
|
+
[WITAN_RUBRIC_VERSION_V17]: "sha256:6a31f7cb96ebf17046ba0620d74b1fadb66582c4b4ae5cb0b5af04480df6dbf2",
|
|
648
|
+
[WITAN_RUBRIC_VERSION_V18]: "sha256:9c54aa1493ff42b001ae2d1828f4bda92b3ebff500551eb36ef8a2b9d2fc391f",
|
|
649
|
+
[WITAN_RUBRIC_VERSION_V19]: "sha256:ed3fa7ff11aa0c0ecf7fc23fccab2c40337c55c5b06abae14eb10e9d73bbcffa",
|
|
650
|
+
[WITAN_RUBRIC_VERSION_V20]: "sha256:eb6ed39afd0e3f3d73e6a85df90787a3490087eaa34aad19fb5fbb31b4502ce5",
|
|
651
|
+
[WITAN_RUBRIC_VERSION_V21]: "sha256:7a890ac663793f807e240e38047ff9fbc069853d118ebf9a765cc103a8bed2a3",
|
|
652
|
+
[WITAN_RUBRIC_VERSION_V22]: "sha256:ac4db093dc7c37369579b49ccd7855d36eec49d9f52136964251ee7bbd69e101",
|
|
653
|
+
[WITAN_RUBRIC_VERSION_V23]: "sha256:7d48de4ac8ef3233e7ef8f4d4312830bf76294485e9766a47a671cd5440676aa",
|
|
654
|
+
[WITAN_RUBRIC_VERSION_V24]: "sha256:0af37b616891a1940f7ba43c86ef2134d6e40f235feef17bf1774cae951afee2",
|
|
655
|
+
[WITAN_RUBRIC_VERSION_V25]: "sha256:31a751882d02c8f053dcc8f3e90b3e4ecd57279f3250e420e95a3af875b9f019"
|
|
653
656
|
});
|
|
654
657
|
function rubricBehaviourFingerprint(rubricVersion) {
|
|
655
658
|
return WITAN_RUBRIC_BEHAVIOUR_FINGERPRINTS[rubricVersion];
|
|
@@ -717,7 +720,7 @@ var WITAN_RUBRIC = [
|
|
|
717
720
|
|
|
718
721
|
// src/witan/scoring.ts
|
|
719
722
|
function usesV17DetectorClosure(rubricVersion) {
|
|
720
|
-
return rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V23;
|
|
723
|
+
return rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V25 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V23;
|
|
721
724
|
}
|
|
722
725
|
var MAX_SIGNAL_ADJUSTMENT = 0.8;
|
|
723
726
|
function createWitanReport(input, inputSignals, rubric = WITAN_RUBRIC, toolVersion) {
|
|
@@ -888,7 +891,7 @@ function statusForScore(score) {
|
|
|
888
891
|
}
|
|
889
892
|
function statusAfterInputAdjustment(nativeStatus, nativeScore, adjustment, rubricVersion) {
|
|
890
893
|
if (adjustment === 0) return nativeStatus;
|
|
891
|
-
if (rubricVersion !== WITAN_RUBRIC_VERSION_V8 && rubricVersion !== WITAN_RUBRIC_VERSION_V9 && rubricVersion !== WITAN_RUBRIC_VERSION_V10 && rubricVersion !== WITAN_RUBRIC_VERSION_V11 && rubricVersion !== WITAN_RUBRIC_VERSION_V12 && rubricVersion !== WITAN_RUBRIC_VERSION_V13 && rubricVersion !== WITAN_RUBRIC_VERSION_V14 && rubricVersion !== WITAN_RUBRIC_VERSION_V15 && rubricVersion !== WITAN_RUBRIC_VERSION_V16 && rubricVersion !== WITAN_RUBRIC_VERSION_V17 && rubricVersion !== WITAN_RUBRIC_VERSION_V18 && rubricVersion !== WITAN_RUBRIC_VERSION_V19 && rubricVersion !== WITAN_RUBRIC_VERSION_V20 && rubricVersion !== WITAN_RUBRIC_VERSION_V21 && rubricVersion !== WITAN_RUBRIC_VERSION_V22 && rubricVersion !== WITAN_RUBRIC_VERSION_V24 && rubricVersion !== WITAN_RUBRIC_VERSION_V23) {
|
|
894
|
+
if (rubricVersion !== WITAN_RUBRIC_VERSION_V8 && rubricVersion !== WITAN_RUBRIC_VERSION_V9 && rubricVersion !== WITAN_RUBRIC_VERSION_V10 && rubricVersion !== WITAN_RUBRIC_VERSION_V11 && rubricVersion !== WITAN_RUBRIC_VERSION_V12 && rubricVersion !== WITAN_RUBRIC_VERSION_V13 && rubricVersion !== WITAN_RUBRIC_VERSION_V14 && rubricVersion !== WITAN_RUBRIC_VERSION_V15 && rubricVersion !== WITAN_RUBRIC_VERSION_V16 && rubricVersion !== WITAN_RUBRIC_VERSION_V17 && rubricVersion !== WITAN_RUBRIC_VERSION_V18 && rubricVersion !== WITAN_RUBRIC_VERSION_V19 && rubricVersion !== WITAN_RUBRIC_VERSION_V20 && rubricVersion !== WITAN_RUBRIC_VERSION_V21 && rubricVersion !== WITAN_RUBRIC_VERSION_V22 && rubricVersion !== WITAN_RUBRIC_VERSION_V25 && rubricVersion !== WITAN_RUBRIC_VERSION_V24 && rubricVersion !== WITAN_RUBRIC_VERSION_V23) {
|
|
892
895
|
return statusForScore(roundScore(Math.max(0, nativeScore - adjustment)));
|
|
893
896
|
}
|
|
894
897
|
const statusFloor = {
|
|
@@ -945,7 +948,7 @@ function mergeSignalsByCriterion(signals) {
|
|
|
945
948
|
return merged;
|
|
946
949
|
}
|
|
947
950
|
function usesMetricScoring(rubricVersion) {
|
|
948
|
-
return rubricVersion === WITAN_RUBRIC_VERSION_V1 || rubricVersion === WITAN_RUBRIC_VERSION_V2 || rubricVersion === WITAN_RUBRIC_VERSION_V3 || rubricVersion === WITAN_RUBRIC_VERSION_V4 || rubricVersion === WITAN_RUBRIC_VERSION_V5 || rubricVersion === WITAN_RUBRIC_VERSION_V6 || rubricVersion === WITAN_RUBRIC_VERSION_V7 || rubricVersion === WITAN_RUBRIC_VERSION_V8 || rubricVersion === WITAN_RUBRIC_VERSION_V9 || rubricVersion === WITAN_RUBRIC_VERSION_V10 || rubricVersion === WITAN_RUBRIC_VERSION_V11 || rubricVersion === WITAN_RUBRIC_VERSION_V12 || rubricVersion === WITAN_RUBRIC_VERSION_V13 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0;
|
|
951
|
+
return rubricVersion === WITAN_RUBRIC_VERSION_V1 || rubricVersion === WITAN_RUBRIC_VERSION_V2 || rubricVersion === WITAN_RUBRIC_VERSION_V3 || rubricVersion === WITAN_RUBRIC_VERSION_V4 || rubricVersion === WITAN_RUBRIC_VERSION_V5 || rubricVersion === WITAN_RUBRIC_VERSION_V6 || rubricVersion === WITAN_RUBRIC_VERSION_V7 || rubricVersion === WITAN_RUBRIC_VERSION_V8 || rubricVersion === WITAN_RUBRIC_VERSION_V9 || rubricVersion === WITAN_RUBRIC_VERSION_V10 || rubricVersion === WITAN_RUBRIC_VERSION_V11 || rubricVersion === WITAN_RUBRIC_VERSION_V12 || rubricVersion === WITAN_RUBRIC_VERSION_V13 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V25 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0;
|
|
949
952
|
}
|
|
950
953
|
function unmeasuredStatus(rubricVersion) {
|
|
951
954
|
return rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0 ? "unverified" : "insufficient_data";
|
|
@@ -1333,7 +1336,7 @@ function calibratedCriterionStateV11(criterionId, metrics) {
|
|
|
1333
1336
|
return void 0;
|
|
1334
1337
|
}
|
|
1335
1338
|
function ensureFindingsExplainStatus(criterionId, score, status, findings, evidence, rubricVersion) {
|
|
1336
|
-
if (rubricVersion !== WITAN_RUBRIC_VERSION_V8 && rubricVersion !== WITAN_RUBRIC_VERSION_V9 && rubricVersion !== WITAN_RUBRIC_VERSION_V10 && rubricVersion !== WITAN_RUBRIC_VERSION_V11 && rubricVersion !== WITAN_RUBRIC_VERSION_V12 && rubricVersion !== WITAN_RUBRIC_VERSION_V13 && rubricVersion !== WITAN_RUBRIC_VERSION_V14 && rubricVersion !== WITAN_RUBRIC_VERSION_V15 && rubricVersion !== WITAN_RUBRIC_VERSION_V16 && rubricVersion !== WITAN_RUBRIC_VERSION_V17 && rubricVersion !== WITAN_RUBRIC_VERSION_V18 && rubricVersion !== WITAN_RUBRIC_VERSION_V19 && rubricVersion !== WITAN_RUBRIC_VERSION_V20 && rubricVersion !== WITAN_RUBRIC_VERSION_V21 && rubricVersion !== WITAN_RUBRIC_VERSION_V22 && rubricVersion !== WITAN_RUBRIC_VERSION_V24 && rubricVersion !== WITAN_RUBRIC_VERSION_V23 && findings.length > 0) {
|
|
1339
|
+
if (rubricVersion !== WITAN_RUBRIC_VERSION_V8 && rubricVersion !== WITAN_RUBRIC_VERSION_V9 && rubricVersion !== WITAN_RUBRIC_VERSION_V10 && rubricVersion !== WITAN_RUBRIC_VERSION_V11 && rubricVersion !== WITAN_RUBRIC_VERSION_V12 && rubricVersion !== WITAN_RUBRIC_VERSION_V13 && rubricVersion !== WITAN_RUBRIC_VERSION_V14 && rubricVersion !== WITAN_RUBRIC_VERSION_V15 && rubricVersion !== WITAN_RUBRIC_VERSION_V16 && rubricVersion !== WITAN_RUBRIC_VERSION_V17 && rubricVersion !== WITAN_RUBRIC_VERSION_V18 && rubricVersion !== WITAN_RUBRIC_VERSION_V19 && rubricVersion !== WITAN_RUBRIC_VERSION_V20 && rubricVersion !== WITAN_RUBRIC_VERSION_V21 && rubricVersion !== WITAN_RUBRIC_VERSION_V22 && rubricVersion !== WITAN_RUBRIC_VERSION_V25 && rubricVersion !== WITAN_RUBRIC_VERSION_V24 && rubricVersion !== WITAN_RUBRIC_VERSION_V23 && findings.length > 0) {
|
|
1337
1340
|
return [...findings];
|
|
1338
1341
|
}
|
|
1339
1342
|
if (status !== "critical" && status !== "warning") return [...findings];
|
|
@@ -1479,7 +1482,7 @@ var CERTIFICATE_GLOSSARY = [
|
|
|
1479
1482
|
{
|
|
1480
1483
|
key: "production-readiness-basic-checks",
|
|
1481
1484
|
term: "Production-readiness basic checks",
|
|
1482
|
-
definition: "A count of six named checks: a build or type-check command, a CI workflow, deployment configuration, an environment template, a health or readiness signal, and an error boundary.",
|
|
1485
|
+
definition: "A count of six named checks: a build or type-check command, a CI workflow, deployment configuration, an environment template, a health or readiness signal, and an error boundary. In the calibrated rubric the health or readiness signal is credited only for a dedicated health or readiness file (such as health.ts or readiness.ts), a Dockerfile HEALTHCHECK, or Kubernetes liveness or readiness probes. A health route declared inline in an application file does not count there. The prospective witan-rubric-v25 also credits such an inline route.",
|
|
1483
1486
|
metricNames: ["prod_readiness_primitives"]
|
|
1484
1487
|
},
|
|
1485
1488
|
{
|
|
@@ -1611,7 +1614,7 @@ var CERTIFICATE_GLOSSARY = [
|
|
|
1611
1614
|
{
|
|
1612
1615
|
key: "protected-path-review-gate",
|
|
1613
1616
|
term: "Protected-path review gate",
|
|
1614
|
-
definition: "A binary check for a CODEOWNERS file or
|
|
1617
|
+
definition: "A binary check for a CODEOWNERS file in a location GitHub reads (the repository root, .github/ or docs/), or a document stating a required-review or branch-protection policy. A changelog, an experiment or calibration record, a review note or a report does not count. This is the repository-visible proxy for human review of sensitive-path changes.",
|
|
1615
1618
|
metricNames: ["protected_path_review_gate"]
|
|
1616
1619
|
}
|
|
1617
1620
|
];
|
|
@@ -1710,7 +1713,7 @@ var BINARY_METRIC_COPY = {
|
|
|
1710
1713
|
},
|
|
1711
1714
|
protected_path_review_gate: {
|
|
1712
1715
|
positive: "present \u2014 CODEOWNERS or a documented required-review policy was detected",
|
|
1713
|
-
negative: "missing \u2014 no CODEOWNERS
|
|
1716
|
+
negative: "missing \u2014 no CODEOWNERS file in a location GitHub reads, and no documented required-review or branch-protection policy detected"
|
|
1714
1717
|
}
|
|
1715
1718
|
};
|
|
1716
1719
|
var CONDITIONAL_METRIC_COPY = {
|
|
@@ -2902,7 +2905,7 @@ function stripBom(text) {
|
|
|
2902
2905
|
|
|
2903
2906
|
// src/witan/repo-signals.ts
|
|
2904
2907
|
function usesV17DetectorClosure2(rubricVersion) {
|
|
2905
|
-
return rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24;
|
|
2908
|
+
return rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V25;
|
|
2906
2909
|
}
|
|
2907
2910
|
var LEGACY_INVENTORY_ABSENCE_CONTEXT = {
|
|
2908
2911
|
rubricGeneration: "legacy",
|
|
@@ -3149,15 +3152,16 @@ function buildWitanInputFromRepoUntracked(options) {
|
|
|
3149
3152
|
rubricGeneration: usesV17Detectors ? "current" : "legacy",
|
|
3150
3153
|
inventoryProvenance: fileInventory.repoFileInventoryScope === "tracked-scan-eligible" ? "tracked-scan-eligible" : "directory-walk"
|
|
3151
3154
|
};
|
|
3152
|
-
const usesV18NativeRls = rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24;
|
|
3153
|
-
const usesV19CommitYear = rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24;
|
|
3154
|
-
const usesV20A3ExplicitGaps = rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24;
|
|
3155
|
-
const usesV21ExecutedEscalations = rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24;
|
|
3156
|
-
const usesV22PackageStartEntrypoint = rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24;
|
|
3155
|
+
const usesV18NativeRls = rubricVersion === WITAN_RUBRIC_VERSION_V18 || rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V25;
|
|
3156
|
+
const usesV19CommitYear = rubricVersion === WITAN_RUBRIC_VERSION_V19 || rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V25;
|
|
3157
|
+
const usesV20A3ExplicitGaps = rubricVersion === WITAN_RUBRIC_VERSION_V20 || rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V25;
|
|
3158
|
+
const usesV21ExecutedEscalations = rubricVersion === WITAN_RUBRIC_VERSION_V21 || rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V25;
|
|
3159
|
+
const usesV22PackageStartEntrypoint = rubricVersion === WITAN_RUBRIC_VERSION_V22 || rubricVersion === WITAN_RUBRIC_VERSION_V23 || rubricVersion === WITAN_RUBRIC_VERSION_V24 || rubricVersion === WITAN_RUBRIC_VERSION_V25;
|
|
3157
3160
|
const usesV23CommandCoverage = rubricVersion === WITAN_RUBRIC_VERSION_V23;
|
|
3158
3161
|
const usesV23PemPrivateKeyGrammar = rubricVersion === WITAN_RUBRIC_VERSION_V23;
|
|
3159
3162
|
const usesV23WithheldPathAbstention = rubricVersion === WITAN_RUBRIC_VERSION_V23;
|
|
3160
3163
|
const usesV24SecretContentContext = rubricVersion === WITAN_RUBRIC_VERSION_V24;
|
|
3164
|
+
const usesV25InlineHealthRoute = rubricVersion === WITAN_RUBRIC_VERSION_V25;
|
|
3161
3165
|
const structuralArchetype = classifyRepoArchetype(inventoryFiles, rubricVersion);
|
|
3162
3166
|
const readableArchetype = rubricVersion === WITAN_RUBRIC_VERSION_V13 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure2(rubricVersion) ? applyReadableSourceRepresentationGate(
|
|
3163
3167
|
options.repoPath,
|
|
@@ -3197,6 +3201,7 @@ function buildWitanInputFromRepoUntracked(options) {
|
|
|
3197
3201
|
usesV23PemPrivateKeyGrammar,
|
|
3198
3202
|
usesV23WithheldPathAbstention,
|
|
3199
3203
|
usesV24SecretContentContext,
|
|
3204
|
+
usesV25InlineHealthRoute,
|
|
3200
3205
|
reviewableSourceProof,
|
|
3201
3206
|
inventoryAbsenceContext,
|
|
3202
3207
|
scanLimitations
|
|
@@ -3811,7 +3816,7 @@ function buildNotApplicableSignal(criterionId, reason) {
|
|
|
3811
3816
|
notApplicable: true
|
|
3812
3817
|
};
|
|
3813
3818
|
}
|
|
3814
|
-
function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, useV18NativeRls, useV19CommitYear, useV20A3ExplicitGaps, useV21ExecutedEscalations, useV22PackageStartEntrypoint, useV23CommandCoverage, useV23PemPrivateKeyGrammar, useV23WithheldPathAbstention, useV24SecretContentContext, reviewableSourceProof, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT, scanLimitations = /* @__PURE__ */ new Set()) {
|
|
3819
|
+
function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, useV18NativeRls, useV19CommitYear, useV20A3ExplicitGaps, useV21ExecutedEscalations, useV22PackageStartEntrypoint, useV23CommandCoverage, useV23PemPrivateKeyGrammar, useV23WithheldPathAbstention, useV24SecretContentContext, useV25InlineHealthRoute, reviewableSourceProof, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT, scanLimitations = /* @__PURE__ */ new Set()) {
|
|
3815
3820
|
const signals = [];
|
|
3816
3821
|
const mono = resolveMonorepoContext(repoPath, scanLimitations);
|
|
3817
3822
|
const collectCriterion = (criterionId, collect) => withContentReadCriterion(criterionId, collect);
|
|
@@ -3854,7 +3859,8 @@ function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, u
|
|
|
3854
3859
|
useV20A3ExplicitGaps,
|
|
3855
3860
|
useV22PackageStartEntrypoint,
|
|
3856
3861
|
useV23WithheldPathAbstention,
|
|
3857
|
-
inventoryAbsenceContext
|
|
3862
|
+
inventoryAbsenceContext,
|
|
3863
|
+
useV25InlineHealthRoute
|
|
3858
3864
|
)
|
|
3859
3865
|
);
|
|
3860
3866
|
const a4Signal = collectCriterion(
|
|
@@ -4752,7 +4758,7 @@ function collectCryptoHygieneEvidence(repoPath, implFiles, useV39Detectors = fal
|
|
|
4752
4758
|
}
|
|
4753
4759
|
return { evidence, findings, hasSurface, clean: hasSurface && !insecureFound };
|
|
4754
4760
|
}
|
|
4755
|
-
function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, useV20ExplicitGaps = false, useV22PackageStartEntrypoint = false, useV23WithheldPathAbstention = false, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT) {
|
|
4761
|
+
function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, useV20ExplicitGaps = false, useV22PackageStartEntrypoint = false, useV23WithheldPathAbstention = false, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT, useV25InlineHealthRoute = false) {
|
|
4756
4762
|
const v20DirectHttpEntrypoint = useV20ExplicitGaps ? findV20DirectHttpServerEntrypointFile(repoPath, repoFiles) : null;
|
|
4757
4763
|
const v22PackageStartHttpEntrypoint = useV22PackageStartEntrypoint ? findV22PackageStartHttpServerEntrypointFile(repoPath, repoFiles) : null;
|
|
4758
4764
|
const v20RuntimeContainer = useV20ExplicitGaps ? findRuntimeContainerEntrypointFile(repoPath, repoFiles, true) : null;
|
|
@@ -4790,8 +4796,16 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
4790
4796
|
)
|
|
4791
4797
|
);
|
|
4792
4798
|
const healthCheck = healthChecks[0];
|
|
4793
|
-
const healthReadinessRouteReads = (file) => isAuthoredProductionPath(file) && (isImplementationFile(file) || HEALTH_ROUTE_FUNCTIONS_DIR_PATTERN.test(file));
|
|
4799
|
+
const healthReadinessRouteReads = (file) => isAuthoredProductionPath(file) && (isImplementationFile(file) || HEALTH_ROUTE_FUNCTIONS_DIR_PATTERN.test(file) || HEALTH_ROUTE_ENTRYPOINT_HOME_PATTERN.test(file));
|
|
4794
4800
|
const observabilityDepthReads = (file) => (!useV27Detectors || isAuthoredProductionPath(file)) && isImplementationFile(file);
|
|
4801
|
+
const inlineHealthRouteFile = useV25InlineHealthRoute && healthChecks.length === 0 ? withContentReadSignal(
|
|
4802
|
+
"A3",
|
|
4803
|
+
"prod_readiness_primitives",
|
|
4804
|
+
() => repoFiles.find(
|
|
4805
|
+
(file) => healthReadinessRouteReads(file) && fileMatchesOutsideComments(repoPath, file, V20_HEALTH_OR_READINESS_ROUTE_PATTERN)
|
|
4806
|
+
)
|
|
4807
|
+
) : void 0;
|
|
4808
|
+
const hasHealthOrReadinessSignal = healthChecks.length > 0 || inlineHealthRouteFile !== void 0;
|
|
4795
4809
|
const { hasV20HealthOrReadinessRoute, hasV22PackageStartHealthOrReadinessRoute } = withContentReadSignal("A3", "health_readiness_route", () => ({
|
|
4796
4810
|
hasV20HealthOrReadinessRoute: useV20ExplicitGaps && repoFiles.some(
|
|
4797
4811
|
(file) => healthReadinessRouteReads(file) && fileContains(repoPath, file, V20_HEALTH_OR_READINESS_ROUTE_PATTERN)
|
|
@@ -4811,14 +4825,14 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
4811
4825
|
const serverEntrypoint = v22PackageStartHttpEntrypoint ?? findServerEntrypointFile(repoPath, repoFiles, useV27Detectors) ?? v20DirectHttpEntrypoint ?? null;
|
|
4812
4826
|
const runtimeContainer = useV27Detectors ? findRuntimeContainerEntrypointFile(repoPath, repoFiles, useV20ExplicitGaps) : null;
|
|
4813
4827
|
const errorBoundaries = repoFiles.filter(
|
|
4814
|
-
(file) => (!useV27Detectors || isAuthoredProductionPath(file)) &&
|
|
4828
|
+
(file) => (!useV27Detectors || isAuthoredProductionPath(file)) && isImplementationEvidencePath(file) && ERROR_BOUNDARY_FILENAME_PATTERN.test(file)
|
|
4815
4829
|
);
|
|
4816
|
-
const errorBoundaryFileReads = (file) => observabilityDepthReads(file) || (!useV27Detectors || isAuthoredProductionPath(file)) && /(^|\/)server\//.test(file) && /\.(?:mjs|cjs)$/.test(file);
|
|
4830
|
+
const errorBoundaryFileReads = (file) => isImplementationEvidencePath(file) && (observabilityDepthReads(file) || (!useV27Detectors || isAuthoredProductionPath(file)) && /(^|\/)server\//.test(file) && /\.(?:mjs|cjs)$/.test(file));
|
|
4817
4831
|
const expressErrorMiddlewareFile = errorBoundaries.length > 0 ? void 0 : withContentReadSignal(
|
|
4818
4832
|
"A3",
|
|
4819
4833
|
"prod_readiness_primitives",
|
|
4820
4834
|
() => repoFiles.find(
|
|
4821
|
-
(file) => errorBoundaryFileReads(file) &&
|
|
4835
|
+
(file) => errorBoundaryFileReads(file) && fileMatchesOutsideComments(repoPath, file, EXPRESS_ERROR_MIDDLEWARE_PATTERN) && fileMatchesOutsideComments(repoPath, file, EXPRESS_MIDDLEWARE_REACHABLE_PATTERN)
|
|
4822
4836
|
)
|
|
4823
4837
|
);
|
|
4824
4838
|
const errorBoundary = errorBoundaries[0] ?? expressErrorMiddlewareFile;
|
|
@@ -4855,12 +4869,28 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
4855
4869
|
/rollback|roll back|migration safety|down migration|reversible|undo migration/i
|
|
4856
4870
|
)
|
|
4857
4871
|
);
|
|
4872
|
+
const rootOnlyScriptsNote = rootOnlyPackageScriptsDisclosure(repoFiles, packageJson);
|
|
4858
4873
|
if (packageJson && (scripts.has("build") || scripts.has("typecheck"))) {
|
|
4859
4874
|
evidence.push(
|
|
4860
4875
|
evidenceForRelative(repoPath, packageJson, "prod_check", "Build or typecheck script")
|
|
4861
4876
|
);
|
|
4862
4877
|
}
|
|
4863
|
-
if (workflow)
|
|
4878
|
+
if (workflow) {
|
|
4879
|
+
evidence.push(
|
|
4880
|
+
evidenceForRelative(
|
|
4881
|
+
repoPath,
|
|
4882
|
+
workflow,
|
|
4883
|
+
"ci_run",
|
|
4884
|
+
ciWorkflowCitationLabel(
|
|
4885
|
+
"CI workflow",
|
|
4886
|
+
"counted",
|
|
4887
|
+
workflows.length,
|
|
4888
|
+
1,
|
|
4889
|
+
unreadCiWorkflowReasons((file) => !useV27Detectors || isAuthoredProductionPath(file))
|
|
4890
|
+
)
|
|
4891
|
+
)
|
|
4892
|
+
);
|
|
4893
|
+
}
|
|
4864
4894
|
if (releaseDeployConfig)
|
|
4865
4895
|
evidence.push(
|
|
4866
4896
|
evidenceForRelative(
|
|
@@ -4889,6 +4919,24 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
4889
4919
|
evidenceForRelative(repoPath, healthCheck, "prod_check", "Health/readiness signal")
|
|
4890
4920
|
)
|
|
4891
4921
|
);
|
|
4922
|
+
} else if (inlineHealthRouteFile) {
|
|
4923
|
+
withContentReadSignal(
|
|
4924
|
+
"A3",
|
|
4925
|
+
"prod_readiness_primitives",
|
|
4926
|
+
() => evidence.push(
|
|
4927
|
+
evidenceForRelativeAtLine(
|
|
4928
|
+
repoPath,
|
|
4929
|
+
inlineHealthRouteFile,
|
|
4930
|
+
"prod_check",
|
|
4931
|
+
"Health/readiness route",
|
|
4932
|
+
findFirstMatchingLineOutsideComments(
|
|
4933
|
+
repoPath,
|
|
4934
|
+
inlineHealthRouteFile,
|
|
4935
|
+
V20_HEALTH_OR_READINESS_ROUTE_PATTERN
|
|
4936
|
+
)
|
|
4937
|
+
)
|
|
4938
|
+
)
|
|
4939
|
+
);
|
|
4892
4940
|
}
|
|
4893
4941
|
if (errorBoundary) {
|
|
4894
4942
|
evidence.push(
|
|
@@ -4897,7 +4945,11 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
4897
4945
|
errorBoundary,
|
|
4898
4946
|
"prod_check",
|
|
4899
4947
|
"Error boundary",
|
|
4900
|
-
|
|
4948
|
+
findFirstMatchingLineOutsideComments(
|
|
4949
|
+
repoPath,
|
|
4950
|
+
errorBoundary,
|
|
4951
|
+
EXPRESS_ERROR_MIDDLEWARE_PATTERN
|
|
4952
|
+
)
|
|
4901
4953
|
) : evidenceForRelative(repoPath, errorBoundary, "prod_check", "Error boundary")
|
|
4902
4954
|
);
|
|
4903
4955
|
}
|
|
@@ -5012,7 +5064,7 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
5012
5064
|
workflows.length > 0,
|
|
5013
5065
|
deployConfigs.length > 0,
|
|
5014
5066
|
envTemplate,
|
|
5015
|
-
|
|
5067
|
+
hasHealthOrReadinessSignal,
|
|
5016
5068
|
errorBoundary !== void 0
|
|
5017
5069
|
].filter(Boolean).length,
|
|
5018
5070
|
6,
|
|
@@ -5029,9 +5081,10 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
5029
5081
|
{ label: "CI workflow", count: workflows.length > 0 ? 1 : 0 },
|
|
5030
5082
|
{ label: "deployment configuration", count: deployConfigs.length > 0 ? 1 : 0 },
|
|
5031
5083
|
{ label: "environment template", count: envTemplate ? 1 : 0 },
|
|
5032
|
-
{ label: "health or readiness signal", count:
|
|
5084
|
+
{ label: "health or readiness signal", count: hasHealthOrReadinessSignal ? 1 : 0 },
|
|
5033
5085
|
{ label: "error boundary", count: errorBoundary !== void 0 ? 1 : 0 }
|
|
5034
|
-
]
|
|
5086
|
+
],
|
|
5087
|
+
...rootOnlyScriptsNote ? { condition: rootOnlyScriptsNote } : {}
|
|
5035
5088
|
}
|
|
5036
5089
|
),
|
|
5037
5090
|
metric(
|
|
@@ -5436,10 +5489,18 @@ function collectB2PrTraceEvidence(repoPath, repoFiles) {
|
|
|
5436
5489
|
(file) => /(^|\/)(pull_request_template|PULL_REQUEST_TEMPLATE)(\.md$|\/[^/]+\.md$)/.test(file)
|
|
5437
5490
|
);
|
|
5438
5491
|
const branchProtectionDoc = repoFiles.find(
|
|
5439
|
-
(file) => /branch.*protection|review.*gate
|
|
5492
|
+
(file) => /branch.*protection|review.*gate/i.test(file) || GITHUB_CODEOWNERS_PATH_PATTERN.test(file)
|
|
5493
|
+
);
|
|
5494
|
+
const citedWorkflows = workflows.slice(0, 3);
|
|
5495
|
+
const workflowLabel = ciWorkflowCitationLabel(
|
|
5496
|
+
"Pull-request CI workflow",
|
|
5497
|
+
"counted",
|
|
5498
|
+
workflows.length,
|
|
5499
|
+
citedWorkflows.length,
|
|
5500
|
+
unreadCiWorkflowReasons(() => true)
|
|
5440
5501
|
);
|
|
5441
5502
|
const evidence = [
|
|
5442
|
-
...
|
|
5503
|
+
...citedWorkflows.map((file) => evidenceForRelative(repoPath, file, "ci_run", workflowLabel)),
|
|
5443
5504
|
...prTemplate ? [evidenceForRelative(repoPath, prTemplate, "pull_request", "Pull request template")] : [],
|
|
5444
5505
|
...branchProtectionDoc ? [
|
|
5445
5506
|
evidenceForRelative(
|
|
@@ -5512,11 +5573,20 @@ function collectB3CiDisciplineEvidence(repoPath, repoFiles, mono) {
|
|
|
5512
5573
|
if (packageJson && scripts.has("lint")) {
|
|
5513
5574
|
evidence.push(evidenceForRelative(repoPath, packageJson, "ci_run", "Lint script"));
|
|
5514
5575
|
}
|
|
5576
|
+
const unreadWorkflows = unreadCiWorkflowReasons(() => true);
|
|
5577
|
+
const workflowsRead = workflows.length + rootWorkflows.length;
|
|
5515
5578
|
if (workflow) {
|
|
5516
5579
|
withContentReadSignals(
|
|
5517
5580
|
"B3",
|
|
5518
5581
|
["ci_script_depth", "default_branch_ci_depth"],
|
|
5519
|
-
() => evidence.push(
|
|
5582
|
+
() => evidence.push(
|
|
5583
|
+
evidenceForRelative(
|
|
5584
|
+
repoPath,
|
|
5585
|
+
workflow,
|
|
5586
|
+
"ci_run",
|
|
5587
|
+
ciWorkflowCitationLabel("CI workflow", "read", workflowsRead, 1, unreadWorkflows)
|
|
5588
|
+
)
|
|
5589
|
+
)
|
|
5520
5590
|
);
|
|
5521
5591
|
} else if (rootWorkflows[0] && mono) {
|
|
5522
5592
|
const rootWorkflow = rootWorkflows[0];
|
|
@@ -5524,7 +5594,18 @@ function collectB3CiDisciplineEvidence(repoPath, repoFiles, mono) {
|
|
|
5524
5594
|
"B3",
|
|
5525
5595
|
["ci_script_depth", "default_branch_ci_depth"],
|
|
5526
5596
|
() => evidence.push(
|
|
5527
|
-
evidenceForRelative(
|
|
5597
|
+
evidenceForRelative(
|
|
5598
|
+
mono.root,
|
|
5599
|
+
rootWorkflow,
|
|
5600
|
+
"ci_run",
|
|
5601
|
+
ciWorkflowCitationLabel(
|
|
5602
|
+
"CI workflow (monorepo root)",
|
|
5603
|
+
"read",
|
|
5604
|
+
workflowsRead,
|
|
5605
|
+
1,
|
|
5606
|
+
unreadWorkflows
|
|
5607
|
+
)
|
|
5608
|
+
)
|
|
5528
5609
|
)
|
|
5529
5610
|
);
|
|
5530
5611
|
}
|
|
@@ -5536,6 +5617,7 @@ function collectB3CiDisciplineEvidence(repoPath, repoFiles, mono) {
|
|
|
5536
5617
|
CI_TYPECHECK_COMMAND_PATTERN,
|
|
5537
5618
|
CI_BUILD_COMMAND_PATTERN
|
|
5538
5619
|
];
|
|
5620
|
+
const rootOnlyScriptsNote = rootOnlyPackageScriptsDisclosure(repoFiles, packageJson);
|
|
5539
5621
|
const scriptDepth = ["test", "lint", "typecheck", "build"].filter(
|
|
5540
5622
|
(s) => s === "test" ? hasCredibleTestScript(scripts) : scripts.has(s)
|
|
5541
5623
|
).length;
|
|
@@ -5581,7 +5663,8 @@ function collectB3CiDisciplineEvidence(repoPath, repoFiles, mono) {
|
|
|
5581
5663
|
label: `monorepo-root CI command: ${["test", "lint", "type-check", "build"][index]}`,
|
|
5582
5664
|
count: rootCategoryHits[index] ? 1 : 0
|
|
5583
5665
|
})) : []
|
|
5584
|
-
]
|
|
5666
|
+
],
|
|
5667
|
+
...rootOnlyScriptsNote ? { condition: rootOnlyScriptsNote } : {}
|
|
5585
5668
|
}
|
|
5586
5669
|
),
|
|
5587
5670
|
metric(
|
|
@@ -5689,32 +5772,36 @@ function collectB4AuditEvidence(repoPath, repoFiles, generatedAt, useV19CommitYe
|
|
|
5689
5772
|
function collectB6PrivilegedOpsGatingEvidence(repoPath, repoFiles, useV39Detectors = false, useV21ExecutedEscalations = false) {
|
|
5690
5773
|
const evidence = [];
|
|
5691
5774
|
const findings = [];
|
|
5692
|
-
const
|
|
5775
|
+
const policyDocFiles = repoFiles.filter(
|
|
5776
|
+
(file) => /\.(md|mdx)$/i.test(file) && isPolicyDocumentEvidencePath(file)
|
|
5777
|
+
);
|
|
5778
|
+
const isPolicyDocMatching = (file, pattern) => fileContains(repoPath, file, pattern) && !isCejelCertificateText(repoPath, file);
|
|
5693
5779
|
const humanGateDoc = withContentReadSignal(
|
|
5694
5780
|
"B6",
|
|
5695
5781
|
"human_gate_documented",
|
|
5696
|
-
() =>
|
|
5782
|
+
() => policyDocFiles.find((file) => isPolicyDocMatching(file, HUMAN_GATE_MARKER_PATTERN))
|
|
5697
5783
|
);
|
|
5698
5784
|
const implFiles = repoFiles.filter(isImplementationFile);
|
|
5785
|
+
const implementationEvidenceFiles = implFiles.filter(isImplementationEvidencePath);
|
|
5699
5786
|
const gatedPrivilegeCheckFile = withContentReadSignal(
|
|
5700
5787
|
"B6",
|
|
5701
5788
|
"fail_closed_privilege_check",
|
|
5702
|
-
() =>
|
|
5703
|
-
(file) =>
|
|
5789
|
+
() => implementationEvidenceFiles.find(
|
|
5790
|
+
(file) => fileMatchesOutsideComments(repoPath, file, GATED_PRIVILEGE_CHECK_PATTERN) && fileMatchesOutsideComments(repoPath, file, SET_ROLE_PATTERN)
|
|
5704
5791
|
)
|
|
5705
5792
|
);
|
|
5706
5793
|
const killSwitchFile = withContentReadSignal(
|
|
5707
5794
|
"B6",
|
|
5708
5795
|
"kill_switch_fail_safe_present",
|
|
5709
|
-
() =>
|
|
5710
|
-
(file) =>
|
|
5796
|
+
() => implementationEvidenceFiles.find(
|
|
5797
|
+
(file) => fileMatchesOutsideComments(repoPath, file, KILL_SWITCH_NAME_PATTERN) && fileMatchesOutsideComments(repoPath, file, KILL_SWITCH_FAIL_CLOSED_PATTERN)
|
|
5711
5798
|
)
|
|
5712
5799
|
);
|
|
5713
|
-
const codeownersFile = repoFiles.find((file) =>
|
|
5800
|
+
const codeownersFile = repoFiles.find((file) => GITHUB_CODEOWNERS_PATH_PATTERN.test(file));
|
|
5714
5801
|
const reviewGateDoc = withContentReadSignal(
|
|
5715
5802
|
"B6",
|
|
5716
5803
|
"protected_path_review_gate",
|
|
5717
|
-
() =>
|
|
5804
|
+
() => policyDocFiles.find((file) => isPolicyDocMatching(file, REQUIRED_REVIEW_PATTERN))
|
|
5718
5805
|
);
|
|
5719
5806
|
const protectedPathReviewGate = codeownersFile ?? reviewGateDoc;
|
|
5720
5807
|
const { executableFiles, v21ExecutedEscalationFileSet, productionUngatedEscalationFiles } = withContentReadSignal("B6", "privilege_escalation_cleanliness", () => {
|
|
@@ -5792,7 +5879,7 @@ function collectB6PrivilegedOpsGatingEvidence(repoPath, repoFiles, useV39Detecto
|
|
|
5792
5879
|
repoPath,
|
|
5793
5880
|
protectedPathReviewGate,
|
|
5794
5881
|
"artifact",
|
|
5795
|
-
"CODEOWNERS
|
|
5882
|
+
protectedPathReviewGate === codeownersFile ? "CODEOWNERS file in a location GitHub reads (protected-path review gate)" : "Documented required-review/branch-protection policy"
|
|
5796
5883
|
)
|
|
5797
5884
|
)
|
|
5798
5885
|
);
|
|
@@ -5883,7 +5970,7 @@ function collectB6PrivilegedOpsGatingEvidence(repoPath, repoFiles, useV39Detecto
|
|
|
5883
5970
|
1,
|
|
5884
5971
|
hasPrivilegedOpsSurface ? 0.2 : 0.6,
|
|
5885
5972
|
"present",
|
|
5886
|
-
"Credits a CODEOWNERS file or documented required-review/branch-protection policy \u2014 the general OSS-observable analogue of human-gating changes to sensitive paths."
|
|
5973
|
+
"Credits a CODEOWNERS file where GitHub reads it (root, .github/ or docs/) or a documented required-review/branch-protection policy (not a changelog, record, review note or report) \u2014 the general OSS-observable analogue of human-gating changes to sensitive paths."
|
|
5887
5974
|
),
|
|
5888
5975
|
...killSwitchMetrics
|
|
5889
5976
|
],
|
|
@@ -5929,6 +6016,19 @@ function isTestFile(file, rubricVersion = WITAN_RUBRIC_VERSION) {
|
|
|
5929
6016
|
}
|
|
5930
6017
|
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)$/;
|
|
5931
6018
|
var NAME_SHAPED_TEST_FILE_PATTERN_V17 = /\.tftest\.hcl$|\.bats$|(^|\/)test[^/]*\.m$|_test\.m$/i;
|
|
6019
|
+
var CALIBRATION_RECORD_DIR_PATTERN = /(^|\/)calibrations?(\/|$)/i;
|
|
6020
|
+
function isImplementationEvidencePath(path) {
|
|
6021
|
+
return isProductionSourcePath(path) && !CALIBRATION_RECORD_DIR_PATTERN.test(path);
|
|
6022
|
+
}
|
|
6023
|
+
var CHANGELOG_FILE_PATTERN = /(^|\/)(?:CHANGELOG|CHANGES|HISTORY|NEWS|RELEASE[-_]?NOTES|RELEASES)(?:\.[^/]*)?$/i;
|
|
6024
|
+
var NON_POLICY_RECORD_DIR_PATTERN = /(^|\/)(?:\.changesets?|changelogs?|changelog\.d|experiments?|calibrations?|reviews|review[-_]notes?|reports)(\/|$)/i;
|
|
6025
|
+
function isPolicyDocumentEvidencePath(path) {
|
|
6026
|
+
return isProductionSourcePath(path) && !CHANGELOG_FILE_PATTERN.test(path) && !NON_POLICY_RECORD_DIR_PATTERN.test(path);
|
|
6027
|
+
}
|
|
6028
|
+
var CEJEL_CERTIFICATE_TEXT_PATTERN = /^# Cejel Trust Report\b[\s\S]*?^- Rubric: /m;
|
|
6029
|
+
function isCejelCertificateText(repoPath, file) {
|
|
6030
|
+
return fileContains(repoPath, file, CEJEL_CERTIFICATE_TEXT_PATTERN);
|
|
6031
|
+
}
|
|
5932
6032
|
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;
|
|
5933
6033
|
function hasCredibleTestScript(scripts) {
|
|
5934
6034
|
const script = scripts.get("test");
|
|
@@ -5980,6 +6080,7 @@ function fileHasV21RawSqlEscalation(repoPath, file) {
|
|
|
5980
6080
|
var GATED_PRIVILEGE_CHECK_PATTERN = /pg_has_role\s*\(|has_role\s*\(|is not a member of/i;
|
|
5981
6081
|
var SET_ROLE_PATTERN = /\bset\s+(local\s+)?role\b/i;
|
|
5982
6082
|
var REQUIRED_REVIEW_PATTERN = /required review|branch protection|protected branch/i;
|
|
6083
|
+
var GITHUB_CODEOWNERS_PATH_PATTERN = /^(?:\.github\/|docs\/)?CODEOWNERS$/;
|
|
5983
6084
|
var HISTORY_SECRET_SCAN_CREDENTIAL_BLOB_LIMIT = 5e3;
|
|
5984
6085
|
var V23_PEM_WIDENED_HISTORY_BLOB_LIMIT = 500;
|
|
5985
6086
|
var SECRET_IDENTIFIER_KEYWORD_PATTERN = /secret|token|api[_-]?key|password|access[_-]?key/gi;
|
|
@@ -5996,7 +6097,7 @@ var HEAVY_TEST_DEPENDENCY_NAME_PATTERN = /^(?:(?:jest|mocha|ava|tape|jasmine|kar
|
|
|
5996
6097
|
var TIMING_SAFE_COMPARE_PATTERN = /\btiming[-_]?safe[-_]?(?:equal|compare)\b|crypto\.timingSafeEqual\s*\(/i;
|
|
5997
6098
|
var CANONICAL_SERIALIZE_PATTERN = /\bcanonicalize\s*\(|\bcanonicalJson\b|\bstableStringify\s*\(|json-stable-stringify|safe-stable-stringify|\bsortKeys\s*\(/i;
|
|
5998
6099
|
var SIGN_OR_HMAC_CALL_PATTERN = /\bcreateHmac\s*\(|\bcreateSign\s*\(|\.sign\s*\(/;
|
|
5999
|
-
var INSECURE_SECRET_COMPARE_LINE_PATTERN = /\b\w*(?:hmac|signature|\bmac
|
|
6100
|
+
var INSECURE_SECRET_COMPARE_LINE_PATTERN = /\b\w*(?:hmac|signature|\bmac)\w*\s*(===|!==)\s*(?!['"`]|undefined\b|null\b)([\w.]+(?:\s*[-+]\s*\d+)?)/i;
|
|
6000
6101
|
var DEFAULT_SECRET_SENTINEL_COMPARE_LINE_PATTERN = /\b(?:secret|token|password|apiKey)\w*\s*(?:===|!==|==|!=)\s*[\w.]*default(?:Secret|Token|Password|ApiKey)\b/i;
|
|
6001
6102
|
var NUMERIC_SHAPED_OPERAND_PATTERN = /^-?\d+$|\.(?:length|len|size|count)\b|(?:length|index|idx|offset|count|size|len)$/i;
|
|
6002
6103
|
function lineHasInsecureSecretCompare(line, useV39Detectors = false) {
|
|
@@ -6390,6 +6491,81 @@ var JS_TEST_ASSERTION_PATTERN = /(expect\(|assert\.|should\.|toEqual\(|toBe\(|as
|
|
|
6390
6491
|
var CPP_TEST_ASSERTION_PATTERN = /\bEXPECT_|ASSERT_EQ\b|ASSERT_TRUE\b|ASSERT_FALSE\b|\bREQUIRE\s*\(|\bCHECK\s*\(|\bTEST\s*\(|\bTEST_F\s*\(|\bTEST_CASE\s*\(|\bSECTION\s*\(/;
|
|
6391
6492
|
var MULTI_ECOSYSTEM_TEST_ASSERTION_PATTERN = /\.assert[A-Z_]\w*\s*\(|\bassert[A-Z]\w*\s*\(|\bpytest\.raises\b|\bself\.fail\s*\(|\bt\.(?:Error|Errorf|Fatal|Fatalf|Fail|FailNow)\b|\brequire\.[A-Z]\w*\s*\(|\b(?:debug_)?assert(?:_eq|_ne)?!\s*\(|\bassert_\w+\b|\$this->assert\w+\s*\(/;
|
|
6392
6493
|
var SUITE_LEVEL_SKIP_PATTERN = /\b(?:describe|suite|context)\.skip\s*\(/;
|
|
6494
|
+
function hasLiveAvaAssertion(contents) {
|
|
6495
|
+
const uncommented = stripJavaScriptComments(contents);
|
|
6496
|
+
const imports = [...uncommented.matchAll(/\bimport\s+([A-Za-z_$][\w$]*)\s+from\s*['"]ava['"]|\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*require\s*\(\s*['"]ava['"]\s*\)/g)];
|
|
6497
|
+
if (!imports.length) return false;
|
|
6498
|
+
let quote = "";
|
|
6499
|
+
let escaped = false;
|
|
6500
|
+
const characters = uncommented.split("");
|
|
6501
|
+
for (let i = 0; i < characters.length; i += 1) {
|
|
6502
|
+
const ch = characters[i];
|
|
6503
|
+
if (quote) {
|
|
6504
|
+
characters[i] = ch === "\n" ? "\n" : " ";
|
|
6505
|
+
if (escaped) escaped = false;
|
|
6506
|
+
else if (ch === "\\") escaped = true;
|
|
6507
|
+
else if (ch === quote) quote = "";
|
|
6508
|
+
} else if (ch === "'" || ch === '"' || ch === "`") {
|
|
6509
|
+
quote = ch;
|
|
6510
|
+
characters[i] = " ";
|
|
6511
|
+
}
|
|
6512
|
+
}
|
|
6513
|
+
const code = characters.join("");
|
|
6514
|
+
const imported = imports.find((candidate) => code[candidate.index] === uncommented[candidate.index]);
|
|
6515
|
+
const runner = imported?.[1] ?? imported?.[2];
|
|
6516
|
+
if (!runner) return false;
|
|
6517
|
+
const escape = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6518
|
+
const calls = new RegExp(`\\b${escape(runner)}((?:\\.\\w+)*)\\s*\\(`, "g");
|
|
6519
|
+
const closeAt = (open, left, right) => {
|
|
6520
|
+
let depth = 1;
|
|
6521
|
+
for (let i = open + 1; i < code.length; i += 1) {
|
|
6522
|
+
if (code[i] === left) depth += 1;
|
|
6523
|
+
else if (code[i] === right && --depth === 0) return i;
|
|
6524
|
+
}
|
|
6525
|
+
return -1;
|
|
6526
|
+
};
|
|
6527
|
+
for (const call of code.matchAll(calls)) {
|
|
6528
|
+
const modifiers = call[1].split(".").filter(Boolean);
|
|
6529
|
+
if (modifiers.some((modifier) => !["serial", "only", "failing"].includes(modifier))) continue;
|
|
6530
|
+
const open = call.index + call[0].length - 1;
|
|
6531
|
+
const close = closeAt(open, "(", ")");
|
|
6532
|
+
if (close < 0) continue;
|
|
6533
|
+
const args = code.slice(open + 1, close);
|
|
6534
|
+
const callback = /(?:\basync\s+)?(?:\(\s*([A-Za-z_$][\w$]*)\s*\)|(?<![\w$])([A-Za-z_$][\w$]*))\s*=>|\bfunction(?:\s+\w+)?\s*\(\s*([A-Za-z_$][\w$]*)\s*\)/.exec(args);
|
|
6535
|
+
const parameter = callback?.[1] ?? callback?.[2] ?? callback?.[3];
|
|
6536
|
+
if (!callback || !parameter) continue;
|
|
6537
|
+
let start = open + 1 + callback.index + callback[0].length;
|
|
6538
|
+
while (/\s/.test(code[start] ?? "") && start < close) start += 1;
|
|
6539
|
+
const end = code[start] === "{" ? closeAt(start, "{", "}") : close;
|
|
6540
|
+
if (end < 0 || end > close) continue;
|
|
6541
|
+
const assertion = new RegExp(`\\b${escape(parameter)}\\.(?:assert|pass|fail|truthy|falsy|true|false|is|not|deepEqual|notDeepEqual|throws|throwsAsync|notThrows|notThrowsAsync|regex|notRegex|snapshot|like)\\s*\\(`);
|
|
6542
|
+
const body = code.slice(start, end);
|
|
6543
|
+
const active = body.split("");
|
|
6544
|
+
let maskedThrough = -1;
|
|
6545
|
+
for (const nested of body.matchAll(/=>\s*|\bfunction(?:\s+\w+)?\s*\([^)]*\)\s*/g)) {
|
|
6546
|
+
if (nested.index < maskedThrough) continue;
|
|
6547
|
+
const begin = nested.index + nested[0].length;
|
|
6548
|
+
let stop = begin;
|
|
6549
|
+
if (body[begin] === "{") {
|
|
6550
|
+
stop = closeAt(start + begin, "{", "}") - start + 1;
|
|
6551
|
+
} else {
|
|
6552
|
+
let depth = 0;
|
|
6553
|
+
while (stop < body.length) {
|
|
6554
|
+
const ch = body[stop];
|
|
6555
|
+
if (depth === 0 && /[;,)]/.test(ch)) break;
|
|
6556
|
+
if (ch === "(" || ch === "[") depth += 1;
|
|
6557
|
+
else if (ch === ")" || ch === "]") depth -= 1;
|
|
6558
|
+
stop += 1;
|
|
6559
|
+
}
|
|
6560
|
+
}
|
|
6561
|
+
if (stop <= begin) continue;
|
|
6562
|
+
for (let i = nested.index; i < Math.min(stop, active.length); i += 1) active[i] = " ";
|
|
6563
|
+
maskedThrough = stop;
|
|
6564
|
+
}
|
|
6565
|
+
if (assertion.test(active.join(""))) return true;
|
|
6566
|
+
}
|
|
6567
|
+
return false;
|
|
6568
|
+
}
|
|
6393
6569
|
function measureNonHollowTestShare(repoPath, files, useV17Detectors = false) {
|
|
6394
6570
|
let nonHollowCount = 0;
|
|
6395
6571
|
let ratedCount = 0;
|
|
@@ -6397,7 +6573,7 @@ function measureNonHollowTestShare(repoPath, files, useV17Detectors = false) {
|
|
|
6397
6573
|
const fullPath = join(repoPath, file);
|
|
6398
6574
|
if (!isRegularFile(fullPath)) continue;
|
|
6399
6575
|
const contents = readRepoText(fullPath, "utf8");
|
|
6400
|
-
const nonHollow = (JS_TEST_ASSERTION_PATTERN.test(contents) || CPP_TEST_ASSERTION_PATTERN.test(contents) || MULTI_ECOSYSTEM_TEST_ASSERTION_PATTERN.test(contents)) && !SUITE_LEVEL_SKIP_PATTERN.test(contents);
|
|
6576
|
+
const nonHollow = (JS_TEST_ASSERTION_PATTERN.test(contents) || CPP_TEST_ASSERTION_PATTERN.test(contents) || MULTI_ECOSYSTEM_TEST_ASSERTION_PATTERN.test(contents) || hasLiveAvaAssertion(contents)) && !SUITE_LEVEL_SKIP_PATTERN.test(contents);
|
|
6401
6577
|
if (nonHollow) {
|
|
6402
6578
|
nonHollowCount += 1;
|
|
6403
6579
|
ratedCount += 1;
|
|
@@ -8035,9 +8211,11 @@ var RACK_ENTRYPOINT_FILE_PATTERN = /(^|\/)(?:config\.ru|(?:main|server|app|start
|
|
|
8035
8211
|
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*\(/;
|
|
8036
8212
|
var V20_DIRECT_HTTP_SERVER_PATTERN = /\b(?:http|https)\.createServer\s*\([\s\S]{0,1500}?\)\.listen\s*\(\s*(?:PORT|port|\d+)/;
|
|
8037
8213
|
var HEALTH_ROUTE_FUNCTIONS_DIR_PATTERN = /(^|\/)functions\/.*\.(?:ts|tsx|js|jsx|py|go|rs|java|rb|cpp|cc|cxx|c|h|hpp|kt|swift|php)$/;
|
|
8214
|
+
var HEALTH_ROUTE_ENTRYPOINT_HOME_PATTERN = /^(?:(?:server|index|app|main)\.(?:ts|tsx|js|jsx|mjs|cjs)|(?:server|backend|api)\/.*\.(?:ts|tsx|js|jsx|mjs|cjs|py|go|rs|java|rb|php))$/;
|
|
8038
8215
|
var V20_HEALTH_OR_READINESS_ROUTE_PATTERN = /["'`](?:[\w${}./-]{0,60}\/[_-]?(?:(?:health|ready|live)z?|readiness|liveness|up)(?=["'`/])|(?:healthz|readiness|liveness)(?=["'`]))|@Get\s*\(\s*(["'`])health\1\s*\)/i;
|
|
8039
|
-
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;
|
|
8216
|
+
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*\)\s*(?:=>|\{)/i;
|
|
8040
8217
|
var EXPRESS_MIDDLEWARE_REACHABLE_PATTERN = /\.use\s*\(|\bmodule\.exports\b|\bexport\s+(?:default\b|function\b|const\b|class\b)/;
|
|
8218
|
+
var ERROR_BOUNDARY_FILENAME_PATTERN = /(^|\/)(?:error-boundary|error)\.(?:tsx|jsx|ts|js)$/;
|
|
8041
8219
|
var RACK_SERVER_ENTRYPOINT_PATTERN = /Rack::(?:Server|Handler(?:::\w+)?)\.(?:start|run)\s*\(/;
|
|
8042
8220
|
var RACK_CONFIG_RUN_PATTERN = /^\s*run\s+(?:(?:[A-Z]\w*(?:::\w+)*(?:\.new)?|lambda)\b|->)/m;
|
|
8043
8221
|
var RUNTIME_CONTAINER_COMMAND_PATTERN = /^\s*(?:CMD|ENTRYPOINT)\s+.*(?:\b(?:start|serve|server|qgis|nginx|apache|gunicorn|uvicorn)\b|manage\.py\s+runserver).*$/im;
|
|
@@ -8220,6 +8398,36 @@ function isV24IgnoredScanFile(file) {
|
|
|
8220
8398
|
function findRootPackageJson(repoFiles) {
|
|
8221
8399
|
return repoFiles.includes("package.json") ? "package.json" : null;
|
|
8222
8400
|
}
|
|
8401
|
+
function ciWorkflowCitationLabel(baseLabel, verb, considered, cited, unread) {
|
|
8402
|
+
const unreadTotal = [...unread.values()].reduce((sum, count) => sum + count, 0);
|
|
8403
|
+
if (considered <= cited && unreadTotal === 0) return baseLabel;
|
|
8404
|
+
const parts = [
|
|
8405
|
+
`${considered} workflow file${considered === 1 ? "" : "s"} ${verb}`,
|
|
8406
|
+
`${cited} cited`
|
|
8407
|
+
];
|
|
8408
|
+
if (unreadTotal > 0) {
|
|
8409
|
+
const reasons = [...unread.keys()].sort().join(", ");
|
|
8410
|
+
parts.push(`${unreadTotal} not read (${reasons})`);
|
|
8411
|
+
}
|
|
8412
|
+
return `${baseLabel} (${parts.join("; ")})`;
|
|
8413
|
+
}
|
|
8414
|
+
function unreadCiWorkflowReasons(includes) {
|
|
8415
|
+
const unread = /* @__PURE__ */ new Map();
|
|
8416
|
+
for (const { path, reasons } of withheldRepoPaths()) {
|
|
8417
|
+
if (!isCiWorkflow(path) || !includes(path)) continue;
|
|
8418
|
+
const reason = [...reasons].sort()[0];
|
|
8419
|
+
if (reason !== void 0) unread.set(reason, (unread.get(reason) ?? 0) + 1);
|
|
8420
|
+
}
|
|
8421
|
+
return unread;
|
|
8422
|
+
}
|
|
8423
|
+
function rootOnlyPackageScriptsDisclosure(repoFiles, rootPackageJson) {
|
|
8424
|
+
const others = repoFiles.filter(
|
|
8425
|
+
(file) => file !== rootPackageJson && /(^|\/)package\.json$/.test(file) && isAuthoredProductionPath(file)
|
|
8426
|
+
).length;
|
|
8427
|
+
if (others === 0) return null;
|
|
8428
|
+
const present = `${others}${rootPackageJson ? " other" : ""} package.json file${others === 1 ? "" : "s"} present`;
|
|
8429
|
+
return `${rootPackageJson ? "" : "no root package.json found; "}package scripts for this metric are read from the root package.json only; ${present}`;
|
|
8430
|
+
}
|
|
8223
8431
|
function isRegularFile(path) {
|
|
8224
8432
|
try {
|
|
8225
8433
|
return lstatSync(path).isFile();
|
|
@@ -8232,11 +8440,22 @@ function fileContains(repoPath, file, pattern) {
|
|
|
8232
8440
|
if (!isRegularFile(fullPath)) return false;
|
|
8233
8441
|
return pattern.test(readRepoText(fullPath, "utf8"));
|
|
8234
8442
|
}
|
|
8235
|
-
|
|
8443
|
+
var HASH_COMMENT_SOURCE_PATTERN = /\.(?:py|rb)$/i;
|
|
8444
|
+
function stripCodeComments(file, contents) {
|
|
8445
|
+
const withoutComments = contents.replace(/\/\*[\s\S]*?\*\//g, (block) => block.replace(/[^\n]/g, "")).replace(/(?<!:)\/\/.*$/gm, "");
|
|
8446
|
+
return HASH_COMMENT_SOURCE_PATTERN.test(file) ? withoutComments.replace(/^[ \t]*#.*$/gm, "") : withoutComments;
|
|
8447
|
+
}
|
|
8448
|
+
function fileMatchesOutsideComments(repoPath, file, pattern) {
|
|
8236
8449
|
const fullPath = join(repoPath, file);
|
|
8237
8450
|
if (!isRegularFile(fullPath)) return false;
|
|
8238
|
-
|
|
8239
|
-
|
|
8451
|
+
return pattern.test(stripCodeComments(file, readRepoText(fullPath, "utf8")));
|
|
8452
|
+
}
|
|
8453
|
+
function findFirstMatchingLineOutsideComments(repoPath, file, pattern) {
|
|
8454
|
+
const fullPath = join(repoPath, file);
|
|
8455
|
+
if (!isRegularFile(fullPath)) return null;
|
|
8456
|
+
const lines = stripCodeComments(file, readRepoText(fullPath, "utf8")).split("\n");
|
|
8457
|
+
const index = lines.findIndex((line) => pattern.test(line));
|
|
8458
|
+
return index === -1 ? null : index + 1;
|
|
8240
8459
|
}
|
|
8241
8460
|
var PEM_PRIVATE_KEY_ASSIGNMENT_PATTERN = /(?:["'])?([A-Za-z_$][\w$.-]*)(?:["'])?\s*[:=]\s*(?:\|[-+0-9]*\s*\r?\n[ \t]*)?["'`]?-----BEGIN((?: (?:RSA|DSA|EC|OPENSSH|ENCRYPTED))? PRIVATE KEY)-----([\s\S]{0,32768}?)-----END\2-----/g;
|
|
8242
8461
|
var BARE_PEM_PRIVATE_KEY_PATTERN = /["'`]?-----BEGIN((?: (?:RSA|DSA|EC|OPENSSH|ENCRYPTED))? PRIVATE KEY)-----([\s\S]{0,32768}?)-----END\1-----/g;
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire as __cejelCreateRequire } from 'node:module';
|
|
|
3
3
|
const require = __cejelCreateRequire(import.meta.url);
|
|
4
4
|
import {
|
|
5
5
|
serveCejelMcpOverStdio
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-HC2WASRS.js";
|
|
7
7
|
import {
|
|
8
8
|
CALLER_CONTEXT_PRODUCT_IDENTITY_NOTICE,
|
|
9
9
|
CERTIFICATE_GLOSSARY,
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
runCejelScan,
|
|
30
30
|
serializeWitanReport,
|
|
31
31
|
verifyWitanAttestationBinding
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-4YK23CST.js";
|
|
33
33
|
import "./chunk-63XQDYQ5.js";
|
|
34
34
|
import {
|
|
35
35
|
external_exports
|
|
@@ -42,7 +42,7 @@ import {
|
|
|
42
42
|
init_esm_shims();
|
|
43
43
|
import { createHash as createHash3 } from "crypto";
|
|
44
44
|
import { existsSync, mkdirSync, readFileSync, realpathSync, writeFileSync } from "fs";
|
|
45
|
-
import { dirname, join, resolve } from "path";
|
|
45
|
+
import { dirname, join, resolve as resolve2 } from "path";
|
|
46
46
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
47
47
|
|
|
48
48
|
// src/issuance/index.ts
|
|
@@ -541,6 +541,43 @@ function renderGitLabCodeQualityFooter(result) {
|
|
|
541
541
|
`;
|
|
542
542
|
}
|
|
543
543
|
|
|
544
|
+
// src/npx-version-guard.ts
|
|
545
|
+
init_esm_shims();
|
|
546
|
+
import { delimiter, resolve } from "path";
|
|
547
|
+
var EXACT_VERSION_PATTERN = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
548
|
+
function npxVersionMismatchWarning(context) {
|
|
549
|
+
const { env, packageName, runningVersion, runningPath } = context;
|
|
550
|
+
if (env.npm_lifecycle_event !== "npx") return void 0;
|
|
551
|
+
if (env.npm_config_call) return void 0;
|
|
552
|
+
const pinned = exactPackageSpecVersion(env.npm_config_package, packageName);
|
|
553
|
+
if (pinned !== void 0) {
|
|
554
|
+
if (pinned === runningVersion) return void 0;
|
|
555
|
+
return `warning: npx was asked for ${packageName}@${pinned}, but cejel ${runningVersion} is running from ${runningPath}. Inside a ${packageName} checkout, npx can run the cejel on PATH; run it from another directory (#436).`;
|
|
556
|
+
}
|
|
557
|
+
const requested = env.npm_package_version;
|
|
558
|
+
if (env.npm_package_name !== packageName || !requested) return void 0;
|
|
559
|
+
if (!resolvedToLocalTree(env, context.cwd)) return void 0;
|
|
560
|
+
if (requested === runningVersion) return void 0;
|
|
561
|
+
const checkout = env.npm_config_local_prefix || context.cwd;
|
|
562
|
+
return `warning: npx resolved ${packageName} to the ${requested} checkout at ${checkout} and ran the cejel on PATH instead: cejel ${runningVersion} from ${runningPath}. Run npx from another directory to get the version you asked for (#436).`;
|
|
563
|
+
}
|
|
564
|
+
function exactPackageSpecVersion(packageSpecs, packageName) {
|
|
565
|
+
if (!packageSpecs) return void 0;
|
|
566
|
+
const prefix = `${packageName}@`;
|
|
567
|
+
for (const spec of packageSpecs.split(/\n+/)) {
|
|
568
|
+
const trimmed = spec.trim();
|
|
569
|
+
if (!trimmed.startsWith(prefix)) continue;
|
|
570
|
+
const version = trimmed.slice(prefix.length);
|
|
571
|
+
if (EXACT_VERSION_PATTERN.test(version)) return version;
|
|
572
|
+
}
|
|
573
|
+
return void 0;
|
|
574
|
+
}
|
|
575
|
+
function resolvedToLocalTree(env, cwd) {
|
|
576
|
+
const pathKey = Object.keys(env).find((key) => /^path$/i.test(key) && env[key]);
|
|
577
|
+
const first = pathKey ? env[pathKey]?.split(delimiter)[0] : void 0;
|
|
578
|
+
return first !== void 0 && first === resolve(cwd, "node_modules", ".bin");
|
|
579
|
+
}
|
|
580
|
+
|
|
544
581
|
// src/terminal.ts
|
|
545
582
|
init_esm_shims();
|
|
546
583
|
function renderMinScoreAbstentionFailure(summary, minScore) {
|
|
@@ -862,8 +899,29 @@ async function main() {
|
|
|
862
899
|
process.exitCode = exitCode;
|
|
863
900
|
}
|
|
864
901
|
async function runWitanFreeCli(args) {
|
|
902
|
+
warnIfNpxRanAnotherVersion();
|
|
865
903
|
return runWitanCli(args);
|
|
866
904
|
}
|
|
905
|
+
function warnIfNpxRanAnotherVersion() {
|
|
906
|
+
const warning = npxVersionMismatchWarning({
|
|
907
|
+
env: process.env,
|
|
908
|
+
cwd: process.cwd(),
|
|
909
|
+
packageName: NPX_PACKAGE_NAME,
|
|
910
|
+
runningVersion: cliVersion(),
|
|
911
|
+
runningPath: runningEntryPath()
|
|
912
|
+
});
|
|
913
|
+
if (warning) process.stderr.write(`${warning}
|
|
914
|
+
`);
|
|
915
|
+
}
|
|
916
|
+
function runningEntryPath() {
|
|
917
|
+
const invokedPath = process.argv[1];
|
|
918
|
+
if (!invokedPath) return process.execPath;
|
|
919
|
+
try {
|
|
920
|
+
return realpathSync(invokedPath);
|
|
921
|
+
} catch {
|
|
922
|
+
return invokedPath;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
867
925
|
async function runWitanV22CalibrationCli(args) {
|
|
868
926
|
return runWitanCli(args, WITAN_RUBRIC_VERSION_V22);
|
|
869
927
|
}
|
|
@@ -1039,8 +1097,8 @@ function parseExportArgs(args) {
|
|
|
1039
1097
|
return {
|
|
1040
1098
|
command: "export",
|
|
1041
1099
|
format,
|
|
1042
|
-
reportPath:
|
|
1043
|
-
outPath:
|
|
1100
|
+
reportPath: resolve2(reportPath),
|
|
1101
|
+
outPath: resolve2(outPath)
|
|
1044
1102
|
};
|
|
1045
1103
|
}
|
|
1046
1104
|
function runExport(invocation) {
|
|
@@ -1074,8 +1132,8 @@ function parseVerifyArgs(args) {
|
|
|
1074
1132
|
if (arg === "--signers" || arg === "--revocations") {
|
|
1075
1133
|
const value = args[index + 1];
|
|
1076
1134
|
if (!value) throw new Error(`Missing value for ${arg}`);
|
|
1077
|
-
if (arg === "--signers") signersPath =
|
|
1078
|
-
else revocationsPath =
|
|
1135
|
+
if (arg === "--signers") signersPath = resolve2(value);
|
|
1136
|
+
else revocationsPath = resolve2(value);
|
|
1079
1137
|
index += 1;
|
|
1080
1138
|
continue;
|
|
1081
1139
|
}
|
|
@@ -1087,10 +1145,10 @@ function parseVerifyArgs(args) {
|
|
|
1087
1145
|
if (!reportPath || !attestationPath) throw new Error(VERIFY_USAGE());
|
|
1088
1146
|
return {
|
|
1089
1147
|
command: "verify",
|
|
1090
|
-
reportPath:
|
|
1091
|
-
attestationPath:
|
|
1092
|
-
...issuancePath ? { issuancePath:
|
|
1093
|
-
...issuanceSignaturePath ? { issuanceSignaturePath:
|
|
1148
|
+
reportPath: resolve2(reportPath),
|
|
1149
|
+
attestationPath: resolve2(attestationPath),
|
|
1150
|
+
...issuancePath ? { issuancePath: resolve2(issuancePath) } : {},
|
|
1151
|
+
...issuanceSignaturePath ? { issuanceSignaturePath: resolve2(issuanceSignaturePath) } : {},
|
|
1094
1152
|
...signersPath ? { signersPath } : {},
|
|
1095
1153
|
...revocationsPath ? { revocationsPath } : {}
|
|
1096
1154
|
};
|
|
@@ -1116,15 +1174,15 @@ function parseIssueArgs(args) {
|
|
|
1116
1174
|
if (arg === void 0) continue;
|
|
1117
1175
|
switch (arg) {
|
|
1118
1176
|
case "--report":
|
|
1119
|
-
reportPath =
|
|
1177
|
+
reportPath = resolve2(takeValue(arg, index + 1));
|
|
1120
1178
|
index += 1;
|
|
1121
1179
|
continue;
|
|
1122
1180
|
case "--attestation":
|
|
1123
|
-
attestationPath =
|
|
1181
|
+
attestationPath = resolve2(takeValue(arg, index + 1));
|
|
1124
1182
|
index += 1;
|
|
1125
1183
|
continue;
|
|
1126
1184
|
case "--key":
|
|
1127
|
-
keyPath =
|
|
1185
|
+
keyPath = resolve2(takeValue(arg, index + 1));
|
|
1128
1186
|
index += 1;
|
|
1129
1187
|
continue;
|
|
1130
1188
|
case "--engagement-ref":
|
|
@@ -1133,7 +1191,7 @@ function parseIssueArgs(args) {
|
|
|
1133
1191
|
continue;
|
|
1134
1192
|
case "--out":
|
|
1135
1193
|
case "--out-dir":
|
|
1136
|
-
outDir =
|
|
1194
|
+
outDir = resolve2(takeValue(arg, index + 1));
|
|
1137
1195
|
index += 1;
|
|
1138
1196
|
continue;
|
|
1139
1197
|
case "--product-name":
|
|
@@ -1177,7 +1235,7 @@ function parseIssueArgs(args) {
|
|
|
1177
1235
|
throw new Error("--product-name and --name cannot be used together");
|
|
1178
1236
|
}
|
|
1179
1237
|
return {
|
|
1180
|
-
repoPath:
|
|
1238
|
+
repoPath: resolve2(repoPath ?? "."),
|
|
1181
1239
|
reportPath,
|
|
1182
1240
|
attestationPath,
|
|
1183
1241
|
keyPath,
|
|
@@ -1530,7 +1588,7 @@ function parseArgs(args) {
|
|
|
1530
1588
|
throw new Error("--product-name and --name cannot be used together");
|
|
1531
1589
|
}
|
|
1532
1590
|
return {
|
|
1533
|
-
repoPath:
|
|
1591
|
+
repoPath: resolve2(repoPath ?? "."),
|
|
1534
1592
|
outDir,
|
|
1535
1593
|
...minScore != null ? { minScore } : {},
|
|
1536
1594
|
...productName ? { productName } : {},
|
package/dist/mcp/index.js
CHANGED
|
@@ -3,8 +3,8 @@ import { createRequire as __cejelCreateRequire } from 'node:module';
|
|
|
3
3
|
const require = __cejelCreateRequire(import.meta.url);
|
|
4
4
|
import {
|
|
5
5
|
serveCejelMcpOverStdio
|
|
6
|
-
} from "../chunk-
|
|
7
|
-
import "../chunk-
|
|
6
|
+
} from "../chunk-HC2WASRS.js";
|
|
7
|
+
import "../chunk-4YK23CST.js";
|
|
8
8
|
import "../chunk-63XQDYQ5.js";
|
|
9
9
|
import "../chunk-FSMZV3Y6.js";
|
|
10
10
|
import {
|