@cejel/cejel 0.2.0 → 0.2.2
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 +88 -11
- package/dist/{chunk-PYI3OIBW.js → chunk-SNDRU52Z.js} +252 -47
- package/dist/index.js +6 -2
- package/dist/mcp/index.js +6 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,10 @@ certificate + badge over all of them. See "Aggregate your scanners" below.
|
|
|
18
18
|
|
|
19
19
|
> Dogfooded in production. Cejel is run continuously on Barg Labs' own multi-product
|
|
20
20
|
> monorepo — the ten-product studio it was built inside — which it currently scores
|
|
21
|
-
> 3.
|
|
21
|
+
> 3.3/4.0 on its rubric-native certificate. That transparency snapshot opts into prospective
|
|
22
|
+
> v18; the public CLI default remains calibrated v17. On the comparative board, our code sits
|
|
23
|
+
> outside the ranked population and receives no verdict band. We score ourselves before
|
|
24
|
+
> asking you to score yourself.
|
|
22
25
|
|
|
23
26
|
## Install
|
|
24
27
|
|
|
@@ -46,6 +49,29 @@ chmod +x cejel
|
|
|
46
49
|
./cejel .
|
|
47
50
|
```
|
|
48
51
|
|
|
52
|
+
**Windows x86_64 (PowerShell).**
|
|
53
|
+
|
|
54
|
+
```powershell
|
|
55
|
+
$asset = "cejel-Windows-x86_64.exe"
|
|
56
|
+
Invoke-WebRequest "https://github.com/BargLabs/cejel/releases/latest/download/$asset" -OutFile $asset
|
|
57
|
+
Invoke-WebRequest "https://github.com/BargLabs/cejel/releases/latest/download/SHA256SUMS" -OutFile SHA256SUMS
|
|
58
|
+
$expected = ((Select-String -Path SHA256SUMS -Pattern " $([regex]::Escape($asset))$").Line -split "\s+")[0]
|
|
59
|
+
$actual = (Get-FileHash -Algorithm SHA256 $asset).Hash.ToLowerInvariant()
|
|
60
|
+
if (-not $expected -or $actual -ne $expected.ToLowerInvariant()) {
|
|
61
|
+
throw "SHA-256 verification failed for $asset"
|
|
62
|
+
}
|
|
63
|
+
.\cejel-Windows-x86_64.exe .
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
> **Windows signing status:** `cejel-Windows-x86_64.exe` is intentionally unsigned in
|
|
67
|
+
> 0.2.2 and may trigger Microsoft SmartScreen. The release build removes Node's inherited
|
|
68
|
+
> signature before SEA injection and fails unless Windows reports the result as `NotSigned`;
|
|
69
|
+
> it does not ship an invalid signature. Before running it, verify `SHA256SUMS` and the
|
|
70
|
+
> GitHub build-provenance attestation. Each binary also has an attached SPDX SBOM and an
|
|
71
|
+
> own-platform verification receipt covering `--version`, `--help`, a real scan,
|
|
72
|
+
> source/binary parity, and a network-denied scan. If your policy requires Authenticode,
|
|
73
|
+
> use the npm package or the OCI image until a human-approved signing path is available.
|
|
74
|
+
|
|
49
75
|
**Don't take the offline claim on trust — check it.** Turn your network off, then run the
|
|
50
76
|
binary. It will score your repository and write you a certificate anyway. That is the whole
|
|
51
77
|
product, and you can falsify it in ten seconds:
|
|
@@ -58,7 +84,17 @@ docker run --rm --network=none -v "$PWD:/w" -w /w -v "$PWD/cejel:/cejel:ro" debi
|
|
|
58
84
|
**npm.**
|
|
59
85
|
|
|
60
86
|
```bash
|
|
61
|
-
npx @cejel/cejel .
|
|
87
|
+
npx @cejel/cejel@latest .
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
> **Distribution note:** Cejel `0.2.2` is the coordinated release version for npm,
|
|
91
|
+
> standalone binaries, Docker/OCI, GitHub Action, Homebrew, and MCP Registry.
|
|
92
|
+
|
|
93
|
+
`npx` can reuse a stale cached package. Force the current npm release with the `@latest`
|
|
94
|
+
specifier above, and check the version that will run before comparing certificates:
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npx @cejel/cejel@latest --version
|
|
62
98
|
```
|
|
63
99
|
|
|
64
100
|
If a root `package.json` still carries a template name, override only the certificate display
|
|
@@ -86,29 +122,30 @@ pnpm install && pnpm build
|
|
|
86
122
|
node dist/index.js .
|
|
87
123
|
```
|
|
88
124
|
|
|
89
|
-
Released binaries: `cejel-Darwin-arm64`, `cejel-Darwin-x86_64`, `cejel-Linux-aarch64`,
|
|
90
|
-
`cejel-Linux-x86_64`. The release also carries
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
125
|
+
Released binaries: `cejel-Darwin-arm64`, `cejel-Darwin-x86_64`, `cejel-Linux-aarch64`,
|
|
126
|
+
`cejel-Linux-x86_64`, and `cejel-Windows-x86_64.exe`. The release also carries
|
|
127
|
+
`SHA256SUMS`, a per-binary SPDX SBOM, and an own-platform verification receipt. Each binary
|
|
128
|
+
is executed against the source build and with networking denied before attachment. Releases
|
|
129
|
+
from v0.1.6 also carry a Sigstore bundle containing GitHub's signed build-provenance
|
|
130
|
+
attestation for the release set. Verify a downloaded binary with:
|
|
94
131
|
|
|
95
132
|
```bash
|
|
96
|
-
gh attestation verify ./cejel-
|
|
133
|
+
gh attestation verify ./cejel-Windows-x86_64.exe -R BargLabs/cejel
|
|
97
134
|
```
|
|
98
135
|
|
|
99
136
|
This is cryptographically signed provenance. It is distinct from Apple Developer ID or
|
|
100
137
|
Microsoft Authenticode code-signing.
|
|
101
138
|
|
|
102
|
-
**Docker / OCI.** The
|
|
139
|
+
**Docker / OCI.** The current container release is `0.2.2`:
|
|
103
140
|
|
|
104
141
|
```bash
|
|
105
|
-
docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.2.
|
|
142
|
+
docker run --rm -i -v "$PWD:/workspace:ro" ghcr.io/barglabs/cejel:0.2.2
|
|
106
143
|
```
|
|
107
144
|
|
|
108
145
|
The image defaults to `cejel-mcp` over stdio. To use the CLI instead:
|
|
109
146
|
|
|
110
147
|
```bash
|
|
111
|
-
docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.2.
|
|
148
|
+
docker run --rm -v "$PWD:/workspace:ro" --entrypoint cejel ghcr.io/barglabs/cejel:0.2.2 .
|
|
112
149
|
```
|
|
113
150
|
|
|
114
151
|
The OCI image carries an SBOM, maximum-mode build provenance, and a signed registry
|
|
@@ -356,6 +393,46 @@ The server exposes one tool and two resources:
|
|
|
356
393
|
Like the CLI, scoring over MCP is fully offline: no network calls, no telemetry, no signup,
|
|
357
394
|
and the server writes no files.
|
|
358
395
|
|
|
396
|
+
## Install on OpenClaw
|
|
397
|
+
|
|
398
|
+
OpenClaw stores outbound MCP servers under `mcp.servers`. Add Cejel with the npm package's
|
|
399
|
+
shipped `cejel-mcp` bin:
|
|
400
|
+
|
|
401
|
+
```json
|
|
402
|
+
{
|
|
403
|
+
"mcp": {
|
|
404
|
+
"servers": {
|
|
405
|
+
"cejel": {
|
|
406
|
+
"command": "npx",
|
|
407
|
+
"args": ["-y", "--package=@cejel/cejel", "cejel-mcp"]
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
The equivalent OpenClaw command is:
|
|
415
|
+
|
|
416
|
+
```bash
|
|
417
|
+
openclaw mcp add cejel --command npx --arg -y --arg --package=@cejel/cejel --arg cejel-mcp
|
|
418
|
+
openclaw mcp doctor cejel --probe
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
The OCI image is an alternative when Docker is the preferred execution boundary. Replace
|
|
422
|
+
the host path with the repository OpenClaw should allow Cejel to read:
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
openclaw mcp set cejel-oci '{"command":"docker","args":["run","--rm","-i","-v","/absolute/path/to/repo:/workspace:ro","ghcr.io/barglabs/cejel:0.2.2"]}'
|
|
426
|
+
openclaw mcp doctor cejel-oci --probe
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Cejel is active in the Official MCP Registry as `io.github.BargLabs/cejel`. The explicit
|
|
430
|
+
OpenClaw configuration above works independently of catalog indexing.
|
|
431
|
+
|
|
432
|
+
Cejel scans code you point it at. This free adoption surface does **not** watch, intercept,
|
|
433
|
+
or govern an agent's runtime actions. Runtime-action governance is a separate boundary for
|
|
434
|
+
the future paid Agent Pack.
|
|
435
|
+
|
|
359
436
|
## What "offline" means here
|
|
360
437
|
|
|
361
438
|
Scoring a repo — `cejel scan .` itself, and the Action's scoring step — makes zero network
|
|
@@ -4368,7 +4368,7 @@ var WitanAttestationStatementSchema = external_exports.object({
|
|
|
4368
4368
|
var WITAN_NO_MEASUREMENT_REASON = "No free-core rubric criterion produced a measurable signal. Cejel abstains rather than publish a numeric zero for an entirely unmeasured repository.";
|
|
4369
4369
|
var WITAN_AUTHENTICATED_A1_ABSENCE_SUMMARY = "Reviewable source is present, but the complete tracked inventory contains no concrete test file, configured test runner, CI test command, or coverage configuration.";
|
|
4370
4370
|
function isWitanNoMeasurementAbstention(report) {
|
|
4371
|
-
return report.verdict === "insufficient_source" && report.insufficientSourceReason
|
|
4371
|
+
return report.verdict === "insufficient_source" && report.insufficientSourceReason.startsWith(WITAN_NO_MEASUREMENT_REASON) && report.criteria.every(
|
|
4372
4372
|
({ status }) => status === "not_applicable" || status === "insufficient_data"
|
|
4373
4373
|
);
|
|
4374
4374
|
}
|
|
@@ -4544,7 +4544,7 @@ function formatMetricValue(value) {
|
|
|
4544
4544
|
}
|
|
4545
4545
|
|
|
4546
4546
|
// src/witan/html.ts
|
|
4547
|
-
function renderWitanHtmlReport(report) {
|
|
4547
|
+
function renderWitanHtmlReport(report, options = {}) {
|
|
4548
4548
|
const codeCriteria = criteriaByCategory(report, "code_trust");
|
|
4549
4549
|
const processCriteria = criteriaByCategory(report, "process_trust");
|
|
4550
4550
|
const verifiedEvidence = report.criteria.flatMap(
|
|
@@ -4555,6 +4555,7 @@ function renderWitanHtmlReport(report) {
|
|
|
4555
4555
|
const externalSourceSummaries = summarizeExternalSources(report.consumedSignals ?? []);
|
|
4556
4556
|
const externalFindings = collectExternalFindings(report.consumedSignals ?? []);
|
|
4557
4557
|
const coverage = computeMeasuredCoverage(report);
|
|
4558
|
+
const gitHistoryUnavailable = !report.repo.headSha;
|
|
4558
4559
|
return `<!doctype html>
|
|
4559
4560
|
<html lang="en">
|
|
4560
4561
|
<head>
|
|
@@ -4577,6 +4578,7 @@ function renderWitanHtmlReport(report) {
|
|
|
4577
4578
|
<dl class="meta">
|
|
4578
4579
|
<div><dt>Date</dt><dd>${escapeHtml(formatDate(report.generatedAt))}</dd></div>
|
|
4579
4580
|
<div><dt>Run</dt><dd>${escapeHtml(renderRepo(report))}</dd></div>
|
|
4581
|
+
<div><dt>CLI</dt><dd>${escapeHtml(options.cliVersion ? `Cejel ${options.cliVersion}` : "Not recorded")}</dd></div>
|
|
4580
4582
|
<div><dt>Rubric</dt><dd>${escapeHtml(report.rubricVersion)}</dd></div>
|
|
4581
4583
|
${contributingSources.length > 0 ? `<div><dt>Sources</dt><dd>Incorporates findings from: ${escapeHtml(contributingSources.join(", "))}<ul class="source-counts">${externalSourceSummaries.map((s) => `<li>${escapeHtml(formatExternalSourceLine(s))}</li>`).join("")}</ul></dd></div>` : ""}
|
|
4582
4584
|
</dl>
|
|
@@ -4597,8 +4599,8 @@ function renderWitanHtmlReport(report) {
|
|
|
4597
4599
|
</header>
|
|
4598
4600
|
|
|
4599
4601
|
<section class="trust-grid" aria-label="Rubric criteria">
|
|
4600
|
-
${renderCriterionColumn("Code trust", codeCriteria)}
|
|
4601
|
-
${renderCriterionColumn("Process trust", processCriteria)}
|
|
4602
|
+
${renderCriterionColumn("Code trust", codeCriteria, gitHistoryUnavailable)}
|
|
4603
|
+
${renderCriterionColumn("Process trust", processCriteria, gitHistoryUnavailable)}
|
|
4602
4604
|
</section>
|
|
4603
4605
|
|
|
4604
4606
|
<section class="evidence-grid" aria-label="Evidence and gaps">
|
|
@@ -4641,7 +4643,7 @@ function renderExternalFindingItems(findings) {
|
|
|
4641
4643
|
function criteriaByCategory(report, category) {
|
|
4642
4644
|
return report.criteria.filter((criterion) => criterion.category === category);
|
|
4643
4645
|
}
|
|
4644
|
-
function renderCriterionColumn(title, criteria) {
|
|
4646
|
+
function renderCriterionColumn(title, criteria, gitHistoryUnavailable) {
|
|
4645
4647
|
const applicable = criteria.filter((criterion) => criterion.status !== "not_applicable");
|
|
4646
4648
|
const notApplicable = criteria.filter((criterion) => criterion.status === "not_applicable");
|
|
4647
4649
|
const notApplicableGroup = notApplicable.length > 0 ? `
|
|
@@ -4649,7 +4651,7 @@ function renderCriterionColumn(title, criteria) {
|
|
|
4649
4651
|
return `<section class="criteria-column">
|
|
4650
4652
|
<h2>${escapeHtml(title)}</h2>
|
|
4651
4653
|
<div class="criteria-list">
|
|
4652
|
-
${applicable.map(renderCriterionCard).join("")}
|
|
4654
|
+
${applicable.map((criterion) => renderCriterionCard(criterion, gitHistoryUnavailable)).join("")}
|
|
4653
4655
|
</div>${notApplicableGroup}
|
|
4654
4656
|
</section>`;
|
|
4655
4657
|
}
|
|
@@ -4665,12 +4667,14 @@ function renderNotApplicableItem(criterion) {
|
|
|
4665
4667
|
const reason = criterion.notes ?? "Not applicable to this repository.";
|
|
4666
4668
|
return `<li><span class="na-id">${escapeHtml(criterion.id)}</span> ${escapeHtml(criterion.title)} \u2014 <span class="na-reason">${escapeHtml(reason)}</span></li>`;
|
|
4667
4669
|
}
|
|
4668
|
-
function renderCriterionCard(criterion) {
|
|
4670
|
+
function renderCriterionCard(criterion, gitHistoryUnavailable) {
|
|
4669
4671
|
const evidence = [
|
|
4670
4672
|
...criterion.evidence.map(renderEvidencePointer),
|
|
4671
4673
|
...criterion.findings.map((finding) => renderFindingEvidence(criterion, finding))
|
|
4672
4674
|
];
|
|
4673
4675
|
const metrics = criterion.metrics.map(renderMetric);
|
|
4676
|
+
const statusReconciliation = renderStatusReconciliation(criterion);
|
|
4677
|
+
const historyWarning = gitHistoryUnavailable && criterion.metrics.some((metric2) => metric2.name === "pr_merge_ratio") ? `<p class="scan-warning"><strong>Scan limitation:</strong> Git history was unavailable (for example, this may be a source tarball), so the recent PR merge ratio is not a measured repository outcome and its displayed zero may undercount ${escapeHtml(criterion.id)}. Re-scan a full Git clone for this signal.</p>` : "";
|
|
4674
4678
|
return `<article class="criterion">
|
|
4675
4679
|
<div class="criterion-top">
|
|
4676
4680
|
<div>
|
|
@@ -4680,6 +4684,8 @@ function renderCriterionCard(criterion) {
|
|
|
4680
4684
|
${renderStatusChip(criterion.status)}
|
|
4681
4685
|
</div>
|
|
4682
4686
|
<div class="criterion-score">${criterion.status === "not_applicable" ? "N/A" : criterion.status === "insufficient_data" ? "No data" : formatScore(criterion.score)}</div>
|
|
4687
|
+
${statusReconciliation}
|
|
4688
|
+
${historyWarning}
|
|
4683
4689
|
<ul class="criterion-metrics">
|
|
4684
4690
|
${metrics.length > 0 ? metrics.map((item) => `<li>${item}</li>`).join("") : "<li>No measured depth metrics supplied.</li>"}
|
|
4685
4691
|
</ul>
|
|
@@ -4688,6 +4694,20 @@ function renderCriterionCard(criterion) {
|
|
|
4688
4694
|
</ul>
|
|
4689
4695
|
</article>`;
|
|
4690
4696
|
}
|
|
4697
|
+
function renderStatusReconciliation(criterion) {
|
|
4698
|
+
if (criterion.status === "not_applicable" || criterion.status === "insufficient_data" || criterion.status === "unverified") {
|
|
4699
|
+
return "";
|
|
4700
|
+
}
|
|
4701
|
+
const numericBand = scoreBandForPresentation(criterion.score);
|
|
4702
|
+
if (numericBand === criterion.status) return "";
|
|
4703
|
+
return `<p class="status-explanation"><strong>Why the labels differ:</strong> the ${escapeHtml(criterion.status)} dimension band is calibrated from criterion evidence thresholds and findings, independently of the ${formatScore(criterion.score)}/4.0 weighted score (which falls in the ${numericBand} numeric band).</p>`;
|
|
4704
|
+
}
|
|
4705
|
+
function scoreBandForPresentation(score) {
|
|
4706
|
+
if (score >= 3.5) return "verified";
|
|
4707
|
+
if (score >= 2.5) return "info";
|
|
4708
|
+
if (score >= 1.5) return "warning";
|
|
4709
|
+
return "critical";
|
|
4710
|
+
}
|
|
4691
4711
|
function renderMetric(metric2) {
|
|
4692
4712
|
const unit = metric2.unit ? ` ${escapeHtml(metric2.unit)}` : "";
|
|
4693
4713
|
if (metric2.kind === "saturating_count" && metric2.max !== void 0 && metric2.value > metric2.max) {
|
|
@@ -4860,6 +4880,12 @@ h2 { font-family: var(--serif); font-size: 30px; font-weight: 400; letter-spacin
|
|
|
4860
4880
|
.criterion-id { color: var(--periwinkle); font-family: var(--mono); font-size: 12px; margin-bottom: 4px; }
|
|
4861
4881
|
h3 { font-size: 15px; line-height: 1.35; font-weight: 600; margin-bottom: 0; }
|
|
4862
4882
|
.criterion-score { margin-top: 12px; color: var(--text); font-family: var(--mono); font-size: 24px; }
|
|
4883
|
+
.status-explanation, .scan-warning {
|
|
4884
|
+
margin: 10px 0 0; border-left: 3px solid var(--periwinkle); padding: 8px 10px;
|
|
4885
|
+
background: var(--periwinkle-weak); color: var(--muted); font-size: 12px; line-height: 1.5;
|
|
4886
|
+
}
|
|
4887
|
+
.scan-warning { border-left-color: var(--warn); background: var(--warn-weak); }
|
|
4888
|
+
.status-explanation strong, .scan-warning strong { color: var(--text); }
|
|
4863
4889
|
.criterion-metrics { display: grid; gap: 7px; margin-top: 10px; padding: 0; list-style: none; font-size: 12px; }
|
|
4864
4890
|
.criterion-metrics li { display: flex; justify-content: space-between; gap: 12px; border-bottom: 1px solid rgba(238, 244, 247, .08); padding-bottom: 6px; }
|
|
4865
4891
|
.criterion-metrics strong { color: var(--text); font-weight: 650; }
|
|
@@ -5086,8 +5112,12 @@ var WITAN_RUBRIC_VERSION_V14 = "witan-rubric-v14-2026-07-23";
|
|
|
5086
5112
|
var WITAN_RUBRIC_VERSION_V15 = "witan-rubric-v15-2026-07-24";
|
|
5087
5113
|
var WITAN_RUBRIC_VERSION_V16 = "witan-rubric-v16-2026-07-24";
|
|
5088
5114
|
var WITAN_RUBRIC_VERSION_V17 = "witan-rubric-v17-2026-07-24";
|
|
5115
|
+
var WITAN_RUBRIC_VERSION_V18 = "witan-rubric-v18-prospective-2026-07-25";
|
|
5089
5116
|
|
|
5090
5117
|
// src/witan/repo-signals.ts
|
|
5118
|
+
function usesV17DetectorClosure(rubricVersion) {
|
|
5119
|
+
return rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18;
|
|
5120
|
+
}
|
|
5091
5121
|
function buildWitanInputFromRepo(options) {
|
|
5092
5122
|
assertRepoPathExists(options.repoPath);
|
|
5093
5123
|
const generatedAt = options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -5096,26 +5126,27 @@ function buildWitanInputFromRepo(options) {
|
|
|
5096
5126
|
const repoFiles = listRepoFiles(options.repoPath);
|
|
5097
5127
|
const inventoryFiles = listRepoInventory(options.repoPath, repoFiles);
|
|
5098
5128
|
const ignoredTargetReason = repoFiles.length === 0 ? explainIgnoredScanTarget(options.repoPath) : void 0;
|
|
5099
|
-
const usesV17Detectors = rubricVersion
|
|
5129
|
+
const usesV17Detectors = usesV17DetectorClosure(rubricVersion);
|
|
5130
|
+
const usesV18NativeRls = rubricVersion === WITAN_RUBRIC_VERSION_V18;
|
|
5100
5131
|
const structuralArchetype = classifyRepoArchetype(inventoryFiles, rubricVersion);
|
|
5101
|
-
const readableArchetype = rubricVersion === WITAN_RUBRIC_VERSION_V13 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || rubricVersion
|
|
5132
|
+
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(
|
|
5102
5133
|
options.repoPath,
|
|
5103
5134
|
inventoryFiles,
|
|
5104
5135
|
structuralArchetype,
|
|
5105
5136
|
headSha,
|
|
5106
5137
|
rubricVersion
|
|
5107
5138
|
) : structuralArchetype;
|
|
5108
|
-
const gatedArchetype = rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || rubricVersion
|
|
5139
|
+
const gatedArchetype = rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure(rubricVersion) ? applySemanticSourceRepresentationGate(
|
|
5109
5140
|
options.repoPath,
|
|
5110
5141
|
inventoryFiles,
|
|
5111
5142
|
readableArchetype,
|
|
5112
5143
|
rubricVersion
|
|
5113
5144
|
) : readableArchetype;
|
|
5114
|
-
const usesV8Detectors = 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
|
|
5115
|
-
const usesV33Detectors = 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
|
|
5116
|
-
const usesV36Detectors = 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
|
|
5117
|
-
const usesV39Detectors = 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
|
|
5118
|
-
const usesV47Detectors = rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || rubricVersion
|
|
5145
|
+
const usesV8Detectors = 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 || usesV17DetectorClosure(rubricVersion);
|
|
5146
|
+
const usesV33Detectors = 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 || usesV17DetectorClosure(rubricVersion);
|
|
5147
|
+
const usesV36Detectors = 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 || usesV17DetectorClosure(rubricVersion);
|
|
5148
|
+
const usesV39Detectors = 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 || usesV17DetectorClosure(rubricVersion);
|
|
5149
|
+
const usesV47Detectors = rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure(rubricVersion);
|
|
5119
5150
|
const reviewableSourceProof = usesV17Detectors ? buildReviewableSourceProof(options.repoPath, inventoryFiles, headSha, rubricVersion) : void 0;
|
|
5120
5151
|
const coreSignals = collectRepoSignals(
|
|
5121
5152
|
options.repoPath,
|
|
@@ -5126,6 +5157,7 @@ function buildWitanInputFromRepo(options) {
|
|
|
5126
5157
|
usesV36Detectors,
|
|
5127
5158
|
usesV39Detectors,
|
|
5128
5159
|
usesV47Detectors,
|
|
5160
|
+
usesV18NativeRls,
|
|
5129
5161
|
reviewableSourceProof
|
|
5130
5162
|
);
|
|
5131
5163
|
const archetype = usesV17Detectors && reviewableSourceProof?.passes === true && isV17RescuableAbstention(gatedArchetype.abstentionKind) && coreSignals.some(isMeasuredCriterionSignal) ? {
|
|
@@ -5233,7 +5265,7 @@ var SOURCE_EXTENSION_PATTERN_V10 = new RegExp(
|
|
|
5233
5265
|
"i"
|
|
5234
5266
|
);
|
|
5235
5267
|
function isRecognizedSourcePath(path, rubricVersion = WITAN_RUBRIC_VERSION) {
|
|
5236
|
-
return (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
|
|
5268
|
+
return (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 || usesV17DetectorClosure(rubricVersion) ? SOURCE_EXTENSION_PATTERN_V10 : SOURCE_EXTENSION_PATTERN).test(path);
|
|
5237
5269
|
}
|
|
5238
5270
|
var BUNDLED_BINARY_EXTENSION_PATTERN = /\.(vsix|zip|tgz|whl|exe|dmg|pkg|msi|jar|war|apk|ipa|dll|dylib|ttf|otf|woff2?|eot|eps)$/i;
|
|
5239
5271
|
var DOCS_OR_MEDIA_EXTENSION_PATTERN = /\.(md|mdx|rst|png|jpe?g|gif|svg|webp|ico|pdf)$/i;
|
|
@@ -5249,6 +5281,7 @@ var SOURCE_DOMINANCE_RATIO_THRESHOLD_V8 = 0.2;
|
|
|
5249
5281
|
var SOURCE_DOMINANCE_RATIO_THRESHOLD_V9 = 0.8;
|
|
5250
5282
|
var SOURCE_DOMINANCE_RATIO_THRESHOLD_V10 = 0.5;
|
|
5251
5283
|
var SOURCE_DOMINANCE_RATIO_THRESHOLD_V11 = 0.2;
|
|
5284
|
+
var V17_REVIEWABLE_SOURCE_RATABLE_SHARE_THRESHOLD = 0.2;
|
|
5252
5285
|
var GENERATED_SOURCE_MINIMUM = 8;
|
|
5253
5286
|
var GENERATED_SOURCE_RATIO_THRESHOLD = 0.8;
|
|
5254
5287
|
var GENERATED_AUTHORED_MAXIMUM = 3;
|
|
@@ -5292,7 +5325,7 @@ function classifyRepoArchetype(repoFiles, rubricVersion = WITAN_RUBRIC_VERSION)
|
|
|
5292
5325
|
insufficientSourceReason: `${catalogSourceFiles.length} of ${sourceFileCount} source-shaped file(s) are under independent solution, exercise, challenge, or algorithm catalog paths; only ${sourceFileCount - catalogSourceFiles.length} source-shaped file(s) remain outside that catalog. Cejel abstains because the repository does not expose one cohesive product implementation to score. ${INGEST_POINTER}`
|
|
5293
5326
|
};
|
|
5294
5327
|
}
|
|
5295
|
-
if (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
|
|
5328
|
+
if (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 || usesV17DetectorClosure(rubricVersion)) {
|
|
5296
5329
|
const authoredSourceFiles = sourceFiles.filter(isAuthoredProductionPath);
|
|
5297
5330
|
const documentationFiles = repoFiles.filter(
|
|
5298
5331
|
(file) => DOCS_OR_MEDIA_EXTENSION_PATTERN.test(file)
|
|
@@ -5310,7 +5343,7 @@ function classifyRepoArchetype(repoFiles, rubricVersion = WITAN_RUBRIC_VERSION)
|
|
|
5310
5343
|
(file) => ARTIFACT_DOMINANCE_EXTENSION_PATTERN.test(file)
|
|
5311
5344
|
);
|
|
5312
5345
|
const materialFiles = authoredSourceFiles.length + artifactFiles.length;
|
|
5313
|
-
if (artifactFiles.length >= 10 && (authoredSourceFiles.length <= 10 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || rubricVersion
|
|
5346
|
+
if (artifactFiles.length >= 10 && (authoredSourceFiles.length <= 10 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure(rubricVersion)) && materialFiles > 0 && authoredSourceFiles.length / materialFiles <= 0.1) {
|
|
5314
5347
|
return {
|
|
5315
5348
|
archetype: "binary_only",
|
|
5316
5349
|
sourceFileCount,
|
|
@@ -5337,7 +5370,7 @@ function classifyRepoArchetype(repoFiles, rubricVersion = WITAN_RUBRIC_VERSION)
|
|
|
5337
5370
|
const docsDistributionFiles = repoFiles.filter(
|
|
5338
5371
|
(file) => DOCS_OR_MEDIA_EXTENSION_PATTERN.test(file) || DOC_DISTRIBUTION_COMPANION_PATTERN.test(file)
|
|
5339
5372
|
);
|
|
5340
|
-
if (docsFiles.length > 0 && (docsDistributionFiles.length === totalFileCount || (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
|
|
5373
|
+
if (docsFiles.length > 0 && (docsDistributionFiles.length === totalFileCount || (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 || usesV17DetectorClosure(rubricVersion)) && unrecognisedSourceFiles.length === 0)) {
|
|
5341
5374
|
return {
|
|
5342
5375
|
archetype: "docs_only",
|
|
5343
5376
|
sourceFileCount,
|
|
@@ -5456,6 +5489,23 @@ function isRepresentativeSourceText(contents) {
|
|
|
5456
5489
|
function representativeSourceRank(rankKey, file) {
|
|
5457
5490
|
return createHash2("sha256").update(`${rankKey}:${file}`).digest("hex");
|
|
5458
5491
|
}
|
|
5492
|
+
function explainNoMeasurementSourceCoverage(repoPath, rubricVersion) {
|
|
5493
|
+
if (!usesV17DetectorClosure(rubricVersion)) return void 0;
|
|
5494
|
+
const repoFiles = listRepoFiles(repoPath);
|
|
5495
|
+
const inventoryFiles = listRepoInventory(repoPath, repoFiles);
|
|
5496
|
+
const proof = buildReviewableSourceProof(
|
|
5497
|
+
repoPath,
|
|
5498
|
+
inventoryFiles,
|
|
5499
|
+
readGitHead(repoPath),
|
|
5500
|
+
rubricVersion
|
|
5501
|
+
);
|
|
5502
|
+
if (proof.sourceShapedFileCount === 0) return void 0;
|
|
5503
|
+
const ratableShare = proof.eligibleSourceFileCount / proof.sourceShapedFileCount;
|
|
5504
|
+
if (ratableShare >= V17_REVIEWABLE_SOURCE_RATABLE_SHARE_THRESHOLD) return void 0;
|
|
5505
|
+
const ratablePct = (ratableShare * 100).toFixed(1);
|
|
5506
|
+
const thresholdPct = (V17_REVIEWABLE_SOURCE_RATABLE_SHARE_THRESHOLD * 100).toFixed(0);
|
|
5507
|
+
return `${WITAN_NO_MEASUREMENT_REASON} Source coverage: ${proof.eligibleSourceFileCount} of ${proof.sourceShapedFileCount} source-shaped files (${ratablePct}%) are criterion-ratable, below the ${thresholdPct}% reviewable-source threshold (${inventoryFiles.length} tracked files in total).`;
|
|
5508
|
+
}
|
|
5459
5509
|
function buildReviewableSourceProof(repoPath, repoFiles, headSha, rubricVersion) {
|
|
5460
5510
|
const sourceShapedFiles = repoFiles.filter(
|
|
5461
5511
|
(path) => isRecognizedSourcePath(path, rubricVersion) || isUnrecognisedSourcePath(path, rubricVersion) || /\.ipynb$/i.test(path)
|
|
@@ -5480,7 +5530,7 @@ function buildReviewableSourceProof(repoPath, repoFiles, headSha, rubricVersion)
|
|
|
5480
5530
|
sampledFileCount: sample.length,
|
|
5481
5531
|
readableSampledFileCount: readablePaths.length,
|
|
5482
5532
|
...readablePaths[0] ? { firstReadablePath: readablePaths[0] } : {},
|
|
5483
|
-
passes: eligibleSourceFiles.length > 0 && ratableShare >=
|
|
5533
|
+
passes: eligibleSourceFiles.length > 0 && ratableShare >= V17_REVIEWABLE_SOURCE_RATABLE_SHARE_THRESHOLD && readablePaths.length > 0 && (readableShare >= 0.75 || readablePaths.length >= 8)
|
|
5484
5534
|
};
|
|
5485
5535
|
}
|
|
5486
5536
|
function applyReadableSourceRepresentationGate(repoPath, repoFiles, classification, headSha, rubricVersion) {
|
|
@@ -5622,7 +5672,7 @@ function readRepresentativeSourceText(repoPath, file) {
|
|
|
5622
5672
|
}
|
|
5623
5673
|
}
|
|
5624
5674
|
function sourceDominanceThreshold(rubricVersion) {
|
|
5625
|
-
if (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
|
|
5675
|
+
if (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 || usesV17DetectorClosure(rubricVersion)) {
|
|
5626
5676
|
return SOURCE_DOMINANCE_RATIO_THRESHOLD_V11;
|
|
5627
5677
|
}
|
|
5628
5678
|
if (rubricVersion === WITAN_RUBRIC_VERSION_V10) return SOURCE_DOMINANCE_RATIO_THRESHOLD_V10;
|
|
@@ -5636,7 +5686,7 @@ function isUnrecognisedSourcePath(file, rubricVersion = WITAN_RUBRIC_VERSION) {
|
|
|
5636
5686
|
const base = basename(file);
|
|
5637
5687
|
if (!/\.([a-zA-Z0-9_]+)$/.test(base)) return false;
|
|
5638
5688
|
if (KNOWN_NON_SOURCE_EXTENSION_PATTERN.test(base)) return false;
|
|
5639
|
-
if ((rubricVersion === WITAN_RUBRIC_VERSION_V13 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || rubricVersion
|
|
5689
|
+
if ((rubricVersion === WITAN_RUBRIC_VERSION_V13 || rubricVersion === WITAN_RUBRIC_VERSION_V14 || rubricVersion === WITAN_RUBRIC_VERSION_V15 || rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure(rubricVersion)) && V13_NON_SOURCE_EXTENSION_PATTERN.test(base)) {
|
|
5640
5690
|
return false;
|
|
5641
5691
|
}
|
|
5642
5692
|
if (DOCS_OR_MEDIA_EXTENSION_PATTERN.test(base)) return false;
|
|
@@ -5722,7 +5772,7 @@ function buildNotApplicableSignal(criterionId, reason) {
|
|
|
5722
5772
|
notApplicable: true
|
|
5723
5773
|
};
|
|
5724
5774
|
}
|
|
5725
|
-
function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, reviewableSourceProof) {
|
|
5775
|
+
function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, useV18NativeRls, reviewableSourceProof) {
|
|
5726
5776
|
const signals = [];
|
|
5727
5777
|
const mono = resolveMonorepoContext(repoPath);
|
|
5728
5778
|
const a1Signal = collectA1TestIntegrityEvidence(
|
|
@@ -5740,7 +5790,8 @@ function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, u
|
|
|
5740
5790
|
useV33Detectors,
|
|
5741
5791
|
useV36Detectors,
|
|
5742
5792
|
useV39Detectors,
|
|
5743
|
-
useV47Detectors
|
|
5793
|
+
useV47Detectors,
|
|
5794
|
+
useV18NativeRls
|
|
5744
5795
|
);
|
|
5745
5796
|
const a3Signal = collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors);
|
|
5746
5797
|
const a4Signal = collectA4DependencyEvidence(
|
|
@@ -6032,7 +6083,7 @@ function buildA1AuthenticatedAbsenceSignal(repoPath, proof) {
|
|
|
6032
6083
|
notes: `V17 authenticated absence: ${proof.eligibleSourceFileCount} criterion-ratable of ${proof.sourceShapedFileCount} source-shaped files; sampled ${proof.sampledFileCount}; ${proof.readableSampledFileCount} representative-text files.`
|
|
6033
6084
|
};
|
|
6034
6085
|
}
|
|
6035
|
-
function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors) {
|
|
6086
|
+
function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, useV18NativeRls) {
|
|
6036
6087
|
const evidence = [];
|
|
6037
6088
|
const findings = [];
|
|
6038
6089
|
const gitignore = repoFiles.find((file) => basename(file) === ".gitignore");
|
|
@@ -6128,19 +6179,21 @@ function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33
|
|
|
6128
6179
|
evidence.push(evidenceForRelative(repoPath, dbLayerImportFile, "artifact", "DB client import"));
|
|
6129
6180
|
}
|
|
6130
6181
|
const v47RlsPolicyFiles = useV47Detectors ? findRlsPolicyFiles(repoPath, repoFiles) : [];
|
|
6131
|
-
const
|
|
6182
|
+
const nativeRlsInventory = useV18NativeRls ? deriveRlsPolicyScopeInventory(repoPath, repoFiles) : null;
|
|
6183
|
+
const tenantWithoutRlsPremiseFiles = useV18NativeRls ? findTenantStoragePremiseFiles(repoPath, repoFiles) : [];
|
|
6184
|
+
const v47TenantStorageFiles = useV47Detectors && !useV18NativeRls ? findTenantStoragePremiseFiles(repoPath, repoFiles) : [];
|
|
6132
6185
|
const rlsMigration = useV47Detectors ? v47RlsPolicyFiles[0] : migrationFiles.find((file) => fileContains(repoPath, file, RLS_PATTERN));
|
|
6133
6186
|
const tenantScopePattern = useV39Detectors ? TENANT_SCOPE_PATTERN_V11 : useV36Detectors ? TENANT_SCOPE_PATTERN_V10 : TENANT_SCOPE_PATTERN;
|
|
6134
|
-
const tenantScopedFile = useV47Detectors ? v47TenantStorageFiles[0] : migrationFiles.find((file) => fileContains(repoPath, file, tenantScopePattern));
|
|
6135
|
-
const rlsPolicyCount = useV47Detectors ? v47RlsPolicyFiles.length : countPatternMatches(
|
|
6187
|
+
const tenantScopedFile = useV18NativeRls ? nativeRlsInventory?.storageFiles[0] : useV47Detectors ? v47TenantStorageFiles[0] : migrationFiles.find((file) => fileContains(repoPath, file, tenantScopePattern));
|
|
6188
|
+
const rlsPolicyCount = useV18NativeRls ? nativeRlsInventory?.policyCount ?? 0 : useV47Detectors ? v47RlsPolicyFiles.length : countPatternMatches(
|
|
6136
6189
|
repoPath,
|
|
6137
6190
|
migrationFiles,
|
|
6138
6191
|
/create policy|enable row level security|force row level security/gi
|
|
6139
6192
|
);
|
|
6140
|
-
const tenantScopedMigrationFileCount = useV47Detectors ? v47TenantStorageFiles.length : countFilesContaining(repoPath, migrationFiles, tenantScopePattern);
|
|
6193
|
+
const tenantScopedMigrationFileCount = useV18NativeRls ? nativeRlsInventory?.storageFiles.length ?? 0 : useV47Detectors ? v47TenantStorageFiles.length : countFilesContaining(repoPath, migrationFiles, tenantScopePattern);
|
|
6141
6194
|
const gitignoreEnvFile = gitignore && fileContains(repoPath, gitignore, /^\.env(\*|\b)|\.env\./m) ? gitignore : null;
|
|
6142
6195
|
const envHandlingDepth = (envExamples.length > 0 ? 1 : 0) + (gitignoreEnvFile ? 1 : 0) + (countFilesContaining(repoPath, repoFiles.filter(isImplementationFile), ENV_READ_PATTERN) > 0 ? 1 : 0);
|
|
6143
|
-
const isMultiTenant = tenantScopedMigrationFileCount > 0;
|
|
6196
|
+
const isMultiTenant = useV18NativeRls ? (nativeRlsInventory?.policyCount ?? 0) > 0 && (nativeRlsInventory?.scopeIdentifiers.length ?? 0) > 0 : tenantScopedMigrationFileCount > 0;
|
|
6144
6197
|
if (gitignoreEnvFile) {
|
|
6145
6198
|
evidence.push(
|
|
6146
6199
|
evidenceForRelative(repoPath, gitignoreEnvFile, "secret_scan", ".env files are gitignored")
|
|
@@ -6156,7 +6209,12 @@ function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33
|
|
|
6156
6209
|
}
|
|
6157
6210
|
if (tenantScopedFile) {
|
|
6158
6211
|
evidence.push(
|
|
6159
|
-
evidenceForRelative(
|
|
6212
|
+
evidenceForRelative(
|
|
6213
|
+
repoPath,
|
|
6214
|
+
tenantScopedFile,
|
|
6215
|
+
"artifact",
|
|
6216
|
+
useV18NativeRls ? `Repository-native RLS scope (${nativeRlsInventory?.scopeIdentifiers.join(", ")})` : "Tenant scoping signal"
|
|
6217
|
+
)
|
|
6160
6218
|
);
|
|
6161
6219
|
}
|
|
6162
6220
|
if (committedSecret) {
|
|
@@ -6214,8 +6272,9 @@ function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33
|
|
|
6214
6272
|
evidence: historySecretScan.envPathEvidence
|
|
6215
6273
|
});
|
|
6216
6274
|
}
|
|
6217
|
-
|
|
6218
|
-
|
|
6275
|
+
const hasTenantWithoutRlsGap = rlsPolicyCount === 0 && (useV18NativeRls ? tenantWithoutRlsPremiseFiles.length > 0 : isMultiTenant);
|
|
6276
|
+
if (hasTenantWithoutRlsGap) {
|
|
6277
|
+
const gapEvidence = rlsMigration ?? tenantScopedFile ?? tenantWithoutRlsPremiseFiles[0];
|
|
6219
6278
|
if (gapEvidence) {
|
|
6220
6279
|
findings.push({
|
|
6221
6280
|
severity: "warning",
|
|
@@ -6258,20 +6317,20 @@ function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33
|
|
|
6258
6317
|
"rls_policy_count",
|
|
6259
6318
|
"RLS policy count",
|
|
6260
6319
|
rlsPolicyCount,
|
|
6261
|
-
Math.max(tenantScopedMigrationFileCount * 3, 3),
|
|
6320
|
+
useV18NativeRls ? Math.max(tenantScopedMigrationFileCount, 1) : Math.max(tenantScopedMigrationFileCount * 3, 3),
|
|
6262
6321
|
0.4,
|
|
6263
6322
|
"policies",
|
|
6264
|
-
"Counts static row-level-security enables, forced-RLS statements, and policy definitions.",
|
|
6323
|
+
useV18NativeRls ? "Counts CREATE POLICY definitions with repository-native USING/WITH CHECK clauses against the repository-native scoped data-layer surface." : "Counts static row-level-security enables, forced-RLS statements, and policy definitions.",
|
|
6265
6324
|
"saturating_count"
|
|
6266
6325
|
),
|
|
6267
6326
|
metric(
|
|
6268
6327
|
"tenant_scope_ratio",
|
|
6269
6328
|
"Tenant-scoped schema ratio",
|
|
6270
|
-
countFilesContaining(repoPath, migrationFiles, tenantScopePattern),
|
|
6329
|
+
useV18NativeRls ? tenantScopedMigrationFileCount : countFilesContaining(repoPath, migrationFiles, tenantScopePattern),
|
|
6271
6330
|
Math.max(migrationFiles.length, 1),
|
|
6272
6331
|
0.25,
|
|
6273
6332
|
"ratio",
|
|
6274
|
-
"Measures tenant/studio/workspace scoping evidence across data-layer files."
|
|
6333
|
+
useV18NativeRls ? `Measures repository-native RLS scope identifiers (${nativeRlsInventory?.scopeIdentifiers.join(", ")}) across data-layer files.` : "Measures tenant/studio/workspace scoping evidence across data-layer files."
|
|
6275
6334
|
)
|
|
6276
6335
|
] : [];
|
|
6277
6336
|
const cryptoMetrics = cryptoHygiene.hasSurface ? [
|
|
@@ -6290,7 +6349,7 @@ function collectA2IsolationEvidence(repoPath, repoFiles, useV27Detectors, useV33
|
|
|
6290
6349
|
positiveEvidence: evidence,
|
|
6291
6350
|
findings,
|
|
6292
6351
|
metrics: [...baseMetrics, ...isolationMetrics, ...cryptoMetrics],
|
|
6293
|
-
notes: "History secret scanning covers all reachable git history for credential-pattern paths unless the explicit credential-blob safety valve is reported."
|
|
6352
|
+
notes: useV18NativeRls ? "History secret scanning covers all reachable git history for credential-pattern paths unless the explicit credential-blob safety valve is reported. Positive multi-tenancy credit is derived only from this repository\u2019s own CREATE POLICY USING/WITH CHECK clauses; no fixed tenant-token vocabulary can create isolation credit. A conservative schema premise is retained only to fail closed when a tenant-shaped schema has zero RLS policies." : "History secret scanning covers all reachable git history for credential-pattern paths unless the explicit credential-blob safety valve is reported."
|
|
6294
6353
|
};
|
|
6295
6354
|
}
|
|
6296
6355
|
function collectCryptoHygieneEvidence(repoPath, implFiles, useV39Detectors = false) {
|
|
@@ -7186,7 +7245,7 @@ var TEST_DIRECTORY_SOURCE_PATTERN_V17 = new RegExp(
|
|
|
7186
7245
|
"i"
|
|
7187
7246
|
);
|
|
7188
7247
|
function isTestFile(file, rubricVersion = WITAN_RUBRIC_VERSION) {
|
|
7189
|
-
return rubricVersion
|
|
7248
|
+
return usesV17DetectorClosure(rubricVersion) && (TEST_DIRECTORY_SOURCE_PATTERN_V17.test(file) || /\.tftest\.hcl$/i.test(file) || /\.bats$/i.test(file) || /(^|\/)test[^/]*\.m$/i.test(file) || /_test\.m$/i.test(file)) || TEST_DIRECTORY_SOURCE_PATTERN.test(file) || // AVA's default discovery includes test.js and test-*.js at the scanned package root.
|
|
7190
7249
|
// Keep this root-anchored: nested files need an existing test-directory/suffix convention.
|
|
7191
7250
|
/^test(?:-[^/]+)?\.[cm]?[jt]sx?$/.test(file) || /\.(test|spec)\.[cm]?[jt]sx?$/.test(file) || /(^|\/)test_.*\.py$/.test(file) || /_test\.go$/.test(file) || /(^|\/)test_.*\.(cpp|cc|cxx)$/.test(file) || /_(test|tests)\.(cpp|cc|cxx)$/.test(file) || /Tests?\.(java|kt)$/.test(file) || /(_test|_spec)\.(rs|rb|php|swift|kt)$/.test(file);
|
|
7192
7251
|
}
|
|
@@ -7857,6 +7916,138 @@ function findRlsPolicyFiles(repoPath, repoFiles) {
|
|
|
7857
7916
|
)
|
|
7858
7917
|
);
|
|
7859
7918
|
}
|
|
7919
|
+
var RLS_CLAUSE_SQL_WORDS = /* @__PURE__ */ new Set([
|
|
7920
|
+
"all",
|
|
7921
|
+
"and",
|
|
7922
|
+
"any",
|
|
7923
|
+
"as",
|
|
7924
|
+
"asc",
|
|
7925
|
+
"between",
|
|
7926
|
+
"by",
|
|
7927
|
+
"case",
|
|
7928
|
+
"cast",
|
|
7929
|
+
"current",
|
|
7930
|
+
"desc",
|
|
7931
|
+
"distinct",
|
|
7932
|
+
"else",
|
|
7933
|
+
"end",
|
|
7934
|
+
"exists",
|
|
7935
|
+
"false",
|
|
7936
|
+
"from",
|
|
7937
|
+
"in",
|
|
7938
|
+
"is",
|
|
7939
|
+
"join",
|
|
7940
|
+
"like",
|
|
7941
|
+
"limit",
|
|
7942
|
+
"not",
|
|
7943
|
+
"null",
|
|
7944
|
+
"on",
|
|
7945
|
+
"or",
|
|
7946
|
+
"order",
|
|
7947
|
+
"select",
|
|
7948
|
+
"then",
|
|
7949
|
+
"text",
|
|
7950
|
+
"true",
|
|
7951
|
+
"uuid",
|
|
7952
|
+
"varchar",
|
|
7953
|
+
"when",
|
|
7954
|
+
"where"
|
|
7955
|
+
]);
|
|
7956
|
+
function extractBalancedSqlClause(statement, keyword) {
|
|
7957
|
+
const clauses = [];
|
|
7958
|
+
const keywordPattern = keyword === "using" ? /\busing\s*\(/gi : /\bwith\s+check\s*\(/gi;
|
|
7959
|
+
for (const match of statement.matchAll(keywordPattern)) {
|
|
7960
|
+
const openingParen = (match.index ?? 0) + match[0].lastIndexOf("(");
|
|
7961
|
+
let depth = 0;
|
|
7962
|
+
let quote = null;
|
|
7963
|
+
for (let index = openingParen; index < statement.length; index += 1) {
|
|
7964
|
+
const character = statement[index];
|
|
7965
|
+
if (quote) {
|
|
7966
|
+
if (character === quote && statement[index - 1] !== "\\") quote = null;
|
|
7967
|
+
continue;
|
|
7968
|
+
}
|
|
7969
|
+
if (character === "'" || character === '"') {
|
|
7970
|
+
quote = character;
|
|
7971
|
+
} else if (character === "(") {
|
|
7972
|
+
depth += 1;
|
|
7973
|
+
} else if (character === ")") {
|
|
7974
|
+
depth -= 1;
|
|
7975
|
+
if (depth === 0) {
|
|
7976
|
+
clauses.push(statement.slice(openingParen + 1, index));
|
|
7977
|
+
break;
|
|
7978
|
+
}
|
|
7979
|
+
}
|
|
7980
|
+
}
|
|
7981
|
+
}
|
|
7982
|
+
return clauses;
|
|
7983
|
+
}
|
|
7984
|
+
function extractRlsScopeIdentifiers(clause) {
|
|
7985
|
+
const scrubbed = clause.replace(/'(?:''|[^'])*'/g, " ").replace(/"(?:""|[^"])*"/g, " ");
|
|
7986
|
+
const identifiers = /* @__PURE__ */ new Set();
|
|
7987
|
+
const identifierPattern = /\b[A-Za-z_][A-Za-z0-9_$]*(?:\.[A-Za-z_][A-Za-z0-9_$]*)*\b/g;
|
|
7988
|
+
for (const match of scrubbed.matchAll(identifierPattern)) {
|
|
7989
|
+
const token = match[0];
|
|
7990
|
+
const segments = token.split(".").map((segment) => segment.toLowerCase());
|
|
7991
|
+
const lastSegment = segments.at(-1);
|
|
7992
|
+
if (!lastSegment || lastSegment.length < 2 || RLS_CLAUSE_SQL_WORDS.has(lastSegment)) continue;
|
|
7993
|
+
if (["app", "auth", "jwt", "request", "session"].includes(segments[0] ?? "")) continue;
|
|
7994
|
+
const remainder = scrubbed.slice((match.index ?? 0) + token.length);
|
|
7995
|
+
if (/^\s*\(/.test(remainder)) continue;
|
|
7996
|
+
if (["auth", "current_setting", "jwt", "pg_catalog", "public", "uid"].includes(lastSegment)) {
|
|
7997
|
+
continue;
|
|
7998
|
+
}
|
|
7999
|
+
identifiers.add(lastSegment);
|
|
8000
|
+
}
|
|
8001
|
+
return [...identifiers].sort();
|
|
8002
|
+
}
|
|
8003
|
+
function deriveRlsPolicyScopeInventory(repoPath, repoFiles) {
|
|
8004
|
+
const candidatePolicyFiles = findRlsPolicyFiles(repoPath, repoFiles);
|
|
8005
|
+
const policyFiles = /* @__PURE__ */ new Set();
|
|
8006
|
+
const scopeIdentifiers = /* @__PURE__ */ new Set();
|
|
8007
|
+
let policyCount = 0;
|
|
8008
|
+
for (const file of candidatePolicyFiles) {
|
|
8009
|
+
let content;
|
|
8010
|
+
try {
|
|
8011
|
+
content = readFileSync(join(repoPath, file), "utf8");
|
|
8012
|
+
} catch {
|
|
8013
|
+
continue;
|
|
8014
|
+
}
|
|
8015
|
+
for (const match of content.matchAll(/\bcreate\s+policy\b[\s\S]*?(?:;|$)/gi)) {
|
|
8016
|
+
const statement = match[0];
|
|
8017
|
+
const clauses = [
|
|
8018
|
+
...extractBalancedSqlClause(statement, "using"),
|
|
8019
|
+
...extractBalancedSqlClause(statement, "with check")
|
|
8020
|
+
];
|
|
8021
|
+
if (clauses.length === 0) continue;
|
|
8022
|
+
policyCount += 1;
|
|
8023
|
+
policyFiles.add(file);
|
|
8024
|
+
for (const clause of clauses) {
|
|
8025
|
+
for (const identifier of extractRlsScopeIdentifiers(clause)) {
|
|
8026
|
+
scopeIdentifiers.add(identifier);
|
|
8027
|
+
}
|
|
8028
|
+
}
|
|
8029
|
+
}
|
|
8030
|
+
}
|
|
8031
|
+
const identifiers = [...scopeIdentifiers].sort();
|
|
8032
|
+
const dataLayerFiles = repoFiles.filter(
|
|
8033
|
+
(file) => /(^|\/)(?:migrations?|drizzle|prisma)\/|\.(?:sql|prisma)$/i.test(file)
|
|
8034
|
+
);
|
|
8035
|
+
const storageFiles = identifiers.length === 0 ? [] : dataLayerFiles.filter(
|
|
8036
|
+
(file) => identifiers.some(
|
|
8037
|
+
(identifier) => fileContains(
|
|
8038
|
+
repoPath,
|
|
8039
|
+
file,
|
|
8040
|
+
new RegExp(`\\b${identifier.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}\\b`, "i")
|
|
8041
|
+
)
|
|
8042
|
+
)
|
|
8043
|
+
);
|
|
8044
|
+
return {
|
|
8045
|
+
policyFiles: [...policyFiles].sort(),
|
|
8046
|
+
policyCount,
|
|
8047
|
+
scopeIdentifiers: identifiers,
|
|
8048
|
+
storageFiles
|
|
8049
|
+
};
|
|
8050
|
+
}
|
|
7860
8051
|
function findDeployableServicePremiseFiles(repoPath, repoFiles, strictOperationalBoundary = false) {
|
|
7861
8052
|
const explicitTargets = repoFiles.filter(
|
|
7862
8053
|
(file) => isAuthoredProductionPath(file) && isExplicitDeployTarget(file) && (!strictOperationalBoundary || isV47OperationalApplicationPath(file))
|
|
@@ -9605,6 +9796,9 @@ var WITAN_RUBRIC = [
|
|
|
9605
9796
|
];
|
|
9606
9797
|
|
|
9607
9798
|
// src/witan/scoring.ts
|
|
9799
|
+
function usesV17DetectorClosure2(rubricVersion) {
|
|
9800
|
+
return rubricVersion === WITAN_RUBRIC_VERSION_V17 || rubricVersion === WITAN_RUBRIC_VERSION_V18;
|
|
9801
|
+
}
|
|
9608
9802
|
var MAX_SIGNAL_ADJUSTMENT = 0.8;
|
|
9609
9803
|
function createWitanReport(input, inputSignals, rubric = WITAN_RUBRIC) {
|
|
9610
9804
|
const parsedInput = WitanReportInputSchema.parse(input);
|
|
@@ -9688,7 +9882,7 @@ function createWitanReport(input, inputSignals, rubric = WITAN_RUBRIC) {
|
|
|
9688
9882
|
const isFreeCoreRubric = rubric.length === WITAN_RUBRIC.length && rubric.every(
|
|
9689
9883
|
({ id, category }, index) => id === WITAN_RUBRIC[index]?.id && category === WITAN_RUBRIC[index]?.category
|
|
9690
9884
|
);
|
|
9691
|
-
const noMeasurementAbstention = (parsedInput.rubricVersion === WITAN_RUBRIC_VERSION_V16 || parsedInput.rubricVersion
|
|
9885
|
+
const noMeasurementAbstention = (parsedInput.rubricVersion === WITAN_RUBRIC_VERSION_V16 || usesV17DetectorClosure2(parsedInput.rubricVersion)) && isFreeCoreRubric && !hasMeasuredCriterion;
|
|
9692
9886
|
const insufficientSourceReason = parsedInput.insufficientSourceReason ?? (noMeasurementAbstention ? WITAN_NO_MEASUREMENT_REASON : void 0);
|
|
9693
9887
|
const abstained = insufficientSourceReason != null;
|
|
9694
9888
|
return WitanReportSchema.parse({
|
|
@@ -9756,7 +9950,7 @@ function statusForScore(score) {
|
|
|
9756
9950
|
}
|
|
9757
9951
|
function statusAfterInputAdjustment(nativeStatus, nativeScore, adjustment, rubricVersion) {
|
|
9758
9952
|
if (adjustment === 0) return nativeStatus;
|
|
9759
|
-
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) {
|
|
9953
|
+
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) {
|
|
9760
9954
|
return statusForScore(roundScore(Math.max(0, nativeScore - adjustment)));
|
|
9761
9955
|
}
|
|
9762
9956
|
const statusFloor = {
|
|
@@ -9800,7 +9994,7 @@ function mergeSignalsByCriterion(signals) {
|
|
|
9800
9994
|
return merged;
|
|
9801
9995
|
}
|
|
9802
9996
|
function usesMetricScoring(rubricVersion) {
|
|
9803
|
-
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_TRADING_RUBRIC_VERSION_V0;
|
|
9997
|
+
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_TRADING_RUBRIC_VERSION_V0;
|
|
9804
9998
|
}
|
|
9805
9999
|
function unmeasuredStatus(rubricVersion) {
|
|
9806
10000
|
return rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0 ? "unverified" : "insufficient_data";
|
|
@@ -9931,7 +10125,7 @@ function scoreMetrics(metrics) {
|
|
|
9931
10125
|
function capScoreForFindings(score, findings, rubricVersion, criterionId) {
|
|
9932
10126
|
if (findings.some((finding) => finding.severity === "critical")) {
|
|
9933
10127
|
const criticalFindings = findings.filter(({ severity }) => severity === "critical");
|
|
9934
|
-
const authenticatedA1Absence = rubricVersion
|
|
10128
|
+
const authenticatedA1Absence = usesV17DetectorClosure2(rubricVersion) && criterionId === "A1" && criticalFindings.length === 1 && criticalFindings[0]?.summary === WITAN_AUTHENTICATED_A1_ABSENCE_SUMMARY;
|
|
9935
10129
|
return authenticatedA1Absence ? Math.min(score, 1.4) : 1.4;
|
|
9936
10130
|
}
|
|
9937
10131
|
if (findings.some((finding) => finding.severity === "warning")) return Math.min(score, 2.4);
|
|
@@ -9940,8 +10134,8 @@ function capScoreForFindings(score, findings, rubricVersion, criterionId) {
|
|
|
9940
10134
|
}
|
|
9941
10135
|
function statusForScoreAndFindings(criterionId, score, findings, metrics, rubricVersion) {
|
|
9942
10136
|
if (findings.some((finding) => finding.severity === "critical")) return "critical";
|
|
9943
|
-
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
|
|
9944
|
-
const calibrated = 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
|
|
10137
|
+
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 || usesV17DetectorClosure2(rubricVersion)) {
|
|
10138
|
+
const calibrated = 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 || usesV17DetectorClosure2(rubricVersion) ? calibratedCriterionStateV11(criterionId, metrics) : rubricVersion === WITAN_RUBRIC_VERSION_V9 || rubricVersion === WITAN_RUBRIC_VERSION_V10 ? calibratedCriterionStateV9(criterionId, metrics) : calibratedCriterionStateV8(criterionId, metrics);
|
|
9945
10139
|
if (calibrated && calibrated !== "verified") return calibrated;
|
|
9946
10140
|
if (calibrated === "verified" && !findings.some((finding) => finding.severity === "warning")) {
|
|
9947
10141
|
return "verified";
|
|
@@ -10167,7 +10361,7 @@ function calibratedCriterionStateV11(criterionId, metrics) {
|
|
|
10167
10361
|
return void 0;
|
|
10168
10362
|
}
|
|
10169
10363
|
function ensureFindingsExplainStatus(criterionId, score, status, findings, evidence, rubricVersion) {
|
|
10170
|
-
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 && findings.length > 0) {
|
|
10364
|
+
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 && findings.length > 0) {
|
|
10171
10365
|
return [...findings];
|
|
10172
10366
|
}
|
|
10173
10367
|
if (status !== "critical" && status !== "warning") return [...findings];
|
|
@@ -10212,7 +10406,18 @@ function scoreRepoWithPublicCejel(options) {
|
|
|
10212
10406
|
...options.rubricVersion ? { rubricVersion: options.rubricVersion } : {}
|
|
10213
10407
|
});
|
|
10214
10408
|
const inputSignals = resolvePublicIngestSignals(options);
|
|
10215
|
-
|
|
10409
|
+
const report = createWitanReport(input, inputSignals.length > 0 ? inputSignals : void 0);
|
|
10410
|
+
if (report.verdict !== "insufficient_source" || !isWitanNoMeasurementAbstention(report)) {
|
|
10411
|
+
return report;
|
|
10412
|
+
}
|
|
10413
|
+
const contextualReason = explainNoMeasurementSourceCoverage(
|
|
10414
|
+
options.repoPath,
|
|
10415
|
+
report.rubricVersion
|
|
10416
|
+
);
|
|
10417
|
+
return contextualReason ? {
|
|
10418
|
+
...report,
|
|
10419
|
+
insufficientSourceReason: contextualReason
|
|
10420
|
+
} : report;
|
|
10216
10421
|
}
|
|
10217
10422
|
function resolvePublicIngestSignals(options) {
|
|
10218
10423
|
const seen = /* @__PURE__ */ new Set();
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
runCejelScan,
|
|
10
10
|
serializeWitanReport,
|
|
11
11
|
verifyWitanAttestationBinding
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-SNDRU52Z.js";
|
|
13
13
|
|
|
14
14
|
// src/index.ts
|
|
15
15
|
import { createHash } from "crypto";
|
|
@@ -224,7 +224,11 @@ async function runWitanFreeCli(args) {
|
|
|
224
224
|
JSON.stringify(attestation, null, 2),
|
|
225
225
|
"utf8"
|
|
226
226
|
);
|
|
227
|
-
writeFileSync(
|
|
227
|
+
writeFileSync(
|
|
228
|
+
join(options.outDir, "certificate.html"),
|
|
229
|
+
renderWitanHtmlReport(report, { cliVersion: cliVersion() }),
|
|
230
|
+
"utf8"
|
|
231
|
+
);
|
|
228
232
|
writeFileSync(
|
|
229
233
|
join(options.outDir, "badge.json"),
|
|
230
234
|
JSON.stringify(renderWitanBadgeEndpoint(report), null, 2),
|
package/dist/mcp/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
renderWitanBadgeSvg,
|
|
11
11
|
renderWitanHtmlReport,
|
|
12
12
|
runCejelScan
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-SNDRU52Z.js";
|
|
14
14
|
|
|
15
15
|
// node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/codegen/code.js
|
|
16
16
|
var require_code = __commonJS({
|
|
@@ -17097,7 +17097,11 @@ function createCejelMcpServer(identity) {
|
|
|
17097
17097
|
if (!lastScan) throw new Error("No scan has run yet \u2014 call the scan tool first.");
|
|
17098
17098
|
return {
|
|
17099
17099
|
contents: [
|
|
17100
|
-
{
|
|
17100
|
+
{
|
|
17101
|
+
uri: uri.href,
|
|
17102
|
+
mimeType: "text/html",
|
|
17103
|
+
text: renderWitanHtmlReport(lastScan.report, { cliVersion: identity.version })
|
|
17104
|
+
}
|
|
17101
17105
|
]
|
|
17102
17106
|
};
|
|
17103
17107
|
}
|