@cejel/cejel 0.6.5 → 0.6.7
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 +6 -6
- package/dist/calibration/llm-detector.js +3 -3
- package/dist/{chunk-M6YYPJSN.js → chunk-5PFYOIOS.js} +1 -1
- package/dist/{chunk-35TRRAEC.js → chunk-TOQPQPDF.js} +1 -1
- package/dist/{chunk-63XQDYQ5.js → chunk-VGBFZBZQ.js} +5 -2
- package/dist/{chunk-7XQVE76B.js → chunk-ZZHQZW26.js} +359 -49
- package/dist/index.js +137 -56
- package/dist/mcp/index.js +3 -3
- package/dist/packs/d-series/index.js +2 -2
- package/package.json +1 -1
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.7 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.7` 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.7`:
|
|
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.7
|
|
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.7 .
|
|
200
200
|
```
|
|
201
201
|
|
|
202
202
|
The OCI image carries an SBOM of its base-image packages, maximum-mode build provenance, and a
|
|
@@ -571,7 +571,7 @@ The OCI image is an alternative when Docker is the preferred execution boundary.
|
|
|
571
571
|
the host path with the repository OpenClaw should allow Cejel to read:
|
|
572
572
|
|
|
573
573
|
```bash
|
|
574
|
-
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.
|
|
574
|
+
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.7"]}'
|
|
575
575
|
npx -y openclaw@latest mcp doctor cejel-oci --probe
|
|
576
576
|
```
|
|
577
577
|
|
|
@@ -5,11 +5,11 @@ import {
|
|
|
5
5
|
deriveProductIdentity,
|
|
6
6
|
runCejelScan,
|
|
7
7
|
serializeWitanReport
|
|
8
|
-
} from "../chunk-
|
|
8
|
+
} from "../chunk-ZZHQZW26.js";
|
|
9
9
|
import {
|
|
10
10
|
listCejelLlmPackFiles
|
|
11
|
-
} from "../chunk-
|
|
12
|
-
import "../chunk-
|
|
11
|
+
} from "../chunk-5PFYOIOS.js";
|
|
12
|
+
import "../chunk-VGBFZBZQ.js";
|
|
13
13
|
import {
|
|
14
14
|
external_exports
|
|
15
15
|
} from "../chunk-FSMZV3Y6.js";
|
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
// src/witan/git-exec.ts
|
|
9
9
|
init_esm_shims();
|
|
10
10
|
import { execFileSync } from "child_process";
|
|
11
|
-
import {
|
|
11
|
+
import { realpathSync } from "fs";
|
|
12
|
+
import { dirname, resolve } from "path";
|
|
12
13
|
var GIT_EXEC_MAX_BUFFER_BYTES = 8 * 1024 * 1024;
|
|
13
14
|
var GIT_EXEC_TIMEOUT_MS = 3e4;
|
|
14
15
|
var HARDENED_GIT_ARGUMENTS = [
|
|
@@ -52,6 +53,7 @@ var HARDENED_GIT_ARGUMENTS = [
|
|
|
52
53
|
"-c",
|
|
53
54
|
"protocol.ssh.allow=never"
|
|
54
55
|
];
|
|
56
|
+
var discoveryCeiling;
|
|
55
57
|
function hardenedGitEnvironment(cwd) {
|
|
56
58
|
const environment = {};
|
|
57
59
|
for (const key of ["PATH", "HOME", "TZ"]) {
|
|
@@ -78,7 +80,8 @@ function hardenedGitEnvironment(cwd) {
|
|
|
78
80
|
// still excluded below.
|
|
79
81
|
GIT_CONFIG_COUNT: "1",
|
|
80
82
|
GIT_CONFIG_KEY_0: "safe.directory",
|
|
81
|
-
GIT_CONFIG_VALUE_0: cwd
|
|
83
|
+
GIT_CONFIG_VALUE_0: cwd,
|
|
84
|
+
...discoveryCeiling === void 0 ? {} : { GIT_CEILING_DIRECTORIES: discoveryCeiling }
|
|
82
85
|
};
|
|
83
86
|
}
|
|
84
87
|
function errorField(error, key) {
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
describeGitFailure,
|
|
6
6
|
execGit,
|
|
7
7
|
isExpectedGitAbsence
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-VGBFZBZQ.js";
|
|
9
9
|
import {
|
|
10
10
|
external_exports
|
|
11
11
|
} from "./chunk-FSMZV3Y6.js";
|
|
@@ -572,6 +572,7 @@ var WITAN_DIRECTORY_WALK_AUTHENTICATED_A1_ABSENCE_SUMMARY = "Reviewable source i
|
|
|
572
572
|
var WITAN_LEGACY_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.";
|
|
573
573
|
var WITAN_A5_RECONCILIATION_UNSETTLED_DISCLOSURE = "Whether this repository's claims are reconciled against its implementation cannot be settled from static evidence; Cejel makes no finding on it.";
|
|
574
574
|
var WITAN_A2_TENANT_ISOLATION_UNSETTLED_DISCLOSURE = "Whether tenant isolation is enforced outside the database cannot be settled from static evidence; Cejel makes no finding on it.";
|
|
575
|
+
var WITAN_A3_BUILD_STEP_UNSETTLED_DISCLOSURE = "Whether this package has a build or type-check step outside the files read cannot be settled from static evidence; Cejel makes no finding on it.";
|
|
575
576
|
function isWitanNoMeasurementAbstention(report) {
|
|
576
577
|
return report.verdict === "insufficient_source" && report.insufficientSourceReason.startsWith(WITAN_NO_MEASUREMENT_REASON) && report.criteria.every(
|
|
577
578
|
({ status }) => status === "not_applicable" || status === "insufficient_data"
|
|
@@ -1973,6 +1974,7 @@ function buildWithheldPathsGapSentence(report) {
|
|
|
1973
1974
|
}
|
|
1974
1975
|
var SETTLING_EVIDENCE_DISCLOSURES = [
|
|
1975
1976
|
{ criterionId: "A2", sentence: WITAN_A2_TENANT_ISOLATION_UNSETTLED_DISCLOSURE },
|
|
1977
|
+
{ criterionId: "A3", sentence: WITAN_A3_BUILD_STEP_UNSETTLED_DISCLOSURE },
|
|
1976
1978
|
{ criterionId: "A5", sentence: WITAN_A5_RECONCILIATION_UNSETTLED_DISCLOSURE }
|
|
1977
1979
|
];
|
|
1978
1980
|
function settlingEvidenceDisclosures(report) {
|
|
@@ -3205,6 +3207,7 @@ function buildWitanInputFromRepoUntracked(options) {
|
|
|
3205
3207
|
const usesV24SecretContentContext = rubricVersion === WITAN_RUBRIC_VERSION_V24;
|
|
3206
3208
|
const usesV25InlineHealthRoute = rubricVersion === WITAN_RUBRIC_VERSION_V25 || rubricVersion === WITAN_RUBRIC_VERSION_V26;
|
|
3207
3209
|
const usesV26SettlingEvidence = rubricVersion === WITAN_RUBRIC_VERSION_V26;
|
|
3210
|
+
const usesV26BuildStepEvidence = rubricVersion === WITAN_RUBRIC_VERSION_V26;
|
|
3208
3211
|
const structuralArchetype = classifyRepoArchetype(inventoryFiles, rubricVersion);
|
|
3209
3212
|
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(
|
|
3210
3213
|
options.repoPath,
|
|
@@ -3246,6 +3249,7 @@ function buildWitanInputFromRepoUntracked(options) {
|
|
|
3246
3249
|
usesV24SecretContentContext,
|
|
3247
3250
|
usesV25InlineHealthRoute,
|
|
3248
3251
|
usesV26SettlingEvidence,
|
|
3252
|
+
usesV26BuildStepEvidence,
|
|
3249
3253
|
reviewableSourceProof,
|
|
3250
3254
|
inventoryAbsenceContext,
|
|
3251
3255
|
scanLimitations
|
|
@@ -3860,7 +3864,7 @@ function buildNotApplicableSignal(criterionId, reason) {
|
|
|
3860
3864
|
notApplicable: true
|
|
3861
3865
|
};
|
|
3862
3866
|
}
|
|
3863
|
-
function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, useV18NativeRls, useV19CommitYear, useV20A3ExplicitGaps, useV21ExecutedEscalations, useV22PackageStartEntrypoint, useV23StrictCoverageAndRecipeRunners, useV23PemPrivateKeyGrammar, useV23WithheldPathAbstention, useV24SecretContentContext, useV25InlineHealthRoute, useV26SettlingEvidence, reviewableSourceProof, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT, scanLimitations = /* @__PURE__ */ new Set()) {
|
|
3867
|
+
function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, useV33Detectors, useV36Detectors, useV39Detectors, useV47Detectors, useV18NativeRls, useV19CommitYear, useV20A3ExplicitGaps, useV21ExecutedEscalations, useV22PackageStartEntrypoint, useV23StrictCoverageAndRecipeRunners, useV23PemPrivateKeyGrammar, useV23WithheldPathAbstention, useV24SecretContentContext, useV25InlineHealthRoute, useV26SettlingEvidence, useV26BuildStepEvidence, reviewableSourceProof, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT, scanLimitations = /* @__PURE__ */ new Set()) {
|
|
3864
3868
|
const signals = [];
|
|
3865
3869
|
const mono = resolveMonorepoContext(repoPath, scanLimitations);
|
|
3866
3870
|
const collectCriterion = (criterionId, collect) => withContentReadCriterion(criterionId, collect);
|
|
@@ -3905,7 +3909,8 @@ function collectRepoSignals(repoPath, generatedAt, repoFiles, useV27Detectors, u
|
|
|
3905
3909
|
useV22PackageStartEntrypoint,
|
|
3906
3910
|
useV23WithheldPathAbstention,
|
|
3907
3911
|
inventoryAbsenceContext,
|
|
3908
|
-
useV25InlineHealthRoute
|
|
3912
|
+
useV25InlineHealthRoute,
|
|
3913
|
+
useV26BuildStepEvidence
|
|
3909
3914
|
)
|
|
3910
3915
|
);
|
|
3911
3916
|
const a4Signal = collectCriterion(
|
|
@@ -4828,7 +4833,7 @@ function collectCryptoHygieneEvidence(repoPath, implFiles, useV39Detectors = fal
|
|
|
4828
4833
|
}
|
|
4829
4834
|
return { evidence, findings, hasSurface, clean: hasSurface && !insecureFound };
|
|
4830
4835
|
}
|
|
4831
|
-
function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, useV20ExplicitGaps = false, useV22PackageStartEntrypoint = false, useV23WithheldPathAbstention = false, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT, useV25InlineHealthRoute = false) {
|
|
4836
|
+
function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, useV20ExplicitGaps = false, useV22PackageStartEntrypoint = false, useV23WithheldPathAbstention = false, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT, useV25InlineHealthRoute = false, useV26BuildStepEvidence = false) {
|
|
4832
4837
|
const v20DirectHttpEntrypoint = useV20ExplicitGaps ? findV20DirectHttpServerEntrypointFile(repoPath, repoFiles) : null;
|
|
4833
4838
|
const v22PackageStartHttpEntrypoint = useV22PackageStartEntrypoint ? findV22PackageStartHttpServerEntrypointFile(repoPath, repoFiles) : null;
|
|
4834
4839
|
const v20RuntimeContainer = useV20ExplicitGaps ? findRuntimeContainerEntrypointFile(repoPath, repoFiles, true) : null;
|
|
@@ -5045,13 +5050,22 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
5045
5050
|
}
|
|
5046
5051
|
}
|
|
5047
5052
|
if (evidence.length === 0) return null;
|
|
5053
|
+
let buildStepSettlement;
|
|
5048
5054
|
if (useV20ExplicitGaps) {
|
|
5049
5055
|
const workspaceManifests = packageJson ? findDeclaredWorkspaceManifests(repoPath, repoFiles, packageJson) : NO_DECLARED_WORKSPACE_MANIFESTS;
|
|
5050
5056
|
const hasBuildOrTypecheck = scripts.has("build") || scripts.has("typecheck") || workspaceManifests.declared > workspaceManifests.read.length || workspaceManifests.read.some((file) => {
|
|
5051
5057
|
const workspaceScripts = readPackageScripts(join(repoPath, file));
|
|
5052
5058
|
return workspaceScripts.has("build") || workspaceScripts.has("typecheck");
|
|
5053
5059
|
});
|
|
5054
|
-
|
|
5060
|
+
buildStepSettlement = useV26BuildStepEvidence && packageJson ? settleV26BuildStepEvidence(
|
|
5061
|
+
repoPath,
|
|
5062
|
+
repoFiles,
|
|
5063
|
+
packageJson,
|
|
5064
|
+
workspaceManifests,
|
|
5065
|
+
workflows,
|
|
5066
|
+
(file) => !useV27Detectors || isAuthoredProductionPath(file)
|
|
5067
|
+
) : void 0;
|
|
5068
|
+
if (packageJson && !hasBuildOrTypecheck && (buildStepSettlement === void 0 || buildStepSettlement === "fires")) {
|
|
5055
5069
|
const workspaceRead = workspaceManifests.read.length;
|
|
5056
5070
|
findings.push({
|
|
5057
5071
|
severity: "info",
|
|
@@ -5192,7 +5206,8 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles, useV27Detectors, us
|
|
|
5192
5206
|
"Counts static rollback or migration-safety artifacts.",
|
|
5193
5207
|
"saturating_count"
|
|
5194
5208
|
)
|
|
5195
|
-
]
|
|
5209
|
+
],
|
|
5210
|
+
...buildStepSettlement === "unsettled" ? { notes: WITAN_A3_BUILD_STEP_UNSETTLED_DISCLOSURE } : {}
|
|
5196
5211
|
};
|
|
5197
5212
|
}
|
|
5198
5213
|
function collectA4DependencyEvidence(repoPath, repoFiles, mono, useV27Detectors, useV47Detectors, inventoryAbsenceContext = LEGACY_INVENTORY_ABSENCE_CONTEXT) {
|
|
@@ -8408,22 +8423,7 @@ function packageScriptReferences(command, scripts) {
|
|
|
8408
8423
|
const names = /* @__PURE__ */ new Set();
|
|
8409
8424
|
let dynamic = false;
|
|
8410
8425
|
for (const segment of splitShellCommandSegments(command)) {
|
|
8411
|
-
|
|
8412
|
-
/\bpnpm\s+run\s+\/((?:\\.|[^/])+)\/([dgimsuvy]*)/giu
|
|
8413
|
-
)) {
|
|
8414
|
-
const source = match[1];
|
|
8415
|
-
if (!source) continue;
|
|
8416
|
-
try {
|
|
8417
|
-
const flags = (match[2] ?? "").replace(/[dgy]/g, "");
|
|
8418
|
-
const selector = new RegExp(source, flags);
|
|
8419
|
-
for (const name of scripts.keys()) {
|
|
8420
|
-
if (selector.test(name)) names.add(name);
|
|
8421
|
-
selector.lastIndex = 0;
|
|
8422
|
-
}
|
|
8423
|
-
} catch {
|
|
8424
|
-
dynamic = true;
|
|
8425
|
-
}
|
|
8426
|
-
}
|
|
8426
|
+
if (/\bpnpm\s+run\s+\//iu.test(segment)) dynamic = true;
|
|
8427
8427
|
for (const match of segment.matchAll(
|
|
8428
8428
|
/\b(?:npm|pnpm|yarn)\s+(?:run\s+)?([A-Za-z0-9][A-Za-z0-9:._-]*)/giu
|
|
8429
8429
|
)) {
|
|
@@ -9411,40 +9411,51 @@ function findRootPackageJson(repoFiles) {
|
|
|
9411
9411
|
var WORKSPACE_PATTERN_LIMIT = 64;
|
|
9412
9412
|
var WORKSPACE_PACKAGE_MANIFEST_LIMIT = 200;
|
|
9413
9413
|
var NO_DECLARED_WORKSPACE_MANIFESTS = { read: [], declared: 0 };
|
|
9414
|
+
var UNREADABLE_WORKSPACE_DECLARATION = {
|
|
9415
|
+
read: [],
|
|
9416
|
+
declared: 0,
|
|
9417
|
+
unreadable: true
|
|
9418
|
+
};
|
|
9414
9419
|
function findDeclaredWorkspaceManifests(repoPath, repoFiles, rootPackageJson) {
|
|
9415
9420
|
const patterns = [];
|
|
9416
9421
|
if (rootPackageJson) {
|
|
9417
9422
|
const declared = readPackageJsonWorkspacePatterns(join(repoPath, rootPackageJson));
|
|
9418
|
-
if (declared === null) return
|
|
9423
|
+
if (declared === null) return UNREADABLE_WORKSPACE_DECLARATION;
|
|
9419
9424
|
patterns.push(...declared);
|
|
9420
9425
|
}
|
|
9421
9426
|
if (repoFiles.includes("pnpm-workspace.yaml")) {
|
|
9422
9427
|
const declared = readPnpmWorkspacePatterns(join(repoPath, "pnpm-workspace.yaml"));
|
|
9423
|
-
if (declared === null) return
|
|
9428
|
+
if (declared === null) return UNREADABLE_WORKSPACE_DECLARATION;
|
|
9424
9429
|
patterns.push(...declared);
|
|
9425
9430
|
}
|
|
9426
|
-
if (patterns.length === 0
|
|
9427
|
-
|
|
9428
|
-
}
|
|
9431
|
+
if (patterns.length === 0) return NO_DECLARED_WORKSPACE_MANIFESTS;
|
|
9432
|
+
if (patterns.length > WORKSPACE_PATTERN_LIMIT) return UNREADABLE_WORKSPACE_DECLARATION;
|
|
9429
9433
|
const include = [];
|
|
9430
9434
|
const exclude = [];
|
|
9435
|
+
let unparsedPattern = false;
|
|
9431
9436
|
for (const pattern of patterns) {
|
|
9432
9437
|
const negated = pattern.startsWith("!");
|
|
9433
|
-
const
|
|
9438
|
+
const matcher = workspaceGlobMatcher(negated ? pattern.slice(1) : pattern);
|
|
9434
9439
|
if (negated) {
|
|
9435
|
-
if (
|
|
9436
|
-
exclude.push(
|
|
9437
|
-
} else if (
|
|
9438
|
-
include.push(
|
|
9440
|
+
if (matcher === null) return UNREADABLE_WORKSPACE_DECLARATION;
|
|
9441
|
+
exclude.push(matcher);
|
|
9442
|
+
} else if (matcher !== null) {
|
|
9443
|
+
include.push(matcher);
|
|
9444
|
+
} else {
|
|
9445
|
+
unparsedPattern = true;
|
|
9439
9446
|
}
|
|
9440
9447
|
}
|
|
9441
9448
|
const matched = repoFiles.filter((file) => {
|
|
9442
9449
|
if (file === rootPackageJson || !file.endsWith("/package.json")) return false;
|
|
9443
9450
|
if (!isAuthoredProductionPath(file)) return false;
|
|
9444
9451
|
const dir = file.slice(0, -"/package.json".length);
|
|
9445
|
-
return include.some((
|
|
9452
|
+
return include.some((matches) => matches(dir)) && !exclude.some((matches) => matches(dir));
|
|
9446
9453
|
}).sort();
|
|
9447
|
-
return {
|
|
9454
|
+
return {
|
|
9455
|
+
read: matched.slice(0, WORKSPACE_PACKAGE_MANIFEST_LIMIT),
|
|
9456
|
+
declared: matched.length,
|
|
9457
|
+
...unparsedPattern ? { unreadable: true } : {}
|
|
9458
|
+
};
|
|
9448
9459
|
}
|
|
9449
9460
|
function readPackageJsonWorkspacePatterns(packageJsonPath) {
|
|
9450
9461
|
if (!isRegularFile(packageJsonPath)) return [];
|
|
@@ -9503,27 +9514,69 @@ function yamlScalar(raw) {
|
|
|
9503
9514
|
const plain = stripYamlLineComment(raw).trim();
|
|
9504
9515
|
return plain === "" || /^["'[{&*|>]/.test(plain) ? null : plain;
|
|
9505
9516
|
}
|
|
9506
|
-
|
|
9517
|
+
var WORKSPACE_GLOB_MAX_LENGTH = 256;
|
|
9518
|
+
var WORKSPACE_GLOB_MAX_SEGMENTS = 32;
|
|
9519
|
+
function workspaceGlobMatcher(pattern) {
|
|
9520
|
+
if (pattern.length > WORKSPACE_GLOB_MAX_LENGTH) return null;
|
|
9507
9521
|
const normalised = pattern.trim().replace(/^\.\//, "").replace(/\/+$/, "");
|
|
9508
9522
|
if (normalised === "" || normalised.startsWith("/") || /(^|\/)\.\.?(\/|$)/.test(normalised) || /[[\]{}()!+@\\]/.test(normalised)) {
|
|
9509
9523
|
return null;
|
|
9510
9524
|
}
|
|
9511
|
-
const
|
|
9512
|
-
|
|
9513
|
-
|
|
9514
|
-
|
|
9515
|
-
segments.
|
|
9516
|
-
|
|
9517
|
-
|
|
9518
|
-
|
|
9525
|
+
const split = normalised.split("/");
|
|
9526
|
+
if (split.length > WORKSPACE_GLOB_MAX_SEGMENTS) return null;
|
|
9527
|
+
const segments = split.filter((segment, index, all) => !(segment === "**" && all[index - 1] === "**"));
|
|
9528
|
+
const isAnySegment = (part) => part !== "" && !part.startsWith(".");
|
|
9529
|
+
if (segments.length === 1 && segments[0] === "**") {
|
|
9530
|
+
return (dir) => dir.split("/").every(isAnySegment);
|
|
9531
|
+
}
|
|
9532
|
+
return (dir) => {
|
|
9533
|
+
let reachable = withGlobstarSkips(segments, [true, ...segments.map(() => false)]);
|
|
9534
|
+
for (const part of dir.split("/")) {
|
|
9535
|
+
const next = segments.map(() => false).concat(false);
|
|
9536
|
+
segments.forEach((segment, index) => {
|
|
9537
|
+
if (!reachable[index]) return;
|
|
9538
|
+
if (segment === "**") {
|
|
9539
|
+
if (isAnySegment(part)) next[index] = true;
|
|
9540
|
+
} else if (matchesWildcardSegment(segment, part)) {
|
|
9541
|
+
next[index + 1] = true;
|
|
9542
|
+
}
|
|
9543
|
+
});
|
|
9544
|
+
reachable = withGlobstarSkips(segments, next);
|
|
9545
|
+
if (!reachable.includes(true)) return false;
|
|
9519
9546
|
}
|
|
9520
|
-
|
|
9521
|
-
|
|
9522
|
-
|
|
9523
|
-
|
|
9524
|
-
|
|
9547
|
+
return reachable[segments.length] === true;
|
|
9548
|
+
};
|
|
9549
|
+
}
|
|
9550
|
+
function withGlobstarSkips(segments, reachable) {
|
|
9551
|
+
segments.forEach((segment, index) => {
|
|
9552
|
+
if (segment === "**" && reachable[index]) reachable[index + 1] = true;
|
|
9525
9553
|
});
|
|
9526
|
-
return
|
|
9554
|
+
return reachable;
|
|
9555
|
+
}
|
|
9556
|
+
function matchesWildcardSegment(glob, part) {
|
|
9557
|
+
if ((glob.startsWith("*") || glob.startsWith("?")) && part.startsWith(".")) return false;
|
|
9558
|
+
let g = 0;
|
|
9559
|
+
let p = 0;
|
|
9560
|
+
let starGlob = -1;
|
|
9561
|
+
let starPart = 0;
|
|
9562
|
+
while (p < part.length) {
|
|
9563
|
+
if (g < glob.length && glob[g] === "*") {
|
|
9564
|
+
starGlob = g;
|
|
9565
|
+
starPart = p;
|
|
9566
|
+
g += 1;
|
|
9567
|
+
} else if (g < glob.length && (glob[g] === "?" || glob[g] === part[p])) {
|
|
9568
|
+
g += 1;
|
|
9569
|
+
p += 1;
|
|
9570
|
+
} else if (starGlob !== -1) {
|
|
9571
|
+
g = starGlob + 1;
|
|
9572
|
+
starPart += 1;
|
|
9573
|
+
p = starPart;
|
|
9574
|
+
} else {
|
|
9575
|
+
return false;
|
|
9576
|
+
}
|
|
9577
|
+
}
|
|
9578
|
+
while (g < glob.length && glob[g] === "*") g += 1;
|
|
9579
|
+
return g === glob.length;
|
|
9527
9580
|
}
|
|
9528
9581
|
function ciWorkflowCitationLabel(baseLabel, verb, considered, cited, unread, delegated = NO_DELEGATED_CI_STEPS) {
|
|
9529
9582
|
const unreadTotal = [...unread.values()].reduce((sum, count) => sum + count, 0);
|
|
@@ -9612,6 +9665,263 @@ function unreadCiWorkflowReasons(includes) {
|
|
|
9612
9665
|
}
|
|
9613
9666
|
return unread;
|
|
9614
9667
|
}
|
|
9668
|
+
var BUILD_STEP_EXECUTABLES = /* @__PURE__ */ new Set([
|
|
9669
|
+
"babel",
|
|
9670
|
+
"esbuild",
|
|
9671
|
+
"ncc",
|
|
9672
|
+
"rollup",
|
|
9673
|
+
"svelte-check",
|
|
9674
|
+
"swc",
|
|
9675
|
+
"tsc",
|
|
9676
|
+
"tsup",
|
|
9677
|
+
"vue-tsc",
|
|
9678
|
+
"webpack",
|
|
9679
|
+
"webpack-cli"
|
|
9680
|
+
]);
|
|
9681
|
+
var BUILD_STEP_SUBCOMMANDS = /* @__PURE__ */ new Map([
|
|
9682
|
+
["bun", "build"],
|
|
9683
|
+
["nest", "build"],
|
|
9684
|
+
["next", "build"],
|
|
9685
|
+
["ng", "build"],
|
|
9686
|
+
["parcel", "build"],
|
|
9687
|
+
["vite", "build"]
|
|
9688
|
+
]);
|
|
9689
|
+
var BUILD_STEP_TASK_RUNNERS = /* @__PURE__ */ new Set([
|
|
9690
|
+
"bun",
|
|
9691
|
+
"gmake",
|
|
9692
|
+
"just",
|
|
9693
|
+
"lerna",
|
|
9694
|
+
"make",
|
|
9695
|
+
"npm",
|
|
9696
|
+
"nx",
|
|
9697
|
+
"pnpm",
|
|
9698
|
+
"turbo",
|
|
9699
|
+
"yarn"
|
|
9700
|
+
]);
|
|
9701
|
+
var BUILD_STEP_TARGET_NAME_PATTERN = /^(?:build|typecheck)$/u;
|
|
9702
|
+
var BUILD_STEP_TARGET_ARGUMENT_PATTERN = /^(?:[^\s:]+:)?(?:build|typecheck)$/u;
|
|
9703
|
+
var TYPESCRIPT_SOURCE_PATTERN = /\.(?:ts|tsx|mts|cts)$/u;
|
|
9704
|
+
var TYPESCRIPT_DECLARATION_PATTERN = /\.d\.(?:ts|mts|cts)$/u;
|
|
9705
|
+
var TSCONFIG_PATTERN = /(^|\/)tsconfig[^/]*\.json$/u;
|
|
9706
|
+
var BUILD_STEP_DOCKERFILE_PATTERN = /(^|\/)(?:dockerfile|containerfile)(?:\.[^/]*)?$|[^/]\.dockerfile$/iu;
|
|
9707
|
+
function settleV26BuildStepEvidence(repoPath, repoFiles, packageJson, workspaceManifests, workflows, includesWorkflow) {
|
|
9708
|
+
const nestedPackageDirs = repoFiles.filter((file) => file !== packageJson && /(^|\/)package\.json$/u.test(file)).map((file) => file.slice(0, -"package.json".length));
|
|
9709
|
+
const hasSomethingToBuild = repoFiles.some(
|
|
9710
|
+
(file) => isAuthoredProductionPath(file) && (TYPESCRIPT_SOURCE_PATTERN.test(file) && !TYPESCRIPT_DECLARATION_PATTERN.test(file) || TSCONFIG_PATTERN.test(file)) && !nestedPackageDirs.some((dir) => file.startsWith(dir))
|
|
9711
|
+
);
|
|
9712
|
+
if (!hasSomethingToBuild) return "nothing-to-build";
|
|
9713
|
+
let unsettled = false;
|
|
9714
|
+
const commandRunsStep = (command) => {
|
|
9715
|
+
const state = classifyBuildStepCommand(command);
|
|
9716
|
+
if (state === "unparseable") unsettled = true;
|
|
9717
|
+
return state === "step";
|
|
9718
|
+
};
|
|
9719
|
+
for (const manifest of [packageJson, ...workspaceManifests.read]) {
|
|
9720
|
+
const scripts = readBuildStepPackageScripts(join(repoPath, manifest));
|
|
9721
|
+
if (scripts === null) {
|
|
9722
|
+
unsettled = true;
|
|
9723
|
+
continue;
|
|
9724
|
+
}
|
|
9725
|
+
for (const [name, command] of scripts) {
|
|
9726
|
+
if (BUILD_STEP_TARGET_NAME_PATTERN.test(name) || commandRunsStep(command)) return "step-found";
|
|
9727
|
+
}
|
|
9728
|
+
}
|
|
9729
|
+
for (const workflow of workflows) {
|
|
9730
|
+
const fullPath = join(repoPath, workflow);
|
|
9731
|
+
if (!/^\.github\/workflows\//u.test(workflow) || !isRegularFile(fullPath)) {
|
|
9732
|
+
unsettled = true;
|
|
9733
|
+
continue;
|
|
9734
|
+
}
|
|
9735
|
+
if (extractCiRunCommands(readRepoText(fullPath, "utf8")).some(commandRunsStep)) {
|
|
9736
|
+
return "step-found";
|
|
9737
|
+
}
|
|
9738
|
+
}
|
|
9739
|
+
for (const file of repoFiles.filter((path) => BUILD_STEP_DOCKERFILE_PATTERN.test(path))) {
|
|
9740
|
+
const fullPath = join(repoPath, file);
|
|
9741
|
+
if (!isRegularFile(fullPath)) {
|
|
9742
|
+
unsettled = true;
|
|
9743
|
+
continue;
|
|
9744
|
+
}
|
|
9745
|
+
const run = dockerfileRunCommands(readRepoText(fullPath, "utf8"));
|
|
9746
|
+
if (run.unparseable) unsettled = true;
|
|
9747
|
+
if (run.commands.some(commandRunsStep)) return "step-found";
|
|
9748
|
+
}
|
|
9749
|
+
for (const file of repoFiles.filter(isRecipeFile)) {
|
|
9750
|
+
const fullPath = join(repoPath, file);
|
|
9751
|
+
if (!isRegularFile(fullPath)) {
|
|
9752
|
+
unsettled = true;
|
|
9753
|
+
continue;
|
|
9754
|
+
}
|
|
9755
|
+
for (const [name, target] of readRecipeTargets(readRepoText(fullPath, "utf8"))) {
|
|
9756
|
+
if (BUILD_STEP_TARGET_NAME_PATTERN.test(name)) return "step-found";
|
|
9757
|
+
if (target.commands.some((command) => commandRunsStep(command.replace(/\\$/u, "")))) {
|
|
9758
|
+
return "step-found";
|
|
9759
|
+
}
|
|
9760
|
+
}
|
|
9761
|
+
}
|
|
9762
|
+
if (workspaceManifests.declared > workspaceManifests.read.length || workspaceManifests.unreadable) {
|
|
9763
|
+
unsettled = true;
|
|
9764
|
+
}
|
|
9765
|
+
if (unreadCiWorkflowReasons(includesWorkflow).size > 0) unsettled = true;
|
|
9766
|
+
const delegated = countDelegatedCiSteps(repoPath, workflows);
|
|
9767
|
+
if (delegated.crossRepositoryReusableWorkflows + delegated.compositeActions > 0) unsettled = true;
|
|
9768
|
+
if (withheldRepoPaths().some(
|
|
9769
|
+
({ path }) => BUILD_STEP_DOCKERFILE_PATTERN.test(path) || isRecipeFile(path) || /(^|\/)package\.json$/u.test(path) && isAuthoredProductionPath(path)
|
|
9770
|
+
)) {
|
|
9771
|
+
unsettled = true;
|
|
9772
|
+
}
|
|
9773
|
+
return unsettled ? "unsettled" : "fires";
|
|
9774
|
+
}
|
|
9775
|
+
function readBuildStepPackageScripts(packageJsonPath) {
|
|
9776
|
+
if (!isRegularFile(packageJsonPath)) return null;
|
|
9777
|
+
const parsed = parseJsonObject(readRepoText(packageJsonPath, "utf8"));
|
|
9778
|
+
if (parsed === null) return null;
|
|
9779
|
+
if (parsed.scripts === void 0) return /* @__PURE__ */ new Map();
|
|
9780
|
+
if (!isRecord(parsed.scripts)) return null;
|
|
9781
|
+
const entries = Object.entries(parsed.scripts);
|
|
9782
|
+
if (!entries.every((entry) => typeof entry[1] === "string")) return null;
|
|
9783
|
+
return new Map(entries);
|
|
9784
|
+
}
|
|
9785
|
+
function dockerfileRunCommands(contents) {
|
|
9786
|
+
if (/^#\s*escape\s*=/imu.test(contents)) return { commands: [], unparseable: true };
|
|
9787
|
+
const lines = contents.split(/\r?\n/u);
|
|
9788
|
+
const commands = [];
|
|
9789
|
+
let unparseable = false;
|
|
9790
|
+
for (let index = 0; index < lines.length; index += 1) {
|
|
9791
|
+
const match = /^\s*RUN(?:\s+(.*))?$/iu.exec(lines[index] ?? "");
|
|
9792
|
+
if (!match) continue;
|
|
9793
|
+
const chunks = [match[1] ?? ""];
|
|
9794
|
+
while (endsWithLineContinuation(chunks) && index + 1 < lines.length) {
|
|
9795
|
+
index += 1;
|
|
9796
|
+
const next = lines[index] ?? "";
|
|
9797
|
+
if (/^\s*#/u.test(next)) continue;
|
|
9798
|
+
dropLineContinuation(chunks);
|
|
9799
|
+
chunks.push(" ", next.trim());
|
|
9800
|
+
}
|
|
9801
|
+
let instruction = chunks.join("");
|
|
9802
|
+
instruction = instruction.replace(/^(?:--[A-Za-z][\w-]*(?:=\S*)?\s+)*/u, "").trim();
|
|
9803
|
+
if (instruction === "" || /<<-?\s*["']?[A-Za-z_]/u.test(instruction)) {
|
|
9804
|
+
unparseable = true;
|
|
9805
|
+
continue;
|
|
9806
|
+
}
|
|
9807
|
+
if (!instruction.startsWith("[")) {
|
|
9808
|
+
commands.push(instruction);
|
|
9809
|
+
continue;
|
|
9810
|
+
}
|
|
9811
|
+
const execForm = dockerfileExecFormCommand(instruction);
|
|
9812
|
+
if (execForm === null) unparseable = true;
|
|
9813
|
+
else commands.push(execForm);
|
|
9814
|
+
}
|
|
9815
|
+
return { commands, unparseable };
|
|
9816
|
+
}
|
|
9817
|
+
function endsWithLineContinuation(chunks) {
|
|
9818
|
+
for (let c = chunks.length - 1; c >= 0; c -= 1) {
|
|
9819
|
+
const chunk = chunks[c] ?? "";
|
|
9820
|
+
for (let i = chunk.length - 1; i >= 0; i -= 1) {
|
|
9821
|
+
const character = chunk.charAt(i);
|
|
9822
|
+
if (/\s/u.test(character)) continue;
|
|
9823
|
+
return character === "\\";
|
|
9824
|
+
}
|
|
9825
|
+
}
|
|
9826
|
+
return false;
|
|
9827
|
+
}
|
|
9828
|
+
function dropLineContinuation(chunks) {
|
|
9829
|
+
while (chunks.length > 0) {
|
|
9830
|
+
const chunk = chunks[chunks.length - 1] ?? "";
|
|
9831
|
+
let i = chunk.length - 1;
|
|
9832
|
+
while (i >= 0 && /\s/u.test(chunk.charAt(i))) i -= 1;
|
|
9833
|
+
if (i < 0) {
|
|
9834
|
+
chunks.pop();
|
|
9835
|
+
continue;
|
|
9836
|
+
}
|
|
9837
|
+
chunks[chunks.length - 1] = chunk.slice(0, i);
|
|
9838
|
+
return;
|
|
9839
|
+
}
|
|
9840
|
+
}
|
|
9841
|
+
function dockerfileExecFormCommand(instruction) {
|
|
9842
|
+
let parsed;
|
|
9843
|
+
try {
|
|
9844
|
+
parsed = JSON.parse(instruction);
|
|
9845
|
+
} catch {
|
|
9846
|
+
return null;
|
|
9847
|
+
}
|
|
9848
|
+
if (!Array.isArray(parsed) || parsed.length === 0 || !parsed.every((part) => typeof part === "string")) {
|
|
9849
|
+
return null;
|
|
9850
|
+
}
|
|
9851
|
+
return parsed.map(
|
|
9852
|
+
(part) => /^[A-Za-z0-9_@%+=:,./-]+$/u.test(part) ? part : `'${part.replaceAll("'", "'\\''")}'`
|
|
9853
|
+
).join(" ");
|
|
9854
|
+
}
|
|
9855
|
+
function classifyBuildStepCommand(command) {
|
|
9856
|
+
return buildStepCommandState(command, 0);
|
|
9857
|
+
}
|
|
9858
|
+
function buildStepCommandState(command, depth) {
|
|
9859
|
+
if (depth > 4) return "unparseable";
|
|
9860
|
+
const states = splitShellCommandSegments(command).map(
|
|
9861
|
+
(segment) => buildStepSegmentState(segment, depth)
|
|
9862
|
+
);
|
|
9863
|
+
if (states.includes("step")) return "step";
|
|
9864
|
+
return states.includes("unparseable") ? "unparseable" : "none";
|
|
9865
|
+
}
|
|
9866
|
+
function buildStepSegmentState(raw, depth) {
|
|
9867
|
+
let segment = stripUnbalancedShellParentheses(raw.trim());
|
|
9868
|
+
for (; ; ) {
|
|
9869
|
+
const keyword = /^(?:if|then|else|elif|do|while|until|exec|!|\{)(?:\s+|$)/u.exec(segment);
|
|
9870
|
+
if (!keyword) break;
|
|
9871
|
+
segment = segment.slice(keyword[0].length);
|
|
9872
|
+
}
|
|
9873
|
+
if (segment === "" || /^(?:fi|done|esac|\})$/u.test(segment)) return "none";
|
|
9874
|
+
const normalized = normalizeCoverageCommandPrefixes(segment);
|
|
9875
|
+
if (normalized.splitShellOperators && splitShellCommandSegments(normalized.segment).length > 1) {
|
|
9876
|
+
return buildStepCommandState(normalized.segment, depth + 1);
|
|
9877
|
+
}
|
|
9878
|
+
if (/\b(?:npm|pnpm|yarn|bun)\s+run\s+(?:\$|["']\$|`)/u.test(normalized.segment)) {
|
|
9879
|
+
return "unparseable";
|
|
9880
|
+
}
|
|
9881
|
+
const words = strictShellWords(normalized.segment);
|
|
9882
|
+
if (words === null) return "unparseable";
|
|
9883
|
+
return words.length === 0 ? "none" : buildStepWordsState(words);
|
|
9884
|
+
}
|
|
9885
|
+
function buildStepWordsState(words) {
|
|
9886
|
+
const first = words[0] === "$(MAKE)" || words[0] === "${MAKE}" ? "make" : words[0] ?? "";
|
|
9887
|
+
if (isUnresolvedCommandWord(first)) return "unparseable";
|
|
9888
|
+
const runner = buildStepCommandName(first);
|
|
9889
|
+
if (BUILD_STEP_TASK_RUNNERS.has(runner) && words.slice(1).some((word) => BUILD_STEP_TARGET_ARGUMENT_PATTERN.test(word))) {
|
|
9890
|
+
return "step";
|
|
9891
|
+
}
|
|
9892
|
+
const command = runner === "bunx" ? words.slice(1) : runner === "bun" && words[1] === "x" ? words.slice(2) : unwrapPackageManagerExecutable(words);
|
|
9893
|
+
const executable = command[0] ?? "";
|
|
9894
|
+
if (isUnresolvedCommandWord(executable)) return "unparseable";
|
|
9895
|
+
const name = buildStepCommandName(executable);
|
|
9896
|
+
if (BUILD_STEP_EXECUTABLES.has(name)) return "step";
|
|
9897
|
+
const subcommand = BUILD_STEP_SUBCOMMANDS.get(name);
|
|
9898
|
+
return subcommand !== void 0 && command.slice(1).includes(subcommand) ? "step" : "none";
|
|
9899
|
+
}
|
|
9900
|
+
function isUnresolvedCommandWord(word) {
|
|
9901
|
+
return word.startsWith("$") || word.includes("`");
|
|
9902
|
+
}
|
|
9903
|
+
function buildStepCommandName(word) {
|
|
9904
|
+
return basename(word).replace(/\.(?:cmd|exe)$/iu, "").toLowerCase();
|
|
9905
|
+
}
|
|
9906
|
+
function stripUnbalancedShellParentheses(segment) {
|
|
9907
|
+
const opens = segment.split("(").length - 1;
|
|
9908
|
+
const closes = segment.split(")").length - 1;
|
|
9909
|
+
if (opens > closes) return segment.replace(/^\(+\s*/u, "");
|
|
9910
|
+
if (closes > opens) return segment.replace(/\s*\)+$/u, "");
|
|
9911
|
+
return segment;
|
|
9912
|
+
}
|
|
9913
|
+
function strictShellWords(segment) {
|
|
9914
|
+
const words = [];
|
|
9915
|
+
let offset = 0;
|
|
9916
|
+
for (; ; ) {
|
|
9917
|
+
while (offset < segment.length && /\s/u.test(segment[offset] ?? "")) offset += 1;
|
|
9918
|
+
if (offset >= segment.length) return words;
|
|
9919
|
+
const scanned = scanShellWord(segment, offset);
|
|
9920
|
+
if (!scanned) return null;
|
|
9921
|
+
if (scanned.word !== "") words.push(scanned.word);
|
|
9922
|
+
offset = scanned.end;
|
|
9923
|
+
}
|
|
9924
|
+
}
|
|
9615
9925
|
function rootOnlyPackageScriptsDisclosure(repoFiles, rootPackageJson) {
|
|
9616
9926
|
const others = repoFiles.filter(
|
|
9617
9927
|
(file) => file !== rootPackageJson && /(^|\/)package\.json$/.test(file) && isAuthoredProductionPath(file)
|
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-TOQPQPDF.js";
|
|
7
7
|
import {
|
|
8
8
|
CALLER_CONTEXT_PRODUCT_IDENTITY_NOTICE,
|
|
9
9
|
CERTIFICATE_GLOSSARY,
|
|
@@ -29,8 +29,8 @@ import {
|
|
|
29
29
|
runCejelScan,
|
|
30
30
|
serializeWitanReport,
|
|
31
31
|
verifyWitanAttestationBinding
|
|
32
|
-
} from "./chunk-
|
|
33
|
-
import "./chunk-
|
|
32
|
+
} from "./chunk-ZZHQZW26.js";
|
|
33
|
+
import "./chunk-VGBFZBZQ.js";
|
|
34
34
|
import {
|
|
35
35
|
external_exports
|
|
36
36
|
} from "./chunk-FSMZV3Y6.js";
|
|
@@ -41,8 +41,8 @@ import {
|
|
|
41
41
|
// src/index.ts
|
|
42
42
|
init_esm_shims();
|
|
43
43
|
import { createHash as createHash3 } from "crypto";
|
|
44
|
-
import { existsSync,
|
|
45
|
-
import { dirname, join, resolve as
|
|
44
|
+
import { existsSync, readFileSync, realpathSync } from "fs";
|
|
45
|
+
import { dirname, join as join2, resolve as resolve3 } from "path";
|
|
46
46
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
47
47
|
|
|
48
48
|
// src/issuance/index.ts
|
|
@@ -578,6 +578,68 @@ function resolvedToLocalTree(env, cwd) {
|
|
|
578
578
|
return first !== void 0 && first === resolve(cwd, "node_modules", ".bin");
|
|
579
579
|
}
|
|
580
580
|
|
|
581
|
+
// src/output-files.ts
|
|
582
|
+
init_esm_shims();
|
|
583
|
+
import { closeSync, constants, lstatSync, mkdirSync, openSync, writeFileSync } from "fs";
|
|
584
|
+
import { join, resolve as resolve2 } from "path";
|
|
585
|
+
var O_NOFOLLOW = constants.O_NOFOLLOW ?? 0;
|
|
586
|
+
function isSymbolicLink(path) {
|
|
587
|
+
try {
|
|
588
|
+
return lstatSync(path).isSymbolicLink();
|
|
589
|
+
} catch (error) {
|
|
590
|
+
if (error.code === "ENOENT") return false;
|
|
591
|
+
throw error;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
function refusal(what, subject) {
|
|
595
|
+
return new Error(
|
|
596
|
+
`Cejel: refusing to write ${what}: ${subject} is a symbolic link. Nothing was written; remove the link or choose another output path.`
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
function refuseSymlinkedDirectory(dir, what) {
|
|
600
|
+
if (isSymbolicLink(resolve2(dir))) throw refusal(what, `output directory ${dir}`);
|
|
601
|
+
}
|
|
602
|
+
function refuseSymlinkedFile(path, what) {
|
|
603
|
+
if (isSymbolicLink(resolve2(path))) throw refusal(what, path);
|
|
604
|
+
}
|
|
605
|
+
function refuseSymlinkedOutputs(dir, names, what) {
|
|
606
|
+
refuseSymlinkedDirectory(dir, what);
|
|
607
|
+
for (const name of names) refuseSymlinkedFile(join(dir, name), what);
|
|
608
|
+
}
|
|
609
|
+
function writeOutputFileNoFollow(path, contents, what) {
|
|
610
|
+
let fd;
|
|
611
|
+
try {
|
|
612
|
+
fd = openSync(
|
|
613
|
+
path,
|
|
614
|
+
constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | O_NOFOLLOW,
|
|
615
|
+
438
|
|
616
|
+
);
|
|
617
|
+
} catch (error) {
|
|
618
|
+
if (error.code === "ELOOP") {
|
|
619
|
+
throw new Error(
|
|
620
|
+
`Cejel: refusing to write ${what}: ${path} is a symbolic link (the open was refused without following it).`
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
throw error;
|
|
624
|
+
}
|
|
625
|
+
try {
|
|
626
|
+
writeFileSync(fd, contents, "utf8");
|
|
627
|
+
} finally {
|
|
628
|
+
closeSync(fd);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
function writeOutputFile(path, contents, what) {
|
|
632
|
+
refuseSymlinkedFile(path, what);
|
|
633
|
+
writeOutputFileNoFollow(path, contents, what);
|
|
634
|
+
}
|
|
635
|
+
function writeOutputFiles(dir, files, what) {
|
|
636
|
+
const names = files.map((file) => file.name);
|
|
637
|
+
refuseSymlinkedOutputs(dir, names, what);
|
|
638
|
+
mkdirSync(dir, { recursive: true });
|
|
639
|
+
refuseSymlinkedDirectory(dir, what);
|
|
640
|
+
for (const file of files) writeOutputFileNoFollow(join(dir, file.name), file.contents, what);
|
|
641
|
+
}
|
|
642
|
+
|
|
581
643
|
// src/terminal.ts
|
|
582
644
|
init_esm_shims();
|
|
583
645
|
function renderMinScoreAbstentionFailure(summary, minScore) {
|
|
@@ -601,19 +663,22 @@ function renderMinScoreCoverageFailure(coverage, minScore) {
|
|
|
601
663
|
return `Cejel: cannot evaluate the required minimum ${minScore.toFixed(1)}/4.0 because fewer than half of the applicable dimensions were measured in at least one score (${formatCoverageSummary(coverage)}). Resolve the reported evidence gaps and re-scan.
|
|
602
664
|
`;
|
|
603
665
|
}
|
|
666
|
+
function stripTerminalControls(text) {
|
|
667
|
+
return text.replace(/[\t\n]/g, " ").replace(/[\u0000-\u001f\u007f-\u009f]/g, "");
|
|
668
|
+
}
|
|
604
669
|
function renderTerminalCertificate(summary, report) {
|
|
605
670
|
const abstained = summary.verdict === "Insufficient source" || summary.verdict === "Insufficient evidence";
|
|
606
671
|
if (!abstained && (summary.overallScore === null || summary.codeTrustScore === null || summary.processTrustScore === null)) {
|
|
607
672
|
throw new Error("A scored Cejel summary must carry numeric headline scores.");
|
|
608
673
|
}
|
|
609
674
|
const lines = abstained ? [
|
|
610
|
-
`Cejel Trust Certificate \u2014 ${summary.productDisplayName}`,
|
|
675
|
+
`Cejel Trust Certificate \u2014 ${stripTerminalControls(summary.productDisplayName)}`,
|
|
611
676
|
"",
|
|
612
677
|
`${summary.verdict} to certify.`,
|
|
613
|
-
` ${summary.insufficientSourceReason
|
|
678
|
+
` ${summary.insufficientSourceReason === void 0 ? "No ratable source or measurable evidence was found." : stripTerminalControls(summary.insufficientSourceReason)}`,
|
|
614
679
|
""
|
|
615
680
|
] : [
|
|
616
|
-
`Cejel Trust Certificate \u2014 ${summary.productDisplayName}`,
|
|
681
|
+
`Cejel Trust Certificate \u2014 ${stripTerminalControls(summary.productDisplayName)}`,
|
|
617
682
|
"",
|
|
618
683
|
`Overall: ${formatScore(summary.overallScore)}/4.0 (${summary.verdict})`,
|
|
619
684
|
` Code trust: ${formatScore(summary.codeTrustScore)}/4.0`,
|
|
@@ -629,7 +694,7 @@ function renderTerminalCertificate(summary, report) {
|
|
|
629
694
|
2,
|
|
630
695
|
0,
|
|
631
696
|
`Scope: ${relyingPartySummary.scope}`,
|
|
632
|
-
`What was examined: ${relyingPartySummary.examined}`,
|
|
697
|
+
`What was examined: ${stripTerminalControls(relyingPartySummary.examined)}`,
|
|
633
698
|
`What was established: ${relyingPartySummary.established}`,
|
|
634
699
|
`What was not established: ${relyingPartySummary.notEstablished}`,
|
|
635
700
|
`What to do next: ${relyingPartySummary.next}`,
|
|
@@ -639,14 +704,14 @@ function renderTerminalCertificate(summary, report) {
|
|
|
639
704
|
if (summary.scanLimitations.length > 0) {
|
|
640
705
|
lines.push(
|
|
641
706
|
"LIMITED EVIDENCE \u2014 the score and verdict are qualified by scan limitations:",
|
|
642
|
-
...summary.scanLimitations.map((limitation) => ` - ${limitation}`),
|
|
707
|
+
...summary.scanLimitations.map((limitation) => ` - ${stripTerminalControls(limitation)}`),
|
|
643
708
|
""
|
|
644
709
|
);
|
|
645
710
|
}
|
|
646
711
|
if (summary.historyLimitations?.length) {
|
|
647
712
|
lines.push(
|
|
648
713
|
"HISTORY LIMITATION \u2014 scored as usual, but some criteria read truncated history:",
|
|
649
|
-
...summary.historyLimitations.map((limitation) => ` - ${limitation}`),
|
|
714
|
+
...summary.historyLimitations.map((limitation) => ` - ${stripTerminalControls(limitation)}`),
|
|
650
715
|
""
|
|
651
716
|
);
|
|
652
717
|
}
|
|
@@ -664,9 +729,11 @@ function renderTerminalCertificate(summary, report) {
|
|
|
664
729
|
lines.push("");
|
|
665
730
|
}
|
|
666
731
|
if (summary.contributingSources.length > 0) {
|
|
667
|
-
lines.push(
|
|
732
|
+
lines.push(
|
|
733
|
+
`Incorporates findings from: ${summary.contributingSources.map(stripTerminalControls).join(", ")}`
|
|
734
|
+
);
|
|
668
735
|
for (const source of summary.externalSources) {
|
|
669
|
-
lines.push(` ${formatExternalSourceLine(source)}`);
|
|
736
|
+
lines.push(` ${stripTerminalControls(formatExternalSourceLine(source))}`);
|
|
670
737
|
}
|
|
671
738
|
lines.push("");
|
|
672
739
|
}
|
|
@@ -697,7 +764,7 @@ function renderTerminalCertificate(summary, report) {
|
|
|
697
764
|
);
|
|
698
765
|
for (const finding of summary.topFindings) {
|
|
699
766
|
lines.push(
|
|
700
|
-
` [finding severity: ${finding.severity}] ${finding.criterionId} [dimension band: ${finding.dimensionBand}]: ${finding.displaySummary ?? finding.summary}`
|
|
767
|
+
` [finding severity: ${finding.severity}] ${finding.criterionId} [dimension band: ${finding.dimensionBand}]: ${stripTerminalControls(finding.displaySummary ?? finding.summary)}`
|
|
701
768
|
);
|
|
702
769
|
}
|
|
703
770
|
const remaining = summary.findingCount - summary.topFindings.length;
|
|
@@ -714,7 +781,7 @@ function renderTerminalCertificate(summary, report) {
|
|
|
714
781
|
);
|
|
715
782
|
for (const finding of summary.topExternalFindings) {
|
|
716
783
|
lines.push(
|
|
717
|
-
` [${finding.severity}] ${finding.label} \u2192 ${finding.dimension}: ${finding.ruleId} \u2014 ${finding.message}${finding.location ? ` (${finding.location})` : ""}`
|
|
784
|
+
` [${finding.severity}] ${stripTerminalControls(finding.label)} \u2192 ${finding.dimension}: ${stripTerminalControls(finding.ruleId)} \u2014 ${stripTerminalControls(finding.message)}${finding.location ? ` (${stripTerminalControls(finding.location)})` : ""}`
|
|
718
785
|
);
|
|
719
786
|
}
|
|
720
787
|
const remaining = summary.externalFindingCount - summary.topExternalFindings.length;
|
|
@@ -739,6 +806,15 @@ function formatScore(score) {
|
|
|
739
806
|
|
|
740
807
|
// src/index.ts
|
|
741
808
|
var DEFAULT_OUT_DIR = ".cejel";
|
|
809
|
+
var SCAN_OUTPUT_FILES = [
|
|
810
|
+
"report.json",
|
|
811
|
+
"attestation.json",
|
|
812
|
+
"certificate.html",
|
|
813
|
+
"badge.json",
|
|
814
|
+
"badge.svg",
|
|
815
|
+
"summary.json"
|
|
816
|
+
];
|
|
817
|
+
var ISSUANCE_OUTPUT_FILE = "issuance.json";
|
|
742
818
|
var ISSUER_SIGNERS_FILE = "issuer-signers";
|
|
743
819
|
var ISSUER_REVOCATIONS_FILE = "issuer-revocations";
|
|
744
820
|
var SECURITY_FILE_CANDIDATES = ["../docs/security/", "../../docs/security/"];
|
|
@@ -951,6 +1027,7 @@ async function runWitanCli(args, rubricVersion) {
|
|
|
951
1027
|
return 0;
|
|
952
1028
|
}
|
|
953
1029
|
const effectiveRubricVersion = options.rubricPin ?? rubricVersion;
|
|
1030
|
+
refuseSymlinkedOutputs(options.outDir, SCAN_OUTPUT_FILES, "scan output");
|
|
954
1031
|
const { report, summary, generatedAt } = runCejelScan({
|
|
955
1032
|
repoPath: options.repoPath,
|
|
956
1033
|
...options.productName ? { productName: options.productName } : {},
|
|
@@ -965,29 +1042,25 @@ async function runWitanCli(args, rubricVersion) {
|
|
|
965
1042
|
generatedAt,
|
|
966
1043
|
...options.runAttempt ? { githubRunAttempt: options.runAttempt } : {}
|
|
967
1044
|
});
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
JSON.stringify(renderWitanBadgeEndpoint(report), null, 2),
|
|
987
|
-
"utf8"
|
|
1045
|
+
writeOutputFiles(
|
|
1046
|
+
options.outDir,
|
|
1047
|
+
[
|
|
1048
|
+
{ name: "report.json", contents: serializeWitanReport(report) },
|
|
1049
|
+
{ name: "attestation.json", contents: JSON.stringify(attestation, null, 2) },
|
|
1050
|
+
{
|
|
1051
|
+
name: "certificate.html",
|
|
1052
|
+
contents: renderWitanHtmlReport(report, {
|
|
1053
|
+
cliVersion: cliVersion(),
|
|
1054
|
+
generatedAt,
|
|
1055
|
+
...options.runAttempt ? { runAttempt: options.runAttempt } : {}
|
|
1056
|
+
})
|
|
1057
|
+
},
|
|
1058
|
+
{ name: "badge.json", contents: JSON.stringify(renderWitanBadgeEndpoint(report), null, 2) },
|
|
1059
|
+
{ name: "badge.svg", contents: renderWitanBadgeSvg(report) },
|
|
1060
|
+
{ name: "summary.json", contents: JSON.stringify(summary, null, 2) }
|
|
1061
|
+
],
|
|
1062
|
+
"scan output"
|
|
988
1063
|
);
|
|
989
|
-
writeFileSync(join(options.outDir, "badge.svg"), renderWitanBadgeSvg(report), "utf8");
|
|
990
|
-
writeFileSync(join(options.outDir, "summary.json"), JSON.stringify(summary, null, 2), "utf8");
|
|
991
1064
|
if (!options.quiet) {
|
|
992
1065
|
process.stdout.write(renderTerminalCertificate(summary, report));
|
|
993
1066
|
process.stdout.write(
|
|
@@ -1097,8 +1170,8 @@ function parseExportArgs(args) {
|
|
|
1097
1170
|
return {
|
|
1098
1171
|
command: "export",
|
|
1099
1172
|
format,
|
|
1100
|
-
reportPath:
|
|
1101
|
-
outPath:
|
|
1173
|
+
reportPath: resolve3(reportPath),
|
|
1174
|
+
outPath: resolve3(outPath)
|
|
1102
1175
|
};
|
|
1103
1176
|
}
|
|
1104
1177
|
function runExport(invocation) {
|
|
@@ -1116,8 +1189,12 @@ ${members.map((member) => ` - ${member}`).join("\n")}
|
|
|
1116
1189
|
return 1;
|
|
1117
1190
|
}
|
|
1118
1191
|
const result = exportGitLabCodeQuality(reportResult.data);
|
|
1119
|
-
|
|
1120
|
-
|
|
1192
|
+
writeOutputFile(
|
|
1193
|
+
invocation.outPath,
|
|
1194
|
+
`${JSON.stringify(result.entries, null, 2)}
|
|
1195
|
+
`,
|
|
1196
|
+
"export output"
|
|
1197
|
+
);
|
|
1121
1198
|
process.stderr.write(renderGitLabCodeQualityFooter(result));
|
|
1122
1199
|
return 0;
|
|
1123
1200
|
}
|
|
@@ -1132,8 +1209,8 @@ function parseVerifyArgs(args) {
|
|
|
1132
1209
|
if (arg === "--signers" || arg === "--revocations") {
|
|
1133
1210
|
const value = args[index + 1];
|
|
1134
1211
|
if (!value) throw new Error(`Missing value for ${arg}`);
|
|
1135
|
-
if (arg === "--signers") signersPath =
|
|
1136
|
-
else revocationsPath =
|
|
1212
|
+
if (arg === "--signers") signersPath = resolve3(value);
|
|
1213
|
+
else revocationsPath = resolve3(value);
|
|
1137
1214
|
index += 1;
|
|
1138
1215
|
continue;
|
|
1139
1216
|
}
|
|
@@ -1145,10 +1222,10 @@ function parseVerifyArgs(args) {
|
|
|
1145
1222
|
if (!reportPath || !attestationPath) throw new Error(VERIFY_USAGE());
|
|
1146
1223
|
return {
|
|
1147
1224
|
command: "verify",
|
|
1148
|
-
reportPath:
|
|
1149
|
-
attestationPath:
|
|
1150
|
-
...issuancePath ? { issuancePath:
|
|
1151
|
-
...issuanceSignaturePath ? { issuanceSignaturePath:
|
|
1225
|
+
reportPath: resolve3(reportPath),
|
|
1226
|
+
attestationPath: resolve3(attestationPath),
|
|
1227
|
+
...issuancePath ? { issuancePath: resolve3(issuancePath) } : {},
|
|
1228
|
+
...issuanceSignaturePath ? { issuanceSignaturePath: resolve3(issuanceSignaturePath) } : {},
|
|
1152
1229
|
...signersPath ? { signersPath } : {},
|
|
1153
1230
|
...revocationsPath ? { revocationsPath } : {}
|
|
1154
1231
|
};
|
|
@@ -1174,15 +1251,15 @@ function parseIssueArgs(args) {
|
|
|
1174
1251
|
if (arg === void 0) continue;
|
|
1175
1252
|
switch (arg) {
|
|
1176
1253
|
case "--report":
|
|
1177
|
-
reportPath =
|
|
1254
|
+
reportPath = resolve3(takeValue(arg, index + 1));
|
|
1178
1255
|
index += 1;
|
|
1179
1256
|
continue;
|
|
1180
1257
|
case "--attestation":
|
|
1181
|
-
attestationPath =
|
|
1258
|
+
attestationPath = resolve3(takeValue(arg, index + 1));
|
|
1182
1259
|
index += 1;
|
|
1183
1260
|
continue;
|
|
1184
1261
|
case "--key":
|
|
1185
|
-
keyPath =
|
|
1262
|
+
keyPath = resolve3(takeValue(arg, index + 1));
|
|
1186
1263
|
index += 1;
|
|
1187
1264
|
continue;
|
|
1188
1265
|
case "--engagement-ref":
|
|
@@ -1191,7 +1268,7 @@ function parseIssueArgs(args) {
|
|
|
1191
1268
|
continue;
|
|
1192
1269
|
case "--out":
|
|
1193
1270
|
case "--out-dir":
|
|
1194
|
-
outDir =
|
|
1271
|
+
outDir = resolve3(takeValue(arg, index + 1));
|
|
1195
1272
|
index += 1;
|
|
1196
1273
|
continue;
|
|
1197
1274
|
case "--product-name":
|
|
@@ -1235,7 +1312,7 @@ function parseIssueArgs(args) {
|
|
|
1235
1312
|
throw new Error("--product-name and --name cannot be used together");
|
|
1236
1313
|
}
|
|
1237
1314
|
return {
|
|
1238
|
-
repoPath:
|
|
1315
|
+
repoPath: resolve3(repoPath ?? "."),
|
|
1239
1316
|
reportPath,
|
|
1240
1317
|
attestationPath,
|
|
1241
1318
|
keyPath,
|
|
@@ -1405,6 +1482,7 @@ ${attestationBinding.errors.map((error) => ` - ${error}`).join("\n")}
|
|
|
1405
1482
|
throw new Error(`Cejel: could not read --key file ${options.keyPath}: ${message}`);
|
|
1406
1483
|
}
|
|
1407
1484
|
const issuerKey = parseIssuerPublicKey(keyContents);
|
|
1485
|
+
refuseSymlinkedOutputs(options.outDir, [ISSUANCE_OUTPUT_FILE], "issuance output");
|
|
1408
1486
|
const reproduction = runCejelScan({
|
|
1409
1487
|
repoPath: options.repoPath,
|
|
1410
1488
|
...options.productName ? { productName: options.productName } : {},
|
|
@@ -1439,9 +1517,12 @@ ${attestationBinding.errors.map((error) => ` - ${error}`).join("\n")}
|
|
|
1439
1517
|
issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1440
1518
|
engagementRef: options.engagementRef
|
|
1441
1519
|
});
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1520
|
+
const issuancePath = join2(options.outDir, ISSUANCE_OUTPUT_FILE);
|
|
1521
|
+
writeOutputFiles(
|
|
1522
|
+
options.outDir,
|
|
1523
|
+
[{ name: ISSUANCE_OUTPUT_FILE, contents: serializeWitanIssuance(statement) }],
|
|
1524
|
+
"issuance output"
|
|
1525
|
+
);
|
|
1445
1526
|
process.stdout.write(
|
|
1446
1527
|
[
|
|
1447
1528
|
`Cejel: reproduced report.json byte for byte (sha256:${reportSha256}).`,
|
|
@@ -1588,7 +1669,7 @@ function parseArgs(args) {
|
|
|
1588
1669
|
throw new Error("--product-name and --name cannot be used together");
|
|
1589
1670
|
}
|
|
1590
1671
|
return {
|
|
1591
|
-
repoPath:
|
|
1672
|
+
repoPath: resolve3(repoPath ?? "."),
|
|
1592
1673
|
outDir,
|
|
1593
1674
|
...minScore != null ? { minScore } : {},
|
|
1594
1675
|
...productName ? { productName } : {},
|
package/dist/mcp/index.js
CHANGED
|
@@ -3,9 +3,9 @@ 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-
|
|
8
|
-
import "../chunk-
|
|
6
|
+
} from "../chunk-TOQPQPDF.js";
|
|
7
|
+
import "../chunk-ZZHQZW26.js";
|
|
8
|
+
import "../chunk-VGBFZBZQ.js";
|
|
9
9
|
import "../chunk-FSMZV3Y6.js";
|
|
10
10
|
import {
|
|
11
11
|
init_esm_shims
|
|
@@ -3,10 +3,10 @@ import { createRequire as __cejelCreateRequire } from 'node:module';
|
|
|
3
3
|
const require = __cejelCreateRequire(import.meta.url);
|
|
4
4
|
import {
|
|
5
5
|
listCejelLlmPackFiles
|
|
6
|
-
} from "../../chunk-
|
|
6
|
+
} from "../../chunk-5PFYOIOS.js";
|
|
7
7
|
import {
|
|
8
8
|
execGit
|
|
9
|
-
} from "../../chunk-
|
|
9
|
+
} from "../../chunk-VGBFZBZQ.js";
|
|
10
10
|
import {
|
|
11
11
|
require_typescript
|
|
12
12
|
} from "../../chunk-RH6FKREX.js";
|