@cejel/cejel 0.6.7 → 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.
@@ -5,19 +5,19 @@ import {
5
5
  renderWitanBadgeSvg,
6
6
  renderWitanHtmlReport,
7
7
  runCejelScan
8
- } from "./chunk-ZZHQZW26.js";
8
+ } from "./chunk-KJVFCZZ3.js";
9
9
  import {
10
10
  ZodFirstPartyTypeKind,
11
11
  ZodOptional,
12
12
  external_exports,
13
13
  objectType
14
- } from "./chunk-FSMZV3Y6.js";
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-O3MHSK25.js";
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({
@@ -3,7 +3,7 @@ import { createRequire as __cejelCreateRequire } from 'node:module';
3
3
  const require = __cejelCreateRequire(import.meta.url);
4
4
  import {
5
5
  init_esm_shims
6
- } from "./chunk-O3MHSK25.js";
6
+ } from "./chunk-AWLKQUI4.js";
7
7
 
8
8
  // src/witan/git-exec.ts
9
9
  init_esm_shims();
@@ -5,10 +5,10 @@ import {
5
5
  describeGitFailure,
6
6
  execGit,
7
7
  isExpectedGitAbsence
8
- } from "./chunk-VGBFZBZQ.js";
8
+ } from "./chunk-NIWSYJ6N.js";
9
9
  import {
10
10
  init_esm_shims
11
- } from "./chunk-O3MHSK25.js";
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-TOQPQPDF.js";
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,21 +25,27 @@ 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-ZZHQZW26.js";
33
- import "./chunk-VGBFZBZQ.js";
41
+ } from "./chunk-KJVFCZZ3.js";
42
+ import "./chunk-NIWSYJ6N.js";
34
43
  import {
35
44
  external_exports
36
- } from "./chunk-FSMZV3Y6.js";
45
+ } from "./chunk-AMVP7L26.js";
37
46
  import {
38
47
  init_esm_shims
39
- } from "./chunk-O3MHSK25.js";
48
+ } from "./chunk-AWLKQUI4.js";
40
49
 
41
50
  // src/index.ts
42
51
  init_esm_shims();
@@ -663,9 +672,6 @@ function renderMinScoreCoverageFailure(coverage, minScore) {
663
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.
664
673
  `;
665
674
  }
666
- function stripTerminalControls(text) {
667
- return text.replace(/[\t\n]/g, " ").replace(/[\u0000-\u001f\u007f-\u009f]/g, "");
668
- }
669
675
  function renderTerminalCertificate(summary, report) {
670
676
  const abstained = summary.verdict === "Insufficient source" || summary.verdict === "Insufficient evidence";
671
677
  if (!abstained && (summary.overallScore === null || summary.codeTrustScore === null || summary.processTrustScore === null)) {
@@ -696,7 +702,7 @@ function renderTerminalCertificate(summary, report) {
696
702
  `Scope: ${relyingPartySummary.scope}`,
697
703
  `What was examined: ${stripTerminalControls(relyingPartySummary.examined)}`,
698
704
  `What was established: ${relyingPartySummary.established}`,
699
- `What was not established: ${relyingPartySummary.notEstablished}`,
705
+ `What was not established: ${stripTerminalControls(relyingPartySummary.notEstablished)}`,
700
706
  `What to do next: ${relyingPartySummary.next}`,
701
707
  ""
702
708
  );
@@ -719,7 +725,7 @@ function renderTerminalCertificate(summary, report) {
719
725
  const reads = summary.contentReadSummary;
720
726
  const errnoCounts = Object.entries(reads.unreadableByErrno).map(([errno, count]) => `${errno}: ${count}`).join(", ");
721
727
  lines.push(
722
- `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}` : ""}).`
723
729
  );
