@cejel/cejel 0.6.6 → 0.6.8
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 +27 -7
- package/dist/calibration/llm-detector.js +5 -5
- package/dist/{chunk-RH6FKREX.js → chunk-6LVNNJTG.js} +1 -1
- package/dist/{chunk-FSMZV3Y6.js → chunk-AMVP7L26.js} +1 -1
- package/dist/{chunk-O3MHSK25.js → chunk-AWLKQUI4.js} +56 -6
- package/dist/{chunk-JNTTFAHQ.js → chunk-KJVFCZZ3.js} +2784 -223
- package/dist/{chunk-BG4ZRBQ5.js → chunk-KNTBED5T.js} +3 -3
- package/dist/{chunk-VGBFZBZQ.js → chunk-NIWSYJ6N.js} +1 -1
- package/dist/{chunk-5PFYOIOS.js → chunk-WXPGEQBE.js} +2 -2
- package/dist/index.js +219 -56
- package/dist/mcp/index.js +5 -5
- package/dist/packs/d-series/index.js +4 -4
- package/dist/packs/decision-contracts/index.js +3 -3
- package/package.json +1 -1
|
@@ -5,19 +5,19 @@ import {
|
|
|
5
5
|
renderWitanBadgeSvg,
|
|
6
6
|
renderWitanHtmlReport,
|
|
7
7
|
runCejelScan
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-KJVFCZZ3.js";
|
|
9
9
|
import {
|
|
10
10
|
ZodFirstPartyTypeKind,
|
|
11
11
|
ZodOptional,
|
|
12
12
|
external_exports,
|
|
13
13
|
objectType
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-AMVP7L26.js";
|
|
15
15
|
import {
|
|
16
16
|
__commonJS,
|
|
17
17
|
__export,
|
|
18
18
|
__toESM,
|
|
19
19
|
init_esm_shims
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-AWLKQUI4.js";
|
|
21
21
|
|
|
22
22
|
// node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/codegen/code.js
|
|
23
23
|
var require_code = __commonJS({
|
|
@@ -5,10 +5,10 @@ import {
|
|
|
5
5
|
describeGitFailure,
|
|
6
6
|
execGit,
|
|
7
7
|
isExpectedGitAbsence
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-NIWSYJ6N.js";
|
|
9
9
|
import {
|
|
10
10
|
init_esm_shims
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-AWLKQUI4.js";
|
|
12
12
|
|
|
13
13
|
// src/packs/llm/files.ts
|
|
14
14
|
init_esm_shims();
|
package/dist/index.js
CHANGED
|
@@ -3,10 +3,11 @@ 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-KNTBED5T.js";
|
|
7
7
|
import {
|
|
8
8
|
CALLER_CONTEXT_PRODUCT_IDENTITY_NOTICE,
|
|
9
9
|
CERTIFICATE_GLOSSARY,
|
|
10
|
+
EXTERNAL_FINDINGS_DISPLAY_LIMIT,
|
|
10
11
|
PROSPECTIVE_RUBRIC_NOTICE,
|
|
11
12
|
WITAN_RUBRIC_VERSION_V22,
|
|
12
13
|
WitanReportSchema,
|
|
@@ -15,6 +16,8 @@ import {
|
|
|
15
16
|
buildVerdictExplanation,
|
|
16
17
|
computeApplicableMeasuredCoverage,
|
|
17
18
|
createWitanAttestation,
|
|
19
|
+
describeInputBindingRecord,
|
|
20
|
+
describeScannedSubject,
|
|
18
21
|
formatCertificateMetricAppliedWeightPercent,
|
|
19
22
|
formatCertificateMetricLabel,
|
|
20
23
|
formatCertificateMetricValue,
|
|
@@ -22,27 +25,33 @@ import {
|
|
|
22
25
|
formatDimensionsMeasuredSentence,
|
|
23
26
|
formatExternalSourceLine,
|
|
24
27
|
formatLowConfidenceSentence,
|
|
28
|
+
importedAdjustmentSentence,
|
|
29
|
+
inheritedFindingNote,
|
|
30
|
+
inputBindingHeadline,
|
|
25
31
|
isProspectiveRubricVersion,
|
|
26
32
|
renderWitanBadgeEndpoint,
|
|
27
33
|
renderWitanBadgeSvg,
|
|
28
34
|
renderWitanHtmlReport,
|
|
35
|
+
resolveIngestFilePath,
|
|
29
36
|
runCejelScan,
|
|
30
37
|
serializeWitanReport,
|
|
38
|
+
stripTerminalControls,
|
|
39
|
+
verifyRecordedInputDigests,
|
|
31
40
|
verifyWitanAttestationBinding
|
|
32
|
-
} from "./chunk-
|
|
33
|
-
import "./chunk-
|
|
41
|
+
} from "./chunk-KJVFCZZ3.js";
|
|
42
|
+
import "./chunk-NIWSYJ6N.js";
|
|
34
43
|
import {
|
|
35
44
|
external_exports
|
|
36
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-AMVP7L26.js";
|
|
37
46
|
import {
|
|
38
47
|
init_esm_shims
|
|
39
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-AWLKQUI4.js";
|
|
40
49
|
|
|
41
50
|
// src/index.ts
|
|
42
51
|
init_esm_shims();
|
|
43
52
|
import { createHash as createHash3 } from "crypto";
|
|
44
|
-
import { existsSync,
|
|
45
|
-
import { dirname, join, resolve as
|
|
53
|
+
import { existsSync, readFileSync, realpathSync } from "fs";
|
|
54
|
+
import { dirname, join as join2, resolve as resolve3 } from "path";
|
|
46
55
|
import { fileURLToPath, pathToFileURL } from "url";
|
|
47
56
|
|
|
48
57
|
// src/issuance/index.ts
|
|
@@ -578,6 +587,68 @@ function resolvedToLocalTree(env, cwd) {
|
|
|
578
587
|
return first !== void 0 && first === resolve(cwd, "node_modules", ".bin");
|
|
579
588
|
}
|
|
580
589
|
|
|
590
|
+
// src/output-files.ts
|
|
591
|
+
init_esm_shims();
|
|
592
|
+
import { closeSync, constants, lstatSync, mkdirSync, openSync, writeFileSync } from "fs";
|
|
593
|
+
import { join, resolve as resolve2 } from "path";
|
|
594
|
+
var O_NOFOLLOW = constants.O_NOFOLLOW ?? 0;
|
|
595
|
+
function isSymbolicLink(path) {
|
|
596
|
+
try {
|
|
597
|
+
return lstatSync(path).isSymbolicLink();
|
|
598
|
+
} catch (error) {
|
|
599
|
+
if (error.code === "ENOENT") return false;
|
|
600
|
+
throw error;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
function refusal(what, subject) {
|
|
604
|
+
return new Error(
|
|
605
|
+
`Cejel: refusing to write ${what}: ${subject} is a symbolic link. Nothing was written; remove the link or choose another output path.`
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
function refuseSymlinkedDirectory(dir, what) {
|
|
609
|
+
if (isSymbolicLink(resolve2(dir))) throw refusal(what, `output directory ${dir}`);
|
|
610
|
+
}
|
|
611
|
+
function refuseSymlinkedFile(path, what) {
|
|
612
|
+
if (isSymbolicLink(resolve2(path))) throw refusal(what, path);
|
|
613
|
+
}
|
|
614
|
+
function refuseSymlinkedOutputs(dir, names, what) {
|
|
615
|
+
refuseSymlinkedDirectory(dir, what);
|
|
616
|
+
for (const name of names) refuseSymlinkedFile(join(dir, name), what);
|
|
617
|
+
}
|
|
618
|
+
function writeOutputFileNoFollow(path, contents, what) {
|
|
619
|
+
let fd;
|
|
620
|
+
try {
|
|
621
|
+
fd = openSync(
|
|
622
|
+
path,
|
|
623
|
+
constants.O_WRONLY | constants.O_CREAT | constants.O_TRUNC | O_NOFOLLOW,
|
|
624
|
+
438
|
|
625
|
+
);
|
|
626
|
+
} catch (error) {
|
|
627
|
+
if (error.code === "ELOOP") {
|
|
628
|
+
throw new Error(
|
|
629
|
+
`Cejel: refusing to write ${what}: ${path} is a symbolic link (the open was refused without following it).`
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
throw error;
|
|
633
|
+
}
|
|
634
|
+
try {
|
|
635
|
+
writeFileSync(fd, contents, "utf8");
|
|
636
|
+
} finally {
|
|
637
|
+
closeSync(fd);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
function writeOutputFile(path, contents, what) {
|
|
641
|
+
refuseSymlinkedFile(path, what);
|
|
642
|
+
writeOutputFileNoFollow(path, contents, what);
|
|
643
|
+
}
|
|
644
|
+
function writeOutputFiles(dir, files, what) {
|
|
645
|
+
const names = files.map((file) => file.name);
|
|
646
|
+
refuseSymlinkedOutputs(dir, names, what);
|
|
647
|
+
mkdirSync(dir, { recursive: true });
|
|
648
|
+
refuseSymlinkedDirectory(dir, what);
|
|
649
|
+
for (const file of files) writeOutputFileNoFollow(join(dir, file.name), file.contents, what);
|
|
650
|
+
}
|
|
651
|
+
|
|
581
652
|
// src/terminal.ts
|
|
582
653
|
init_esm_shims();
|
|
583
654
|
function renderMinScoreAbstentionFailure(summary, minScore) {
|
|
@@ -601,9 +672,6 @@ function renderMinScoreCoverageFailure(coverage, minScore) {
|
|
|
601
672
|
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
673
|
`;
|
|
603
674
|
}
|
|
604
|
-
function stripTerminalControls(text) {
|
|
605
|
-
return text.replace(/[\t\n]/g, " ").replace(/[\u0000-\u001f\u007f-\u009f]/g, "");
|
|
606
|
-
}
|
|
607
675
|
function renderTerminalCertificate(summary, report) {
|
|
608
676
|
const abstained = summary.verdict === "Insufficient source" || summary.verdict === "Insufficient evidence";
|
|
609
677
|
if (!abstained && (summary.overallScore === null || summary.codeTrustScore === null || summary.processTrustScore === null)) {
|
|
@@ -634,7 +702,7 @@ function renderTerminalCertificate(summary, report) {
|
|
|
634
702
|
`Scope: ${relyingPartySummary.scope}`,
|
|
635
703
|
`What was examined: ${stripTerminalControls(relyingPartySummary.examined)}`,
|
|
636
704
|
`What was established: ${relyingPartySummary.established}`,
|
|
637
|
-
`What was not established: ${relyingPartySummary.notEstablished}`,
|
|
705
|
+
`What was not established: ${stripTerminalControls(relyingPartySummary.notEstablished)}`,
|
|
638
706
|
`What to do next: ${relyingPartySummary.next}`,
|
|
639
707
|
""
|
|
640
708
|
);
|
|
@@ -657,7 +725,7 @@ function renderTerminalCertificate(summary, report) {
|
|
|
657
725
|
const reads = summary.contentReadSummary;
|
|
658
726
|
const errnoCounts = Object.entries(reads.unreadableByErrno).map(([errno, count]) => `${errno}: ${count}`).join(", ");
|
|
659
727
|
lines.push(
|
|
660
|
-
`Skipped content entries: ${reads.skipped} (unreadable: ${reads.byReason.unreadable}${errnoCounts ? ` [${errnoCounts}]` : ""}; too large: ${reads.byReason.tooLarge}; excluded by extension: ${reads.byReason.excludedByExtension}; denied path: ${reads.byReason.deniedPath}; non-regular file: ${reads.byReason.nonRegularFile}).`
|
|
728
|
+
`Skipped content entries: ${reads.skipped} (unreadable: ${reads.byReason.unreadable}${errnoCounts ? ` [${errnoCounts}]` : ""}; too large: ${reads.byReason.tooLarge}; excluded by extension: ${reads.byReason.excludedByExtension}; denied path: ${reads.byReason.deniedPath}; non-regular file: ${reads.byReason.nonRegularFile}${reads.byReason.lfsPointer ? `; Git LFS pointer: ${reads.byReason.lfsPointer}` : ""}).`
|
|
661
729
|
);
|
|
662
730
|
if (reads.affectedCriteria.length > 0) {
|
|
663
731
|
lines.push(
|
|
@@ -675,6 +743,20 @@ function renderTerminalCertificate(summary, report) {
|
|
|
675
743
|
}
|
|
676
744
|
lines.push("");
|
|
677
745
|
}
|
|
746
|
+
if (report?.inputBinding) {
|
|
747
|
+
lines.push(stripTerminalControls(inputBindingHeadline(report.inputBinding)));
|
|
748
|
+
lines.push(` ${stripTerminalControls(describeScannedSubject(report.inputBinding))}`);
|
|
749
|
+
for (const input of report.inputBinding.inputs.slice(0, EXTERNAL_FINDINGS_DISPLAY_LIMIT)) {
|
|
750
|
+
lines.push(` ${stripTerminalControls(describeInputBindingRecord(input))}`);
|
|
751
|
+
}
|
|
752
|
+
const remaining = report.inputBinding.inputs.length - EXTERNAL_FINDINGS_DISPLAY_LIMIT;
|
|
753
|
+
if (remaining > 0) lines.push(` ...and ${remaining} more \u2014 see report.json inputBinding.`);
|
|
754
|
+
for (const criterion of report.criteria) {
|
|
755
|
+
const sentence = importedAdjustmentSentence(criterion);
|
|
756
|
+
if (sentence) lines.push(` ${criterion.id}: ${sentence}`);
|
|
757
|
+
}
|
|
758
|
+
lines.push("");
|
|
759
|
+
}
|
|
678
760
|
const measurements = report?.criteria.flatMap(
|
|
679
761
|
(criterion) => criterion.metrics.map((metric) => ({
|
|
680
762
|
criterionId: criterion.id,
|
|
@@ -687,7 +769,7 @@ function renderTerminalCertificate(summary, report) {
|
|
|
687
769
|
lines.push("Measurements:");
|
|
688
770
|
for (const measurement of measurements ?? []) {
|
|
689
771
|
lines.push(
|
|
690
|
-
` ${measurement.criterionId} \u2014 ${measurement.label}: ${measurement.value} (weight ${measurement.weightPercent}% of ${measurement.criterionId})`
|
|
772
|
+
` ${measurement.criterionId} \u2014 ${measurement.label}: ${stripTerminalControls(measurement.value)} (weight ${measurement.weightPercent}% of ${measurement.criterionId})`
|
|
691
773
|
);
|
|
692
774
|
}
|
|
693
775
|
lines.push("");
|
|
@@ -721,6 +803,8 @@ function renderTerminalCertificate(summary, report) {
|
|
|
721
803
|
lines.push(
|
|
722
804
|
` [${finding.severity}] ${stripTerminalControls(finding.label)} \u2192 ${finding.dimension}: ${stripTerminalControls(finding.ruleId)} \u2014 ${stripTerminalControls(finding.message)}${finding.location ? ` (${stripTerminalControls(finding.location)})` : ""}`
|
|
723
805
|
);
|
|
806
|
+
const note = inheritedFindingNote(finding.ruleId);
|
|
807
|
+
if (note) lines.push(` Note: ${note}`);
|
|
724
808
|
}
|
|
725
809
|
const remaining = summary.externalFindingCount - summary.topExternalFindings.length;
|
|
726
810
|
if (remaining > 0) {
|
|
@@ -744,6 +828,15 @@ function formatScore(score) {
|
|
|
744
828
|
|
|
745
829
|
// src/index.ts
|
|
746
830
|
var DEFAULT_OUT_DIR = ".cejel";
|
|
831
|
+
var SCAN_OUTPUT_FILES = [
|
|
832
|
+
"report.json",
|
|
833
|
+
"attestation.json",
|
|
834
|
+
"certificate.html",
|
|
835
|
+
"badge.json",
|
|
836
|
+
"badge.svg",
|
|
837
|
+
"summary.json"
|
|
838
|
+
];
|
|
839
|
+
var ISSUANCE_OUTPUT_FILE = "issuance.json";
|
|
747
840
|
var ISSUER_SIGNERS_FILE = "issuer-signers";
|
|
748
841
|
var ISSUER_REVOCATIONS_FILE = "issuer-revocations";
|
|
749
842
|
var SECURITY_FILE_CANDIDATES = ["../docs/security/", "../../docs/security/"];
|
|
@@ -790,6 +883,17 @@ var CLI_FLAG_SPECS = [
|
|
|
790
883
|
description: "fold in a SARIF/JSON scanner report (repeatable)",
|
|
791
884
|
kind: "ingest"
|
|
792
885
|
},
|
|
886
|
+
{
|
|
887
|
+
tokens: ["--subject-repository"],
|
|
888
|
+
value: "<repo>",
|
|
889
|
+
description: "name this repository (e.g. github.com/owner/repo) so ingested inputs declaring another repository are recorded as mismatched",
|
|
890
|
+
kind: "subjectRepository"
|
|
891
|
+
},
|
|
892
|
+
{
|
|
893
|
+
tokens: ["--strict-ingest"],
|
|
894
|
+
description: "refuse ingested inputs for another repository or commit, observed before this commit, or duplicated (default: record only)",
|
|
895
|
+
kind: "strictIngest"
|
|
896
|
+
},
|
|
793
897
|
{
|
|
794
898
|
tokens: ["--rubric-pin"],
|
|
795
899
|
value: "<version>",
|
|
@@ -882,6 +986,8 @@ ${usageOptions}
|
|
|
882
986
|
Verify options:
|
|
883
987
|
--signers <file> use this allowed-signers file instead of the published one
|
|
884
988
|
--revocations <file> use this revocations file instead of the published one
|
|
989
|
+
--input <file> an ingested input (repeatable); fails unless the supplied set of files
|
|
990
|
+
has exactly the sha256 digests report.json records in inputBinding
|
|
885
991
|
|
|
886
992
|
Issue options:
|
|
887
993
|
--report <file> the report.json being countersigned (required)
|
|
@@ -893,6 +999,7 @@ Issue options:
|
|
|
893
999
|
--name <display> pass exactly what the original scan used, or the bytes will not reproduce
|
|
894
1000
|
--rubric-pin <version> pass exactly what the original scan used, or the bytes will not reproduce
|
|
895
1001
|
--ingest <file> pass exactly what the original scan used, or the bytes will not reproduce
|
|
1002
|
+
(--strict-ingest and --subject-repository are read from report.json's inputBinding)
|
|
896
1003
|
|
|
897
1004
|
cejel never signs and never reads private key material.
|
|
898
1005
|
|
|
@@ -956,6 +1063,7 @@ async function runWitanCli(args, rubricVersion) {
|
|
|
956
1063
|
return 0;
|
|
957
1064
|
}
|
|
958
1065
|
const effectiveRubricVersion = options.rubricPin ?? rubricVersion;
|
|
1066
|
+
refuseSymlinkedOutputs(options.outDir, SCAN_OUTPUT_FILES, "scan output");
|
|
959
1067
|
const { report, summary, generatedAt } = runCejelScan({
|
|
960
1068
|
repoPath: options.repoPath,
|
|
961
1069
|
...options.productName ? { productName: options.productName } : {},
|
|
@@ -963,6 +1071,8 @@ async function runWitanCli(args, rubricVersion) {
|
|
|
963
1071
|
...effectiveRubricVersion ? { rubricVersion: effectiveRubricVersion } : {},
|
|
964
1072
|
ingestPatterns: options.ingestPatterns,
|
|
965
1073
|
warnOnEmptyIngestMatch: !options.quiet,
|
|
1074
|
+
...options.strictIngest ? { strictIngest: true } : {},
|
|
1075
|
+
...options.subjectRepository ? { subjectRepository: options.subjectRepository } : {},
|
|
966
1076
|
toolVersion: cliVersion()
|
|
967
1077
|
});
|
|
968
1078
|
const attestation = createWitanAttestation(report, {
|
|
@@ -970,29 +1080,25 @@ async function runWitanCli(args, rubricVersion) {
|
|
|
970
1080
|
generatedAt,
|
|
971
1081
|
...options.runAttempt ? { githubRunAttempt: options.runAttempt } : {}
|
|
972
1082
|
});
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
JSON.stringify(renderWitanBadgeEndpoint(report), null, 2),
|
|
992
|
-
"utf8"
|
|
1083
|
+
writeOutputFiles(
|
|
1084
|
+
options.outDir,
|
|
1085
|
+
[
|
|
1086
|
+
{ name: "report.json", contents: serializeWitanReport(report) },
|
|
1087
|
+
{ name: "attestation.json", contents: JSON.stringify(attestation, null, 2) },
|
|
1088
|
+
{
|
|
1089
|
+
name: "certificate.html",
|
|
1090
|
+
contents: renderWitanHtmlReport(report, {
|
|
1091
|
+
cliVersion: cliVersion(),
|
|
1092
|
+
generatedAt,
|
|
1093
|
+
...options.runAttempt ? { runAttempt: options.runAttempt } : {}
|
|
1094
|
+
})
|
|
1095
|
+
},
|
|
1096
|
+
{ name: "badge.json", contents: JSON.stringify(renderWitanBadgeEndpoint(report), null, 2) },
|
|
1097
|
+
{ name: "badge.svg", contents: renderWitanBadgeSvg(report) },
|
|
1098
|
+
{ name: "summary.json", contents: JSON.stringify(summary, null, 2) }
|
|
1099
|
+
],
|
|
1100
|
+
"scan output"
|
|
993
1101
|
);
|
|
994
|
-
writeFileSync(join(options.outDir, "badge.svg"), renderWitanBadgeSvg(report), "utf8");
|
|
995
|
-
writeFileSync(join(options.outDir, "summary.json"), JSON.stringify(summary, null, 2), "utf8");
|
|
996
1102
|
if (!options.quiet) {
|
|
997
1103
|
process.stdout.write(renderTerminalCertificate(summary, report));
|
|
998
1104
|
process.stdout.write(
|
|
@@ -1102,8 +1208,8 @@ function parseExportArgs(args) {
|
|
|
1102
1208
|
return {
|
|
1103
1209
|
command: "export",
|
|
1104
1210
|
format,
|
|
1105
|
-
reportPath:
|
|
1106
|
-
outPath:
|
|
1211
|
+
reportPath: resolve3(reportPath),
|
|
1212
|
+
outPath: resolve3(outPath)
|
|
1107
1213
|
};
|
|
1108
1214
|
}
|
|
1109
1215
|
function runExport(invocation) {
|
|
@@ -1121,24 +1227,36 @@ ${members.map((member) => ` - ${member}`).join("\n")}
|
|
|
1121
1227
|
return 1;
|
|
1122
1228
|
}
|
|
1123
1229
|
const result = exportGitLabCodeQuality(reportResult.data);
|
|
1124
|
-
|
|
1125
|
-
|
|
1230
|
+
writeOutputFile(
|
|
1231
|
+
invocation.outPath,
|
|
1232
|
+
`${JSON.stringify(result.entries, null, 2)}
|
|
1233
|
+
`,
|
|
1234
|
+
"export output"
|
|
1235
|
+
);
|
|
1126
1236
|
process.stderr.write(renderGitLabCodeQualityFooter(result));
|
|
1127
1237
|
return 0;
|
|
1128
1238
|
}
|
|
1129
|
-
var VERIFY_USAGE = () => `Usage: npx ${NPX_PACKAGE_NAME} verify <report.json> <attestation.json> [issuance.json issuance.json.sig] [--signers <file>] [--revocations <file>]`;
|
|
1239
|
+
var VERIFY_USAGE = () => `Usage: npx ${NPX_PACKAGE_NAME} verify <report.json> <attestation.json> [issuance.json issuance.json.sig] [--signers <file>] [--revocations <file>] [--input <file>...]`;
|
|
1130
1240
|
function parseVerifyArgs(args) {
|
|
1131
1241
|
const positionals = [];
|
|
1132
1242
|
let signersPath;
|
|
1133
1243
|
let revocationsPath;
|
|
1244
|
+
const inputPaths = [];
|
|
1134
1245
|
for (let index = 0; index < args.length; index += 1) {
|
|
1135
1246
|
const arg = args[index];
|
|
1136
1247
|
if (arg === void 0) continue;
|
|
1248
|
+
if (arg === "--input") {
|
|
1249
|
+
const value = args[index + 1];
|
|
1250
|
+
if (!value) throw new Error(`Missing value for ${arg}`);
|
|
1251
|
+
inputPaths.push(resolve3(value));
|
|
1252
|
+
index += 1;
|
|
1253
|
+
continue;
|
|
1254
|
+
}
|
|
1137
1255
|
if (arg === "--signers" || arg === "--revocations") {
|
|
1138
1256
|
const value = args[index + 1];
|
|
1139
1257
|
if (!value) throw new Error(`Missing value for ${arg}`);
|
|
1140
|
-
if (arg === "--signers") signersPath =
|
|
1141
|
-
else revocationsPath =
|
|
1258
|
+
if (arg === "--signers") signersPath = resolve3(value);
|
|
1259
|
+
else revocationsPath = resolve3(value);
|
|
1142
1260
|
index += 1;
|
|
1143
1261
|
continue;
|
|
1144
1262
|
}
|
|
@@ -1150,12 +1268,13 @@ function parseVerifyArgs(args) {
|
|
|
1150
1268
|
if (!reportPath || !attestationPath) throw new Error(VERIFY_USAGE());
|
|
1151
1269
|
return {
|
|
1152
1270
|
command: "verify",
|
|
1153
|
-
reportPath:
|
|
1154
|
-
attestationPath:
|
|
1155
|
-
...issuancePath ? { issuancePath:
|
|
1156
|
-
...issuanceSignaturePath ? { issuanceSignaturePath:
|
|
1271
|
+
reportPath: resolve3(reportPath),
|
|
1272
|
+
attestationPath: resolve3(attestationPath),
|
|
1273
|
+
...issuancePath ? { issuancePath: resolve3(issuancePath) } : {},
|
|
1274
|
+
...issuanceSignaturePath ? { issuanceSignaturePath: resolve3(issuanceSignaturePath) } : {},
|
|
1157
1275
|
...signersPath ? { signersPath } : {},
|
|
1158
|
-
...revocationsPath ? { revocationsPath } : {}
|
|
1276
|
+
...revocationsPath ? { revocationsPath } : {},
|
|
1277
|
+
...inputPaths.length > 0 ? { inputPaths } : {}
|
|
1159
1278
|
};
|
|
1160
1279
|
}
|
|
1161
1280
|
function parseIssueArgs(args) {
|
|
@@ -1179,15 +1298,15 @@ function parseIssueArgs(args) {
|
|
|
1179
1298
|
if (arg === void 0) continue;
|
|
1180
1299
|
switch (arg) {
|
|
1181
1300
|
case "--report":
|
|
1182
|
-
reportPath =
|
|
1301
|
+
reportPath = resolve3(takeValue(arg, index + 1));
|
|
1183
1302
|
index += 1;
|
|
1184
1303
|
continue;
|
|
1185
1304
|
case "--attestation":
|
|
1186
|
-
attestationPath =
|
|
1305
|
+
attestationPath = resolve3(takeValue(arg, index + 1));
|
|
1187
1306
|
index += 1;
|
|
1188
1307
|
continue;
|
|
1189
1308
|
case "--key":
|
|
1190
|
-
keyPath =
|
|
1309
|
+
keyPath = resolve3(takeValue(arg, index + 1));
|
|
1191
1310
|
index += 1;
|
|
1192
1311
|
continue;
|
|
1193
1312
|
case "--engagement-ref":
|
|
@@ -1196,7 +1315,7 @@ function parseIssueArgs(args) {
|
|
|
1196
1315
|
continue;
|
|
1197
1316
|
case "--out":
|
|
1198
1317
|
case "--out-dir":
|
|
1199
|
-
outDir =
|
|
1318
|
+
outDir = resolve3(takeValue(arg, index + 1));
|
|
1200
1319
|
index += 1;
|
|
1201
1320
|
continue;
|
|
1202
1321
|
case "--product-name":
|
|
@@ -1240,7 +1359,7 @@ function parseIssueArgs(args) {
|
|
|
1240
1359
|
throw new Error("--product-name and --name cannot be used together");
|
|
1241
1360
|
}
|
|
1242
1361
|
return {
|
|
1243
|
-
repoPath:
|
|
1362
|
+
repoPath: resolve3(repoPath ?? "."),
|
|
1244
1363
|
reportPath,
|
|
1245
1364
|
attestationPath,
|
|
1246
1365
|
keyPath,
|
|
@@ -1280,6 +1399,26 @@ ${result.errors.map((error) => ` - ${error}`).join("\n")}
|
|
|
1280
1399
|
return 1;
|
|
1281
1400
|
}
|
|
1282
1401
|
process.stdout.write("Cejel: report/attestation binding verified.\n");
|
|
1402
|
+
if (invocation.inputPaths) {
|
|
1403
|
+
let inputCheck;
|
|
1404
|
+
try {
|
|
1405
|
+
inputCheck = verifyRecordedInputDigests(
|
|
1406
|
+
reportResult.data,
|
|
1407
|
+
invocation.inputPaths,
|
|
1408
|
+
(path) => readFileSync(resolveIngestFilePath(path))
|
|
1409
|
+
);
|
|
1410
|
+
} catch (error) {
|
|
1411
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1412
|
+
process.stderr.write(
|
|
1413
|
+
`Cejel: input digests not verified \u2014 ${stripTerminalControls(message.replace(/^Cejel: /, ""))}
|
|
1414
|
+
`
|
|
1415
|
+
);
|
|
1416
|
+
return 1;
|
|
1417
|
+
}
|
|
1418
|
+
for (const line of inputCheck.lines) process.stdout.write(`${stripTerminalControls(line)}
|
|
1419
|
+
`);
|
|
1420
|
+
if (!inputCheck.valid) return 1;
|
|
1421
|
+
}
|
|
1283
1422
|
if (!invocation.issuancePath || !invocation.issuanceSignaturePath) {
|
|
1284
1423
|
process.stdout.write("Cejel: signature and signer identity were not verified.\n");
|
|
1285
1424
|
return 0;
|
|
@@ -1410,6 +1549,7 @@ ${attestationBinding.errors.map((error) => ` - ${error}`).join("\n")}
|
|
|
1410
1549
|
throw new Error(`Cejel: could not read --key file ${options.keyPath}: ${message}`);
|
|
1411
1550
|
}
|
|
1412
1551
|
const issuerKey = parseIssuerPublicKey(keyContents);
|
|
1552
|
+
refuseSymlinkedOutputs(options.outDir, [ISSUANCE_OUTPUT_FILE], "issuance output");
|
|
1413
1553
|
const reproduction = runCejelScan({
|
|
1414
1554
|
repoPath: options.repoPath,
|
|
1415
1555
|
...options.productName ? { productName: options.productName } : {},
|
|
@@ -1417,6 +1557,12 @@ ${attestationBinding.errors.map((error) => ` - ${error}`).join("\n")}
|
|
|
1417
1557
|
...options.rubricPin ? { rubricVersion: options.rubricPin } : {},
|
|
1418
1558
|
ingestPatterns: options.ingestPatterns,
|
|
1419
1559
|
warnOnEmptyIngestMatch: true,
|
|
1560
|
+
// The binding policy and the named subject repository are part of the invocation the report
|
|
1561
|
+
// records, so the reproduction reads them from the report it is reproducing rather than from
|
|
1562
|
+
// flags an issuer could forget. Anything else a report states differently fails the byte
|
|
1563
|
+
// comparison below, as it always has.
|
|
1564
|
+
...suppliedReport.inputBinding?.policy === "strict" ? { strictIngest: true } : {},
|
|
1565
|
+
...suppliedReport.inputBinding?.scannedSubject.repository ? { subjectRepository: suppliedReport.inputBinding.scannedSubject.repository } : {},
|
|
1420
1566
|
toolVersion: cliVersion()
|
|
1421
1567
|
});
|
|
1422
1568
|
const reproducedBytes = serializeWitanReport(reproduction.report);
|
|
@@ -1444,9 +1590,12 @@ ${attestationBinding.errors.map((error) => ` - ${error}`).join("\n")}
|
|
|
1444
1590
|
issuedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1445
1591
|
engagementRef: options.engagementRef
|
|
1446
1592
|
});
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1593
|
+
const issuancePath = join2(options.outDir, ISSUANCE_OUTPUT_FILE);
|
|
1594
|
+
writeOutputFiles(
|
|
1595
|
+
options.outDir,
|
|
1596
|
+
[{ name: ISSUANCE_OUTPUT_FILE, contents: serializeWitanIssuance(statement) }],
|
|
1597
|
+
"issuance output"
|
|
1598
|
+
);
|
|
1450
1599
|
process.stdout.write(
|
|
1451
1600
|
[
|
|
1452
1601
|
`Cejel: reproduced report.json byte for byte (sha256:${reportSha256}).`,
|
|
@@ -1492,6 +1641,8 @@ function parseArgs(args) {
|
|
|
1492
1641
|
let showVersion = false;
|
|
1493
1642
|
let rubricPin;
|
|
1494
1643
|
let runAttempt;
|
|
1644
|
+
let strictIngest = false;
|
|
1645
|
+
let subjectRepository;
|
|
1495
1646
|
const ingestPatterns = [];
|
|
1496
1647
|
for (let index = 0; index < args.length; index += 1) {
|
|
1497
1648
|
const arg = args[index];
|
|
@@ -1570,6 +1721,16 @@ function parseArgs(args) {
|
|
|
1570
1721
|
index += 1;
|
|
1571
1722
|
break;
|
|
1572
1723
|
}
|
|
1724
|
+
case "strictIngest":
|
|
1725
|
+
strictIngest = true;
|
|
1726
|
+
break;
|
|
1727
|
+
case "subjectRepository": {
|
|
1728
|
+
const value = args[index + 1];
|
|
1729
|
+
if (!value) throw new Error("Missing value for --subject-repository");
|
|
1730
|
+
subjectRepository = value;
|
|
1731
|
+
index += 1;
|
|
1732
|
+
break;
|
|
1733
|
+
}
|
|
1573
1734
|
case "runAttempt": {
|
|
1574
1735
|
const value = args[index + 1];
|
|
1575
1736
|
if (!value) throw new Error("Missing value for --run-attempt");
|
|
@@ -1593,7 +1754,7 @@ function parseArgs(args) {
|
|
|
1593
1754
|
throw new Error("--product-name and --name cannot be used together");
|
|
1594
1755
|
}
|
|
1595
1756
|
return {
|
|
1596
|
-
repoPath:
|
|
1757
|
+
repoPath: resolve3(repoPath ?? "."),
|
|
1597
1758
|
outDir,
|
|
1598
1759
|
...minScore != null ? { minScore } : {},
|
|
1599
1760
|
...productName ? { productName } : {},
|
|
@@ -1602,6 +1763,8 @@ function parseArgs(args) {
|
|
|
1602
1763
|
showHelp,
|
|
1603
1764
|
showVersion,
|
|
1604
1765
|
ingestPatterns,
|
|
1766
|
+
...strictIngest ? { strictIngest } : {},
|
|
1767
|
+
...subjectRepository ? { subjectRepository } : {},
|
|
1605
1768
|
...rubricPin ? { rubricPin } : {},
|
|
1606
1769
|
...runAttempt ? { runAttempt } : {}
|
|
1607
1770
|
};
|
package/dist/mcp/index.js
CHANGED
|
@@ -3,13 +3,13 @@ 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-
|
|
9
|
-
import "../chunk-
|
|
6
|
+
} from "../chunk-KNTBED5T.js";
|
|
7
|
+
import "../chunk-KJVFCZZ3.js";
|
|
8
|
+
import "../chunk-NIWSYJ6N.js";
|
|
9
|
+
import "../chunk-AMVP7L26.js";
|
|
10
10
|
import {
|
|
11
11
|
init_esm_shims
|
|
12
|
-
} from "../chunk-
|
|
12
|
+
} from "../chunk-AWLKQUI4.js";
|
|
13
13
|
|
|
14
14
|
// src/mcp/index.ts
|
|
15
15
|
init_esm_shims();
|
|
@@ -3,18 +3,18 @@ import { createRequire as __cejelCreateRequire } from 'node:module';
|
|
|
3
3
|
const require = __cejelCreateRequire(import.meta.url);
|
|
4
4
|
import {
|
|
5
5
|
listCejelLlmPackFiles
|
|
6
|
-
} from "../../chunk-
|
|
6
|
+
} from "../../chunk-WXPGEQBE.js";
|
|
7
7
|
import {
|
|
8
8
|
execGit
|
|
9
|
-
} from "../../chunk-
|
|
9
|
+
} from "../../chunk-NIWSYJ6N.js";
|
|
10
10
|
import {
|
|
11
11
|
require_typescript
|
|
12
|
-
} from "../../chunk-
|
|
12
|
+
} from "../../chunk-6LVNNJTG.js";
|
|
13
13
|
import {
|
|
14
14
|
__toESM,
|
|
15
15
|
init_esm_shims,
|
|
16
16
|
readRepoText
|
|
17
|
-
} from "../../chunk-
|
|
17
|
+
} from "../../chunk-AWLKQUI4.js";
|
|
18
18
|
|
|
19
19
|
// src/packs/d-series/index.ts
|
|
20
20
|
init_esm_shims();
|
|
@@ -3,15 +3,15 @@ import { createRequire as __cejelCreateRequire } from 'node:module';
|
|
|
3
3
|
const require = __cejelCreateRequire(import.meta.url);
|
|
4
4
|
import {
|
|
5
5
|
external_exports
|
|
6
|
-
} from "../../chunk-
|
|
6
|
+
} from "../../chunk-AMVP7L26.js";
|
|
7
7
|
import {
|
|
8
8
|
require_typescript
|
|
9
|
-
} from "../../chunk-
|
|
9
|
+
} from "../../chunk-6LVNNJTG.js";
|
|
10
10
|
import {
|
|
11
11
|
__toESM,
|
|
12
12
|
init_esm_shims,
|
|
13
13
|
readRepoText
|
|
14
|
-
} from "../../chunk-
|
|
14
|
+
} from "../../chunk-AWLKQUI4.js";
|
|
15
15
|
|
|
16
16
|
// src/packs/decision-contracts/index.ts
|
|
17
17
|
init_esm_shims();
|