724
730
  if (reads.affectedCriteria.length > 0) {
725
731
  lines.push(
@@ -737,6 +743,20 @@ function renderTerminalCertificate(summary, report) {
737
743
  }
738
744
  lines.push("");
739
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
+ }
740
760
  const measurements = report?.criteria.flatMap(
741
761
  (criterion) => criterion.metrics.map((metric) => ({
742
762
  criterionId: criterion.id,
@@ -749,7 +769,7 @@ function renderTerminalCertificate(summary, report) {
749
769
  lines.push("Measurements:");
750
770
  for (const measurement of measurements ?? []) {
751
771
  lines.push(
752
- ` ${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})`
753
773
  );
754
774
  }
755
775
  lines.push("");
@@ -783,6 +803,8 @@ function renderTerminalCertificate(summary, report) {
783
803
  lines.push(
784
804
  ` [${finding.severity}] ${stripTerminalControls(finding.label)} \u2192 ${finding.dimension}: ${stripTerminalControls(finding.ruleId)} \u2014 ${stripTerminalControls(finding.message)}${finding.location ? ` (${stripTerminalControls(finding.location)})` : ""}`
785
805
  );
806
+ const note = inheritedFindingNote(finding.ruleId);
807
+ if (note) lines.push(` Note: ${note}`);
786
808
  }
787
809
  const remaining = summary.externalFindingCount - summary.topExternalFindings.length;
788
810
  if (remaining > 0) {
@@ -861,6 +883,17 @@ var CLI_FLAG_SPECS = [
861
883
  description: "fold in a SARIF/JSON scanner report (repeatable)",
862
884
  kind: "ingest"
863
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
+ },
864
897
  {
865
898
  tokens: ["--rubric-pin"],
866
899
  value: "<version>",
@@ -953,6 +986,8 @@ ${usageOptions}
953
986
  Verify options:
954
987
  --signers <file> use this allowed-signers file instead of the published one
955
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
956
991
 
957
992
  Issue options:
958
993
  --report <file> the report.json being countersigned (required)
@@ -964,6 +999,7 @@ Issue options:
964
999
  --name <display> pass exactly what the original scan used, or the bytes will not reproduce
965
1000
  --rubric-pin <version> pass exactly what the original scan used, or the bytes will not reproduce
966
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)
967
1003
 
968
1004
  cejel never signs and never reads private key material.
969
1005
 
@@ -1035,6 +1071,8 @@ async function runWitanCli(args, rubricVersion) {
1035
1071
  ...effectiveRubricVersion ? { rubricVersion: effectiveRubricVersion } : {},
1036
1072
  ingestPatterns: options.ingestPatterns,
1037
1073
  warnOnEmptyIngestMatch: !options.quiet,
1074
+ ...options.strictIngest ? { strictIngest: true } : {},
1075
+ ...options.subjectRepository ? { subjectRepository: options.subjectRepository } : {},
1038
1076
  toolVersion: cliVersion()
1039
1077
  });
1040
1078
  const attestation = createWitanAttestation(report, {
@@ -1198,14 +1236,22 @@ ${members.map((member) => ` - ${member}`).join("\n")}
1198
1236
  process.stderr.write(renderGitLabCodeQualityFooter(result));
1199
1237
  return 0;
1200
1238
  }
1201
- 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>...]`;
1202
1240
  function parseVerifyArgs(args) {
1203
1241
  const positionals = [];
1204
1242
  let signersPath;
1205
1243
  let revocationsPath;
1244
+ const inputPaths = [];
1206
1245
  for (let index = 0; index < args.length; index += 1) {
1207
1246
  const arg = args[index];
1208
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
+ }
1209
1255
  if (arg === "--signers" || arg === "--revocations") {
1210
1256
  const value = args[index + 1];
1211
1257
  if (!value) throw new Error(`Missing value for ${arg}`);
@@ -1227,7 +1273,8 @@ function parseVerifyArgs(args) {
1227
1273
  ...issuancePath ? { issuancePath: resolve3(issuancePath) } : {},
1228
1274
  ...issuanceSignaturePath ? { issuanceSignaturePath: resolve3(issuanceSignaturePath) } : {},
1229
1275
  ...signersPath ? { signersPath } : {},
1230
- ...revocationsPath ? { revocationsPath } : {}
1276
+ ...revocationsPath ? { revocationsPath } : {},
1277
+ ...inputPaths.length > 0 ? { inputPaths } : {}
1231
1278
  };
1232
1279
  }
1233
1280
  function parseIssueArgs(args) {
@@ -1352,6 +1399,26 @@ ${result.errors.map((error) => ` - ${error}`).join("\n")}
1352
1399
  return 1;
1353
1400
  }
1354
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
+ }
1355
1422
  if (!invocation.issuancePath || !invocation.issuanceSignaturePath) {
1356
1423
  process.stdout.write("Cejel: signature and signer identity were not verified.\n");
1357
1424
  return 0;
@@ -1490,6 +1557,12 @@ ${attestationBinding.errors.map((error) => ` - ${error}`).join("\n")}
1490
1557
  ...options.rubricPin ? { rubricVersion: options.rubricPin } : {},
1491
1558
  ingestPatterns: options.ingestPatterns,
1492
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 } : {},
1493
1566
  toolVersion: cliVersion()
1494
1567
  });
1495
1568
  const reproducedBytes = serializeWitanReport(reproduction.report);
@@ -1568,6 +1641,8 @@ function parseArgs(args) {
1568
1641
  let showVersion = false;
1569
1642
  let rubricPin;
1570
1643
  let runAttempt;
1644
+ let strictIngest = false;
1645
+ let subjectRepository;
1571
1646
  const ingestPatterns = [];
1572
1647
  for (let index = 0; index < args.length; index += 1) {
1573
1648
  const arg = args[index];
@@ -1646,6 +1721,16 @@ function parseArgs(args) {
1646
1721
  index += 1;
1647
1722
  break;
1648
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
+ }
1649
1734
  case "runAttempt": {
1650
1735
  const value = args[index + 1];
1651
1736
  if (!value) throw new Error("Missing value for --run-attempt");
@@ -1678,6 +1763,8 @@ function parseArgs(args) {
1678
1763
  showHelp,
1679
1764
  showVersion,
1680
1765
  ingestPatterns,
1766
+ ...strictIngest ? { strictIngest } : {},
1767
+ ...subjectRepository ? { subjectRepository } : {},
1681
1768
  ...rubricPin ? { rubricPin } : {},
1682
1769
  ...runAttempt ? { runAttempt } : {}
1683
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-TOQPQPDF.js";
7
- import "../chunk-ZZHQZW26.js";
8
- import "../chunk-VGBFZBZQ.js";
9
- import "../chunk-FSMZV3Y6.js";
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-O3MHSK25.js";
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-5PFYOIOS.js";
6
+ } from "../../chunk-WXPGEQBE.js";
7
7
  import {
8
8
  execGit
9
- } from "../../chunk-VGBFZBZQ.js";
9
+ } from "../../chunk-NIWSYJ6N.js";
10
10
  import {
11
11
  require_typescript
12
- } from "../../chunk-RH6FKREX.js";
12
+ } from "../../chunk-6LVNNJTG.js";
13
13
  import {
14
14
  __toESM,
15
15
  init_esm_shims,
16
16
  readRepoText
17
- } from "../../chunk-O3MHSK25.js";
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-FSMZV3Y6.js";
6
+ } from "../../chunk-AMVP7L26.js";
7
7
  import {
8
8
  require_typescript
9
- } from "../../chunk-RH6FKREX.js";
9
+ } from "../../chunk-6LVNNJTG.js";
10
10
  import {
11
11
  __toESM,
12
12
  init_esm_shims,
13
13
  readRepoText
14
- } from "../../chunk-O3MHSK25.js";
14
+ } from "../../chunk-AWLKQUI4.js";
15
15
 
16
16
  // src/packs/decision-contracts/index.ts
17
17
  init_esm_shims();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cejel/cejel",
3
- "version": "0.6.7",
3
+ "version": "0.6.8",
4
4
  "mcpName": "io.github.BargLabs/cejel",
5
5
  "private": false,
6
6
  "publishConfig": {