@cejel/cejel 0.1.1 → 0.1.3
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 +147 -79
- package/dist/{chunk-H5T65GGS.js → chunk-QQVCIG4N.js} +2803 -1208
- package/dist/index.js +124 -30
- package/dist/mcp/index.js +222 -218
- package/package.json +10 -9
|
@@ -29,7 +29,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
29
29
|
mod
|
|
30
30
|
));
|
|
31
31
|
|
|
32
|
-
// src/
|
|
32
|
+
// ../witan/src/external-findings.ts
|
|
33
33
|
var EXTERNAL_FINDINGS_DISPLAY_LIMIT = 10;
|
|
34
34
|
var SEVERITY_RANK = {
|
|
35
35
|
critical: 0,
|
|
@@ -82,7 +82,7 @@ function collectExternalFindings(consumedSignals) {
|
|
|
82
82
|
});
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
// src/
|
|
85
|
+
// ../witan/src/html.ts
|
|
86
86
|
function renderWitanHtmlReport(report) {
|
|
87
87
|
const codeCriteria = criteriaByCategory(report, "code_trust");
|
|
88
88
|
const processCriteria = criteriaByCategory(report, "process_trust");
|
|
@@ -403,7 +403,7 @@ a:hover { text-decoration: underline; text-underline-offset: 2px; }
|
|
|
403
403
|
}
|
|
404
404
|
`;
|
|
405
405
|
|
|
406
|
-
// src/
|
|
406
|
+
// ../witan/src/badge.ts
|
|
407
407
|
var VERDICT_COLOR = {
|
|
408
408
|
Verified: "brightgreen",
|
|
409
409
|
Conditional: "yellow",
|
|
@@ -470,7 +470,15 @@ function escapeXml(value) {
|
|
|
470
470
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
471
471
|
}
|
|
472
472
|
|
|
473
|
-
//
|
|
473
|
+
// ../witan/src/claim-reality.ts
|
|
474
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "fs";
|
|
475
|
+
import { join } from "path";
|
|
476
|
+
|
|
477
|
+
// ../witan/src/leaderboard.ts
|
|
478
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync8, writeFileSync as writeFileSync2 } from "fs";
|
|
479
|
+
import { join as join6 } from "path";
|
|
480
|
+
|
|
481
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
|
|
474
482
|
var external_exports = {};
|
|
475
483
|
__export(external_exports, {
|
|
476
484
|
BRAND: () => BRAND,
|
|
@@ -582,7 +590,7 @@ __export(external_exports, {
|
|
|
582
590
|
void: () => voidType
|
|
583
591
|
});
|
|
584
592
|
|
|
585
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js
|
|
593
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js
|
|
586
594
|
var util;
|
|
587
595
|
(function(util2) {
|
|
588
596
|
util2.assertEqual = (_) => {
|
|
@@ -716,7 +724,7 @@ var getParsedType = (data) => {
|
|
|
716
724
|
}
|
|
717
725
|
};
|
|
718
726
|
|
|
719
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js
|
|
727
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js
|
|
720
728
|
var ZodIssueCode = util.arrayToEnum([
|
|
721
729
|
"invalid_type",
|
|
722
730
|
"invalid_literal",
|
|
@@ -834,7 +842,7 @@ ZodError.create = (issues) => {
|
|
|
834
842
|
return error;
|
|
835
843
|
};
|
|
836
844
|
|
|
837
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js
|
|
845
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js
|
|
838
846
|
var errorMap = (issue, _ctx) => {
|
|
839
847
|
let message;
|
|
840
848
|
switch (issue.code) {
|
|
@@ -937,7 +945,7 @@ var errorMap = (issue, _ctx) => {
|
|
|
937
945
|
};
|
|
938
946
|
var en_default = errorMap;
|
|
939
947
|
|
|
940
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js
|
|
948
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js
|
|
941
949
|
var overrideErrorMap = en_default;
|
|
942
950
|
function setErrorMap(map) {
|
|
943
951
|
overrideErrorMap = map;
|
|
@@ -946,7 +954,7 @@ function getErrorMap() {
|
|
|
946
954
|
return overrideErrorMap;
|
|
947
955
|
}
|
|
948
956
|
|
|
949
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
957
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
950
958
|
var makeIssue = (params) => {
|
|
951
959
|
const { data, path, errorMaps, issueData } = params;
|
|
952
960
|
const fullPath = [...path, ...issueData.path || []];
|
|
@@ -1056,14 +1064,14 @@ var isDirty = (x) => x.status === "dirty";
|
|
|
1056
1064
|
var isValid = (x) => x.status === "valid";
|
|
1057
1065
|
var isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
|
|
1058
1066
|
|
|
1059
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
|
|
1067
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/errorUtil.js
|
|
1060
1068
|
var errorUtil;
|
|
1061
1069
|
(function(errorUtil2) {
|
|
1062
1070
|
errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
|
|
1063
1071
|
errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
|
|
1064
1072
|
})(errorUtil || (errorUtil = {}));
|
|
1065
1073
|
|
|
1066
|
-
// node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
1074
|
+
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
1067
1075
|
var ParseInputLazyPath = class {
|
|
1068
1076
|
constructor(parent, value, path, key) {
|
|
1069
1077
|
this._cachedPath = [];
|
|
@@ -4511,10 +4519,853 @@ var coerce = {
|
|
|
4511
4519
|
};
|
|
4512
4520
|
var NEVER = INVALID;
|
|
4513
4521
|
|
|
4514
|
-
// src/
|
|
4522
|
+
// ../shared/src/types/attestation.ts
|
|
4523
|
+
var attestationOutcomeSchema = external_exports.enum([
|
|
4524
|
+
"ATTESTED_READY",
|
|
4525
|
+
"ATTESTED_WITH_GAPS",
|
|
4526
|
+
"NOT_READY",
|
|
4527
|
+
"REVOKED"
|
|
4528
|
+
]);
|
|
4529
|
+
var attestationKindSchema = external_exports.enum(["OPERATOR_READINESS", "EXTERNAL_ASSESSOR_REFERENCE"]);
|
|
4530
|
+
var attestationEvidenceRefKindSchema = external_exports.enum([
|
|
4531
|
+
"runbook_path",
|
|
4532
|
+
"github_run_url",
|
|
4533
|
+
"vercel_deployment_id",
|
|
4534
|
+
"neon_query_evidence",
|
|
4535
|
+
"report_hash",
|
|
4536
|
+
"external_assessor_ref"
|
|
4537
|
+
]);
|
|
4538
|
+
var attestationEvidenceRefSchema = external_exports.object({
|
|
4539
|
+
kind: attestationEvidenceRefKindSchema,
|
|
4540
|
+
/** Redacted reference string (path, URL, ID, or hash). Max 512 chars. */
|
|
4541
|
+
ref: external_exports.string().min(1).max(512),
|
|
4542
|
+
/** Optional one-line redacted description. */
|
|
4543
|
+
note: external_exports.string().max(280).optional()
|
|
4544
|
+
});
|
|
4545
|
+
var createAttestationInputSchema = external_exports.object({
|
|
4546
|
+
studioId: external_exports.string().uuid(),
|
|
4547
|
+
complianceProfileId: external_exports.string().uuid(),
|
|
4548
|
+
productId: external_exports.string().uuid().nullable().optional(),
|
|
4549
|
+
framework: external_exports.string().min(1).max(120),
|
|
4550
|
+
kind: attestationKindSchema,
|
|
4551
|
+
outcome: attestationOutcomeSchema,
|
|
4552
|
+
/** Redacted operator statement; no payloads. */
|
|
4553
|
+
statement: external_exports.string().min(1).max(4e3),
|
|
4554
|
+
evidenceRefs: external_exports.array(attestationEvidenceRefSchema).min(1),
|
|
4555
|
+
supersedesAttestationId: external_exports.string().uuid().nullable().optional(),
|
|
4556
|
+
metadata: external_exports.record(external_exports.unknown()).default({})
|
|
4557
|
+
});
|
|
4558
|
+
|
|
4559
|
+
// ../shared/src/types/standup-provisioning.ts
|
|
4560
|
+
var ScaffoldFileSchema = external_exports.object({
|
|
4561
|
+
path: external_exports.string().min(1),
|
|
4562
|
+
contents: external_exports.string()
|
|
4563
|
+
}).strict();
|
|
4564
|
+
var ScaffoldManifestSchema = external_exports.array(ScaffoldFileSchema).min(1);
|
|
4565
|
+
var RepoRefSchema = external_exports.object({
|
|
4566
|
+
studioId: external_exports.string().uuid(),
|
|
4567
|
+
owner: external_exports.string().min(1),
|
|
4568
|
+
// GitHub org/account that owns the repo
|
|
4569
|
+
name: external_exports.string().min(1),
|
|
4570
|
+
fullName: external_exports.string().min(1),
|
|
4571
|
+
// owner/name
|
|
4572
|
+
htmlUrl: external_exports.string().url(),
|
|
4573
|
+
defaultBranch: external_exports.string().min(1).default("main")
|
|
4574
|
+
}).strict();
|
|
4575
|
+
var ScopedTokenSchema = external_exports.object({
|
|
4576
|
+
token: external_exports.string().min(1),
|
|
4577
|
+
expiresAt: external_exports.string(),
|
|
4578
|
+
// ISO-8601
|
|
4579
|
+
scope: external_exports.string().min(1)
|
|
4580
|
+
// human-readable, e.g. "contents:write on owner/name"
|
|
4581
|
+
}).strict();
|
|
4582
|
+
var BranchProtectionStatusSchema = external_exports.object({
|
|
4583
|
+
protected: external_exports.boolean(),
|
|
4584
|
+
requiresPullRequestReview: external_exports.boolean(),
|
|
4585
|
+
requiredApprovingReviewCount: external_exports.number().int().nonnegative(),
|
|
4586
|
+
allowsForcePushes: external_exports.boolean(),
|
|
4587
|
+
allowsDeletions: external_exports.boolean()
|
|
4588
|
+
}).strict();
|
|
4589
|
+
var RenderParamsSchema = external_exports.object({
|
|
4590
|
+
productName: external_exports.string().min(1),
|
|
4591
|
+
slug: external_exports.string().min(1),
|
|
4592
|
+
vertical: external_exports.string().min(1)
|
|
4593
|
+
}).strict();
|
|
4594
|
+
var TemplateInputFieldSchema = external_exports.object({
|
|
4595
|
+
name: external_exports.string().min(1),
|
|
4596
|
+
label: external_exports.string().min(1),
|
|
4597
|
+
inputType: external_exports.enum(["text", "number", "date", "slug"]),
|
|
4598
|
+
required: external_exports.boolean().default(true),
|
|
4599
|
+
helperText: external_exports.string().min(1),
|
|
4600
|
+
example: external_exports.string().min(1),
|
|
4601
|
+
defaultValue: external_exports.string().optional()
|
|
4602
|
+
}).strict();
|
|
4603
|
+
var TemplateInputSchema = external_exports.object({
|
|
4604
|
+
fields: external_exports.array(TemplateInputFieldSchema).min(1)
|
|
4605
|
+
}).strict();
|
|
4606
|
+
var TemplateDescriptorSchema = external_exports.object({
|
|
4607
|
+
templateRef: external_exports.string().min(1),
|
|
4608
|
+
vertical: external_exports.string().min(1),
|
|
4609
|
+
description: external_exports.string().default(""),
|
|
4610
|
+
inputSchema: TemplateInputSchema.optional()
|
|
4611
|
+
}).strict();
|
|
4612
|
+
var StandupDryRunPlanSchema = external_exports.object({
|
|
4613
|
+
planOnly: external_exports.literal(true),
|
|
4614
|
+
planOnlyMessage: external_exports.string().min(1),
|
|
4615
|
+
product: external_exports.object({
|
|
4616
|
+
studioId: external_exports.string().min(1),
|
|
4617
|
+
productId: external_exports.string().min(1),
|
|
4618
|
+
name: external_exports.string().min(1),
|
|
4619
|
+
slug: external_exports.string().min(1),
|
|
4620
|
+
vertical: external_exports.string().min(1)
|
|
4621
|
+
}).strict(),
|
|
4622
|
+
targetRepo: external_exports.object({
|
|
4623
|
+
owner: external_exports.string().min(1),
|
|
4624
|
+
name: external_exports.string().min(1),
|
|
4625
|
+
fullName: external_exports.string().min(1),
|
|
4626
|
+
defaultBranch: external_exports.string().min(1),
|
|
4627
|
+
plannedState: external_exports.literal("would_create"),
|
|
4628
|
+
exists: external_exports.literal(false)
|
|
4629
|
+
}).strict(),
|
|
4630
|
+
template: TemplateDescriptorSchema,
|
|
4631
|
+
scaffold: external_exports.object({
|
|
4632
|
+
label: external_exports.literal("scaffold (template output)"),
|
|
4633
|
+
files: ScaffoldManifestSchema
|
|
4634
|
+
}).strict(),
|
|
4635
|
+
buildAgentSeed: external_exports.object({
|
|
4636
|
+
label: external_exports.literal("build-agent instructions (not yet run)"),
|
|
4637
|
+
instructions: external_exports.array(external_exports.string().min(1)).min(1),
|
|
4638
|
+
product: external_exports.object({
|
|
4639
|
+
name: external_exports.string().min(1),
|
|
4640
|
+
slug: external_exports.string().min(1),
|
|
4641
|
+
vertical: external_exports.string().min(1)
|
|
4642
|
+
}).strict(),
|
|
4643
|
+
repoFullName: external_exports.string().min(1)
|
|
4644
|
+
}).strict(),
|
|
4645
|
+
safetyEnvelope: external_exports.object({
|
|
4646
|
+
estimatedCostUsd: external_exports.number().finite().nonnegative(),
|
|
4647
|
+
costCapUsd: external_exports.number().finite().nonnegative(),
|
|
4648
|
+
networkPolicy: external_exports.object({
|
|
4649
|
+
mode: external_exports.literal("restricted"),
|
|
4650
|
+
allowedHosts: external_exports.array(external_exports.string().min(1)).min(1)
|
|
4651
|
+
}).strict(),
|
|
4652
|
+
scopedToken: external_exports.object({
|
|
4653
|
+
tokenMinted: external_exports.literal(false),
|
|
4654
|
+
scope: external_exports.string().min(1),
|
|
4655
|
+
ttlSeconds: external_exports.number().int().positive()
|
|
4656
|
+
}).strict()
|
|
4657
|
+
}).strict()
|
|
4658
|
+
}).strict();
|
|
4659
|
+
var ConstructionWorkflowArtifactKindSchema = external_exports.enum([
|
|
4660
|
+
"profile",
|
|
4661
|
+
"milestone_schedule",
|
|
4662
|
+
"risk_register",
|
|
4663
|
+
"submittal_register",
|
|
4664
|
+
"long_lead_log",
|
|
4665
|
+
"rfi_log",
|
|
4666
|
+
"responsibility_matrix"
|
|
4667
|
+
]);
|
|
4668
|
+
var IsoDateSchema = external_exports.string().regex(/^\d{4}-\d{2}-\d{2}$/);
|
|
4669
|
+
var ConstructionWorkflowTemplateDescriptorSchema = external_exports.object({
|
|
4670
|
+
templateRef: external_exports.string().min(1),
|
|
4671
|
+
workflowKind: external_exports.literal("construction_project"),
|
|
4672
|
+
templateKind: external_exports.literal("workflow_documents"),
|
|
4673
|
+
name: external_exports.string().min(1),
|
|
4674
|
+
description: external_exports.string().default(""),
|
|
4675
|
+
artifacts: external_exports.array(ConstructionWorkflowArtifactKindSchema).min(1),
|
|
4676
|
+
inputSchema: TemplateInputSchema
|
|
4677
|
+
}).strict();
|
|
4678
|
+
var ConstructionProjectSeedSchema = external_exports.object({
|
|
4679
|
+
projectName: external_exports.string().min(1).max(120),
|
|
4680
|
+
areaSqFt: external_exports.number().int().positive(),
|
|
4681
|
+
projectType: external_exports.string().min(1).max(120),
|
|
4682
|
+
buildingName: external_exports.string().min(1).max(160),
|
|
4683
|
+
ntpDate: IsoDateSchema,
|
|
4684
|
+
scheduleTargetDate: IsoDateSchema
|
|
4685
|
+
}).strict();
|
|
4686
|
+
var ConstructionMilestoneSchema = external_exports.object({
|
|
4687
|
+
id: external_exports.string().min(1),
|
|
4688
|
+
name: external_exports.string().min(1),
|
|
4689
|
+
targetDate: IsoDateSchema,
|
|
4690
|
+
status: external_exports.enum(["planned", "at_risk", "slipped", "complete"])
|
|
4691
|
+
}).strict();
|
|
4692
|
+
var ConstructionSubmittalSchema = external_exports.object({
|
|
4693
|
+
id: external_exports.string().min(1),
|
|
4694
|
+
item: external_exports.string().min(1),
|
|
4695
|
+
division: external_exports.string().min(1),
|
|
4696
|
+
needByDate: IsoDateSchema,
|
|
4697
|
+
status: external_exports.enum(["not_started", "open", "in_review", "approved", "done"])
|
|
4698
|
+
}).strict();
|
|
4699
|
+
var ConstructionRfiSchema = external_exports.object({
|
|
4700
|
+
id: external_exports.string().min(1),
|
|
4701
|
+
subject: external_exports.string().min(1),
|
|
4702
|
+
to: external_exports.string().min(1),
|
|
4703
|
+
status: external_exports.enum(["draft", "open", "answered", "closed"]),
|
|
4704
|
+
openedDate: IsoDateSchema
|
|
4705
|
+
}).strict();
|
|
4706
|
+
var ConstructionRiskSchema = external_exports.object({
|
|
4707
|
+
id: external_exports.string().min(1),
|
|
4708
|
+
risk: external_exports.string().min(1),
|
|
4709
|
+
rating: external_exports.enum(["low", "medium", "high"]),
|
|
4710
|
+
mitigation: external_exports.string().min(1),
|
|
4711
|
+
confidence: external_exports.number().min(0).max(1)
|
|
4712
|
+
}).strict();
|
|
4713
|
+
var ConstructionLongLeadItemSchema = external_exports.object({
|
|
4714
|
+
id: external_exports.string().min(1),
|
|
4715
|
+
item: external_exports.string().min(1),
|
|
4716
|
+
needByDate: IsoDateSchema,
|
|
4717
|
+
status: external_exports.enum(["tracking", "ordered", "received", "done"]),
|
|
4718
|
+
assumption: external_exports.string().min(1)
|
|
4719
|
+
}).strict();
|
|
4720
|
+
var ConstructionResponsibilitySchema = external_exports.object({
|
|
4721
|
+
id: external_exports.string().min(1),
|
|
4722
|
+
role: external_exports.string().min(1),
|
|
4723
|
+
owner: external_exports.string().min(1),
|
|
4724
|
+
responsibility: external_exports.string().min(1)
|
|
4725
|
+
}).strict();
|
|
4726
|
+
var ConstructionMarkdownArtifactSchema = external_exports.object({
|
|
4727
|
+
kind: ConstructionWorkflowArtifactKindSchema,
|
|
4728
|
+
path: external_exports.string().min(1),
|
|
4729
|
+
markdown: external_exports.string().min(1)
|
|
4730
|
+
}).strict();
|
|
4731
|
+
var ConstructionWorkflowArtifactSetSchema = external_exports.object({
|
|
4732
|
+
projectName: external_exports.string().min(1),
|
|
4733
|
+
generatedAt: external_exports.string().datetime(),
|
|
4734
|
+
assumptions: external_exports.array(external_exports.string().min(1)).default([]),
|
|
4735
|
+
needsPmData: external_exports.array(external_exports.string().min(1)).default([]),
|
|
4736
|
+
markdownArtifacts: external_exports.array(ConstructionMarkdownArtifactSchema).min(1),
|
|
4737
|
+
structured: external_exports.object({
|
|
4738
|
+
milestones: external_exports.array(ConstructionMilestoneSchema),
|
|
4739
|
+
submittals: external_exports.array(ConstructionSubmittalSchema),
|
|
4740
|
+
rfis: external_exports.array(ConstructionRfiSchema),
|
|
4741
|
+
risks: external_exports.array(ConstructionRiskSchema),
|
|
4742
|
+
longLeadItems: external_exports.array(ConstructionLongLeadItemSchema),
|
|
4743
|
+
responsibilities: external_exports.array(ConstructionResponsibilitySchema)
|
|
4744
|
+
}).strict()
|
|
4745
|
+
}).strict();
|
|
4746
|
+
var ConstructionWorkflowDryRunPlanSchema = external_exports.object({
|
|
4747
|
+
planOnly: external_exports.literal(true),
|
|
4748
|
+
planOnlyMessage: external_exports.string().min(1),
|
|
4749
|
+
product: external_exports.object({
|
|
4750
|
+
studioId: external_exports.string().min(1),
|
|
4751
|
+
productId: external_exports.string().min(1),
|
|
4752
|
+
name: external_exports.string().min(1),
|
|
4753
|
+
vertical: external_exports.string().min(1)
|
|
4754
|
+
}).strict(),
|
|
4755
|
+
template: ConstructionWorkflowTemplateDescriptorSchema,
|
|
4756
|
+
seed: ConstructionProjectSeedSchema,
|
|
4757
|
+
safetyEnvelope: external_exports.object({
|
|
4758
|
+
executor: external_exports.literal("benign_workflow_populator"),
|
|
4759
|
+
sandboxUsed: external_exports.literal(false),
|
|
4760
|
+
scopedTokenMinted: external_exports.literal(false),
|
|
4761
|
+
externalWritesAllowed: external_exports.literal(false),
|
|
4762
|
+
workspaceWriteMode: external_exports.literal("markdown_only")
|
|
4763
|
+
}).strict()
|
|
4764
|
+
}).strict();
|
|
4765
|
+
|
|
4766
|
+
// ../shared/src/types/construction-log-excel.ts
|
|
4767
|
+
var CONSTRUCTION_LOG_EXCEL_SCHEMA_VERSION = "construction-log-excel-v1";
|
|
4768
|
+
var ConstructionLogExcelSheetKeySchema = external_exports.enum([
|
|
4769
|
+
"submittals",
|
|
4770
|
+
"rfis",
|
|
4771
|
+
"riskRegister",
|
|
4772
|
+
"longLead",
|
|
4773
|
+
"responsibilityMatrix",
|
|
4774
|
+
"milestones"
|
|
4775
|
+
]);
|
|
4776
|
+
var ConstructionLogExcelColumnSchema = external_exports.object({
|
|
4777
|
+
key: external_exports.string().min(1),
|
|
4778
|
+
header: external_exports.string().min(1),
|
|
4779
|
+
required: external_exports.boolean(),
|
|
4780
|
+
description: external_exports.string().min(1)
|
|
4781
|
+
}).strict().describe("Canonical column definition for Alfred construction log Excel round-trips.");
|
|
4782
|
+
var ConstructionLogExcelSheetSchema = external_exports.object({
|
|
4783
|
+
key: ConstructionLogExcelSheetKeySchema,
|
|
4784
|
+
sheetName: external_exports.string().min(1),
|
|
4785
|
+
description: external_exports.string().min(1),
|
|
4786
|
+
columns: external_exports.array(ConstructionLogExcelColumnSchema).min(1)
|
|
4787
|
+
}).strict().describe("Canonical worksheet definition for Alfred construction log Excel round-trips.");
|
|
4788
|
+
var ConstructionLogExcelWorkbookSchema = external_exports.object({
|
|
4789
|
+
schemaVersion: external_exports.literal(CONSTRUCTION_LOG_EXCEL_SCHEMA_VERSION),
|
|
4790
|
+
sheets: external_exports.record(ConstructionLogExcelSheetKeySchema, ConstructionLogExcelSheetSchema)
|
|
4791
|
+
}).strict().describe(
|
|
4792
|
+
"Canonical Alfred construction log Excel workbook schema shared by native output generation and export-upload ingestion."
|
|
4793
|
+
);
|
|
4794
|
+
var CONSTRUCTION_LOG_EXCEL_SHEETS = {
|
|
4795
|
+
submittals: {
|
|
4796
|
+
key: "submittals",
|
|
4797
|
+
sheetName: "Submittals",
|
|
4798
|
+
description: "Submittal register rows generated by Alfred or edited by the PM.",
|
|
4799
|
+
columns: [
|
|
4800
|
+
column("id", "ID", true, "Stable submittal identifier, for example SUB-001."),
|
|
4801
|
+
column("item", "Item", true, "Submittal item or package name."),
|
|
4802
|
+
column("division", "Division", true, "Spec division or trade grouping."),
|
|
4803
|
+
column("needByDate", "Need By Date", true, "Date needed in YYYY-MM-DD format."),
|
|
4804
|
+
column("status", "Status", true, "One of not_started, open, in_review, approved, or done."),
|
|
4805
|
+
commonColumn("assumptionsNotes")
|
|
4806
|
+
]
|
|
4807
|
+
},
|
|
4808
|
+
rfis: {
|
|
4809
|
+
key: "rfis",
|
|
4810
|
+
sheetName: "RFIs",
|
|
4811
|
+
description: "RFI log rows generated by Alfred or edited by the PM.",
|
|
4812
|
+
columns: [
|
|
4813
|
+
column("id", "ID", true, "Stable RFI identifier, for example RFI-001."),
|
|
4814
|
+
column("subject", "Subject", true, "RFI subject."),
|
|
4815
|
+
column("to", "To", true, "Responsible recipient or ball-in-court party."),
|
|
4816
|
+
column("status", "Status", true, "One of draft, open, answered, or closed."),
|
|
4817
|
+
column("openedDate", "Opened Date", true, "Date opened in YYYY-MM-DD format."),
|
|
4818
|
+
commonColumn("assumptionsNotes")
|
|
4819
|
+
]
|
|
4820
|
+
},
|
|
4821
|
+
riskRegister: {
|
|
4822
|
+
key: "riskRegister",
|
|
4823
|
+
sheetName: "Risk Register",
|
|
4824
|
+
description: "Risk register rows generated by Alfred or edited by the PM.",
|
|
4825
|
+
columns: [
|
|
4826
|
+
column("id", "ID", true, "Stable risk identifier, for example RISK-001."),
|
|
4827
|
+
column("risk", "Risk", true, "Risk statement."),
|
|
4828
|
+
column("rating", "Rating", true, "One of low, medium, or high."),
|
|
4829
|
+
column("mitigation", "Mitigation", true, "Mitigation plan."),
|
|
4830
|
+
column("confidence", "Confidence", true, "Confidence score from 0 to 1."),
|
|
4831
|
+
commonColumn("assumptionsNotes")
|
|
4832
|
+
]
|
|
4833
|
+
},
|
|
4834
|
+
longLead: {
|
|
4835
|
+
key: "longLead",
|
|
4836
|
+
sheetName: "Long-Lead",
|
|
4837
|
+
description: "Long-lead procurement rows generated by Alfred or edited by the PM.",
|
|
4838
|
+
columns: [
|
|
4839
|
+
column("id", "ID", true, "Stable long-lead identifier, for example LL-001."),
|
|
4840
|
+
column("item", "Item", true, "Long-lead item name."),
|
|
4841
|
+
column("needByDate", "Need By Date", true, "Date needed in YYYY-MM-DD format."),
|
|
4842
|
+
column("status", "Status", true, "One of tracking, ordered, received, or done."),
|
|
4843
|
+
column("assumption", "Assumption", true, "Procurement assumption behind this row."),
|
|
4844
|
+
commonColumn("assumptionsNotes")
|
|
4845
|
+
]
|
|
4846
|
+
},
|
|
4847
|
+
responsibilityMatrix: {
|
|
4848
|
+
key: "responsibilityMatrix",
|
|
4849
|
+
sheetName: "Responsibility Matrix",
|
|
4850
|
+
description: "Responsibility matrix rows generated by Alfred or edited by the PM.",
|
|
4851
|
+
columns: [
|
|
4852
|
+
column("id", "ID", true, "Stable responsibility identifier, for example RESP-001."),
|
|
4853
|
+
column("role", "Role", true, "Role or party."),
|
|
4854
|
+
column("owner", "Owner", true, "Named owner, or Needs PM input when unknown."),
|
|
4855
|
+
column("responsibility", "Responsibility", true, "Responsibility statement."),
|
|
4856
|
+
commonColumn("assumptionsNotes")
|
|
4857
|
+
]
|
|
4858
|
+
},
|
|
4859
|
+
milestones: {
|
|
4860
|
+
key: "milestones",
|
|
4861
|
+
sheetName: "Milestones",
|
|
4862
|
+
description: "Milestone schedule rows used to generate the MS Project XML schedule.",
|
|
4863
|
+
columns: [
|
|
4864
|
+
column("id", "ID", true, "Stable milestone identifier, for example MS-001."),
|
|
4865
|
+
column("name", "Name", true, "Milestone or task name."),
|
|
4866
|
+
column("targetDate", "Target Date", true, "Target date in YYYY-MM-DD format."),
|
|
4867
|
+
column("status", "Status", true, "One of planned, at_risk, slipped, or complete."),
|
|
4868
|
+
column("predecessorId", "Predecessor ID", false, "Optional predecessor milestone ID."),
|
|
4869
|
+
commonColumn("assumptionsNotes")
|
|
4870
|
+
]
|
|
4871
|
+
}
|
|
4872
|
+
};
|
|
4873
|
+
var CONSTRUCTION_LOG_EXCEL_WORKBOOK_SCHEMA = ConstructionLogExcelWorkbookSchema.parse({
|
|
4874
|
+
schemaVersion: CONSTRUCTION_LOG_EXCEL_SCHEMA_VERSION,
|
|
4875
|
+
sheets: CONSTRUCTION_LOG_EXCEL_SHEETS
|
|
4876
|
+
});
|
|
4877
|
+
function column(key, header, required, description) {
|
|
4878
|
+
return { key, header, required, description };
|
|
4879
|
+
}
|
|
4880
|
+
function commonColumn(key) {
|
|
4881
|
+
return column(
|
|
4882
|
+
key,
|
|
4883
|
+
"Assumptions / Notes",
|
|
4884
|
+
false,
|
|
4885
|
+
"Show-your-work note, including generated assumptions and PM-input gaps."
|
|
4886
|
+
);
|
|
4887
|
+
}
|
|
4888
|
+
|
|
4889
|
+
// ../shared/src/types/dev-task-dispatch.ts
|
|
4890
|
+
var CodingAgentExecutorSchema = external_exports.enum(["claude-code", "codex"]);
|
|
4891
|
+
var DevTaskDispatchRequestSchema = external_exports.object({
|
|
4892
|
+
studioId: external_exports.string().uuid(),
|
|
4893
|
+
productId: external_exports.string().uuid(),
|
|
4894
|
+
repo: RepoRefSchema,
|
|
4895
|
+
task: external_exports.string().min(1).max(2e4),
|
|
4896
|
+
executor: CodingAgentExecutorSchema
|
|
4897
|
+
}).strict();
|
|
4898
|
+
var DevTaskDispatchDryRunPlanSchema = external_exports.object({
|
|
4899
|
+
planOnly: external_exports.literal(true),
|
|
4900
|
+
planOnlyMessage: external_exports.string().min(1),
|
|
4901
|
+
targetRepo: RepoRefSchema,
|
|
4902
|
+
task: external_exports.string().min(1),
|
|
4903
|
+
executor: CodingAgentExecutorSchema,
|
|
4904
|
+
branchName: external_exports.string().min(1),
|
|
4905
|
+
safetyEnvelope: external_exports.object({
|
|
4906
|
+
estimatedCostUsd: external_exports.number().finite().nonnegative(),
|
|
4907
|
+
costCapUsd: external_exports.number().finite().nonnegative(),
|
|
4908
|
+
timeoutMs: external_exports.number().int().positive(),
|
|
4909
|
+
scopedToken: external_exports.object({
|
|
4910
|
+
tokenMinted: external_exports.literal(false),
|
|
4911
|
+
scope: external_exports.string().min(1),
|
|
4912
|
+
ttlSeconds: external_exports.number().int().positive()
|
|
4913
|
+
}).strict(),
|
|
4914
|
+
prOnly: external_exports.object({
|
|
4915
|
+
opensPullRequest: external_exports.literal(true),
|
|
4916
|
+
mergesPullRequest: external_exports.literal(false),
|
|
4917
|
+
pushesMain: external_exports.literal(false),
|
|
4918
|
+
deploys: external_exports.literal(false)
|
|
4919
|
+
}).strict()
|
|
4920
|
+
}).strict()
|
|
4921
|
+
}).strict();
|
|
4922
|
+
var CodingAgentRunInputSchema = external_exports.object({
|
|
4923
|
+
executor: CodingAgentExecutorSchema,
|
|
4924
|
+
repo: RepoRefSchema,
|
|
4925
|
+
task: external_exports.string().min(1),
|
|
4926
|
+
scopedToken: ScopedTokenSchema,
|
|
4927
|
+
branchName: external_exports.string().min(1),
|
|
4928
|
+
costCapUsd: external_exports.number().finite().nonnegative(),
|
|
4929
|
+
timeoutMs: external_exports.number().int().positive()
|
|
4930
|
+
}).strict();
|
|
4931
|
+
var CodingAgentRunResultSchema = external_exports.discriminatedUnion("status", [
|
|
4932
|
+
external_exports.object({
|
|
4933
|
+
status: external_exports.literal("succeeded"),
|
|
4934
|
+
prUrl: external_exports.string().url(),
|
|
4935
|
+
summary: external_exports.string().min(1),
|
|
4936
|
+
costUsd: external_exports.number().finite().nonnegative(),
|
|
4937
|
+
/**
|
|
4938
|
+
* The exact commit sha the PR branch was pushed at when it opened —
|
|
4939
|
+
* captured server-side (see server-dispatch-backend.ts) right after a
|
|
4940
|
+
* successful run, before the workspace is torn down. Lets the Maeve
|
|
4941
|
+
* in-flight-fix detector (maeve-in-flight-pr-fix-lesson.ts) key off the
|
|
4942
|
+
* real PR-open head instead of falling back to timestamp matching.
|
|
4943
|
+
*/
|
|
4944
|
+
openedHeadSha: external_exports.string().min(1).optional()
|
|
4945
|
+
}).strict(),
|
|
4946
|
+
external_exports.object({
|
|
4947
|
+
status: external_exports.literal("failed"),
|
|
4948
|
+
summary: external_exports.string().min(1),
|
|
4949
|
+
reason: external_exports.string().min(1),
|
|
4950
|
+
costUsd: external_exports.number().finite().nonnegative().optional()
|
|
4951
|
+
}).strict()
|
|
4952
|
+
]);
|
|
4953
|
+
var DevTaskOutcomeSchema = external_exports.enum(["ci_passed", "pr_merged", "ci_failed"]);
|
|
4954
|
+
var SecurityFindingClassSchema = external_exports.enum(["authz", "csrf", "injection", "secrets", "ssrf"]);
|
|
4955
|
+
var RecordDevTaskOutcomeInputSchema = external_exports.object({
|
|
4956
|
+
product: external_exports.string().min(1).max(120),
|
|
4957
|
+
repo: external_exports.string().min(1).max(240),
|
|
4958
|
+
prUrl: external_exports.string().url(),
|
|
4959
|
+
outcome: DevTaskOutcomeSchema,
|
|
4960
|
+
task: external_exports.string().min(1).max(2e4).optional(),
|
|
4961
|
+
executor: CodingAgentExecutorSchema.optional(),
|
|
4962
|
+
occurredAt: external_exports.string().datetime().optional(),
|
|
4963
|
+
maeveLessonStatement: external_exports.string().min(1).max(1e3).optional(),
|
|
4964
|
+
maeveLessonTags: external_exports.array(external_exports.string().min(1).max(120)).optional(),
|
|
4965
|
+
/** Security metadata — enriches the Maeve lesson with class/pattern, never raw vulnerable detail. */
|
|
4966
|
+
findingClass: SecurityFindingClassSchema.optional(),
|
|
4967
|
+
ruleId: external_exports.string().min(1).max(120).optional(),
|
|
4968
|
+
signalSource: external_exports.string().min(1).max(240).optional()
|
|
4969
|
+
}).strict();
|
|
4970
|
+
|
|
4971
|
+
// ../shared/src/schemas/standup-plan.ts
|
|
4972
|
+
var StandupRequestSchema = external_exports.object({
|
|
4973
|
+
productName: external_exports.string().min(1).max(80),
|
|
4974
|
+
slug: external_exports.string().min(1).optional(),
|
|
4975
|
+
vertical: external_exports.string().min(1).max(80),
|
|
4976
|
+
repoTarget: external_exports.string().min(1).default("barg-labs"),
|
|
4977
|
+
repoName: external_exports.string().min(1).optional(),
|
|
4978
|
+
templateRef: external_exports.string().min(1).optional(),
|
|
4979
|
+
scopeNotes: external_exports.string().max(2e3).optional()
|
|
4980
|
+
}).strict();
|
|
4981
|
+
var StandupPlanSchema = external_exports.object({
|
|
4982
|
+
productName: external_exports.string().min(1).max(80),
|
|
4983
|
+
slug: external_exports.string().regex(/^[a-z0-9][a-z0-9-]*[a-z0-9]$/),
|
|
4984
|
+
vertical: external_exports.string().min(1).max(80),
|
|
4985
|
+
templateRef: external_exports.string().min(1),
|
|
4986
|
+
repoTarget: external_exports.string().min(1),
|
|
4987
|
+
repoName: external_exports.string().regex(/^[a-z0-9][a-z0-9-]*[a-z0-9]$/),
|
|
4988
|
+
fileManifest: external_exports.array(external_exports.string().min(1)).min(1),
|
|
4989
|
+
credentialScope: external_exports.string().min(1),
|
|
4990
|
+
estimatedCostUsd: external_exports.number().nonnegative(),
|
|
4991
|
+
steps: external_exports.array(external_exports.string().min(1)).min(1),
|
|
4992
|
+
dryRun: external_exports.literal(true)
|
|
4993
|
+
}).strict();
|
|
4994
|
+
|
|
4995
|
+
// ../shared/src/types/coordinator-prompt.ts
|
|
4996
|
+
var CoordinatorPromptContextBlockSchema = external_exports.object({
|
|
4997
|
+
title: external_exports.string().min(1).max(120),
|
|
4998
|
+
body: external_exports.string().min(1).max(6e3),
|
|
4999
|
+
source: external_exports.string().max(500).optional()
|
|
5000
|
+
});
|
|
5001
|
+
var CoordinatorPromptInputPayloadSchema = external_exports.object({
|
|
5002
|
+
objective: external_exports.string().min(1).max(4e3),
|
|
5003
|
+
productId: external_exports.string().min(1),
|
|
5004
|
+
context: external_exports.array(CoordinatorPromptContextBlockSchema).min(1).max(20),
|
|
5005
|
+
escalationHints: external_exports.array(external_exports.string().min(1).max(500)).max(10).optional()
|
|
5006
|
+
});
|
|
5007
|
+
var CoordinatorPromptTokensUsedSchema = external_exports.object({
|
|
5008
|
+
input: external_exports.number().int().nonnegative(),
|
|
5009
|
+
output: external_exports.number().int().nonnegative(),
|
|
5010
|
+
total: external_exports.number().int().nonnegative(),
|
|
5011
|
+
costCents: external_exports.number().nonnegative()
|
|
5012
|
+
});
|
|
5013
|
+
var CoordinatorPromptSchema = external_exports.object({
|
|
5014
|
+
id: external_exports.string().uuid(),
|
|
5015
|
+
studioId: external_exports.string().min(1),
|
|
5016
|
+
productId: external_exports.string().min(1),
|
|
5017
|
+
draftedAt: external_exports.coerce.date(),
|
|
5018
|
+
inputPayload: CoordinatorPromptInputPayloadSchema,
|
|
5019
|
+
markdown: external_exports.string().min(1),
|
|
5020
|
+
metadata: external_exports.object({
|
|
5021
|
+
tokensUsed: CoordinatorPromptTokensUsedSchema.optional(),
|
|
5022
|
+
model: external_exports.string().optional(),
|
|
5023
|
+
templateVersion: external_exports.string().optional()
|
|
5024
|
+
}).catchall(external_exports.unknown()).optional()
|
|
5025
|
+
});
|
|
5026
|
+
var CreateCoordinatorPromptInputSchema = external_exports.object({
|
|
5027
|
+
productId: external_exports.string().min(1),
|
|
5028
|
+
inputPayload: CoordinatorPromptInputPayloadSchema,
|
|
5029
|
+
markdown: external_exports.string().min(1),
|
|
5030
|
+
metadata: external_exports.record(external_exports.unknown()).optional(),
|
|
5031
|
+
draftedAt: external_exports.coerce.date().optional()
|
|
5032
|
+
});
|
|
5033
|
+
var ListCoordinatorPromptsInputSchema = external_exports.object({
|
|
5034
|
+
productId: external_exports.string().min(1).optional(),
|
|
5035
|
+
since: external_exports.coerce.date().optional()
|
|
5036
|
+
});
|
|
5037
|
+
|
|
5038
|
+
// ../shared/src/schemas/inbox-triage.ts
|
|
5039
|
+
var InboxTriageClassificationSchema = external_exports.enum([
|
|
5040
|
+
"needs_reply",
|
|
5041
|
+
"fyi",
|
|
5042
|
+
"waiting",
|
|
5043
|
+
"escalate"
|
|
5044
|
+
]);
|
|
5045
|
+
var InboxTriageLegacyUrgencySchema = external_exports.enum(["needs_reply", "fyi", "noise", "escalation"]);
|
|
5046
|
+
var InboxTriageThreadSchema = external_exports.object({
|
|
5047
|
+
id: external_exports.string().min(1),
|
|
5048
|
+
subject: external_exports.string().min(1),
|
|
5049
|
+
from: external_exports.string(),
|
|
5050
|
+
to: external_exports.string(),
|
|
5051
|
+
snippet: external_exports.string(),
|
|
5052
|
+
labels: external_exports.array(external_exports.string()),
|
|
5053
|
+
unread: external_exports.boolean(),
|
|
5054
|
+
needsReply: external_exports.boolean(),
|
|
5055
|
+
updatedAt: external_exports.string().min(1),
|
|
5056
|
+
url: external_exports.string().min(1),
|
|
5057
|
+
messageCount: external_exports.number().int().nonnegative()
|
|
5058
|
+
});
|
|
5059
|
+
var InboxTriageResultSchema = external_exports.object({
|
|
5060
|
+
threadId: external_exports.string().min(1),
|
|
5061
|
+
classification: InboxTriageClassificationSchema,
|
|
5062
|
+
confidence: external_exports.number().min(0).max(1),
|
|
5063
|
+
reason: external_exports.string(),
|
|
5064
|
+
labelName: external_exports.string(),
|
|
5065
|
+
applied: external_exports.boolean(),
|
|
5066
|
+
error: external_exports.string().optional()
|
|
5067
|
+
});
|
|
5068
|
+
var TriageInboxUsageSchema = external_exports.object({
|
|
5069
|
+
input_tokens: external_exports.number().int().nonnegative(),
|
|
5070
|
+
output_tokens: external_exports.number().int().nonnegative(),
|
|
5071
|
+
cached_tokens: external_exports.number().int().nonnegative().optional(),
|
|
5072
|
+
cost_cents: external_exports.number().nonnegative()
|
|
5073
|
+
});
|
|
5074
|
+
var TriageInboxResultSchema = external_exports.object({
|
|
5075
|
+
productId: external_exports.string().min(1),
|
|
5076
|
+
results: external_exports.array(InboxTriageResultSchema),
|
|
5077
|
+
usage: TriageInboxUsageSchema.optional()
|
|
5078
|
+
});
|
|
5079
|
+
|
|
5080
|
+
// ../shared/src/schemas/inference-usage.ts
|
|
5081
|
+
var InferenceUsageSurfaceSchema = external_exports.string().min(1).max(80).regex(/^[a-z][a-z0-9_-]*$/);
|
|
5082
|
+
var RecordInferenceUsageInputSchema = external_exports.object({
|
|
5083
|
+
product: external_exports.string().min(1).optional(),
|
|
5084
|
+
surface: InferenceUsageSurfaceSchema,
|
|
5085
|
+
model: external_exports.string().min(1).max(120),
|
|
5086
|
+
inputTokens: external_exports.number().int().nonnegative(),
|
|
5087
|
+
outputTokens: external_exports.number().int().nonnegative(),
|
|
5088
|
+
cachedTokens: external_exports.number().int().nonnegative().default(0),
|
|
5089
|
+
costCents: external_exports.number().nonnegative(),
|
|
5090
|
+
timestamp: external_exports.coerce.date().optional()
|
|
5091
|
+
});
|
|
5092
|
+
var InferenceUsageBreakdownQuerySchema = external_exports.object({
|
|
5093
|
+
from: external_exports.coerce.date(),
|
|
5094
|
+
to: external_exports.coerce.date()
|
|
5095
|
+
});
|
|
5096
|
+
var InferenceUsageGroupSchema = external_exports.object({
|
|
5097
|
+
calls: external_exports.number().int().nonnegative(),
|
|
5098
|
+
costCents: external_exports.number().nonnegative(),
|
|
5099
|
+
inputTokens: external_exports.number().int().nonnegative(),
|
|
5100
|
+
outputTokens: external_exports.number().int().nonnegative(),
|
|
5101
|
+
cachedTokens: external_exports.number().int().nonnegative()
|
|
5102
|
+
});
|
|
5103
|
+
var InferenceUsageBreakdownSchema = external_exports.object({
|
|
5104
|
+
from: external_exports.string().datetime(),
|
|
5105
|
+
to: external_exports.string().datetime(),
|
|
5106
|
+
totals: InferenceUsageGroupSchema,
|
|
5107
|
+
bySurface: external_exports.array(InferenceUsageGroupSchema.extend({ surface: InferenceUsageSurfaceSchema })),
|
|
5108
|
+
byModel: external_exports.array(InferenceUsageGroupSchema.extend({ model: external_exports.string().min(1) }))
|
|
5109
|
+
});
|
|
5110
|
+
|
|
5111
|
+
// ../shared/src/schemas/product-health.ts
|
|
5112
|
+
var DEFAULT_PRODUCT_HEALTH_INTERVAL_SECONDS = 24 * 60 * 60;
|
|
5113
|
+
var ISO_DATE_STRING = external_exports.string().datetime({ offset: true }).describe("ISO-8601 timestamp with timezone offset.");
|
|
5114
|
+
var ProductHealthStatusSchema = external_exports.enum(["healthy", "degraded", "halted"]);
|
|
5115
|
+
var ProductHealthDetailsSchema = external_exports.record(external_exports.unknown()).superRefine((details, ctx) => {
|
|
5116
|
+
const credentialPath = findCredentialLikePath(details);
|
|
5117
|
+
if (!credentialPath) return;
|
|
5118
|
+
ctx.addIssue({
|
|
5119
|
+
code: external_exports.ZodIssueCode.custom,
|
|
5120
|
+
message: `Product health details must not contain credentials (${credentialPath}).`
|
|
5121
|
+
});
|
|
5122
|
+
});
|
|
5123
|
+
var ProductHealthReportInputSchema = external_exports.object({
|
|
5124
|
+
productId: external_exports.string().min(1).max(120),
|
|
5125
|
+
status: ProductHealthStatusSchema,
|
|
5126
|
+
lastActivityAt: ISO_DATE_STRING,
|
|
5127
|
+
summary: external_exports.string().min(1).max(1e3),
|
|
5128
|
+
details: ProductHealthDetailsSchema.optional(),
|
|
5129
|
+
reportedAt: ISO_DATE_STRING,
|
|
5130
|
+
expectedIntervalSeconds: external_exports.number().int().positive().optional()
|
|
5131
|
+
});
|
|
5132
|
+
var StoredProductHealthReportSchema = ProductHealthReportInputSchema.extend({
|
|
5133
|
+
expectedIntervalSeconds: external_exports.number().int().positive()
|
|
5134
|
+
});
|
|
5135
|
+
var ProductLivenessStateSchema = external_exports.enum([
|
|
5136
|
+
"healthy",
|
|
5137
|
+
"degraded",
|
|
5138
|
+
"halted",
|
|
5139
|
+
"stale",
|
|
5140
|
+
"unknown"
|
|
5141
|
+
]);
|
|
5142
|
+
var ProductLivenessSnapshotEntrySchema = external_exports.object({
|
|
5143
|
+
productId: external_exports.string().min(1),
|
|
5144
|
+
state: ProductLivenessStateSchema,
|
|
5145
|
+
flagged: external_exports.boolean(),
|
|
5146
|
+
status: ProductHealthStatusSchema.optional(),
|
|
5147
|
+
lastActivityAt: ISO_DATE_STRING.optional(),
|
|
5148
|
+
reportedAt: ISO_DATE_STRING.optional(),
|
|
5149
|
+
expectedIntervalSeconds: external_exports.number().int().positive(),
|
|
5150
|
+
ageSeconds: external_exports.number().int().nonnegative().nullable(),
|
|
5151
|
+
summary: external_exports.string()
|
|
5152
|
+
});
|
|
5153
|
+
function findCredentialLikePath(value, path = []) {
|
|
5154
|
+
if (!value || typeof value !== "object") return null;
|
|
5155
|
+
if (Array.isArray(value)) {
|
|
5156
|
+
for (const [index, item] of value.entries()) {
|
|
5157
|
+
const match = findCredentialLikePath(item, [...path, String(index)]);
|
|
5158
|
+
if (match) return match;
|
|
5159
|
+
}
|
|
5160
|
+
return null;
|
|
5161
|
+
}
|
|
5162
|
+
for (const [key, nested] of Object.entries(value)) {
|
|
5163
|
+
const nextPath = [...path, key];
|
|
5164
|
+
if (/(?:secret|token|password|credential|api[-_]?key|private[-_]?key)/i.test(key)) {
|
|
5165
|
+
return nextPath.join(".");
|
|
5166
|
+
}
|
|
5167
|
+
const match = findCredentialLikePath(nested, nextPath);
|
|
5168
|
+
if (match) return match;
|
|
5169
|
+
}
|
|
5170
|
+
return null;
|
|
5171
|
+
}
|
|
5172
|
+
|
|
5173
|
+
// ../shared/src/schemas/interaction-trace.ts
|
|
5174
|
+
var InteractionTraceVerificationSignalSchema = external_exports.enum([
|
|
5175
|
+
"no_signal",
|
|
5176
|
+
"human_accepted_output",
|
|
5177
|
+
"human_rejected_output",
|
|
5178
|
+
"ci_pr_succeeded",
|
|
5179
|
+
"ci_pr_failed",
|
|
5180
|
+
"brief_accepted",
|
|
5181
|
+
"brief_rejected",
|
|
5182
|
+
"standup_completed",
|
|
5183
|
+
"standup_failed"
|
|
5184
|
+
]);
|
|
5185
|
+
var InteractionTraceVerificationSchema = external_exports.object({
|
|
5186
|
+
success: external_exports.boolean(),
|
|
5187
|
+
signal: InteractionTraceVerificationSignalSchema,
|
|
5188
|
+
confidence: external_exports.number().min(0).max(1),
|
|
5189
|
+
reason: external_exports.string().min(1).max(1e3)
|
|
5190
|
+
});
|
|
5191
|
+
var InteractionTraceActorSchema = external_exports.object({
|
|
5192
|
+
type: external_exports.enum(["human", "agent", "system"]),
|
|
5193
|
+
id: external_exports.string().min(1).max(200),
|
|
5194
|
+
name: external_exports.string().min(1).max(200).optional()
|
|
5195
|
+
});
|
|
5196
|
+
var RecordInteractionTraceInputSchema = external_exports.object({
|
|
5197
|
+
product: external_exports.string().min(1).max(120),
|
|
5198
|
+
intent: external_exports.string().min(1).max(500),
|
|
5199
|
+
actionSummary: external_exports.string().min(1).max(4e3),
|
|
5200
|
+
outcomeSummary: external_exports.string().min(1).max(4e3),
|
|
5201
|
+
model: external_exports.string().min(1).max(200).nullable().optional(),
|
|
5202
|
+
actor: InteractionTraceActorSchema,
|
|
5203
|
+
occurredAt: external_exports.string().datetime().optional(),
|
|
5204
|
+
verification: InteractionTraceVerificationSchema.optional(),
|
|
5205
|
+
metadata: external_exports.record(external_exports.unknown()).optional()
|
|
5206
|
+
});
|
|
5207
|
+
var StoredInteractionTraceSchema = RecordInteractionTraceInputSchema.extend({
|
|
5208
|
+
id: external_exports.string().uuid(),
|
|
5209
|
+
occurredAt: external_exports.string().datetime(),
|
|
5210
|
+
createdAt: external_exports.string().datetime(),
|
|
5211
|
+
verification: InteractionTraceVerificationSchema
|
|
5212
|
+
});
|
|
5213
|
+
var InteractionTraceQualityScoreSchema = external_exports.number().min(0).max(1);
|
|
5214
|
+
var RetrieveRelevantTracesQuerySchema = external_exports.object({
|
|
5215
|
+
product: external_exports.string().min(1).max(120),
|
|
5216
|
+
intent: external_exports.string().min(1).max(500),
|
|
5217
|
+
limit: external_exports.number().int().positive().max(10).optional()
|
|
5218
|
+
});
|
|
5219
|
+
var RetrievedInteractionTraceSchema = StoredInteractionTraceSchema.extend({
|
|
5220
|
+
score: external_exports.number().min(0).max(1),
|
|
5221
|
+
qualityScore: InteractionTraceQualityScoreSchema
|
|
5222
|
+
});
|
|
5223
|
+
|
|
5224
|
+
// ../shared/src/schemas/maeve-lesson.ts
|
|
5225
|
+
var MaeveLessonStatusSchema = external_exports.enum(["candidate", "verified", "retired"]);
|
|
5226
|
+
var MaeveLessonEvidenceSchema = external_exports.object({
|
|
5227
|
+
source: external_exports.enum(["interaction_trace", "artifact"]),
|
|
5228
|
+
traceId: external_exports.string().uuid().optional(),
|
|
5229
|
+
artifact: external_exports.string().min(1).max(1e3).optional(),
|
|
5230
|
+
summary: external_exports.string().min(1).max(1e3),
|
|
5231
|
+
hash: external_exports.string().regex(/^sha256:[a-f0-9]{64}$/)
|
|
5232
|
+
});
|
|
5233
|
+
var MaeveLessonSchema = external_exports.object({
|
|
5234
|
+
id: external_exports.string().uuid(),
|
|
5235
|
+
product: external_exports.string().min(1).max(120),
|
|
5236
|
+
statement: external_exports.string().min(1).max(1e3),
|
|
5237
|
+
scope: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5238
|
+
tags: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5239
|
+
evidence: external_exports.array(MaeveLessonEvidenceSchema),
|
|
5240
|
+
status: MaeveLessonStatusSchema,
|
|
5241
|
+
createdAt: external_exports.string().datetime(),
|
|
5242
|
+
lastSeenAt: external_exports.string().datetime()
|
|
5243
|
+
});
|
|
5244
|
+
var CreateMaeveLessonInputSchema = external_exports.object({
|
|
5245
|
+
product: external_exports.string().min(1).max(120),
|
|
5246
|
+
statement: external_exports.string().min(1).max(1e3),
|
|
5247
|
+
scope: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5248
|
+
tags: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5249
|
+
evidence: external_exports.array(MaeveLessonEvidenceSchema).default([]),
|
|
5250
|
+
status: MaeveLessonStatusSchema.default("candidate"),
|
|
5251
|
+
lastSeenAt: external_exports.string().datetime().optional()
|
|
5252
|
+
});
|
|
5253
|
+
var PromoteMaeveLessonInputSchema = external_exports.object({
|
|
5254
|
+
id: external_exports.string().uuid(),
|
|
5255
|
+
status: MaeveLessonStatusSchema,
|
|
5256
|
+
appendEvidence: external_exports.array(MaeveLessonEvidenceSchema).optional()
|
|
5257
|
+
});
|
|
5258
|
+
var RecallMaeveLessonsQuerySchema = external_exports.object({
|
|
5259
|
+
product: external_exports.string().min(1).max(120).optional(),
|
|
5260
|
+
taskType: external_exports.string().min(1).max(120).optional(),
|
|
5261
|
+
tags: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5262
|
+
limit: external_exports.number().int().positive().max(10).default(5),
|
|
5263
|
+
/**
|
|
5264
|
+
* Free-text query for semantic (pgvector cosine) recall. When set and an
|
|
5265
|
+
* EmbeddingProvider is configured, recallMaeveLessons embeds this text and
|
|
5266
|
+
* retrieves by cosine similarity, with exact-tag matches as a boost.
|
|
5267
|
+
* Falls back to exact-class matching when the provider is NoOp.
|
|
5268
|
+
*/
|
|
5269
|
+
semanticQuery: external_exports.string().min(1).max(500).optional()
|
|
5270
|
+
});
|
|
5271
|
+
var MaeveLessonSeedAnchorSchema = external_exports.object({
|
|
5272
|
+
commit: external_exports.string().regex(/^[0-9a-f]{40}$/i, "commit must be a full 40-character git SHA"),
|
|
5273
|
+
pr: external_exports.number().int().positive().nullable(),
|
|
5274
|
+
summary: external_exports.string().min(1).max(1e3)
|
|
5275
|
+
});
|
|
5276
|
+
var MaeveLessonSeedSchema = external_exports.object({
|
|
5277
|
+
statement: external_exports.string().min(1).max(1e3),
|
|
5278
|
+
scope: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5279
|
+
tags: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5280
|
+
anchors: external_exports.array(MaeveLessonSeedAnchorSchema).min(1),
|
|
5281
|
+
lastSeenAt: external_exports.string().datetime()
|
|
5282
|
+
});
|
|
5283
|
+
var ReviewFindingSeveritySchema = external_exports.enum(["critical", "high", "medium", "low"]);
|
|
5284
|
+
var ReviewFindingLessonInputSchema = external_exports.object({
|
|
5285
|
+
studioId: external_exports.string().min(1),
|
|
5286
|
+
findingStudioId: external_exports.string().min(1),
|
|
5287
|
+
product: external_exports.string().min(1).max(120),
|
|
5288
|
+
repository: external_exports.string().min(1).max(240),
|
|
5289
|
+
pullRequestNumber: external_exports.number().int().positive(),
|
|
5290
|
+
findingText: external_exports.string().min(1).max(4e3),
|
|
5291
|
+
severity: ReviewFindingSeveritySchema,
|
|
5292
|
+
reviewer: external_exports.string().min(1).max(120),
|
|
5293
|
+
remediatingCommitSha: external_exports.string().min(4).max(64),
|
|
5294
|
+
/** The durable, reusable rule distilled from the finding — NOT the finding text verbatim. */
|
|
5295
|
+
lessonStatement: external_exports.string().min(1).max(1e3),
|
|
5296
|
+
scope: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5297
|
+
tags: external_exports.array(external_exports.string().min(1).max(120)).default([]),
|
|
5298
|
+
occurredAt: external_exports.string().datetime()
|
|
5299
|
+
});
|
|
5300
|
+
|
|
5301
|
+
// ../shared/src/schemas/operator-trace.ts
|
|
5302
|
+
var TRACE_ACTORS = [
|
|
5303
|
+
"human",
|
|
5304
|
+
"cowork",
|
|
5305
|
+
"claude-code",
|
|
5306
|
+
"codex",
|
|
5307
|
+
"goal-runner",
|
|
5308
|
+
"ci"
|
|
5309
|
+
];
|
|
5310
|
+
var TraceActorSchema = external_exports.enum(TRACE_ACTORS);
|
|
5311
|
+
var TRACE_SOURCES = [
|
|
5312
|
+
"shell",
|
|
5313
|
+
"cowork",
|
|
5314
|
+
"claude-code",
|
|
5315
|
+
"codex",
|
|
5316
|
+
"goal-runner",
|
|
5317
|
+
"github"
|
|
5318
|
+
];
|
|
5319
|
+
var TraceSourceSchema = external_exports.enum(TRACE_SOURCES);
|
|
5320
|
+
var TraceProvenanceSchema = external_exports.object({
|
|
5321
|
+
source: TraceSourceSchema,
|
|
5322
|
+
/** Absolute path of the source file/dir, or the gh query for CI events. */
|
|
5323
|
+
path: external_exports.string().min(1).max(1e3),
|
|
5324
|
+
/** Line number, session id, or PR number locating the row inside the source. */
|
|
5325
|
+
locator: external_exports.string().min(1).max(200).optional()
|
|
5326
|
+
});
|
|
5327
|
+
var TraceRecordSchema = external_exports.object({
|
|
5328
|
+
t: external_exports.string().datetime(),
|
|
5329
|
+
actor: TraceActorSchema,
|
|
5330
|
+
action: external_exports.string().min(1).max(2e3),
|
|
5331
|
+
target: external_exports.string().max(1e3).default(""),
|
|
5332
|
+
outcome: external_exports.string().max(2e3).default(""),
|
|
5333
|
+
product: external_exports.string().min(1).max(120).optional(),
|
|
5334
|
+
provenance: TraceProvenanceSchema
|
|
5335
|
+
});
|
|
5336
|
+
var ShellRedactionSchema = external_exports.enum(["none", "secret", "unclassified"]);
|
|
5337
|
+
var ShellTraceEntrySchema = external_exports.object({
|
|
5338
|
+
ts: external_exports.string().datetime(),
|
|
5339
|
+
cwd: external_exports.string().min(1).max(1e3),
|
|
5340
|
+
command: external_exports.string().min(1).max(4e3),
|
|
5341
|
+
exitCode: external_exports.number().int(),
|
|
5342
|
+
shellSessionId: external_exports.string().min(1).max(200),
|
|
5343
|
+
redaction: ShellRedactionSchema
|
|
5344
|
+
});
|
|
5345
|
+
var TraceSourceReportSchema = external_exports.discriminatedUnion("status", [
|
|
5346
|
+
external_exports.object({
|
|
5347
|
+
status: external_exports.literal("ok"),
|
|
5348
|
+
source: TraceSourceSchema,
|
|
5349
|
+
recordCount: external_exports.number().int().nonnegative(),
|
|
5350
|
+
/** Files/entries present but skipped (unparseable, filtered) — named, not silent. */
|
|
5351
|
+
skipped: external_exports.array(external_exports.string().min(1).max(500)).default([])
|
|
5352
|
+
}),
|
|
5353
|
+
external_exports.object({
|
|
5354
|
+
status: external_exports.literal("dark"),
|
|
5355
|
+
source: TraceSourceSchema,
|
|
5356
|
+
reason: external_exports.string().min(1).max(500)
|
|
5357
|
+
})
|
|
5358
|
+
]);
|
|
5359
|
+
var OperatorTimelineSchema = external_exports.object({
|
|
5360
|
+
records: external_exports.array(TraceRecordSchema),
|
|
5361
|
+
sources: external_exports.array(TraceSourceReportSchema)
|
|
5362
|
+
});
|
|
5363
|
+
|
|
5364
|
+
// ../shared/src/schemas/witan.ts
|
|
4515
5365
|
var WITAN_RUBRIC_VERSION_V1 = "witan-rubric-v1-2026-06-24";
|
|
4516
5366
|
var WITAN_RUBRIC_VERSION_V2 = "witan-rubric-v2-2026-07-12";
|
|
4517
|
-
var
|
|
5367
|
+
var WITAN_RUBRIC_VERSION_V3 = "witan-rubric-v3-2026-07-13";
|
|
5368
|
+
var WITAN_RUBRIC_VERSION = WITAN_RUBRIC_VERSION_V3;
|
|
4518
5369
|
var WITAN_TRADING_RUBRIC_VERSION_V0 = "witan-trading-rubric-v0-2026-07-01";
|
|
4519
5370
|
var WITAN_CRITERION_IDS = [
|
|
4520
5371
|
"A1",
|
|
@@ -4540,9 +5391,11 @@ var WITAN_TRADING_RUBRIC_V0_CRITERION_IDS = [
|
|
|
4540
5391
|
"audit-completeness",
|
|
4541
5392
|
"claim-reality"
|
|
4542
5393
|
];
|
|
5394
|
+
var WITAN_QUANT_INTEGRITY_RUBRIC_V0_CRITERION_IDS = ["quant-integrity"];
|
|
4543
5395
|
var WitanCriterionIdSchema = external_exports.enum([
|
|
4544
5396
|
...WITAN_CRITERION_IDS,
|
|
4545
|
-
...WITAN_TRADING_RUBRIC_V0_CRITERION_IDS
|
|
5397
|
+
...WITAN_TRADING_RUBRIC_V0_CRITERION_IDS,
|
|
5398
|
+
...WITAN_QUANT_INTEGRITY_RUBRIC_V0_CRITERION_IDS
|
|
4546
5399
|
]);
|
|
4547
5400
|
var WitanTradingCriterionIdSchema = external_exports.enum(WITAN_TRADING_RUBRIC_V0_CRITERION_IDS);
|
|
4548
5401
|
var WitanCriterionCategorySchema = external_exports.enum([
|
|
@@ -4584,6 +5437,7 @@ var WITAN_REPO_ARCHETYPES = [
|
|
|
4584
5437
|
"monorepo",
|
|
4585
5438
|
"docs_only",
|
|
4586
5439
|
"binary_only",
|
|
5440
|
+
"unrecognised_ecosystem",
|
|
4587
5441
|
"empty"
|
|
4588
5442
|
];
|
|
4589
5443
|
var WitanRepoArchetypeSchema = external_exports.enum(WITAN_REPO_ARCHETYPES);
|
|
@@ -4592,7 +5446,10 @@ var WitanEvidencePointerSchema = external_exports.object({
|
|
|
4592
5446
|
label: external_exports.string().min(1).max(180),
|
|
4593
5447
|
url: external_exports.string().url().optional(),
|
|
4594
5448
|
path: external_exports.string().min(1).max(700).optional(),
|
|
4595
|
-
|
|
5449
|
+
// Explicit null means the finding is file-scoped and no real match position was measured —
|
|
5450
|
+
// never a fabricated line (e.g. `1`) standing in for a position the detector never found
|
|
5451
|
+
// (goal_cejel_a2_one_notion_of_production_code_2026-07-13).
|
|
5452
|
+
line: external_exports.number().int().positive().nullable().optional(),
|
|
4596
5453
|
contentHash: external_exports.string().min(8).max(160).optional(),
|
|
4597
5454
|
capturedAt: external_exports.string().datetime({ offset: true }).optional()
|
|
4598
5455
|
}).strict().refine((value) => Boolean(value.url ?? value.path ?? value.contentHash), {
|
|
@@ -4697,91 +5554,1144 @@ var WitanReportSchema = external_exports.object({
|
|
|
4697
5554
|
categoryScores: external_exports.record(external_exports.string(), external_exports.number().min(0).max(4)).optional(),
|
|
4698
5555
|
// Repo-archetype metadata (see WitanRepoArchetypeSchema above). Both fields are omitted for
|
|
4699
5556
|
// callers that don't classify an archetype (e.g. the trading rubric). insufficientSourceReason
|
|
4700
|
-
// is present only for the non-source archetypes ('docs_only' | 'binary_only' |
|
|
4701
|
-
// presence is what presentation layers
|
|
4702
|
-
// insufficient-source verdict instead of
|
|
5557
|
+
// is present only for the non-source archetypes ('docs_only' | 'binary_only' |
|
|
5558
|
+
// 'unrecognised_ecosystem' | 'empty') — its presence is what presentation layers
|
|
5559
|
+
// (badge/terminal/verdict) key off to show an explicit insufficient-source verdict instead of
|
|
5560
|
+
// a confident numeric score.
|
|
4703
5561
|
archetype: WitanRepoArchetypeSchema.optional(),
|
|
4704
5562
|
insufficientSourceReason: external_exports.string().min(1).max(2e3).optional()
|
|
4705
5563
|
}).strict();
|
|
4706
5564
|
|
|
4707
|
-
// src/
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
|
|
4711
|
-
|
|
5565
|
+
// ../shared/src/schemas/work-item.ts
|
|
5566
|
+
var WorkItemTypeSchema = external_exports.enum(["feature", "bug"]);
|
|
5567
|
+
var WorkItemPrioritySchema = external_exports.enum(["low", "normal", "high", "urgent"]);
|
|
5568
|
+
var WorkItemStatusSchema = external_exports.enum([
|
|
5569
|
+
"submitted",
|
|
5570
|
+
"scoped",
|
|
5571
|
+
"dispatched",
|
|
5572
|
+
"pr_open",
|
|
5573
|
+
"done",
|
|
5574
|
+
"declined"
|
|
5575
|
+
]);
|
|
5576
|
+
var CreateWorkItemInputSchema = external_exports.object({
|
|
5577
|
+
productId: external_exports.string().uuid(),
|
|
5578
|
+
type: WorkItemTypeSchema,
|
|
5579
|
+
title: external_exports.string().min(3).max(180),
|
|
5580
|
+
description: external_exports.string().min(8).max(2e4),
|
|
5581
|
+
acceptanceCriteria: external_exports.string().max(2e4).optional(),
|
|
5582
|
+
priority: WorkItemPrioritySchema.default("normal")
|
|
5583
|
+
}).strict();
|
|
5584
|
+
var ScopeWorkItemInputSchema = external_exports.object({
|
|
5585
|
+
scopedTask: external_exports.string().min(8).max(2e4).optional()
|
|
5586
|
+
}).strict();
|
|
5587
|
+
var ListWorkItemsQuerySchema = external_exports.object({
|
|
5588
|
+
productId: external_exports.string().uuid().optional(),
|
|
5589
|
+
status: WorkItemStatusSchema.optional()
|
|
5590
|
+
}).strict();
|
|
5591
|
+
var DispatchWorkItemInputSchema = external_exports.object({
|
|
5592
|
+
executor: external_exports.enum(["claude-code", "codex"]).default("codex"),
|
|
5593
|
+
mode: external_exports.enum(["dry-run", "execute"]).default("dry-run")
|
|
5594
|
+
}).strict();
|
|
4712
5595
|
|
|
4713
|
-
// src/
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
5596
|
+
// ../shared/src/schemas/goal-frontmatter.ts
|
|
5597
|
+
var GoalStreamKindSchema = external_exports.enum(["code", "process"]);
|
|
5598
|
+
var GoalPrioritySchema = external_exports.enum(["p0", "p1", "p2"]);
|
|
5599
|
+
var GoalFrontmatterExtrasSchema = external_exports.object({
|
|
5600
|
+
stream: external_exports.string().min(1).nullable().default(null),
|
|
5601
|
+
order: external_exports.number().int().nullable().default(null),
|
|
5602
|
+
dependsOn: external_exports.array(external_exports.string().min(1)).default([]),
|
|
5603
|
+
priority: GoalPrioritySchema.nullable().default(null),
|
|
5604
|
+
kind: GoalStreamKindSchema.default("code")
|
|
5605
|
+
});
|
|
4717
5606
|
|
|
4718
|
-
// src/
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
|
|
5607
|
+
// ../shared/src/schemas/stream.ts
|
|
5608
|
+
var StreamSchema = external_exports.object({
|
|
5609
|
+
id: external_exports.string().uuid(),
|
|
5610
|
+
studioId: external_exports.string().uuid(),
|
|
5611
|
+
name: external_exports.string().min(1).max(120),
|
|
5612
|
+
tag: external_exports.string().max(60).nullable(),
|
|
5613
|
+
kind: GoalStreamKindSchema,
|
|
5614
|
+
orderIndex: external_exports.number().int(),
|
|
5615
|
+
createdAt: external_exports.coerce.date(),
|
|
5616
|
+
updatedAt: external_exports.coerce.date()
|
|
5617
|
+
});
|
|
5618
|
+
var StreamItemSchema = external_exports.object({
|
|
5619
|
+
id: external_exports.string().uuid(),
|
|
5620
|
+
studioId: external_exports.string().uuid(),
|
|
5621
|
+
streamId: external_exports.string().uuid(),
|
|
5622
|
+
orderIndex: external_exports.number().int(),
|
|
5623
|
+
title: external_exports.string().min(1).max(200),
|
|
5624
|
+
/** docs/orchestration/goal_*.md filename (no extension) for code items; null for process items. */
|
|
5625
|
+
goalName: external_exports.string().min(1).nullable(),
|
|
5626
|
+
refLabel: external_exports.string().max(60).nullable(),
|
|
5627
|
+
/** Free-form governed-run prompt text (mirrors the prototype's per-item `run` string). Null = no run control shown. */
|
|
5628
|
+
runPrompt: external_exports.string().min(1).nullable(),
|
|
5629
|
+
createdAt: external_exports.coerce.date(),
|
|
5630
|
+
updatedAt: external_exports.coerce.date()
|
|
5631
|
+
});
|
|
5632
|
+
var StreamItemDisplayStatusSchema = external_exports.enum([
|
|
5633
|
+
"done",
|
|
5634
|
+
"in-review",
|
|
5635
|
+
"running",
|
|
5636
|
+
"queued",
|
|
5637
|
+
"blocked",
|
|
5638
|
+
"local-unknown"
|
|
5639
|
+
]);
|
|
5640
|
+
|
|
5641
|
+
// ../shared/src/schemas/runner-dispatch.ts
|
|
5642
|
+
var RUNNER_DISPATCH_MODES = ["dry-run", "execute"];
|
|
5643
|
+
var RunnerDispatchModeSchema = external_exports.enum(RUNNER_DISPATCH_MODES);
|
|
5644
|
+
var RUNNER_DISPATCH_STATUSES = ["queued", "claimed", "running", "done", "failed"];
|
|
5645
|
+
var RunnerDispatchStatusSchema = external_exports.enum(RUNNER_DISPATCH_STATUSES);
|
|
5646
|
+
var GOAL_CARD_PATTERN = /^docs\/orchestration\/[A-Za-z0-9_./-]+\.md$/;
|
|
5647
|
+
function isAllowedGoalCardPath(goalCard) {
|
|
5648
|
+
if (!GOAL_CARD_PATTERN.test(goalCard)) return false;
|
|
5649
|
+
return goalCard.split("/").every((segment) => segment !== "." && segment !== "..");
|
|
5650
|
+
}
|
|
5651
|
+
var GoalCardPathSchema = external_exports.string().min(1).max(300).refine(isAllowedGoalCardPath, { message: "goal_card_invalid" });
|
|
5652
|
+
var RunnerDispatchRequestSchema = external_exports.object({
|
|
5653
|
+
goalCard: GoalCardPathSchema,
|
|
5654
|
+
stream: external_exports.string().min(1).max(120).optional(),
|
|
5655
|
+
mode: RunnerDispatchModeSchema
|
|
5656
|
+
});
|
|
5657
|
+
|
|
5658
|
+
// ../shared/src/schemas/witan-metrics-manifest.ts
|
|
5659
|
+
var WITAN_METRICS_MANIFEST_SCHEMA_VERSION = "witan-metrics-manifest-v0";
|
|
5660
|
+
var WitanMetricsManifestReturnsFrequencySchema = external_exports.enum([
|
|
5661
|
+
"daily",
|
|
5662
|
+
"weekly",
|
|
5663
|
+
"monthly",
|
|
5664
|
+
"annual"
|
|
5665
|
+
]);
|
|
5666
|
+
var WitanMetricsManifestFoldSchema = external_exports.object({
|
|
5667
|
+
foldId: external_exports.string().min(1).max(80),
|
|
5668
|
+
inSampleSharpe: external_exports.number().optional(),
|
|
5669
|
+
outOfSampleSharpe: external_exports.number().optional()
|
|
5670
|
+
}).strict();
|
|
5671
|
+
var WitanMetricsManifestCscvTrialSchema = external_exports.object({
|
|
5672
|
+
trialId: external_exports.string().min(1).max(80),
|
|
5673
|
+
blockReturns: external_exports.array(external_exports.number()).min(2)
|
|
5674
|
+
}).strict();
|
|
5675
|
+
var WitanMetricsManifestCscvSchema = external_exports.object({
|
|
5676
|
+
// Must be even (split into IS/OOS halves) — enforced by the grader, not the schema.
|
|
5677
|
+
blocks: external_exports.number().int().min(4).max(16),
|
|
5678
|
+
trials: external_exports.array(WitanMetricsManifestCscvTrialSchema).min(2).max(200)
|
|
5679
|
+
}).strict();
|
|
5680
|
+
var WitanMetricsManifestCostModelSchema = external_exports.object({
|
|
5681
|
+
feeBps: external_exports.number().min(0).optional(),
|
|
5682
|
+
slippageBps: external_exports.number().min(0).optional(),
|
|
5683
|
+
borrowBps: external_exports.number().min(0).optional(),
|
|
5684
|
+
notes: external_exports.string().min(1).max(300).optional()
|
|
5685
|
+
}).strict();
|
|
5686
|
+
var WitanMetricsManifestParameterPointSchema = external_exports.object({
|
|
5687
|
+
// Human-readable label for this point (e.g. "72" or "72 bars") — evidence/display only.
|
|
5688
|
+
paramLabel: external_exports.string().min(1).max(80),
|
|
5689
|
+
// The point's position on its swept axis, used to find its nearest neighbors by distance.
|
|
5690
|
+
paramValue: external_exports.number(),
|
|
5691
|
+
outOfSampleSharpe: external_exports.number()
|
|
5692
|
+
}).strict();
|
|
5693
|
+
var WitanMetricsManifestParameterSweepSchema = external_exports.object({
|
|
5694
|
+
// Name of the swept parameter (e.g. "lookback_bars") — evidence/display only.
|
|
5695
|
+
paramName: external_exports.string().min(1).max(80),
|
|
5696
|
+
points: external_exports.array(WitanMetricsManifestParameterPointSchema).min(3).max(500)
|
|
5697
|
+
}).strict();
|
|
5698
|
+
var WitanMetricsManifestLabelSourceSchema = external_exports.enum([
|
|
5699
|
+
"real_forward_returns",
|
|
5700
|
+
"synthetic",
|
|
5701
|
+
"unknown"
|
|
5702
|
+
]);
|
|
5703
|
+
var WitanMetricsManifestSchema = external_exports.object({
|
|
5704
|
+
schemaVersion: external_exports.literal(WITAN_METRICS_MANIFEST_SCHEMA_VERSION),
|
|
5705
|
+
strategyName: external_exports.string().min(1).max(200).optional(),
|
|
5706
|
+
// The headline reported Sharpe ratio the target repo is claiming.
|
|
5707
|
+
reportedSharpe: external_exports.number(),
|
|
5708
|
+
// How many trials/backtests were run in the search that produced reportedSharpe (the
|
|
5709
|
+
// "1-of-42" count) — required so the grader can correct for selection bias.
|
|
5710
|
+
trialCount: external_exports.number().int().positive(),
|
|
5711
|
+
// Track-record length in return observations (e.g. 252 for a year of daily returns) —
|
|
5712
|
+
// the `n` in the Probabilistic/Deflated Sharpe Ratio formula.
|
|
5713
|
+
trackRecordObservations: external_exports.number().int().positive(),
|
|
5714
|
+
returnsFrequency: WitanMetricsManifestReturnsFrequencySchema.default("daily"),
|
|
5715
|
+
// Skew/kurtosis of the returns distribution; default to the normal-distribution values
|
|
5716
|
+
// (0 skew, kurtosis 3) when the repo does not report them.
|
|
5717
|
+
skewness: external_exports.number().default(0),
|
|
5718
|
+
kurtosis: external_exports.number().min(0).default(3),
|
|
5719
|
+
// Whether reportedSharpe is net of trading costs (fees/slippage/borrow/roll).
|
|
5720
|
+
netOfCosts: external_exports.boolean(),
|
|
5721
|
+
costModel: WitanMetricsManifestCostModelSchema.optional(),
|
|
5722
|
+
// Per-fold in-sample vs out-of-sample breakdown, when the repo reports one.
|
|
5723
|
+
folds: external_exports.array(WitanMetricsManifestFoldSchema).default([]),
|
|
5724
|
+
// Per-trial, per-block performance matrix for the CSCV/PBO computation, when available.
|
|
5725
|
+
cscv: WitanMetricsManifestCscvSchema.optional(),
|
|
5726
|
+
// Parameter-sweep breakdown for the run-tier (L3b) parameter-neighborhood robustness
|
|
5727
|
+
// grader, when the run swept a parameter (e.g. a lookback window) and recorded OOS
|
|
5728
|
+
// performance at each swept value.
|
|
5729
|
+
parameterSweep: WitanMetricsManifestParameterSweepSchema.optional(),
|
|
5730
|
+
// Provenance of the labels behind reportedSharpe (labelling-integrity, L1+artifact tier).
|
|
5731
|
+
labelSource: WitanMetricsManifestLabelSourceSchema.optional()
|
|
5732
|
+
}).strict();
|
|
5733
|
+
|
|
5734
|
+
// ../shared/src/schemas/witan-strategy-adapter.ts
|
|
5735
|
+
var WITAN_STRATEGY_ADAPTER_CONFIG_SCHEMA_VERSION = "witan-strategy-adapter-v0";
|
|
5736
|
+
var WitanStrategyAdapterConfigSchema = external_exports.object({
|
|
5737
|
+
schemaVersion: external_exports.literal(WITAN_STRATEGY_ADAPTER_CONFIG_SCHEMA_VERSION),
|
|
5738
|
+
// Argv for the strategy entrypoint, e.g. ["python3", "strategy.py"] or ["node", "run.mjs"].
|
|
5739
|
+
// Command-argv (not a language enum) is what keeps the adapter language-agnostic — most
|
|
5740
|
+
// real targets are Python, but the contract does not assume it.
|
|
5741
|
+
command: external_exports.array(external_exports.string().min(1).max(300)).min(1).max(20),
|
|
5742
|
+
// Relative path (within the target repo) to the data the strategy should backtest against.
|
|
5743
|
+
dataPath: external_exports.string().min(1).max(500).optional(),
|
|
5744
|
+
// Backtest window, as the target repo defines its own date strings (ISO-8601 recommended).
|
|
5745
|
+
// Optional — a strategy may declare its own default window instead.
|
|
5746
|
+
windowStart: external_exports.string().min(1).max(40).optional(),
|
|
5747
|
+
windowEnd: external_exports.string().min(1).max(40).optional(),
|
|
5748
|
+
// Relative path (within the sandboxed workspace) the entrypoint must write its raw result
|
|
5749
|
+
// to — see WitanStrategyRunResultSchema below.
|
|
5750
|
+
outputPath: external_exports.string().min(1).max(300).default("witan-run-result.json"),
|
|
5751
|
+
timeoutMs: external_exports.number().int().positive().max(30 * 60 * 1e3).default(2 * 60 * 1e3),
|
|
5752
|
+
// Explicit opt-in egress allowlist. Empty by default — no network from the sandboxed run
|
|
5753
|
+
// unless the target repo explicitly whitelists hosts here.
|
|
5754
|
+
allowedHosts: external_exports.array(external_exports.string().min(1).max(255)).max(20).default([])
|
|
5755
|
+
}).strict();
|
|
5756
|
+
var WitanStrategyRunResultSchema = WitanMetricsManifestSchema.omit({
|
|
5757
|
+
schemaVersion: true
|
|
5758
|
+
});
|
|
5759
|
+
|
|
5760
|
+
// ../shared/src/types/tactical-action.ts
|
|
5761
|
+
var TacticalActionTypeSchema = external_exports.enum([
|
|
5762
|
+
"merge_pr_auto_merge_safe",
|
|
5763
|
+
"deploy_staging",
|
|
5764
|
+
"acknowledge_canary_alert",
|
|
5765
|
+
"update_status_md",
|
|
5766
|
+
"provision_product",
|
|
5767
|
+
"dispatch_dev_task"
|
|
5768
|
+
]);
|
|
5769
|
+
var TacticalActionStatusSchema = external_exports.enum(["executed", "blocked", "dry_run"]);
|
|
5770
|
+
var TacticalActionPolicySchema = external_exports.object({
|
|
5771
|
+
studioId: external_exports.string().uuid(),
|
|
5772
|
+
productId: external_exports.string().uuid(),
|
|
5773
|
+
actionType: TacticalActionTypeSchema,
|
|
5774
|
+
allowed: external_exports.boolean(),
|
|
5775
|
+
dryRun: external_exports.boolean(),
|
|
5776
|
+
promotedAt: external_exports.coerce.date().nullable(),
|
|
5777
|
+
forceEnableReason: external_exports.string().nullable()
|
|
5778
|
+
});
|
|
5779
|
+
var BaseActionSchema = external_exports.object({
|
|
5780
|
+
actionType: TacticalActionTypeSchema,
|
|
5781
|
+
productId: external_exports.string().uuid(),
|
|
5782
|
+
coordinatorSessionId: external_exports.string().uuid().nullable().optional(),
|
|
5783
|
+
customerFacingProduction: external_exports.boolean().default(false)
|
|
5784
|
+
});
|
|
5785
|
+
var MergePrTacticalActionSchema = BaseActionSchema.extend({
|
|
5786
|
+
actionType: external_exports.literal("merge_pr_auto_merge_safe"),
|
|
5787
|
+
repository: external_exports.string().min(1),
|
|
5788
|
+
pullRequestNumber: external_exports.number().int().positive(),
|
|
5789
|
+
labels: external_exports.array(external_exports.string()),
|
|
5790
|
+
ciStatus: external_exports.enum(["green", "red", "unknown"]),
|
|
5791
|
+
humanApprovals: external_exports.number().int().nonnegative(),
|
|
5792
|
+
coworkClaudeApprovedStatus: external_exports.enum(["green", "red", "unknown"]),
|
|
5793
|
+
// The PR head SHA captured at the SAME live precondition snapshot that
|
|
5794
|
+
// verified the label/CI/approvals/cowork-claude-approved gates. Threaded
|
|
5795
|
+
// through to the GitHub merge call as the conditional `sha` parameter so a
|
|
5796
|
+
// commit that lands between the snapshot and the merge (a fast follow-up
|
|
5797
|
+
// push, or a re-triggered CI run resetting status) can never be
|
|
5798
|
+
// squash-merged unverified — GitHub rejects the merge with 409 instead.
|
|
5799
|
+
headSha: external_exports.string().min(1)
|
|
5800
|
+
});
|
|
5801
|
+
var DeployStagingTacticalActionSchema = BaseActionSchema.extend({
|
|
5802
|
+
actionType: external_exports.literal("deploy_staging"),
|
|
5803
|
+
environment: external_exports.literal("staging"),
|
|
5804
|
+
mainStatus: external_exports.enum(["green", "red", "unknown"]),
|
|
5805
|
+
stagingStatus: external_exports.enum(["green", "red", "unknown"])
|
|
5806
|
+
});
|
|
5807
|
+
var AcknowledgeCanaryAlertTacticalActionSchema = BaseActionSchema.extend({
|
|
5808
|
+
actionType: external_exports.literal("acknowledge_canary_alert"),
|
|
5809
|
+
alertId: external_exports.string().min(1),
|
|
5810
|
+
fingerprint: external_exports.string().min(1),
|
|
5811
|
+
knownFalsePositiveFingerprints: external_exports.array(external_exports.string()).default([])
|
|
5812
|
+
});
|
|
5813
|
+
var UpdateStatusMdTacticalActionSchema = BaseActionSchema.extend({
|
|
5814
|
+
actionType: external_exports.literal("update_status_md"),
|
|
5815
|
+
source: external_exports.literal("daily_brief_synthesis"),
|
|
5816
|
+
statusMarkdown: external_exports.string().min(1).max(2e4)
|
|
5817
|
+
});
|
|
5818
|
+
var ProvisionProductTacticalActionSchema = BaseActionSchema.extend({
|
|
5819
|
+
actionType: external_exports.literal("provision_product"),
|
|
5820
|
+
productName: external_exports.string().min(1).max(80),
|
|
5821
|
+
vertical: external_exports.string().min(1).max(80),
|
|
5822
|
+
repoTarget: external_exports.string().min(1),
|
|
5823
|
+
templateRef: external_exports.string().min(1),
|
|
5824
|
+
scopeNotes: external_exports.string().max(2e3).optional()
|
|
5825
|
+
});
|
|
5826
|
+
var DispatchDevTaskTacticalActionSchema = BaseActionSchema.extend({
|
|
5827
|
+
actionType: external_exports.literal("dispatch_dev_task"),
|
|
5828
|
+
repo: RepoRefSchema,
|
|
5829
|
+
task: external_exports.string().min(1).max(2e4),
|
|
5830
|
+
executor: CodingAgentExecutorSchema
|
|
5831
|
+
});
|
|
5832
|
+
var TacticalActionSchema = external_exports.discriminatedUnion("actionType", [
|
|
5833
|
+
MergePrTacticalActionSchema,
|
|
5834
|
+
DeployStagingTacticalActionSchema,
|
|
5835
|
+
AcknowledgeCanaryAlertTacticalActionSchema,
|
|
5836
|
+
UpdateStatusMdTacticalActionSchema,
|
|
5837
|
+
ProvisionProductTacticalActionSchema,
|
|
5838
|
+
DispatchDevTaskTacticalActionSchema
|
|
5839
|
+
]);
|
|
5840
|
+
var TacticalActionContextSchema = external_exports.object({
|
|
5841
|
+
studioId: external_exports.string().uuid(),
|
|
5842
|
+
actorUserId: external_exports.string().uuid().nullable().optional(),
|
|
5843
|
+
requestedAt: external_exports.coerce.date().optional()
|
|
5844
|
+
});
|
|
5845
|
+
var TacticalActionPermitResultSchema = external_exports.discriminatedUnion("status", [
|
|
5846
|
+
external_exports.object({
|
|
5847
|
+
status: external_exports.literal("executed"),
|
|
5848
|
+
auditLogId: external_exports.string().uuid(),
|
|
5849
|
+
reason: external_exports.literal("permit_allowed")
|
|
5850
|
+
}),
|
|
5851
|
+
external_exports.object({
|
|
5852
|
+
status: external_exports.literal("blocked"),
|
|
5853
|
+
auditLogId: external_exports.string().uuid().optional(),
|
|
5854
|
+
reason: external_exports.string().min(1)
|
|
5855
|
+
}),
|
|
5856
|
+
external_exports.object({
|
|
5857
|
+
status: external_exports.literal("dry_run"),
|
|
5858
|
+
auditLogId: external_exports.string().uuid(),
|
|
5859
|
+
reason: external_exports.literal("dry_run_mode"),
|
|
5860
|
+
wouldHaveDone: external_exports.record(external_exports.unknown())
|
|
5861
|
+
})
|
|
5862
|
+
]);
|
|
5863
|
+
var TacticalActionLogEntrySchema = external_exports.object({
|
|
5864
|
+
id: external_exports.string().uuid(),
|
|
5865
|
+
studioId: external_exports.string().uuid(),
|
|
5866
|
+
productId: external_exports.string().uuid(),
|
|
5867
|
+
product: external_exports.string().nullable().optional(),
|
|
5868
|
+
coordinatorSessionId: external_exports.string().uuid().nullable(),
|
|
5869
|
+
actionType: TacticalActionTypeSchema.or(external_exports.string()),
|
|
5870
|
+
context: external_exports.record(external_exports.unknown()),
|
|
5871
|
+
permitResult: external_exports.record(external_exports.unknown()),
|
|
5872
|
+
status: TacticalActionStatusSchema,
|
|
5873
|
+
outcome: external_exports.string().nullable(),
|
|
5874
|
+
wouldHaveDone: external_exports.record(external_exports.unknown()).nullable(),
|
|
5875
|
+
attemptedAt: external_exports.string(),
|
|
5876
|
+
executedAt: external_exports.string().nullable()
|
|
5877
|
+
});
|
|
5878
|
+
|
|
5879
|
+
// ../shared/src/schemas/index.ts
|
|
5880
|
+
var StudioSchema = external_exports.object({
|
|
5881
|
+
id: external_exports.string().uuid(),
|
|
5882
|
+
name: external_exports.string().min(1).max(100),
|
|
5883
|
+
billingStatus: external_exports.enum(["trial", "active", "past_due", "cancelled"]),
|
|
5884
|
+
planTier: external_exports.enum(["trial", "solo", "studio", "studio_plus", "self_hosted", "enterprise"]),
|
|
5885
|
+
onPrem: external_exports.boolean().default(false),
|
|
5886
|
+
createdAt: external_exports.coerce.date()
|
|
5887
|
+
});
|
|
5888
|
+
var HumanSchema = external_exports.object({
|
|
5889
|
+
id: external_exports.string().uuid(),
|
|
5890
|
+
studioId: external_exports.string().uuid(),
|
|
5891
|
+
email: external_exports.string().email(),
|
|
5892
|
+
name: external_exports.string().min(1).max(120),
|
|
5893
|
+
oauthProviders: external_exports.array(external_exports.enum(["google", "microsoft", "apple"])).default([]),
|
|
5894
|
+
role: external_exports.enum(["owner", "member", "advisor", "per_product"]),
|
|
5895
|
+
timezone: external_exports.string(),
|
|
5896
|
+
briefTime: external_exports.string().regex(/^\d{2}:\d{2}$/),
|
|
5897
|
+
createdAt: external_exports.coerce.date()
|
|
5898
|
+
});
|
|
5899
|
+
var ProductSchema = external_exports.object({
|
|
5900
|
+
id: external_exports.string().uuid(),
|
|
5901
|
+
studioId: external_exports.string().uuid(),
|
|
5902
|
+
name: external_exports.string().min(1).max(80),
|
|
5903
|
+
slug: external_exports.string().regex(/^[a-z0-9][a-z0-9-]*[a-z0-9]$/),
|
|
5904
|
+
status: external_exports.enum(["active", "snoozed", "wound_down", "deleted"]),
|
|
5905
|
+
description: external_exports.string().max(280).optional(),
|
|
5906
|
+
repoUrl: external_exports.string().url().optional(),
|
|
5907
|
+
calendarTag: external_exports.string().optional(),
|
|
5908
|
+
emailLabelPrefix: external_exports.string().optional(),
|
|
5909
|
+
colorHex: external_exports.string().regex(/^#[0-9a-fA-F]{6}$/).optional(),
|
|
5910
|
+
scheduleBriefTime: external_exports.string().regex(/^\d{2}:\d{2}$/).optional(),
|
|
5911
|
+
briefTemplateId: external_exports.string().uuid().optional(),
|
|
5912
|
+
regulated: external_exports.boolean().default(false),
|
|
5913
|
+
createdAt: external_exports.coerce.date(),
|
|
5914
|
+
lastTouchedAt: external_exports.coerce.date()
|
|
5915
|
+
});
|
|
5916
|
+
var AgentSchema = external_exports.object({
|
|
5917
|
+
id: external_exports.string().uuid(),
|
|
5918
|
+
studioId: external_exports.string().uuid(),
|
|
5919
|
+
productId: external_exports.string().uuid(),
|
|
5920
|
+
agentType: external_exports.enum(["codex", "claude-code", "cowork", "cursor", "cline", "aider", "other"]),
|
|
5921
|
+
sessionId: external_exports.string().optional(),
|
|
5922
|
+
status: external_exports.enum(["active", "idle", "registered", "archived"]),
|
|
5923
|
+
registeredAt: external_exports.coerce.date(),
|
|
5924
|
+
lastActiveAt: external_exports.coerce.date().optional(),
|
|
5925
|
+
totalCostCentsLifetime: external_exports.number().int().nonnegative().default(0)
|
|
5926
|
+
});
|
|
5927
|
+
var AgentRunSchema = external_exports.object({
|
|
5928
|
+
id: external_exports.string().uuid(),
|
|
5929
|
+
agentId: external_exports.string().uuid(),
|
|
5930
|
+
coordinatorSessionId: external_exports.string().uuid().nullable().optional(),
|
|
5931
|
+
startedAt: external_exports.coerce.date(),
|
|
5932
|
+
completedAt: external_exports.coerce.date().optional(),
|
|
5933
|
+
actionType: external_exports.string(),
|
|
5934
|
+
toolName: external_exports.string().optional(),
|
|
5935
|
+
toolInputSummary: external_exports.string().optional(),
|
|
5936
|
+
toolOutputSummary: external_exports.string().optional(),
|
|
5937
|
+
tokensUsedInput: external_exports.number().int().nonnegative().default(0),
|
|
5938
|
+
tokensUsedOutput: external_exports.number().int().nonnegative().default(0),
|
|
5939
|
+
costCents: external_exports.number().int().nonnegative().default(0),
|
|
5940
|
+
durationMs: external_exports.number().int().nonnegative().default(0),
|
|
5941
|
+
resultStatus: external_exports.enum(["success", "failure", "partial", "timeout"]).optional(),
|
|
5942
|
+
resultSummary: external_exports.string().optional(),
|
|
5943
|
+
filesTouched: external_exports.array(external_exports.string()).default([])
|
|
5944
|
+
});
|
|
5945
|
+
var CoordinatorStatusSchema = external_exports.enum([
|
|
5946
|
+
"draft",
|
|
5947
|
+
"spawned",
|
|
5948
|
+
"in_progress",
|
|
5949
|
+
"reporting",
|
|
5950
|
+
"closed"
|
|
5951
|
+
]);
|
|
5952
|
+
var CoordinatorEscalationPolicySchema = external_exports.object({
|
|
5953
|
+
stuck_after_hours: external_exports.number().int().positive(),
|
|
5954
|
+
method: external_exports.literal("flag_for_human"),
|
|
5955
|
+
urgency: external_exports.enum(["low", "medium", "high", "critical"]).optional()
|
|
5956
|
+
});
|
|
5957
|
+
var CoordinatorSessionSchema = external_exports.object({
|
|
5958
|
+
id: external_exports.string().uuid(),
|
|
5959
|
+
studioId: external_exports.string().uuid(),
|
|
5960
|
+
productId: external_exports.string().uuid(),
|
|
5961
|
+
promptId: external_exports.string().uuid().nullable(),
|
|
5962
|
+
objective: external_exports.string(),
|
|
5963
|
+
status: CoordinatorStatusSchema,
|
|
5964
|
+
spawnedAt: external_exports.coerce.date().nullable(),
|
|
5965
|
+
closedAt: external_exports.coerce.date().nullable(),
|
|
5966
|
+
escalationPolicy: CoordinatorEscalationPolicySchema.nullable(),
|
|
5967
|
+
outcomeSummary: external_exports.string().nullable(),
|
|
5968
|
+
createdAt: external_exports.coerce.date()
|
|
5969
|
+
});
|
|
5970
|
+
var AgentActivityWindowSchema = external_exports.enum(["24h", "7d", "30d"]);
|
|
5971
|
+
var AgentCostBucketSchema = external_exports.object({
|
|
5972
|
+
key: external_exports.string(),
|
|
5973
|
+
name: external_exports.string(),
|
|
5974
|
+
runCount: external_exports.number().int().nonnegative(),
|
|
5975
|
+
costUsd: external_exports.number().nonnegative()
|
|
5976
|
+
});
|
|
5977
|
+
var AgentCostRollupSchema = external_exports.object({
|
|
5978
|
+
window: AgentActivityWindowSchema,
|
|
5979
|
+
studioTotalUsd: external_exports.number().nonnegative(),
|
|
5980
|
+
runCount: external_exports.number().int().nonnegative(),
|
|
5981
|
+
byAgent: external_exports.array(AgentCostBucketSchema),
|
|
5982
|
+
byProduct: external_exports.array(AgentCostBucketSchema)
|
|
5983
|
+
});
|
|
5984
|
+
var AgentConflictRecordSchema = external_exports.object({
|
|
5985
|
+
file: external_exports.string(),
|
|
5986
|
+
agents: external_exports.array(external_exports.string()).min(2),
|
|
5987
|
+
references: external_exports.array(
|
|
5988
|
+
external_exports.object({
|
|
5989
|
+
runId: external_exports.string(),
|
|
5990
|
+
agent: external_exports.string(),
|
|
5991
|
+
product: external_exports.string().nullable(),
|
|
5992
|
+
startedAt: external_exports.string(),
|
|
5993
|
+
sessionRef: external_exports.string().nullable(),
|
|
5994
|
+
prUrl: external_exports.string().nullable()
|
|
5995
|
+
})
|
|
5996
|
+
)
|
|
5997
|
+
});
|
|
5998
|
+
var AgentLeaderboardEntrySchema = external_exports.object({
|
|
5999
|
+
agent: external_exports.string(),
|
|
6000
|
+
product: external_exports.string().nullable(),
|
|
6001
|
+
runCount: external_exports.number().int().nonnegative(),
|
|
6002
|
+
completedRuns: external_exports.number().int().nonnegative(),
|
|
6003
|
+
failedRuns: external_exports.number().int().nonnegative(),
|
|
6004
|
+
costUsd: external_exports.number().nonnegative(),
|
|
6005
|
+
filesTouched: external_exports.number().int().nonnegative(),
|
|
6006
|
+
conflicts: external_exports.number().int().nonnegative(),
|
|
6007
|
+
state: external_exports.enum(["productive", "idle", "duplicating"]),
|
|
6008
|
+
lastActiveAt: external_exports.string().nullable()
|
|
6009
|
+
});
|
|
6010
|
+
var ModelCostEstimateInputSchema = external_exports.object({
|
|
6011
|
+
model: external_exports.string().optional(),
|
|
6012
|
+
inputTokens: external_exports.number().int().nonnegative().default(0),
|
|
6013
|
+
outputTokens: external_exports.number().int().nonnegative().default(0)
|
|
6014
|
+
});
|
|
6015
|
+
var ModelCostEstimateSchema = external_exports.object({
|
|
6016
|
+
costUsd: external_exports.number().nonnegative(),
|
|
6017
|
+
method: external_exports.enum(["estimated_from_model_rate", "unknown_model_rate"]),
|
|
6018
|
+
rateModel: external_exports.enum(["claude-haiku", "claude-sonnet", "claude-opus", "unknown"])
|
|
6019
|
+
});
|
|
6020
|
+
var IntegrationSchema = external_exports.object({
|
|
6021
|
+
id: external_exports.string().uuid(),
|
|
6022
|
+
studioId: external_exports.string().uuid(),
|
|
6023
|
+
productId: external_exports.string().uuid().nullable(),
|
|
6024
|
+
kind: external_exports.string(),
|
|
6025
|
+
oauthTokenEncrypted: external_exports.string().optional(),
|
|
6026
|
+
refreshTokenEncrypted: external_exports.string().optional(),
|
|
6027
|
+
status: external_exports.enum(["active", "broken", "revoked"]),
|
|
6028
|
+
lastSyncAt: external_exports.coerce.date().optional(),
|
|
6029
|
+
errorCount: external_exports.number().int().nonnegative().default(0)
|
|
6030
|
+
});
|
|
6031
|
+
var EmailAccountSchema = external_exports.object({
|
|
6032
|
+
id: external_exports.string().uuid(),
|
|
6033
|
+
studioId: external_exports.string().uuid(),
|
|
6034
|
+
provider: external_exports.enum(["gmail", "m365", "imap"]),
|
|
6035
|
+
oauthTokenEncrypted: external_exports.string().optional(),
|
|
6036
|
+
defaultLabelPrefix: external_exports.string().optional(),
|
|
6037
|
+
triageCadenceMins: external_exports.number().int().positive().default(240)
|
|
6038
|
+
});
|
|
6039
|
+
var RoutineSchema = external_exports.object({
|
|
6040
|
+
id: external_exports.string().uuid(),
|
|
6041
|
+
productId: external_exports.string().uuid().nullable(),
|
|
6042
|
+
name: external_exports.string(),
|
|
6043
|
+
cronExpression: external_exports.string(),
|
|
6044
|
+
promptTemplate: external_exports.string(),
|
|
6045
|
+
model: external_exports.enum(["sonnet", "opus", "haiku"]).default("sonnet"),
|
|
6046
|
+
lastRunAt: external_exports.coerce.date().optional(),
|
|
6047
|
+
nextRunAt: external_exports.coerce.date().optional(),
|
|
6048
|
+
enabled: external_exports.boolean().default(true),
|
|
6049
|
+
retryCount: external_exports.number().int().nonnegative().default(0)
|
|
6050
|
+
});
|
|
6051
|
+
var RoutineRunSchema = external_exports.object({
|
|
6052
|
+
id: external_exports.string().uuid(),
|
|
6053
|
+
routineId: external_exports.string().uuid(),
|
|
6054
|
+
startedAt: external_exports.coerce.date(),
|
|
6055
|
+
completedAt: external_exports.coerce.date().optional(),
|
|
6056
|
+
status: external_exports.enum(["success", "failed", "retried"]),
|
|
6057
|
+
outputBriefId: external_exports.string().uuid().optional(),
|
|
6058
|
+
errorMessage: external_exports.string().optional(),
|
|
6059
|
+
inferenceCostCents: external_exports.number().int().nonnegative().default(0)
|
|
6060
|
+
});
|
|
6061
|
+
var BriefSchema = external_exports.object({
|
|
6062
|
+
id: external_exports.string().uuid(),
|
|
6063
|
+
studioId: external_exports.string().uuid(),
|
|
6064
|
+
generatedAt: external_exports.coerce.date(),
|
|
6065
|
+
type: external_exports.enum(["daily", "weekly", "on_demand"]),
|
|
6066
|
+
html: external_exports.string().optional(),
|
|
6067
|
+
markdown: external_exports.string(),
|
|
6068
|
+
sourceLinks: external_exports.array(external_exports.object({ label: external_exports.string(), url: external_exports.string() })).default([]),
|
|
6069
|
+
shared: external_exports.boolean().default(false),
|
|
6070
|
+
shareToken: external_exports.string().optional(),
|
|
6071
|
+
shareExpiresAt: external_exports.coerce.date().optional(),
|
|
6072
|
+
inferenceCostCents: external_exports.number().int().nonnegative().default(0)
|
|
6073
|
+
});
|
|
6074
|
+
var MemoryEntrySchema = external_exports.object({
|
|
6075
|
+
id: external_exports.string().uuid(),
|
|
6076
|
+
productId: external_exports.string().uuid(),
|
|
6077
|
+
kind: external_exports.enum(["decision", "fact", "customer", "status", "pattern", "thread"]),
|
|
6078
|
+
content: external_exports.string(),
|
|
6079
|
+
// embedding stored separately in pgvector; not modelled in API layer
|
|
6080
|
+
createdAt: external_exports.coerce.date(),
|
|
6081
|
+
lastReferencedAt: external_exports.coerce.date().optional(),
|
|
6082
|
+
referenceCount: external_exports.number().int().nonnegative().default(0),
|
|
6083
|
+
pinned: external_exports.boolean().default(false)
|
|
6084
|
+
});
|
|
6085
|
+
var InboxClassificationSchema = external_exports.object({
|
|
6086
|
+
id: external_exports.string().uuid(),
|
|
6087
|
+
emailAccountId: external_exports.string().uuid(),
|
|
6088
|
+
productId: external_exports.string().uuid().nullable(),
|
|
6089
|
+
messageId: external_exports.string(),
|
|
6090
|
+
sender: external_exports.string(),
|
|
6091
|
+
labelApplied: external_exports.string(),
|
|
6092
|
+
urgency: external_exports.enum(["needs_reply", "fyi", "noise", "escalation"]),
|
|
6093
|
+
confidence: external_exports.number().min(0).max(1),
|
|
6094
|
+
action: external_exports.enum(["labelled", "archived", "drafted_reply"]),
|
|
6095
|
+
userCorrected: external_exports.boolean().default(false),
|
|
6096
|
+
correctedTo: external_exports.string().optional()
|
|
6097
|
+
});
|
|
6098
|
+
var DraftReplySchema = external_exports.object({
|
|
6099
|
+
id: external_exports.string().uuid(),
|
|
6100
|
+
classificationId: external_exports.string().uuid(),
|
|
6101
|
+
draftText: external_exports.string(),
|
|
6102
|
+
confidence: external_exports.number().min(0).max(1),
|
|
6103
|
+
sentAt: external_exports.coerce.date().optional(),
|
|
6104
|
+
sentVia: external_exports.string().optional()
|
|
6105
|
+
});
|
|
6106
|
+
var AlwaysAlertRuleSchema = external_exports.object({
|
|
6107
|
+
id: external_exports.string().uuid(),
|
|
6108
|
+
studioId: external_exports.string().uuid(),
|
|
6109
|
+
ruleType: external_exports.enum(["sender", "subject", "domain"]),
|
|
6110
|
+
value: external_exports.string(),
|
|
6111
|
+
escalationMethod: external_exports.enum(["push", "slack", "email", "brief_pin"]).default("brief_pin")
|
|
6112
|
+
});
|
|
6113
|
+
var AuditEventSchema = external_exports.object({
|
|
6114
|
+
id: external_exports.string().uuid(),
|
|
6115
|
+
studioId: external_exports.string().uuid(),
|
|
6116
|
+
actor: external_exports.enum(["user", "agent", "system"]),
|
|
6117
|
+
action: external_exports.string(),
|
|
6118
|
+
integrationId: external_exports.string().uuid().optional(),
|
|
6119
|
+
productId: external_exports.string().uuid().optional(),
|
|
6120
|
+
timestamp: external_exports.coerce.date(),
|
|
6121
|
+
metadata: external_exports.record(external_exports.unknown()).default({})
|
|
6122
|
+
});
|
|
6123
|
+
var SubscriptionSchema = external_exports.object({
|
|
6124
|
+
id: external_exports.string().uuid(),
|
|
6125
|
+
studioId: external_exports.string().uuid(),
|
|
6126
|
+
stripeSubscriptionId: external_exports.string().optional(),
|
|
6127
|
+
tier: external_exports.enum(["trial", "solo", "studio", "studio_plus", "self_hosted", "enterprise"]),
|
|
6128
|
+
seats: external_exports.number().int().positive(),
|
|
6129
|
+
status: external_exports.string(),
|
|
6130
|
+
currentPeriodEnd: external_exports.coerce.date(),
|
|
6131
|
+
cancelAt: external_exports.coerce.date().optional()
|
|
6132
|
+
});
|
|
6133
|
+
var ProductMembershipSchema = external_exports.object({
|
|
6134
|
+
humanId: external_exports.string().uuid(),
|
|
6135
|
+
productId: external_exports.string().uuid(),
|
|
6136
|
+
role: external_exports.enum(["lead", "contributor", "observer"])
|
|
6137
|
+
});
|
|
6138
|
+
|
|
6139
|
+
// ../witan/src/batch.ts
|
|
6140
|
+
import { execFileSync as execFileSync3 } from "child_process";
|
|
6141
|
+
import { mkdirSync as mkdirSync2, writeFileSync } from "fs";
|
|
6142
|
+
import { basename as basename2, join as join5 } from "path";
|
|
6143
|
+
|
|
6144
|
+
// ../witan/src/public-scan.ts
|
|
6145
|
+
import { resolve as resolve2 } from "path";
|
|
6146
|
+
|
|
6147
|
+
// ../witan/src/ingest.ts
|
|
6148
|
+
import { readFileSync as readFileSync5, readdirSync as readdirSync2 } from "fs";
|
|
6149
|
+
import { join as join2 } from "path";
|
|
6150
|
+
|
|
6151
|
+
// ../witan/src/finding-limits.ts
|
|
6152
|
+
var RULE_ID_MAX = 200;
|
|
6153
|
+
var MESSAGE_MAX = 500;
|
|
6154
|
+
var LOCATION_MAX = 700;
|
|
6155
|
+
function clamp(value, max) {
|
|
6156
|
+
if (value.length <= max) return value;
|
|
6157
|
+
const ellipsis = "...";
|
|
6158
|
+
return `${value.slice(0, Math.max(max - ellipsis.length, 0))}${ellipsis}`;
|
|
6159
|
+
}
|
|
6160
|
+
function clampFinding(finding) {
|
|
4725
6161
|
return {
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
...headSha ? { headSha } : {}
|
|
4731
|
-
},
|
|
4732
|
-
generatedAt,
|
|
4733
|
-
...options.rubricVersion ? { rubricVersion: options.rubricVersion } : {},
|
|
4734
|
-
archetype: archetype.archetype,
|
|
4735
|
-
...archetype.insufficientSourceReason ? { insufficientSourceReason: archetype.insufficientSourceReason } : {},
|
|
4736
|
-
signals: [
|
|
4737
|
-
...collectRepoSignals(options.repoPath, generatedAt, repoFiles),
|
|
4738
|
-
...(options.domainCollectors ?? []).map((collect) => collect(options.repoPath, repoFiles)),
|
|
4739
|
-
...options.additionalSignals ?? []
|
|
4740
|
-
]
|
|
6162
|
+
...finding,
|
|
6163
|
+
ruleId: clamp(finding.ruleId, RULE_ID_MAX),
|
|
6164
|
+
message: clamp(finding.message, MESSAGE_MAX),
|
|
6165
|
+
...finding.location ? { location: clamp(finding.location, LOCATION_MAX) } : {}
|
|
4741
6166
|
};
|
|
4742
6167
|
}
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
6168
|
+
|
|
6169
|
+
// ../witan/src/generic-adapter.ts
|
|
6170
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
6171
|
+
|
|
6172
|
+
// ../witan/src/json-safe.ts
|
|
6173
|
+
function stripBom(text) {
|
|
6174
|
+
return text.charCodeAt(0) === 65279 ? text.slice(1) : text;
|
|
6175
|
+
}
|
|
6176
|
+
|
|
6177
|
+
// ../witan/src/generic-adapter.ts
|
|
6178
|
+
var VALID_DIMENSIONS = /* @__PURE__ */ new Set([
|
|
6179
|
+
"A1",
|
|
6180
|
+
"A2",
|
|
6181
|
+
"A3",
|
|
6182
|
+
"A4",
|
|
6183
|
+
"A5",
|
|
6184
|
+
"B1",
|
|
6185
|
+
"B2",
|
|
6186
|
+
"B3",
|
|
6187
|
+
"B4",
|
|
6188
|
+
"B5",
|
|
6189
|
+
"B6"
|
|
6190
|
+
]);
|
|
6191
|
+
var VALID_SEVERITIES = /* @__PURE__ */ new Set(["critical", "warning", "info"]);
|
|
6192
|
+
function isGenericSignalDocument(raw) {
|
|
6193
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return false;
|
|
6194
|
+
const doc = raw;
|
|
6195
|
+
return typeof doc.tool === "string" && doc.tool.length > 0 && Array.isArray(doc.signals);
|
|
6196
|
+
}
|
|
6197
|
+
function parseGenericJson(raw) {
|
|
6198
|
+
if (!isGenericSignalDocument(raw)) return [];
|
|
6199
|
+
const source = raw.tool ?? "unknown";
|
|
6200
|
+
const signals = [];
|
|
6201
|
+
for (const signal of raw.signals ?? []) {
|
|
6202
|
+
const dimension = signal.dimension;
|
|
6203
|
+
if (!dimension || !VALID_DIMENSIONS.has(dimension)) continue;
|
|
6204
|
+
const weight = typeof signal.weight === "number" && Number.isFinite(signal.weight) ? Math.min(Math.max(signal.weight, 0), 1) : 0.5;
|
|
6205
|
+
const findings = [];
|
|
6206
|
+
for (const finding of signal.findings ?? []) {
|
|
6207
|
+
const severity = finding.severity;
|
|
6208
|
+
if (!severity || !VALID_SEVERITIES.has(severity)) continue;
|
|
6209
|
+
const ruleId = finding.ruleId ?? "unknown";
|
|
6210
|
+
findings.push({
|
|
6211
|
+
ruleId,
|
|
6212
|
+
severity,
|
|
6213
|
+
message: finding.message ?? ruleId,
|
|
6214
|
+
...finding.location ? { location: finding.location } : {}
|
|
6215
|
+
});
|
|
6216
|
+
}
|
|
6217
|
+
if (findings.length === 0) continue;
|
|
6218
|
+
signals.push({ source, dimension, weight, findings });
|
|
6219
|
+
}
|
|
6220
|
+
return signals;
|
|
6221
|
+
}
|
|
6222
|
+
|
|
6223
|
+
// ../witan/src/sarif-adapter.ts
|
|
6224
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
6225
|
+
var DIMENSION_RULES = [
|
|
6226
|
+
// A2 — injection / secrets / auth (high weight)
|
|
6227
|
+
{
|
|
6228
|
+
pattern: /sql[- _]?inject|cwe-89|sqli|command[- _]?inject|cwe-78|os[- _]?cmd|rce|remote[- _]?code/i,
|
|
6229
|
+
dimension: "A2",
|
|
6230
|
+
weight: 0.9
|
|
6231
|
+
},
|
|
6232
|
+
{
|
|
6233
|
+
pattern: /secret|credential|api[- _]?key|password[- _]?leak|hardcoded[- _]?(token|key|secret)|cwe-259|cwe-798/i,
|
|
6234
|
+
dimension: "A2",
|
|
6235
|
+
weight: 0.9
|
|
6236
|
+
},
|
|
6237
|
+
{
|
|
6238
|
+
pattern: /path[- _]?traversal|directory[- _]?traversal|cwe-22|lfi|rfi/i,
|
|
6239
|
+
dimension: "A2",
|
|
6240
|
+
weight: 0.8
|
|
6241
|
+
},
|
|
6242
|
+
{
|
|
6243
|
+
pattern: /ssrf|server[- _]?side[- _]?request[- _]?forg|cwe-918/i,
|
|
6244
|
+
dimension: "A2",
|
|
6245
|
+
weight: 0.8
|
|
6246
|
+
},
|
|
6247
|
+
{
|
|
6248
|
+
pattern: /xxe|xml[- _]?external[- _]?entity|cwe-611/i,
|
|
6249
|
+
dimension: "A2",
|
|
6250
|
+
weight: 0.8
|
|
6251
|
+
},
|
|
6252
|
+
{
|
|
6253
|
+
pattern: /auth[- _]?bypass|broken[- _]?auth|missing[- _]?auth|cwe-287|cwe-306|cwe-863|cwe-862/i,
|
|
6254
|
+
dimension: "A2",
|
|
6255
|
+
weight: 0.7
|
|
6256
|
+
},
|
|
6257
|
+
{
|
|
6258
|
+
pattern: /xss|cross[- _]?site[- _]?script|cwe-79/i,
|
|
6259
|
+
dimension: "A2",
|
|
6260
|
+
weight: 0.6
|
|
6261
|
+
},
|
|
6262
|
+
// A4 — dependency vulnerabilities
|
|
6263
|
+
{
|
|
6264
|
+
pattern: /cve-\d{4}-\d+|supply[- _]?chain|depend[a-z]*[- _]?vulner|outdated[- _]?depend|deprecated[- _]?package/i,
|
|
6265
|
+
dimension: "A4",
|
|
6266
|
+
weight: 0.8
|
|
6267
|
+
},
|
|
6268
|
+
{
|
|
6269
|
+
pattern: /npm[- _]?audit|yarn[- _]?audit|pnpm[- _]?audit|pip[- _]?audit|cargo[- _]?audit/i,
|
|
6270
|
+
dimension: "A4",
|
|
6271
|
+
weight: 0.7
|
|
6272
|
+
},
|
|
6273
|
+
// A3 — production readiness / insecure config
|
|
6274
|
+
{
|
|
6275
|
+
pattern: /insecure[- _]?tls|weak[- _]?cipher|tls[- _]?version|http[- _]?strict|hsts|csp[- _]?missing|cwe-326|cwe-327/i,
|
|
6276
|
+
dimension: "A3",
|
|
6277
|
+
weight: 0.5
|
|
6278
|
+
},
|
|
6279
|
+
{
|
|
6280
|
+
pattern: /error[- _]?handl|unhandled[- _]?exception|crash|uncaught|stacktrace[- _]?leak/i,
|
|
6281
|
+
dimension: "A3",
|
|
6282
|
+
weight: 0.4
|
|
6283
|
+
},
|
|
6284
|
+
{
|
|
6285
|
+
pattern: /debug[- _]?mode|dev[- _]?endpoint|staging[- _]?secret/i,
|
|
6286
|
+
dimension: "A3",
|
|
6287
|
+
weight: 0.4
|
|
6288
|
+
},
|
|
6289
|
+
// A1 — test integrity (low weight; SARIF rarely surfaces this)
|
|
6290
|
+
{
|
|
6291
|
+
pattern: /skipped[- _]?test|hollow[- _]?test|empty[- _]?assert|no[- _]?assertion/i,
|
|
6292
|
+
dimension: "A1",
|
|
6293
|
+
weight: 0.2
|
|
6294
|
+
}
|
|
6295
|
+
];
|
|
6296
|
+
var DEFAULT_DIMENSION = "A2";
|
|
6297
|
+
var DEFAULT_WEIGHT = 0.3;
|
|
6298
|
+
var DROP_LEVEL = /* @__PURE__ */ new Set(["none"]);
|
|
6299
|
+
function mapLevel(level) {
|
|
6300
|
+
if (!level || DROP_LEVEL.has(level)) return null;
|
|
6301
|
+
if (level === "error") return "critical";
|
|
6302
|
+
if (level === "warning") return "warning";
|
|
6303
|
+
return "info";
|
|
6304
|
+
}
|
|
6305
|
+
function mapRuleToDimension(ruleId, rules) {
|
|
6306
|
+
for (const rule of rules) {
|
|
6307
|
+
if (rule.pattern.test(ruleId)) {
|
|
6308
|
+
return { dimension: rule.dimension, weight: rule.weight };
|
|
6309
|
+
}
|
|
6310
|
+
}
|
|
6311
|
+
return { dimension: DEFAULT_DIMENSION, weight: DEFAULT_WEIGHT };
|
|
6312
|
+
}
|
|
6313
|
+
function renderLocation(result) {
|
|
6314
|
+
const loc = result.locations?.[0]?.physicalLocation;
|
|
6315
|
+
if (!loc) return void 0;
|
|
6316
|
+
const uri = loc.artifactLocation?.uri;
|
|
6317
|
+
const line = loc.region?.startLine;
|
|
6318
|
+
if (!uri) return void 0;
|
|
6319
|
+
return line != null ? `${uri}:${line}` : uri;
|
|
6320
|
+
}
|
|
6321
|
+
function dedupeFindings(findings) {
|
|
6322
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6323
|
+
return findings.filter((f) => {
|
|
6324
|
+
const key = `${f.ruleId}|${f.severity}|${f.location ?? ""}`;
|
|
6325
|
+
if (seen.has(key)) return false;
|
|
6326
|
+
seen.add(key);
|
|
6327
|
+
return true;
|
|
6328
|
+
});
|
|
6329
|
+
}
|
|
6330
|
+
function parseSarifJson(raw, extraDimensionRules) {
|
|
6331
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return [];
|
|
6332
|
+
const dimensionRules = extraDimensionRules ? [...DIMENSION_RULES, ...extraDimensionRules] : DIMENSION_RULES;
|
|
6333
|
+
const doc = raw;
|
|
6334
|
+
if (!Array.isArray(doc.runs)) return [];
|
|
6335
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
6336
|
+
for (const run of doc.runs) {
|
|
6337
|
+
const driverName = run.tool?.driver?.name ?? "unknown";
|
|
6338
|
+
const source = `sarif:${driverName}`;
|
|
6339
|
+
const ruleDefaultLevels = /* @__PURE__ */ new Map();
|
|
6340
|
+
for (const rule of run.tool?.driver?.rules ?? []) {
|
|
6341
|
+
if (rule.id && rule.defaultConfiguration?.level) {
|
|
6342
|
+
ruleDefaultLevels.set(rule.id, rule.defaultConfiguration.level);
|
|
6343
|
+
}
|
|
6344
|
+
}
|
|
6345
|
+
for (const result of run.results ?? []) {
|
|
6346
|
+
const ruleId = result.ruleId ?? "unknown";
|
|
6347
|
+
const effectiveLevel = result.level ?? ruleDefaultLevels.get(ruleId) ?? "warning";
|
|
6348
|
+
const severity = mapLevel(effectiveLevel);
|
|
6349
|
+
if (!severity) continue;
|
|
6350
|
+
const message = result.message?.text ?? ruleId;
|
|
6351
|
+
const location = renderLocation(result);
|
|
6352
|
+
const { dimension, weight } = mapRuleToDimension(ruleId, dimensionRules);
|
|
6353
|
+
const bucketKey = `${source}|${dimension}`;
|
|
6354
|
+
if (!buckets.has(bucketKey)) {
|
|
6355
|
+
buckets.set(bucketKey, { source, dimension, weight, findings: [] });
|
|
6356
|
+
}
|
|
6357
|
+
buckets.get(bucketKey)?.findings.push({ ruleId, severity, message, ...location ? { location } : {} });
|
|
6358
|
+
}
|
|
6359
|
+
}
|
|
6360
|
+
return Array.from(buckets.values()).map(({ source, dimension, weight, findings }) => ({
|
|
6361
|
+
source,
|
|
6362
|
+
dimension,
|
|
6363
|
+
weight,
|
|
6364
|
+
findings: dedupeFindings(findings)
|
|
6365
|
+
}));
|
|
6366
|
+
}
|
|
6367
|
+
|
|
6368
|
+
// ../witan/src/scorecard-adapter.ts
|
|
6369
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
6370
|
+
var CHECK_RULES = {
|
|
6371
|
+
// B2 — PR outcome traceability
|
|
6372
|
+
"Branch-Protection": { dimension: "B2", weight: 0.8 },
|
|
6373
|
+
"Code-Review": { dimension: "B2", weight: 0.7 },
|
|
6374
|
+
// B3 — CI and QA discipline
|
|
6375
|
+
"Dangerous-Workflow": { dimension: "B3", weight: 0.9 },
|
|
6376
|
+
"Token-Permissions": { dimension: "B3", weight: 0.8 },
|
|
6377
|
+
"CI-Tests": { dimension: "B3", weight: 0.7 },
|
|
6378
|
+
Maintained: { dimension: "B3", weight: 0.3 },
|
|
6379
|
+
// B4 — audit trail / release integrity
|
|
6380
|
+
"Signed-Releases": { dimension: "B4", weight: 0.7 },
|
|
6381
|
+
Packaging: { dimension: "B4", weight: 0.4 },
|
|
6382
|
+
"Security-Policy": { dimension: "B4", weight: 0.4 },
|
|
6383
|
+
// A4 — dependency hygiene
|
|
6384
|
+
Vulnerabilities: { dimension: "A4", weight: 0.9 },
|
|
6385
|
+
"Pinned-Dependencies": { dimension: "A4", weight: 0.8 },
|
|
6386
|
+
"Dependency-Update-Tool": { dimension: "A4", weight: 0.6 },
|
|
6387
|
+
// A2 — data-layer / static analysis
|
|
6388
|
+
SAST: { dimension: "A2", weight: 0.7 },
|
|
6389
|
+
"Binary-Artifacts": { dimension: "A2", weight: 0.6 },
|
|
6390
|
+
// A1 — test integrity
|
|
6391
|
+
Fuzzing: { dimension: "A1", weight: 0.3 }
|
|
6392
|
+
};
|
|
6393
|
+
function mapScoreToSeverity(score) {
|
|
6394
|
+
if (score == null || Number.isNaN(score)) return null;
|
|
6395
|
+
if (score < 0) return null;
|
|
6396
|
+
if (score >= 10) return null;
|
|
6397
|
+
if (score <= 3) return "critical";
|
|
6398
|
+
if (score <= 6) return "warning";
|
|
6399
|
+
return "info";
|
|
6400
|
+
}
|
|
6401
|
+
function dedupeFindings2(findings) {
|
|
6402
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6403
|
+
return findings.filter((f) => {
|
|
6404
|
+
const key = `${f.ruleId}|${f.severity}|${f.location ?? ""}`;
|
|
6405
|
+
if (seen.has(key)) return false;
|
|
6406
|
+
seen.add(key);
|
|
6407
|
+
return true;
|
|
6408
|
+
});
|
|
6409
|
+
}
|
|
6410
|
+
function parseScorecardJson(raw) {
|
|
6411
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return [];
|
|
6412
|
+
const doc = raw;
|
|
6413
|
+
if (!Array.isArray(doc.checks)) return [];
|
|
6414
|
+
const buckets = /* @__PURE__ */ new Map();
|
|
6415
|
+
for (const check of doc.checks) {
|
|
6416
|
+
const name = check.name;
|
|
6417
|
+
if (!name) continue;
|
|
6418
|
+
const rule = CHECK_RULES[name];
|
|
6419
|
+
if (!rule) continue;
|
|
6420
|
+
const severity = mapScoreToSeverity(check.score);
|
|
6421
|
+
if (!severity) continue;
|
|
6422
|
+
const scoreText = typeof check.score === "number" ? `${check.score}/10` : "n/a";
|
|
6423
|
+
const message = `${name} (Scorecard ${scoreText}): ${check.reason ?? "weakness detected"}`.slice(0, 500);
|
|
6424
|
+
const location = check.documentation?.url;
|
|
6425
|
+
const bucket = buckets.get(rule.dimension) ?? { weight: 0, findings: [] };
|
|
6426
|
+
bucket.weight = Math.max(bucket.weight, rule.weight);
|
|
6427
|
+
bucket.findings.push({
|
|
6428
|
+
ruleId: `scorecard:${name}`,
|
|
6429
|
+
severity,
|
|
6430
|
+
message,
|
|
6431
|
+
...location ? { location } : {}
|
|
6432
|
+
});
|
|
6433
|
+
buckets.set(rule.dimension, bucket);
|
|
6434
|
+
}
|
|
6435
|
+
return Array.from(buckets.entries()).map(([dimension, { weight, findings }]) => ({
|
|
6436
|
+
source: "scorecard",
|
|
6437
|
+
dimension,
|
|
6438
|
+
weight,
|
|
6439
|
+
findings: dedupeFindings2(findings)
|
|
6440
|
+
}));
|
|
6441
|
+
}
|
|
6442
|
+
|
|
6443
|
+
// ../witan/src/ingest.ts
|
|
6444
|
+
function looksLikeSarif(raw) {
|
|
6445
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return false;
|
|
6446
|
+
return Array.isArray(raw.runs);
|
|
6447
|
+
}
|
|
6448
|
+
function looksLikeScorecard(raw) {
|
|
6449
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return false;
|
|
6450
|
+
return Array.isArray(raw.checks);
|
|
6451
|
+
}
|
|
6452
|
+
function countRawEntries(raw) {
|
|
6453
|
+
const obj = raw;
|
|
6454
|
+
if (Array.isArray(obj.runs)) {
|
|
6455
|
+
return obj.runs.reduce((sum, run) => {
|
|
6456
|
+
const results = run.results;
|
|
6457
|
+
return sum + (Array.isArray(results) ? results.length : 0);
|
|
6458
|
+
}, 0);
|
|
6459
|
+
}
|
|
6460
|
+
if (Array.isArray(obj.checks)) return obj.checks.length;
|
|
6461
|
+
if (Array.isArray(obj.signals)) {
|
|
6462
|
+
return obj.signals.reduce((sum, signal) => {
|
|
6463
|
+
const findings = signal.findings;
|
|
6464
|
+
return sum + (Array.isArray(findings) ? findings.length : 0);
|
|
6465
|
+
}, 0);
|
|
6466
|
+
}
|
|
6467
|
+
return 0;
|
|
6468
|
+
}
|
|
6469
|
+
function rawToolName(raw) {
|
|
6470
|
+
const obj = raw;
|
|
6471
|
+
if (Array.isArray(obj.runs)) {
|
|
6472
|
+
const firstRun = obj.runs[0];
|
|
6473
|
+
return firstRun?.tool?.driver?.name ?? "unknown";
|
|
6474
|
+
}
|
|
6475
|
+
if (typeof obj.tool === "string" && obj.tool.length > 0) return obj.tool;
|
|
6476
|
+
return "scorecard";
|
|
6477
|
+
}
|
|
6478
|
+
function parseIngestFile(filePath) {
|
|
6479
|
+
let raw;
|
|
6480
|
+
try {
|
|
6481
|
+
raw = JSON.parse(stripBom(readFileSync5(filePath, "utf8")));
|
|
6482
|
+
} catch (error) {
|
|
6483
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6484
|
+
throw new Error(`Cejel: could not parse ingest file as JSON: ${filePath} (${message})`);
|
|
6485
|
+
}
|
|
6486
|
+
let signals;
|
|
6487
|
+
if (looksLikeSarif(raw)) signals = parseSarifJson(raw);
|
|
6488
|
+
else if (looksLikeScorecard(raw)) signals = parseScorecardJson(raw);
|
|
6489
|
+
else if (isGenericSignalDocument(raw)) signals = parseGenericJson(raw);
|
|
6490
|
+
if (!signals) {
|
|
6491
|
+
throw new Error(
|
|
6492
|
+
`Cejel: unrecognized ingest file format: ${filePath} \u2014 expected SARIF (a "runs" array), OpenSSF Scorecard JSON (a "checks" array), or the generic Cejel external-signal shape (a "tool" string + "signals" array). See the cejel README "Aggregate your scanners".`
|
|
6493
|
+
);
|
|
6494
|
+
}
|
|
6495
|
+
const rawCount = countRawEntries(raw);
|
|
6496
|
+
const mappedCount = signals.reduce((sum, signal) => sum + signal.findings.length, 0);
|
|
6497
|
+
if (rawCount > 0 && mappedCount === 0) {
|
|
6498
|
+
process.stderr.write(
|
|
6499
|
+
`Cejel: ${rawCount} findings from ${rawToolName(raw)} (${filePath}), 0 mapped to trust criteria
|
|
6500
|
+
`
|
|
6501
|
+
);
|
|
6502
|
+
}
|
|
6503
|
+
return signals.map((signal) => ({
|
|
6504
|
+
...signal,
|
|
6505
|
+
findings: signal.findings.map(clampFinding)
|
|
6506
|
+
}));
|
|
6507
|
+
}
|
|
6508
|
+
function expandIngestPattern(pattern) {
|
|
6509
|
+
if (!pattern.includes("*")) return [pattern];
|
|
6510
|
+
const lastSlash = pattern.lastIndexOf("/");
|
|
6511
|
+
const dir = lastSlash === -1 ? "." : pattern.slice(0, lastSlash);
|
|
6512
|
+
const filePattern = lastSlash === -1 ? pattern : pattern.slice(lastSlash + 1);
|
|
6513
|
+
const regexSource = filePattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*");
|
|
6514
|
+
const regex = new RegExp(`^${regexSource}$`);
|
|
6515
|
+
let entries;
|
|
6516
|
+
try {
|
|
6517
|
+
entries = readdirSync2(dir);
|
|
6518
|
+
} catch {
|
|
6519
|
+
return [];
|
|
6520
|
+
}
|
|
6521
|
+
return entries.filter((name) => regex.test(name)).sort().map((name) => join2(dir, name));
|
|
6522
|
+
}
|
|
6523
|
+
function discoverIngestInputs(repoPath) {
|
|
6524
|
+
const inputsDir = join2(repoPath, ".cejel", "inputs");
|
|
6525
|
+
let entries;
|
|
6526
|
+
try {
|
|
6527
|
+
entries = readdirSync2(inputsDir);
|
|
6528
|
+
} catch {
|
|
6529
|
+
return [];
|
|
6530
|
+
}
|
|
6531
|
+
return entries.filter((name) => /\.(sarif|json)$/i.test(name)).sort().map((name) => join2(inputsDir, name));
|
|
6532
|
+
}
|
|
6533
|
+
|
|
6534
|
+
// ../witan/src/repo-signals.ts
|
|
6535
|
+
import { execFileSync } from "child_process";
|
|
6536
|
+
import { createHash } from "crypto";
|
|
6537
|
+
import { readFileSync as readFileSync6, readdirSync as readdirSync3, realpathSync, statSync as statSync2 } from "fs";
|
|
6538
|
+
import { basename, join as join3, relative, resolve, sep } from "path";
|
|
6539
|
+
function buildWitanInputFromRepo(options) {
|
|
6540
|
+
assertRepoPathExists(options.repoPath);
|
|
6541
|
+
const generatedAt = options.generatedAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
6542
|
+
const headSha = readGitHead(options.repoPath);
|
|
6543
|
+
const repoFiles = listRepoFiles(options.repoPath);
|
|
6544
|
+
const archetype = classifyRepoArchetype(repoFiles);
|
|
6545
|
+
return {
|
|
6546
|
+
productSlug: options.productSlug,
|
|
6547
|
+
productDisplayName: options.productDisplayName,
|
|
6548
|
+
repo: {
|
|
6549
|
+
path: options.repoPath,
|
|
6550
|
+
...headSha ? { headSha } : {}
|
|
6551
|
+
},
|
|
6552
|
+
generatedAt,
|
|
6553
|
+
...options.rubricVersion ? { rubricVersion: options.rubricVersion } : {},
|
|
6554
|
+
archetype: archetype.archetype,
|
|
6555
|
+
...archetype.insufficientSourceReason ? { insufficientSourceReason: archetype.insufficientSourceReason } : {},
|
|
6556
|
+
signals: [
|
|
6557
|
+
...collectRepoSignals(options.repoPath, generatedAt, repoFiles),
|
|
6558
|
+
...(options.domainCollectors ?? []).map((collect) => collect(options.repoPath, repoFiles)),
|
|
6559
|
+
...options.additionalSignals ?? []
|
|
6560
|
+
]
|
|
6561
|
+
};
|
|
6562
|
+
}
|
|
6563
|
+
var SOURCE_LANGUAGES = [
|
|
6564
|
+
{
|
|
6565
|
+
name: "JS/TS",
|
|
6566
|
+
tier: "deep",
|
|
6567
|
+
extensions: ["ts", "tsx", "mts", "cts", "js", "jsx", "mjs", "cjs"]
|
|
6568
|
+
},
|
|
6569
|
+
{ name: "Python", tier: "deep", extensions: ["py"] },
|
|
6570
|
+
{ name: "Go", tier: "partial", extensions: ["go"] },
|
|
6571
|
+
{ name: "Rust", tier: "partial", extensions: ["rs"] },
|
|
6572
|
+
{ name: "Java", tier: "partial", extensions: ["java"] },
|
|
6573
|
+
{ name: "Ruby", tier: "partial", extensions: ["rb"] },
|
|
6574
|
+
{ name: "PHP", tier: "partial", extensions: ["php"] },
|
|
6575
|
+
{ name: "C#", tier: "partial", extensions: ["cs"] },
|
|
6576
|
+
{ name: "C/C++", tier: "partial", extensions: ["cpp", "cc", "cxx", "c", "h", "hpp"] },
|
|
6577
|
+
{ name: "Swift", tier: "partial", extensions: ["swift"] },
|
|
6578
|
+
{ name: "Kotlin", tier: "partial", extensions: ["kt", "kts"] },
|
|
6579
|
+
{ name: "Dart", tier: "partial", extensions: ["dart"] },
|
|
6580
|
+
{ name: "Elixir", tier: "partial", extensions: ["ex", "exs"] },
|
|
6581
|
+
{ name: "Scala", tier: "partial", extensions: ["scala"] },
|
|
6582
|
+
{ name: "shell", tier: "unmodelled", extensions: ["sh", "bash", "zsh"] },
|
|
6583
|
+
{ name: "R", tier: "unmodelled", extensions: ["r"] },
|
|
6584
|
+
{ name: "Lua", tier: "unmodelled", extensions: ["lua"] },
|
|
6585
|
+
{ name: "Julia", tier: "unmodelled", extensions: ["jl"] },
|
|
6586
|
+
{ name: "Haskell", tier: "unmodelled", extensions: ["hs"] },
|
|
6587
|
+
{ name: "Terraform", tier: "unmodelled", extensions: ["tf", "tfvars"] },
|
|
6588
|
+
{ name: "SQL", tier: "unmodelled", extensions: ["sql"] },
|
|
6589
|
+
{ name: "Perl", tier: "unmodelled", extensions: ["pl", "pm"] },
|
|
6590
|
+
{ name: "OCaml", tier: "unmodelled", extensions: ["ml", "mli"] },
|
|
6591
|
+
{ name: "Clojure", tier: "unmodelled", extensions: ["clj", "cljs", "cljc"] },
|
|
6592
|
+
{ name: "Erlang", tier: "unmodelled", extensions: ["erl", "hrl"] },
|
|
6593
|
+
{ name: "Nim", tier: "unmodelled", extensions: ["nim"] },
|
|
6594
|
+
{ name: "Zig", tier: "unmodelled", extensions: ["zig"] },
|
|
6595
|
+
{ name: "F#", tier: "unmodelled", extensions: ["fs", "fsx"] },
|
|
6596
|
+
{ name: "Groovy", tier: "unmodelled", extensions: ["groovy", "gvy"] }
|
|
6597
|
+
];
|
|
6598
|
+
var SOURCE_EXTENSION_PATTERN = new RegExp(
|
|
6599
|
+
`\\.(${SOURCE_LANGUAGES.flatMap((language) => language.extensions).join("|")})$`,
|
|
6600
|
+
"i"
|
|
6601
|
+
);
|
|
6602
|
+
var BUNDLED_BINARY_EXTENSION_PATTERN = /\.(vsix|zip|tgz|whl|exe|dmg|pkg|msi|jar|war|apk|ipa|dll|dylib)$/i;
|
|
6603
|
+
var DOCS_OR_MEDIA_EXTENSION_PATTERN = /\.(md|mdx|rst|png|jpe?g|gif|svg|webp|ico|pdf)$/i;
|
|
6604
|
+
var KNOWN_NON_SOURCE_EXTENSION_PATTERN = /\.(json|jsonc|json5|ya?ml|toml|txt|lock|xml|csv|tsv|ini|cfg|conf|properties|env|sum|mod|graphql|gql|proto|editorconfig|gitignore|gitattributes|npmrc|nvmrc|dockerignore|log|txt\.license)$/i;
|
|
6605
|
+
var INGEST_POINTER = "To assess a closed/bundled tool, ingest its scanner output via --ingest <sarif|scorecard>.";
|
|
6606
|
+
var SOURCE_DOMINANCE_RATIO_THRESHOLD = 0.2;
|
|
6607
|
+
function classifyRepoArchetype(repoFiles) {
|
|
6608
|
+
const totalFileCount = repoFiles.length;
|
|
6609
|
+
const sourceFileCount = repoFiles.filter((file) => SOURCE_EXTENSION_PATTERN.test(file)).length;
|
|
6610
|
+
if (totalFileCount === 0) {
|
|
6611
|
+
return {
|
|
6612
|
+
archetype: "empty",
|
|
6613
|
+
sourceFileCount: 0,
|
|
6614
|
+
totalFileCount: 0,
|
|
6615
|
+
insufficientSourceReason: "Repository has no tracked files \u2014 there is nothing to certify."
|
|
4773
6616
|
};
|
|
4774
6617
|
}
|
|
4775
|
-
const
|
|
4776
|
-
if (
|
|
6618
|
+
const unrecognisedSourceFiles = collectUnrecognisedSourceFiles(repoFiles);
|
|
6619
|
+
if (sourceFileCount === 0) {
|
|
6620
|
+
const binaryFiles = repoFiles.filter((file) => BUNDLED_BINARY_EXTENSION_PATTERN.test(file));
|
|
6621
|
+
if (binaryFiles.length > 0) {
|
|
6622
|
+
const sample = binaryFiles[0];
|
|
6623
|
+
return {
|
|
6624
|
+
archetype: "binary_only",
|
|
6625
|
+
sourceFileCount,
|
|
6626
|
+
totalFileCount,
|
|
6627
|
+
insufficientSourceReason: `${sourceFileCount} source file(s) found among ${totalFileCount} tracked file(s); repo appears to be a binary/bundled-distribution tree (e.g. ${sample ? basename(sample) : "a packaged artifact"}) \u2014 cejel rates source, not binaries. ${INGEST_POINTER}`
|
|
6628
|
+
};
|
|
6629
|
+
}
|
|
6630
|
+
const docsFiles = repoFiles.filter((file) => DOCS_OR_MEDIA_EXTENSION_PATTERN.test(file));
|
|
6631
|
+
if (docsFiles.length > 0 && docsFiles.length === totalFileCount) {
|
|
6632
|
+
return {
|
|
6633
|
+
archetype: "docs_only",
|
|
6634
|
+
sourceFileCount,
|
|
6635
|
+
totalFileCount,
|
|
6636
|
+
insufficientSourceReason: `${sourceFileCount} source file(s) found among ${totalFileCount} tracked file(s); repo appears to be a docs/distribution tree (README/markdown/media), not a source tree \u2014 cejel rates source, not docs. ${INGEST_POINTER}`
|
|
6637
|
+
};
|
|
6638
|
+
}
|
|
6639
|
+
if (unrecognisedSourceFiles.length > 0) {
|
|
6640
|
+
return unrecognisedEcosystemResult(sourceFileCount, totalFileCount, unrecognisedSourceFiles);
|
|
6641
|
+
}
|
|
6642
|
+
return { archetype: "source", sourceFileCount, totalFileCount };
|
|
6643
|
+
}
|
|
6644
|
+
if (unrecognisedSourceFiles.length === 0) {
|
|
4777
6645
|
return {
|
|
4778
|
-
archetype: "
|
|
6646
|
+
archetype: isLikelyMonorepo(repoFiles) ? "monorepo" : "source",
|
|
4779
6647
|
sourceFileCount,
|
|
4780
|
-
totalFileCount
|
|
4781
|
-
insufficientSourceReason: `${sourceFileCount} source file(s) found among ${totalFileCount} tracked file(s); repo appears to be a docs/distribution tree (README/markdown/media), not a source tree \u2014 cejel rates source, not docs. ${INGEST_POINTER}`
|
|
6648
|
+
totalFileCount
|
|
4782
6649
|
};
|
|
4783
6650
|
}
|
|
4784
|
-
|
|
6651
|
+
const dominanceRatio = sourceFileCount / (sourceFileCount + unrecognisedSourceFiles.length);
|
|
6652
|
+
if (dominanceRatio >= SOURCE_DOMINANCE_RATIO_THRESHOLD) {
|
|
6653
|
+
return {
|
|
6654
|
+
archetype: isLikelyMonorepo(repoFiles) ? "monorepo" : "source",
|
|
6655
|
+
sourceFileCount,
|
|
6656
|
+
totalFileCount
|
|
6657
|
+
};
|
|
6658
|
+
}
|
|
6659
|
+
return unrecognisedEcosystemResult(sourceFileCount, totalFileCount, unrecognisedSourceFiles);
|
|
6660
|
+
}
|
|
6661
|
+
function collectUnrecognisedSourceFiles(repoFiles) {
|
|
6662
|
+
return repoFiles.filter((file) => {
|
|
6663
|
+
const base = basename(file);
|
|
6664
|
+
if (!/\.([a-zA-Z0-9_]+)$/.test(base)) return false;
|
|
6665
|
+
if (KNOWN_NON_SOURCE_EXTENSION_PATTERN.test(base)) return false;
|
|
6666
|
+
if (DOCS_OR_MEDIA_EXTENSION_PATTERN.test(base)) return false;
|
|
6667
|
+
if (BUNDLED_BINARY_EXTENSION_PATTERN.test(base)) return false;
|
|
6668
|
+
if (SOURCE_EXTENSION_PATTERN.test(base)) return false;
|
|
6669
|
+
return true;
|
|
6670
|
+
});
|
|
6671
|
+
}
|
|
6672
|
+
function extensionsByFileCountDescending(files) {
|
|
6673
|
+
const counts = /* @__PURE__ */ new Map();
|
|
6674
|
+
for (const file of files) {
|
|
6675
|
+
const match = /\.([a-zA-Z0-9_]+)$/.exec(basename(file));
|
|
6676
|
+
const ext = match?.[1];
|
|
6677
|
+
if (!ext) continue;
|
|
6678
|
+
const key = `.${ext.toLowerCase()}`;
|
|
6679
|
+
counts.set(key, (counts.get(key) ?? 0) + 1);
|
|
6680
|
+
}
|
|
6681
|
+
return [...counts.entries()].sort(([extA, countA], [extB, countB]) => countB - countA || extA.localeCompare(extB)).map(([ext]) => ext);
|
|
6682
|
+
}
|
|
6683
|
+
function unrecognisedEcosystemResult(sourceFileCount, totalFileCount, unrecognisedSourceFiles) {
|
|
6684
|
+
const sample = extensionsByFileCountDescending(unrecognisedSourceFiles).slice(0, 6).join(", ");
|
|
6685
|
+
const candidateCount = sourceFileCount + unrecognisedSourceFiles.length;
|
|
6686
|
+
const dominancePct = candidateCount > 0 ? (sourceFileCount / candidateCount * 100).toFixed(1) : "0.0";
|
|
6687
|
+
const thresholdPct = (SOURCE_DOMINANCE_RATIO_THRESHOLD * 100).toFixed(0);
|
|
6688
|
+
const measuredClause = sourceFileCount > 0 ? `${sourceFileCount} of ${candidateCount} source-shaped file(s) (${dominancePct}%) are in a language Cejel reads \u2014 below the ${thresholdPct}% dominance threshold a score would need to be meaningful (${totalFileCount} tracked files in total; manifests, lockfiles, docs, media and bundled binaries are excluded from both sides of the ratio)` : `0 of ${totalFileCount} tracked file(s) matched a recognised source extension`;
|
|
6689
|
+
return {
|
|
6690
|
+
archetype: "unrecognised_ecosystem",
|
|
6691
|
+
sourceFileCount,
|
|
6692
|
+
totalFileCount,
|
|
6693
|
+
insufficientSourceReason: `Cejel does not yet read this repository's dominant source language(s) (${sample}) \u2014 ${measuredClause}. Cejel abstains from a verdict rather than score a repository whose recognised source is incidental rather than dominant; the Criterion Profile and Measured coverage below show exactly which dimensions were and were not measured. ${INGEST_POINTER}`
|
|
6694
|
+
};
|
|
4785
6695
|
}
|
|
4786
6696
|
function isLikelyMonorepo(repoFiles) {
|
|
4787
6697
|
const packageRoots = new Set(
|
|
@@ -4792,7 +6702,7 @@ function isLikelyMonorepo(repoFiles) {
|
|
|
4792
6702
|
function assertRepoPathExists(repoPath) {
|
|
4793
6703
|
let stats;
|
|
4794
6704
|
try {
|
|
4795
|
-
stats =
|
|
6705
|
+
stats = statSync2(repoPath);
|
|
4796
6706
|
} catch {
|
|
4797
6707
|
throw new Error(`Cejel: path not found: ${repoPath}`);
|
|
4798
6708
|
}
|
|
@@ -4820,14 +6730,14 @@ function collectRepoSignals(repoPath, generatedAt, repoFiles) {
|
|
|
4820
6730
|
const a5Signal = collectA5ClaimRealityEvidence(repoPath, repoFiles);
|
|
4821
6731
|
const b1Signal = buildNotApplicableSignal(
|
|
4822
6732
|
"B1",
|
|
4823
|
-
"
|
|
6733
|
+
"Repository scans do not evaluate the dispatch-trace process dimension."
|
|
4824
6734
|
);
|
|
4825
6735
|
const b2Signal = collectB2PrTraceEvidence(repoPath, repoFiles);
|
|
4826
6736
|
const b3Signal = collectB3CiDisciplineEvidence(repoPath, repoFiles, mono);
|
|
4827
6737
|
const b4Signal = collectB4AuditEvidence(repoPath, repoFiles, generatedAt);
|
|
4828
6738
|
const b5Signal = buildNotApplicableSignal(
|
|
4829
6739
|
"B5",
|
|
4830
|
-
"
|
|
6740
|
+
"Repository scans do not evaluate the learning-trace process dimension."
|
|
4831
6741
|
);
|
|
4832
6742
|
const b6Signal = collectB6PrivilegedOpsGatingEvidence(repoPath, repoFiles);
|
|
4833
6743
|
for (const signal of [
|
|
@@ -4860,7 +6770,7 @@ function collectA1TestIntegrityEvidence(repoPath, repoFiles) {
|
|
|
4860
6770
|
const runnerFiles = repoFiles.filter(isTestRunnerConfig).slice(0, 6);
|
|
4861
6771
|
const coverageFiles = repoFiles.filter(isCoverageConfig).slice(0, 4);
|
|
4862
6772
|
const packageJson = findRootPackageJson(repoFiles);
|
|
4863
|
-
const packageScripts = packageJson ? readPackageScripts(
|
|
6773
|
+
const packageScripts = packageJson ? readPackageScripts(join3(repoPath, packageJson)) : /* @__PURE__ */ new Map();
|
|
4864
6774
|
const coveragePercent = readCoveragePercent(repoPath, coverageFiles);
|
|
4865
6775
|
const ciWorkflows = repoFiles.filter(isCiWorkflow);
|
|
4866
6776
|
const ciTestWorkflow = ciWorkflows.find(
|
|
@@ -5014,8 +6924,7 @@ function collectA1TestIntegrityEvidence(repoPath, repoFiles) {
|
|
|
5014
6924
|
};
|
|
5015
6925
|
}
|
|
5016
6926
|
function collectA2IsolationEvidence(repoPath, repoFiles) {
|
|
5017
|
-
const
|
|
5018
|
-
const evidence = [...alfredEvidence];
|
|
6927
|
+
const evidence = [];
|
|
5019
6928
|
const findings = [];
|
|
5020
6929
|
const gitignore = repoFiles.find((file) => basename(file) === ".gitignore");
|
|
5021
6930
|
const envExamples = repoFiles.filter((file) => isEnvTemplatePath(file));
|
|
@@ -5031,47 +6940,43 @@ function collectA2IsolationEvidence(repoPath, repoFiles) {
|
|
|
5031
6940
|
repoPath,
|
|
5032
6941
|
repoFiles.filter(isImplementationFile).slice(0, 60)
|
|
5033
6942
|
);
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
6943
|
+
const implFiles = repoFiles.filter(isImplementationFile);
|
|
6944
|
+
const gitignoreHasEnvRule = gitignore != null && fileContains(repoPath, gitignore, /^\.env(\*|\b)|\.env\./m);
|
|
6945
|
+
const committedEnvFilePath = repoFiles.find(
|
|
6946
|
+
(f) => /(?:^|\/)\.env(?:\.|$)/i.test(f) && !isEnvTemplatePath(f)
|
|
6947
|
+
);
|
|
6948
|
+
const hasEnvInHistory = committedEnvFilePath === void 0 && hasEnvPathInGitHistory(repoPath);
|
|
6949
|
+
const dbLayerImportFile = migrationFiles.length === 0 ? implFiles.slice(0, 30).find((f) => fileContains(repoPath, f, DB_CLIENT_PATTERN)) : void 0;
|
|
6950
|
+
const hasDataLayer = migrationFiles.length > 0 || dbLayerImportFile !== void 0;
|
|
6951
|
+
const hasSecretsSurface = envExamples.length > 0 || committedEnvFilePath !== void 0 || gitignoreHasEnvRule || hasEnvInHistory;
|
|
6952
|
+
if (!hasDataLayer && !hasSecretsSurface && !hasConfirmedSecretFinding && !cryptoHygiene.hasSurface) {
|
|
6953
|
+
return buildNotApplicableSignal(
|
|
6954
|
+
"A2",
|
|
6955
|
+
"No data layer (DB/ORM/migrations) or ratable secrets surface detected \u2014 A2 not applicable to this repo archetype. A ratable surface requires .env* files, .gitignore .env rule, committed/history .env path, or detected signing/HMAC/secret-comparison code; bare env reads (process.env / os.environ / std::env::) do not qualify."
|
|
5039
6956
|
);
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
"
|
|
5047
|
-
"
|
|
5048
|
-
)
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
path: ".git",
|
|
5064
|
-
contentHash: readGitHead(repoPath) ?? "env-history-scan"
|
|
5065
|
-
});
|
|
5066
|
-
} else if (migrationFiles[0] != null) {
|
|
5067
|
-
evidence.push(
|
|
5068
|
-
evidenceForRelative(repoPath, migrationFiles[0], "artifact", "Data layer migration")
|
|
5069
|
-
);
|
|
5070
|
-
} else if (dbLayerImportFile != null) {
|
|
5071
|
-
evidence.push(
|
|
5072
|
-
evidenceForRelative(repoPath, dbLayerImportFile, "artifact", "DB client import")
|
|
5073
|
-
);
|
|
5074
|
-
}
|
|
6957
|
+
}
|
|
6958
|
+
if (committedEnvFilePath) {
|
|
6959
|
+
evidence.push(
|
|
6960
|
+
evidenceForRelative(
|
|
6961
|
+
repoPath,
|
|
6962
|
+
committedEnvFilePath,
|
|
6963
|
+
"secret_scan",
|
|
6964
|
+
"Committed .env file in repository tree"
|
|
6965
|
+
)
|
|
6966
|
+
);
|
|
6967
|
+
} else if (hasEnvInHistory) {
|
|
6968
|
+
evidence.push({
|
|
6969
|
+
kind: "secret_scan",
|
|
6970
|
+
label: ".env path detected in git history",
|
|
6971
|
+
path: ".git",
|
|
6972
|
+
contentHash: readGitHead(repoPath) ?? "env-history-scan"
|
|
6973
|
+
});
|
|
6974
|
+
} else if (migrationFiles[0] != null) {
|
|
6975
|
+
evidence.push(
|
|
6976
|
+
evidenceForRelative(repoPath, migrationFiles[0], "artifact", "Data layer migration")
|
|
6977
|
+
);
|
|
6978
|
+
} else if (dbLayerImportFile != null) {
|
|
6979
|
+
evidence.push(evidenceForRelative(repoPath, dbLayerImportFile, "artifact", "DB client import"));
|
|
5075
6980
|
}
|
|
5076
6981
|
const rlsMigration = migrationFiles.find((file) => fileContains(repoPath, file, RLS_PATTERN));
|
|
5077
6982
|
const tenantScopedFile = migrationFiles.find(
|
|
@@ -5231,7 +7136,8 @@ function collectCryptoHygieneEvidence(repoPath, implFiles) {
|
|
|
5231
7136
|
const findings = [];
|
|
5232
7137
|
let hasSurface = false;
|
|
5233
7138
|
let insecureFound = false;
|
|
5234
|
-
const
|
|
7139
|
+
const productionImplFiles = implFiles.filter(isProductionSourcePath);
|
|
7140
|
+
const timingSafeFile = productionImplFiles.find(
|
|
5235
7141
|
(file) => fileContains(repoPath, file, TIMING_SAFE_COMPARE_PATTERN)
|
|
5236
7142
|
);
|
|
5237
7143
|
if (timingSafeFile) {
|
|
@@ -5245,7 +7151,7 @@ function collectCryptoHygieneEvidence(repoPath, implFiles) {
|
|
|
5245
7151
|
)
|
|
5246
7152
|
);
|
|
5247
7153
|
}
|
|
5248
|
-
const canonicalSignFile =
|
|
7154
|
+
const canonicalSignFile = productionImplFiles.find(
|
|
5249
7155
|
(file) => fileContains(repoPath, file, CANONICAL_SERIALIZE_PATTERN) && fileContains(repoPath, file, SIGN_OR_HMAC_CALL_PATTERN)
|
|
5250
7156
|
);
|
|
5251
7157
|
if (canonicalSignFile) {
|
|
@@ -5259,20 +7165,31 @@ function collectCryptoHygieneEvidence(repoPath, implFiles) {
|
|
|
5259
7165
|
)
|
|
5260
7166
|
);
|
|
5261
7167
|
}
|
|
5262
|
-
|
|
5263
|
-
|
|
5264
|
-
)
|
|
7168
|
+
let insecureCompareFile = null;
|
|
7169
|
+
let insecureCompareLine = null;
|
|
7170
|
+
for (const file of implFiles) {
|
|
7171
|
+
const line = findInsecureSecretCompareLine(repoPath, file);
|
|
7172
|
+
if (line != null) {
|
|
7173
|
+
insecureCompareFile = file;
|
|
7174
|
+
insecureCompareLine = line;
|
|
7175
|
+
break;
|
|
7176
|
+
}
|
|
7177
|
+
}
|
|
5265
7178
|
if (insecureCompareFile) {
|
|
5266
|
-
|
|
5267
|
-
|
|
7179
|
+
const isTestPath = isTestOrFixturePath(insecureCompareFile);
|
|
7180
|
+
if (!isTestPath) {
|
|
7181
|
+
hasSurface = true;
|
|
7182
|
+
insecureFound = true;
|
|
7183
|
+
}
|
|
5268
7184
|
findings.push({
|
|
5269
|
-
severity: "warning",
|
|
5270
|
-
summary: "A secret/HMAC/signature value appears compared with a plain equality operator instead of a constant-time comparison \u2014 potential timing side-channel.",
|
|
5271
|
-
evidence:
|
|
7185
|
+
severity: isTestPath ? "info" : "warning",
|
|
7186
|
+
summary: isTestPath ? `A secret/HMAC/signature comparison via plain equality appears in a test/fixture file (${insecureCompareFile}) \u2014 likely a test assertion, not a production timing leak; verify.` : "A secret/HMAC/signature value appears compared with a plain equality operator instead of a constant-time comparison \u2014 potential timing side-channel.",
|
|
7187
|
+
evidence: evidenceForRelativeAtLine(
|
|
5272
7188
|
repoPath,
|
|
5273
7189
|
insecureCompareFile,
|
|
5274
7190
|
"artifact",
|
|
5275
|
-
"Non-constant-time secret comparison"
|
|
7191
|
+
"Non-constant-time secret comparison",
|
|
7192
|
+
insecureCompareLine
|
|
5276
7193
|
)
|
|
5277
7194
|
});
|
|
5278
7195
|
}
|
|
@@ -5280,16 +7197,25 @@ function collectCryptoHygieneEvidence(repoPath, implFiles) {
|
|
|
5280
7197
|
(file) => fileContains(repoPath, file, UNSORTED_JSON_SIGN_PATTERN) && !fileContains(repoPath, file, CANONICAL_SERIALIZE_PATTERN)
|
|
5281
7198
|
);
|
|
5282
7199
|
if (unsortedSignFile) {
|
|
5283
|
-
|
|
5284
|
-
|
|
7200
|
+
const isTestPath = isTestOrFixturePath(unsortedSignFile);
|
|
7201
|
+
if (!isTestPath) {
|
|
7202
|
+
hasSurface = true;
|
|
7203
|
+
insecureFound = true;
|
|
7204
|
+
}
|
|
7205
|
+
const unsortedSignLine = findFirstMatchingLine(
|
|
7206
|
+
repoPath,
|
|
7207
|
+
unsortedSignFile,
|
|
7208
|
+
UNSORTED_JSON_SIGN_PATTERN
|
|
7209
|
+
);
|
|
5285
7210
|
findings.push({
|
|
5286
|
-
severity: "warning",
|
|
5287
|
-
summary: "A signature/HMAC appears computed directly over JSON.stringify output with no canonical key ordering in the same file \u2014 signatures may not verify across equivalent payloads.",
|
|
5288
|
-
evidence:
|
|
7211
|
+
severity: isTestPath ? "info" : "warning",
|
|
7212
|
+
summary: isTestPath ? `Signing over unsorted JSON serialization appears in a test/fixture file (${unsortedSignFile}) \u2014 likely a test assertion, not a production signing gap; verify.` : "A signature/HMAC appears computed directly over JSON.stringify output with no canonical key ordering in the same file \u2014 signatures may not verify across equivalent payloads.",
|
|
7213
|
+
evidence: evidenceForRelativeAtLine(
|
|
5289
7214
|
repoPath,
|
|
5290
7215
|
unsortedSignFile,
|
|
5291
7216
|
"artifact",
|
|
5292
|
-
"Signing over unsorted JSON serialization"
|
|
7217
|
+
"Signing over unsorted JSON serialization",
|
|
7218
|
+
unsortedSignLine
|
|
5293
7219
|
)
|
|
5294
7220
|
});
|
|
5295
7221
|
}
|
|
@@ -5305,7 +7231,7 @@ function collectA3ProdReadinessEvidence(repoPath, repoFiles) {
|
|
|
5305
7231
|
const evidence = [];
|
|
5306
7232
|
const findings = [];
|
|
5307
7233
|
const packageJson = findRootPackageJson(repoFiles);
|
|
5308
|
-
const scripts = packageJson ? readPackageScripts(
|
|
7234
|
+
const scripts = packageJson ? readPackageScripts(join3(repoPath, packageJson)) : /* @__PURE__ */ new Map();
|
|
5309
7235
|
const workflows = repoFiles.filter(isCiWorkflow);
|
|
5310
7236
|
const workflow = workflows[0];
|
|
5311
7237
|
const deployConfigs = repoFiles.filter(isDeployConfig);
|
|
@@ -5579,45 +7505,6 @@ function hasDeclaredVersionConstraint(dependency) {
|
|
|
5579
7505
|
return /^v?\d/.test(trimmed);
|
|
5580
7506
|
}
|
|
5581
7507
|
function collectA5ClaimRealityEvidence(repoPath, repoFiles) {
|
|
5582
|
-
const alfredEvidence = [];
|
|
5583
|
-
if (alfredEvidence.length > 0) {
|
|
5584
|
-
const claimStats = readClaimRealityStats(repoPath);
|
|
5585
|
-
return {
|
|
5586
|
-
criterionId: "A5",
|
|
5587
|
-
positiveEvidence: alfredEvidence,
|
|
5588
|
-
findings: [],
|
|
5589
|
-
metrics: [
|
|
5590
|
-
metric(
|
|
5591
|
-
"claim_match_rate",
|
|
5592
|
-
"Claim match rate",
|
|
5593
|
-
claimStats?.matchRate ?? 0,
|
|
5594
|
-
1,
|
|
5595
|
-
0.6,
|
|
5596
|
-
"ratio",
|
|
5597
|
-
"Measures supported and partially supported claims in the structured reconciliation artifact."
|
|
5598
|
-
),
|
|
5599
|
-
metric(
|
|
5600
|
-
"claim_registry_depth",
|
|
5601
|
-
"Claim registry depth",
|
|
5602
|
-
claimStats?.claimCount ?? 0,
|
|
5603
|
-
Math.max(claimStats?.claimCount ?? 0, 8),
|
|
5604
|
-
0.25,
|
|
5605
|
-
"claims",
|
|
5606
|
-
"Credits the number of concrete claims reconciled without giving unlimited credit for one artifact."
|
|
5607
|
-
),
|
|
5608
|
-
metric(
|
|
5609
|
-
"reconciliation_artifact_depth",
|
|
5610
|
-
"Reconciliation artifact depth",
|
|
5611
|
-
alfredEvidence.length,
|
|
5612
|
-
3,
|
|
5613
|
-
0.15,
|
|
5614
|
-
"artifacts",
|
|
5615
|
-
"Credits implementation, Markdown, and structured reconciliation artifacts."
|
|
5616
|
-
)
|
|
5617
|
-
],
|
|
5618
|
-
notes: "A5 is evidenced by deterministic claim-vs-reality implementation and report artifacts, not a model-opinion verdict."
|
|
5619
|
-
};
|
|
5620
|
-
}
|
|
5621
7508
|
const claimDoc = repoFiles.find((file) => /(^|\/)(README|readme)\.md$/.test(file)) ?? repoFiles.find((file) => /(^|\/)docs\/.*\.(md|mdx)$/.test(file));
|
|
5622
7509
|
if (!claimDoc) {
|
|
5623
7510
|
return buildNotApplicableSignal(
|
|
@@ -5778,7 +7665,7 @@ function collectB2PrTraceEvidence(repoPath, repoFiles) {
|
|
|
5778
7665
|
function collectB3CiDisciplineEvidence(repoPath, repoFiles, mono) {
|
|
5779
7666
|
const evidence = [];
|
|
5780
7667
|
const packageJson = findRootPackageJson(repoFiles);
|
|
5781
|
-
const scripts = packageJson ? readPackageScripts(
|
|
7668
|
+
const scripts = packageJson ? readPackageScripts(join3(repoPath, packageJson)) : /* @__PURE__ */ new Map();
|
|
5782
7669
|
const workflows = repoFiles.filter(isCiWorkflow);
|
|
5783
7670
|
const workflow = workflows[0];
|
|
5784
7671
|
const rootWorkflows = mono ? mono.sharedFiles.filter(isCiWorkflow) : [];
|
|
@@ -6044,11 +7931,20 @@ function collectB6PrivilegedOpsGatingEvidence(repoPath, repoFiles) {
|
|
|
6044
7931
|
var CPP_TEST_FRAMEWORK_PATTERN = /<gtest\/gtest\.h>|<catch2\/|<doctest\/|<boost\/test\/|"gtest\/gtest\.h"|"catch2\//;
|
|
6045
7932
|
var CPP_TEST_MACRO_PATTERN = /\bTEST\s*\(|\bTEST_F\s*\(|\bTEST_CASE\s*\(|\bSECTION\s*\(|\bCATCH_|BOOST_AUTO_TEST_CASE\b|BOOST_FIXTURE_TEST_CASE\b/;
|
|
6046
7933
|
var CPP_CONTENT_SCAN_LIMIT = 150;
|
|
6047
|
-
var
|
|
6048
|
-
var
|
|
7934
|
+
var NON_PRODUCTION_DIR_PATTERN = /(^|\/)(__tests__|__mocks__|__fixtures__|tests?|fixtures?|testdata|e2e|cypress|examples?|samples?|demos?)(\/|$)/i;
|
|
7935
|
+
var NON_PRODUCTION_FILE_SUFFIX_PATTERN = /\.(test|spec|stories)\.[^/]+$/i;
|
|
6049
7936
|
function isTestOrFixturePath(path) {
|
|
6050
|
-
return
|
|
7937
|
+
return NON_PRODUCTION_DIR_PATTERN.test(path) || NON_PRODUCTION_FILE_SUFFIX_PATTERN.test(path);
|
|
7938
|
+
}
|
|
7939
|
+
function isProductionSourcePath(path) {
|
|
7940
|
+
return !isTestOrFixturePath(path);
|
|
7941
|
+
}
|
|
7942
|
+
function isTestFile(file) {
|
|
7943
|
+
return /(^|\/)(__tests__|test|tests|spec)\/.*\.(?:[cm]?[jt]sx?|py|go|rs|java|rb|cpp|cc|cxx)$/.test(
|
|
7944
|
+
file
|
|
7945
|
+
) || /\.(test|spec)\.[cm]?[jt]sx?$/.test(file) || /(^|\/)test_.*\.py$/.test(file) || /_test\.go$/.test(file) || /(^|\/)test_.*\.(cpp|cc|cxx)$/.test(file) || /_(test|tests)\.(cpp|cc|cxx)$/.test(file) || /Tests?\.(java|kt)$/.test(file) || /(_test|_spec)\.(rs|rb|php|swift|kt)$/.test(file);
|
|
6051
7946
|
}
|
|
7947
|
+
var NAME_SHAPED_TEST_FILE_PATTERN = /\.(test|spec)\.[cm]?[jt]sx?$|(^|\/)__tests__\/|(^|\/)test_[^/]*\.py$|(^|\/)tests?\.py$|_test\.go$|(^|\/)test_[^/]*\.(cpp|cc|cxx)$|_(test|tests)\.(cpp|cc|cxx)$|Tests?\.(java|kt)$|(_test|_spec)\.(rs|rb|php|swift|kt)$/;
|
|
6052
7948
|
var TEST_RUNNER_PATTERN = /\b(vitest|jest|mocha|ava|tap|pytest|go test|cargo test|rspec|phpunit|gradle test|mvn test)\b/i;
|
|
6053
7949
|
var CI_TEST_COMMAND_PATTERN = /\b(pytest|go\s+test|cargo\s+test|mvn\s+test|gradle\s+test|ctest|make\s+test|jest|vitest|mocha|rspec|phpunit|pnpm\s+test|npm\s+test|yarn\s+test|node\s+--test|node:test)\b/i;
|
|
6054
7950
|
var CI_LINT_COMMAND_PATTERN = /\b(eslint|pylint|flake8|black|ruff)\b/i;
|
|
@@ -6081,7 +7977,28 @@ var HEAVY_TEST_DEPENDENCY_NAME_PATTERN = /^(?:jest|mocha|ava|tape|jasmine|karma)
|
|
|
6081
7977
|
var TIMING_SAFE_COMPARE_PATTERN = /\btiming[-_]?safe[-_]?(?:equal|compare)\b|crypto\.timingSafeEqual\s*\(/i;
|
|
6082
7978
|
var CANONICAL_SERIALIZE_PATTERN = /\bcanonicalize\s*\(|\bcanonicalJson\b|\bstableStringify\s*\(|json-stable-stringify|safe-stable-stringify|\bsortKeys\s*\(/i;
|
|
6083
7979
|
var SIGN_OR_HMAC_CALL_PATTERN = /\bcreateHmac\s*\(|\bcreateSign\s*\(|\.sign\s*\(/;
|
|
6084
|
-
var
|
|
7980
|
+
var INSECURE_SECRET_COMPARE_LINE_PATTERN = /\b\w*(?:hmac|signature|\bmac|digest)\w*\s*(===|!==)\s*(?!['"`]|undefined\b|null\b)([\w.]+(?:\s*[-+]\s*\d+)?)/i;
|
|
7981
|
+
var NUMERIC_SHAPED_OPERAND_PATTERN = /^-?\d+$|\.(?:length|len|size|count)\b|(?:length|index|idx|offset|count|size|len)$/i;
|
|
7982
|
+
function lineHasInsecureSecretCompare(line) {
|
|
7983
|
+
const match = INSECURE_SECRET_COMPARE_LINE_PATTERN.exec(line);
|
|
7984
|
+
const operand = match?.[2];
|
|
7985
|
+
if (!operand) return false;
|
|
7986
|
+
return !NUMERIC_SHAPED_OPERAND_PATTERN.test(operand.trim());
|
|
7987
|
+
}
|
|
7988
|
+
function findInsecureSecretCompareLine(repoPath, file) {
|
|
7989
|
+
const fullPath = join3(repoPath, file);
|
|
7990
|
+
if (!isRegularFile(fullPath)) return null;
|
|
7991
|
+
const lines = readFileSync6(fullPath, "utf8").split("\n");
|
|
7992
|
+
const index = lines.findIndex((line) => lineHasInsecureSecretCompare(line));
|
|
7993
|
+
return index === -1 ? null : index + 1;
|
|
7994
|
+
}
|
|
7995
|
+
function findFirstMatchingLine(repoPath, file, pattern) {
|
|
7996
|
+
const fullPath = join3(repoPath, file);
|
|
7997
|
+
if (!isRegularFile(fullPath)) return null;
|
|
7998
|
+
const lines = readFileSync6(fullPath, "utf8").split("\n");
|
|
7999
|
+
const index = lines.findIndex((line) => pattern.test(line));
|
|
8000
|
+
return index === -1 ? null : index + 1;
|
|
8001
|
+
}
|
|
6085
8002
|
var UNSORTED_JSON_SIGN_PATTERN = /\.update\s*\(\s*JSON\.stringify\s*\(|\.sign\s*\([^)]*JSON\.stringify\s*\(/;
|
|
6086
8003
|
var KILL_SWITCH_NAME_FRAGMENT = "kill[_-]?switch|emergency[_-]?stop|circuit[_-]?breaker|safety[_-]?(?:toggle|gate|switch)|governance[_-]?(?:toggle|gate)";
|
|
6087
8004
|
var KILL_SWITCH_NAME_PATTERN = new RegExp(`\\b(?:${KILL_SWITCH_NAME_FRAGMENT})\\b`, "i");
|
|
@@ -6193,13 +8110,13 @@ function listGitTrackedFiles(repoPath) {
|
|
|
6193
8110
|
function visitRepoDir(repoPath, dirPath, files) {
|
|
6194
8111
|
let entries;
|
|
6195
8112
|
try {
|
|
6196
|
-
entries =
|
|
8113
|
+
entries = readdirSync3(dirPath, { withFileTypes: true });
|
|
6197
8114
|
} catch {
|
|
6198
8115
|
return;
|
|
6199
8116
|
}
|
|
6200
8117
|
for (const entry of entries) {
|
|
6201
8118
|
if (shouldSkipDir(entry.name)) continue;
|
|
6202
|
-
const fullPath =
|
|
8119
|
+
const fullPath = join3(dirPath, entry.name);
|
|
6203
8120
|
if (entry.isDirectory()) {
|
|
6204
8121
|
visitRepoDir(repoPath, fullPath, files);
|
|
6205
8122
|
continue;
|
|
@@ -6207,7 +8124,7 @@ function visitRepoDir(repoPath, dirPath, files) {
|
|
|
6207
8124
|
if (!entry.isFile()) continue;
|
|
6208
8125
|
let size;
|
|
6209
8126
|
try {
|
|
6210
|
-
size =
|
|
8127
|
+
size = statSync2(fullPath).size;
|
|
6211
8128
|
} catch {
|
|
6212
8129
|
continue;
|
|
6213
8130
|
}
|
|
@@ -6235,17 +8152,12 @@ function shouldSkipDir(name) {
|
|
|
6235
8152
|
function isHardExcludedPath(path) {
|
|
6236
8153
|
return HARD_EXCLUDED_PATH_PATTERN.test(path);
|
|
6237
8154
|
}
|
|
6238
|
-
function isTestFile(file) {
|
|
6239
|
-
return /(^|\/)(__tests__|test|tests|spec)\/.*\.(?:[cm]?[jt]sx?|py|go|rs|java|rb|cpp|cc|cxx)$/.test(
|
|
6240
|
-
file
|
|
6241
|
-
) || /\.(test|spec)\.[cm]?[jt]sx?$/.test(file) || /(^|\/)test_.*\.py$/.test(file) || /_test\.go$/.test(file) || /(^|\/)test_.*\.(cpp|cc|cxx)$/.test(file) || /_(test|tests)\.(cpp|cc|cxx)$/.test(file) || /Tests?\.(java|kt)$/.test(file) || /(_test|_spec)\.(rs|rb|php|swift|kt)$/.test(file);
|
|
6242
|
-
}
|
|
6243
8155
|
function collectContentBasedCppTestFiles(repoPath, repoFiles) {
|
|
6244
8156
|
const candidates = repoFiles.filter((file) => /\.(cpp|cc|cxx)$/.test(file) && !isTestFile(file)).slice(0, CPP_CONTENT_SCAN_LIMIT);
|
|
6245
8157
|
return candidates.filter((file) => {
|
|
6246
|
-
const fullPath =
|
|
8158
|
+
const fullPath = join3(repoPath, file);
|
|
6247
8159
|
if (!isRegularFile(fullPath)) return false;
|
|
6248
|
-
const contents =
|
|
8160
|
+
const contents = readFileSync6(fullPath, "utf8");
|
|
6249
8161
|
return CPP_TEST_FRAMEWORK_PATTERN.test(contents) || CPP_TEST_MACRO_PATTERN.test(contents);
|
|
6250
8162
|
});
|
|
6251
8163
|
}
|
|
@@ -6259,14 +8171,13 @@ var JS_TEST_ASSERTION_PATTERN = /(expect\(|assert\.|should\.|toEqual\(|toBe\(|as
|
|
|
6259
8171
|
var CPP_TEST_ASSERTION_PATTERN = /\bEXPECT_|ASSERT_EQ\b|ASSERT_TRUE\b|ASSERT_FALSE\b|\bREQUIRE\s*\(|\bCHECK\s*\(|\bTEST\s*\(|\bTEST_F\s*\(|\bTEST_CASE\s*\(|\bSECTION\s*\(/;
|
|
6260
8172
|
var MULTI_ECOSYSTEM_TEST_ASSERTION_PATTERN = /\.assert[A-Z_]\w*\s*\(|\bassert[A-Z]\w*\s*\(|\bpytest\.raises\b|\bself\.fail\s*\(|\bt\.(?:Error|Errorf|Fatal|Fatalf|Fail|FailNow)\b|\brequire\.[A-Z]\w*\s*\(|\b(?:debug_)?assert(?:_eq|_ne)?!\s*\(|\bassert_\w+\b|\$this->assert\w+\s*\(/;
|
|
6261
8173
|
var SUITE_LEVEL_SKIP_PATTERN = /\b(?:describe|suite|context)\.skip\s*\(/;
|
|
6262
|
-
var NAME_SHAPED_TEST_FILE_PATTERN = /\.(test|spec)\.[cm]?[jt]sx?$|(^|\/)__tests__\/|(^|\/)test_[^/]*\.py$|(^|\/)tests?\.py$|_test\.go$|(^|\/)test_[^/]*\.(cpp|cc|cxx)$|_(test|tests)\.(cpp|cc|cxx)$|Tests?\.(java|kt)$|(_test|_spec)\.(rs|rb|php|swift|kt)$/;
|
|
6263
8174
|
function measureNonHollowTestShare(repoPath, files) {
|
|
6264
8175
|
let nonHollowCount = 0;
|
|
6265
8176
|
let ratedCount = 0;
|
|
6266
8177
|
for (const file of files) {
|
|
6267
|
-
const fullPath =
|
|
8178
|
+
const fullPath = join3(repoPath, file);
|
|
6268
8179
|
if (!isRegularFile(fullPath)) continue;
|
|
6269
|
-
const contents =
|
|
8180
|
+
const contents = readFileSync6(fullPath, "utf8");
|
|
6270
8181
|
const nonHollow = (JS_TEST_ASSERTION_PATTERN.test(contents) || CPP_TEST_ASSERTION_PATTERN.test(contents) || MULTI_ECOSYSTEM_TEST_ASSERTION_PATTERN.test(contents)) && !SUITE_LEVEL_SKIP_PATTERN.test(contents);
|
|
6271
8182
|
if (nonHollow) {
|
|
6272
8183
|
nonHollowCount += 1;
|
|
@@ -6285,17 +8196,17 @@ function countPatternMatches(repoPath, files, pattern) {
|
|
|
6285
8196
|
const matcher = new RegExp(pattern.source, flags);
|
|
6286
8197
|
let count = 0;
|
|
6287
8198
|
for (const file of files) {
|
|
6288
|
-
const fullPath =
|
|
8199
|
+
const fullPath = join3(repoPath, file);
|
|
6289
8200
|
if (!isRegularFile(fullPath)) continue;
|
|
6290
|
-
count += [...
|
|
8201
|
+
count += [...readFileSync6(fullPath, "utf8").matchAll(matcher)].length;
|
|
6291
8202
|
}
|
|
6292
8203
|
return count;
|
|
6293
8204
|
}
|
|
6294
8205
|
function readCoveragePercent(repoPath, files) {
|
|
6295
8206
|
for (const file of files) {
|
|
6296
|
-
const fullPath =
|
|
8207
|
+
const fullPath = join3(repoPath, file);
|
|
6297
8208
|
if (!isRegularFile(fullPath)) continue;
|
|
6298
|
-
const contents =
|
|
8209
|
+
const contents = readFileSync6(fullPath, "utf8");
|
|
6299
8210
|
const summaryPercent = parseCoverageSummaryPercent(contents);
|
|
6300
8211
|
if (summaryPercent !== null) return summaryPercent;
|
|
6301
8212
|
const thresholdPercent = parseCoverageThresholdPercent(contents);
|
|
@@ -6339,7 +8250,7 @@ function pickPrimaryDependencyManifest(repoPath, manifests) {
|
|
|
6339
8250
|
function readDependencySpecs(repoPath, manifests) {
|
|
6340
8251
|
const specs = [];
|
|
6341
8252
|
for (const manifest of manifests) {
|
|
6342
|
-
const fullPath =
|
|
8253
|
+
const fullPath = join3(repoPath, manifest);
|
|
6343
8254
|
if (!isRegularFile(fullPath)) continue;
|
|
6344
8255
|
if (manifest.endsWith("package.json")) {
|
|
6345
8256
|
specs.push(...readPackageJsonDependencySpecs(fullPath));
|
|
@@ -6385,7 +8296,7 @@ function readDependencySpecs(repoPath, manifests) {
|
|
|
6385
8296
|
}
|
|
6386
8297
|
function readGoModDependencySpecs(path) {
|
|
6387
8298
|
const specs = [];
|
|
6388
|
-
const contents =
|
|
8299
|
+
const contents = readFileSync6(path, "utf8");
|
|
6389
8300
|
const blockPattern = /require\s*\(([^)]+)\)/gs;
|
|
6390
8301
|
const singlePattern = /^require\s+(\S+)\s+(\S+)/gm;
|
|
6391
8302
|
for (const blockMatch of contents.matchAll(blockPattern)) {
|
|
@@ -6406,7 +8317,7 @@ function readGoModDependencySpecs(path) {
|
|
|
6406
8317
|
}
|
|
6407
8318
|
function readCargoTomlDependencySpecs(path) {
|
|
6408
8319
|
const specs = [];
|
|
6409
|
-
const contents =
|
|
8320
|
+
const contents = readFileSync6(path, "utf8");
|
|
6410
8321
|
const depSectionPattern = /^\[(?:dependencies|dev-dependencies|build-dependencies)\]([\s\S]*?)(?=^\[|(?![\s\S]))/gm;
|
|
6411
8322
|
for (const sectionMatch of contents.matchAll(depSectionPattern)) {
|
|
6412
8323
|
const section = sectionMatch[1] ?? "";
|
|
@@ -6428,7 +8339,7 @@ function readCargoTomlDependencySpecs(path) {
|
|
|
6428
8339
|
}
|
|
6429
8340
|
function readPyprojectDependencySpecs(path) {
|
|
6430
8341
|
const specs = [];
|
|
6431
|
-
const contents =
|
|
8342
|
+
const contents = readFileSync6(path, "utf8");
|
|
6432
8343
|
const poetrySectionPattern = /^\[tool\.poetry\.dependencies\]([\s\S]*?)(?=^\[|(?![\s\S]))/gm;
|
|
6433
8344
|
for (const sectionMatch of contents.matchAll(poetrySectionPattern)) {
|
|
6434
8345
|
const section = sectionMatch[1] ?? "";
|
|
@@ -6462,7 +8373,7 @@ function readPyprojectDependencySpecs(path) {
|
|
|
6462
8373
|
}
|
|
6463
8374
|
function readPipfileDependencySpecs(path) {
|
|
6464
8375
|
const specs = [];
|
|
6465
|
-
const contents =
|
|
8376
|
+
const contents = readFileSync6(path, "utf8");
|
|
6466
8377
|
const sectionPattern = /^\[(?:packages|dev-packages)\]([\s\S]*?)(?=^\[|$(?![\s\S]))/gm;
|
|
6467
8378
|
for (const sectionMatch of contents.matchAll(sectionPattern)) {
|
|
6468
8379
|
for (const line of (sectionMatch[1] ?? "").split("\n")) {
|
|
@@ -6475,7 +8386,7 @@ function readPipfileDependencySpecs(path) {
|
|
|
6475
8386
|
return specs;
|
|
6476
8387
|
}
|
|
6477
8388
|
function readVcpkgJsonDependencySpecs(path) {
|
|
6478
|
-
const parsed = parseJsonObject(
|
|
8389
|
+
const parsed = parseJsonObject(readFileSync6(path, "utf8"));
|
|
6479
8390
|
if (!parsed) return [];
|
|
6480
8391
|
const rawDeps = Array.isArray(parsed.dependencies) ? parsed.dependencies : [];
|
|
6481
8392
|
const specs = [];
|
|
@@ -6491,7 +8402,7 @@ function readVcpkgJsonDependencySpecs(path) {
|
|
|
6491
8402
|
}
|
|
6492
8403
|
function readConanfileTxtDependencySpecs(path) {
|
|
6493
8404
|
const specs = [];
|
|
6494
|
-
const contents =
|
|
8405
|
+
const contents = readFileSync6(path, "utf8");
|
|
6495
8406
|
const requiresMatch = /^\[requires\]([\s\S]*?)(?=^\[|$(?![\s\S]))/m.exec(contents);
|
|
6496
8407
|
if (!requiresMatch) return specs;
|
|
6497
8408
|
for (const line of (requiresMatch[1] ?? "").split("\n")) {
|
|
@@ -6504,7 +8415,7 @@ function readConanfileTxtDependencySpecs(path) {
|
|
|
6504
8415
|
}
|
|
6505
8416
|
function readConanfilePyDependencySpecs(path) {
|
|
6506
8417
|
const specs = [];
|
|
6507
|
-
const contents =
|
|
8418
|
+
const contents = readFileSync6(path, "utf8");
|
|
6508
8419
|
for (const match of contents.matchAll(/self\.requires\s*\(\s*["']([\w.\-]+)\/([\w.\-]+)["']/g)) {
|
|
6509
8420
|
specs.push({ name: match[1] ?? "", version: match[2] ?? "" });
|
|
6510
8421
|
}
|
|
@@ -6518,7 +8429,7 @@ function readConanfilePyDependencySpecs(path) {
|
|
|
6518
8429
|
}
|
|
6519
8430
|
function readCMakeDependencySpecs(path) {
|
|
6520
8431
|
const specs = [];
|
|
6521
|
-
const contents =
|
|
8432
|
+
const contents = readFileSync6(path, "utf8");
|
|
6522
8433
|
for (const match of contents.matchAll(/find_package\s*\(\s*([\w]+)(?:\s+([\d.]+))?/gi)) {
|
|
6523
8434
|
const name = match[1];
|
|
6524
8435
|
if (!name) continue;
|
|
@@ -6533,7 +8444,7 @@ function readCMakeDependencySpecs(path) {
|
|
|
6533
8444
|
return specs;
|
|
6534
8445
|
}
|
|
6535
8446
|
function readPackageJsonDependencySpecs(packageJsonPath) {
|
|
6536
|
-
const parsed = parseJsonObject(
|
|
8447
|
+
const parsed = parseJsonObject(readFileSync6(packageJsonPath, "utf8"));
|
|
6537
8448
|
if (!parsed) return [];
|
|
6538
8449
|
const optionalPeerNames = /* @__PURE__ */ new Set();
|
|
6539
8450
|
const peerDependenciesMeta = parsed.peerDependenciesMeta;
|
|
@@ -6560,7 +8471,7 @@ function readPackageJsonDependencySpecs(packageJsonPath) {
|
|
|
6560
8471
|
return specs;
|
|
6561
8472
|
}
|
|
6562
8473
|
function readRequirementsDependencySpecs(path) {
|
|
6563
|
-
return
|
|
8474
|
+
return readFileSync6(path, "utf8").split("\n").map((line) => line.trim()).filter((line) => line.length > 0 && !line.startsWith("#")).map((line) => {
|
|
6564
8475
|
const [name = line, version = ""] = line.split(/[<>=~!]=?/, 2);
|
|
6565
8476
|
return { name: name.trim(), version: line.includes("==") ? version.trim() : line };
|
|
6566
8477
|
});
|
|
@@ -6575,33 +8486,10 @@ function isPinnedDependencyVersion(version) {
|
|
|
6575
8486
|
if (trimmed === "find") return false;
|
|
6576
8487
|
return /^\d+\.\d+(?:\.\d+)?(?:[-+][0-9A-Za-z.-]+)?$/.test(trimmed);
|
|
6577
8488
|
}
|
|
6578
|
-
function readClaimRealityStats(repoPath) {
|
|
6579
|
-
const path = join(repoPath, "docs/witan/claim_reality_reconciliation.json");
|
|
6580
|
-
if (!isRegularFile(path)) return null;
|
|
6581
|
-
const parsed = parseJsonObject(readFileSync(path, "utf8"));
|
|
6582
|
-
const claims = Array.isArray(parsed?.claims) ? parsed.claims : [];
|
|
6583
|
-
if (claims.length === 0) return null;
|
|
6584
|
-
const totalScore = claims.reduce((sum, claim) => {
|
|
6585
|
-
if (!isRecord(claim) || typeof claim.status !== "string") return sum;
|
|
6586
|
-
return sum + scoreClaimRealityStatus(claim.status);
|
|
6587
|
-
}, 0);
|
|
6588
|
-
return {
|
|
6589
|
-
claimCount: claims.length,
|
|
6590
|
-
matchRate: Math.round(totalScore / claims.length * 1e3) / 1e3
|
|
6591
|
-
};
|
|
6592
|
-
}
|
|
6593
|
-
function scoreClaimRealityStatus(status) {
|
|
6594
|
-
const normalized = status.toLowerCase();
|
|
6595
|
-
if (/supported|verified|matched|true/.test(normalized) && !/unsupported/.test(normalized)) {
|
|
6596
|
-
return 1;
|
|
6597
|
-
}
|
|
6598
|
-
if (/partial|mixed|needs[-_ ]?evidence/.test(normalized)) return 0.5;
|
|
6599
|
-
return 0;
|
|
6600
|
-
}
|
|
6601
8489
|
function workflowTargetsDefaultBranch(repoPath, file) {
|
|
6602
|
-
const fullPath =
|
|
8490
|
+
const fullPath = join3(repoPath, file);
|
|
6603
8491
|
if (!isRegularFile(fullPath)) return false;
|
|
6604
|
-
const contents =
|
|
8492
|
+
const contents = readFileSync6(fullPath, "utf8").toLowerCase();
|
|
6605
8493
|
return /\bpull_request\b/.test(contents) || /\bbranches:\s*\[[^\]]*\b(main|master)\b[^\]]*\]/.test(contents) || /\bbranches:\s*\n\s*-\s*(main|master)\b/.test(contents);
|
|
6606
8494
|
}
|
|
6607
8495
|
function isPrMergeCommit(commit) {
|
|
@@ -6637,7 +8525,6 @@ function isExplicitDeployTarget(file) {
|
|
|
6637
8525
|
return /^(vercel|netlify|fly|render|railway)\.(json|toml|ya?ml)$/.test(file) || /^docker-compose\.ya?ml$/.test(file) || /^Procfile$/.test(file) || /^app\.ya?ml$/.test(file) || /^serverless\.ya?ml$/.test(file) || /^(k8s|kubernetes|manifests?)\/.+\.ya?ml$/i.test(file) || /^(charts?|helm)\/.+\.ya?ml$/i.test(file);
|
|
6638
8526
|
}
|
|
6639
8527
|
var MAIN_ENTRYPOINT_FILE_PATTERN = /(^|\/)(main|server|app|wsgi|asgi|index|entry|start|run)\.(ts|tsx|js|jsx|mjs|cjs|py|go|rs)$/i;
|
|
6640
|
-
var EXAMPLE_OR_TEST_DIR_PATTERN = /(?:^|\/)(examples?|samples?|demos?|tests?|__tests__|spec|fixtures?)(?:\/|$)/i;
|
|
6641
8528
|
var SERVER_ENTRYPOINT_PATTERN = /\bapp\.listen\s*\(|\bserver\.listen\s*\(\s*(?:PORT|port|\d+)|http\.ListenAndServe\s*\(|http\.ListenAndServeTLS\s*\(|axum::Server(?:::|\.)|actix_web::HttpServer(?:::|\.)|uvicorn\.run\s*\(/;
|
|
6642
8529
|
var CI_DEPLOY_JOB_PATTERN = /(?:^\s{2,4}deploy\s*:|\b(?:fly|heroku|vercel|netlify|railway|render)\s+deploy\b|kubectl\s+apply\b|helm\s+(?:install|upgrade|deploy)\b|docker\s+push\b)/im;
|
|
6643
8530
|
function isDeployableService(repoPath, repoFiles) {
|
|
@@ -6654,9 +8541,7 @@ function detectServerEntrypoint(repoPath, repoFiles) {
|
|
|
6654
8541
|
return findServerEntrypointFile(repoPath, repoFiles) !== null;
|
|
6655
8542
|
}
|
|
6656
8543
|
function findServerEntrypointFile(repoPath, repoFiles) {
|
|
6657
|
-
const candidates = repoFiles.filter(
|
|
6658
|
-
(file) => MAIN_ENTRYPOINT_FILE_PATTERN.test(file) && !EXAMPLE_OR_TEST_DIR_PATTERN.test(file)
|
|
6659
|
-
).slice(0, 30);
|
|
8544
|
+
const candidates = repoFiles.filter((file) => MAIN_ENTRYPOINT_FILE_PATTERN.test(file) && isProductionSourcePath(file)).slice(0, 30);
|
|
6660
8545
|
return candidates.find((file) => fileContains(repoPath, file, SERVER_ENTRYPOINT_PATTERN)) ?? null;
|
|
6661
8546
|
}
|
|
6662
8547
|
function isHealthCheckSignalFile(repoPath, file) {
|
|
@@ -6688,15 +8573,15 @@ function isDependencyUpdateConfig(file) {
|
|
|
6688
8573
|
}
|
|
6689
8574
|
function packageJsonHasAuditScript(repoPath, manifest) {
|
|
6690
8575
|
if (!manifest.endsWith("package.json")) return false;
|
|
6691
|
-
const scripts = readPackageScripts(
|
|
8576
|
+
const scripts = readPackageScripts(join3(repoPath, manifest));
|
|
6692
8577
|
return [...scripts.values()].some(
|
|
6693
8578
|
(script) => /\b(audit|npm audit|pnpm audit|yarn audit)\b/i.test(script)
|
|
6694
8579
|
);
|
|
6695
8580
|
}
|
|
6696
8581
|
function packageJsonHasHeavyTestDependency(repoPath, manifest) {
|
|
6697
|
-
const fullPath =
|
|
8582
|
+
const fullPath = join3(repoPath, manifest);
|
|
6698
8583
|
if (!isRegularFile(fullPath)) return false;
|
|
6699
|
-
const parsed = parseJsonObject(
|
|
8584
|
+
const parsed = parseJsonObject(readFileSync6(fullPath, "utf8"));
|
|
6700
8585
|
if (!parsed) return false;
|
|
6701
8586
|
const names = [
|
|
6702
8587
|
...Object.keys(isRecord(parsed.dependencies) ? parsed.dependencies : {}),
|
|
@@ -6735,20 +8620,20 @@ function findRootPackageJson(repoFiles) {
|
|
|
6735
8620
|
}
|
|
6736
8621
|
function isRegularFile(path) {
|
|
6737
8622
|
try {
|
|
6738
|
-
return
|
|
8623
|
+
return statSync2(path).isFile();
|
|
6739
8624
|
} catch {
|
|
6740
8625
|
return false;
|
|
6741
8626
|
}
|
|
6742
8627
|
}
|
|
6743
8628
|
function fileContains(repoPath, file, pattern) {
|
|
6744
|
-
const fullPath =
|
|
8629
|
+
const fullPath = join3(repoPath, file);
|
|
6745
8630
|
if (!isRegularFile(fullPath)) return false;
|
|
6746
|
-
return pattern.test(
|
|
8631
|
+
return pattern.test(readFileSync6(fullPath, "utf8"));
|
|
6747
8632
|
}
|
|
6748
8633
|
function fileContainsCommittedSecret(repoPath, file) {
|
|
6749
|
-
const fullPath =
|
|
8634
|
+
const fullPath = join3(repoPath, file);
|
|
6750
8635
|
if (!isRegularFile(fullPath)) return false;
|
|
6751
|
-
return containsRealSecret(
|
|
8636
|
+
return containsRealSecret(readFileSync6(fullPath, "utf8"));
|
|
6752
8637
|
}
|
|
6753
8638
|
function containsRealSecret(contents) {
|
|
6754
8639
|
SECRET_ASSIGNMENT_PATTERN.lastIndex = 0;
|
|
@@ -6802,1015 +8687,749 @@ function readCredentialHistoryEntries(repoPath) {
|
|
|
6802
8687
|
const key = `${entry.commit}:${entry.path}`;
|
|
6803
8688
|
if (seen.has(key)) return;
|
|
6804
8689
|
seen.add(key);
|
|
6805
|
-
entries.push(entry);
|
|
6806
|
-
};
|
|
6807
|
-
try {
|
|
6808
|
-
const commits = execFileSync("git", ["rev-list", "--all"], {
|
|
6809
|
-
cwd: repoPath,
|
|
6810
|
-
encoding: "utf8",
|
|
6811
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
6812
|
-
});
|
|
6813
|
-
const output = execFileSync(
|
|
6814
|
-
"git",
|
|
6815
|
-
[
|
|
6816
|
-
"diff-tree",
|
|
6817
|
-
"--stdin",
|
|
6818
|
-
"--root",
|
|
6819
|
-
"--name-only",
|
|
6820
|
-
"-r",
|
|
6821
|
-
"--diff-filter=AM",
|
|
6822
|
-
"--pretty=format:commit:%H"
|
|
6823
|
-
],
|
|
6824
|
-
{
|
|
6825
|
-
cwd: repoPath,
|
|
6826
|
-
encoding: "utf8",
|
|
6827
|
-
input: commits,
|
|
6828
|
-
stdio: ["pipe", "pipe", "ignore"]
|
|
6829
|
-
}
|
|
6830
|
-
);
|
|
6831
|
-
let currentCommit = null;
|
|
6832
|
-
for (const line of output.split("\n")) {
|
|
6833
|
-
if (line.startsWith("commit:")) {
|
|
6834
|
-
currentCommit = line.slice("commit:".length);
|
|
6835
|
-
continue;
|
|
6836
|
-
}
|
|
6837
|
-
const path = line.trim();
|
|
6838
|
-
if (!currentCommit || !path) continue;
|
|
6839
|
-
if (!isCredentialHistoryPath(path)) continue;
|
|
6840
|
-
appendEntry({ commit: currentCommit, path });
|
|
6841
|
-
}
|
|
6842
|
-
} catch {
|
|
6843
|
-
}
|
|
6844
|
-
for (const entry of readDeletedCredentialHistoryEntries(repoPath)) {
|
|
6845
|
-
appendEntry(entry);
|
|
6846
|
-
}
|
|
6847
|
-
return entries;
|
|
6848
|
-
}
|
|
6849
|
-
function readDeletedCredentialHistoryEntries(repoPath) {
|
|
6850
|
-
const deletedPaths = readDeletedCredentialHistoryPaths(repoPath);
|
|
6851
|
-
const entries = [];
|
|
6852
|
-
const seen = /* @__PURE__ */ new Set();
|
|
6853
|
-
for (const path of deletedPaths) {
|
|
6854
|
-
for (const commit of readHistoryCommitsForPath(repoPath, path)) {
|
|
6855
|
-
const key = `${commit}:${path}`;
|
|
6856
|
-
if (seen.has(key)) continue;
|
|
6857
|
-
seen.add(key);
|
|
6858
|
-
entries.push({ commit, path });
|
|
6859
|
-
}
|
|
6860
|
-
}
|
|
6861
|
-
return entries;
|
|
6862
|
-
}
|
|
6863
|
-
function readDeletedCredentialHistoryPaths(repoPath) {
|
|
6864
|
-
try {
|
|
6865
|
-
const output = execFileSync(
|
|
6866
|
-
"git",
|
|
6867
|
-
["log", "--all", "--diff-filter=D", "--name-status", "--format=commit:%H"],
|
|
6868
|
-
{
|
|
6869
|
-
cwd: repoPath,
|
|
6870
|
-
encoding: "utf8",
|
|
6871
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
6872
|
-
}
|
|
6873
|
-
);
|
|
6874
|
-
const paths = [];
|
|
6875
|
-
const seen = /* @__PURE__ */ new Set();
|
|
6876
|
-
for (const line of output.split("\n")) {
|
|
6877
|
-
if (!line.startsWith("D ")) continue;
|
|
6878
|
-
const path = line.slice(2).trim();
|
|
6879
|
-
if (!path || seen.has(path)) continue;
|
|
6880
|
-
if (!isCredentialHistoryPath(path)) continue;
|
|
6881
|
-
seen.add(path);
|
|
6882
|
-
paths.push(path);
|
|
6883
|
-
}
|
|
6884
|
-
return paths;
|
|
6885
|
-
} catch {
|
|
6886
|
-
return [];
|
|
6887
|
-
}
|
|
6888
|
-
}
|
|
6889
|
-
function readHistoryCommitsForPath(repoPath, path) {
|
|
6890
|
-
try {
|
|
6891
|
-
const output = execFileSync(
|
|
6892
|
-
"git",
|
|
6893
|
-
["log", "--all", "--diff-filter=AM", "--format=%H", "--", path],
|
|
6894
|
-
{
|
|
6895
|
-
cwd: repoPath,
|
|
6896
|
-
encoding: "utf8",
|
|
6897
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
6898
|
-
}
|
|
6899
|
-
);
|
|
6900
|
-
return output.split("\n").map((line) => line.trim()).filter((line) => /^[0-9a-f]{40}$/i.test(line));
|
|
6901
|
-
} catch {
|
|
6902
|
-
return [];
|
|
6903
|
-
}
|
|
6904
|
-
}
|
|
6905
|
-
function isCredentialHistoryPath(path) {
|
|
6906
|
-
if (isHardExcludedPath(path)) return false;
|
|
6907
|
-
const lowerPath = path.toLowerCase();
|
|
6908
|
-
const basename3 = lowerPath.split("/").at(-1) ?? lowerPath;
|
|
6909
|
-
if (/\.env(?:\.|$)/.test(basename3)) {
|
|
6910
|
-
return true;
|
|
6911
|
-
}
|
|
6912
|
-
return lowerPath.includes("secret") || lowerPath.includes("credential") || basename3.endsWith(".pem") || basename3.endsWith(".key") || basename3 === "id_rsa" || basename3.endsWith(".p12") || basename3.endsWith(".pfx");
|
|
6913
|
-
}
|
|
6914
|
-
function isEnvHistoryPath(path) {
|
|
6915
|
-
if (isEnvTemplatePath(path)) return false;
|
|
6916
|
-
const basename3 = path.toLowerCase().split("/").at(-1) ?? path.toLowerCase();
|
|
6917
|
-
return /\.env(?:\.|$)/.test(basename3);
|
|
6918
|
-
}
|
|
6919
|
-
function readGitBlob(repoPath, commit, path) {
|
|
6920
|
-
try {
|
|
6921
|
-
return execFileSync("git", ["show", `${commit}:${path}`], {
|
|
6922
|
-
cwd: repoPath,
|
|
6923
|
-
encoding: "utf8",
|
|
6924
|
-
maxBuffer: 512e3,
|
|
6925
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
6926
|
-
});
|
|
6927
|
-
} catch {
|
|
6928
|
-
return null;
|
|
6929
|
-
}
|
|
6930
|
-
}
|
|
6931
|
-
var ALL_CAPS_SNAKE_PLACEHOLDER_PATTERN = /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+$/;
|
|
6932
|
-
function isPlaceholderSecretValue(value) {
|
|
6933
|
-
const normalized = value.trim().toLowerCase();
|
|
6934
|
-
return PLACEHOLDER_SECRET_PATTERN.test(normalized) || normalized.includes("your-") || normalized.includes("example") || ALL_CAPS_SNAKE_PLACEHOLDER_PATTERN.test(value.trim()) || isSyntheticFixtureSecretValue(normalized) || isFillerRunSecretValue(normalized);
|
|
6935
|
-
}
|
|
6936
|
-
function isFillerRunSecretValue(value) {
|
|
6937
|
-
const candidates = [value];
|
|
6938
|
-
const sepIdx = Math.max(value.lastIndexOf("_"), value.lastIndexOf("-"));
|
|
6939
|
-
if (sepIdx > 0 && sepIdx < value.length - 1) {
|
|
6940
|
-
candidates.push(value.slice(sepIdx + 1));
|
|
6941
|
-
}
|
|
6942
|
-
for (const body of candidates) {
|
|
6943
|
-
if (body.length < 8) continue;
|
|
6944
|
-
const counts = /* @__PURE__ */ new Map();
|
|
6945
|
-
for (const ch of body) counts.set(ch, (counts.get(ch) ?? 0) + 1);
|
|
6946
|
-
const distinct = counts.size;
|
|
6947
|
-
const maxRun = Math.max(...counts.values());
|
|
6948
|
-
if (distinct <= 2 && maxRun / body.length >= 0.8) return true;
|
|
6949
|
-
}
|
|
6950
|
-
return false;
|
|
6951
|
-
}
|
|
6952
|
-
function isSyntheticFixtureSecretValue(value) {
|
|
6953
|
-
return value.includes("abcdefghijklmnopqrstuvwxyz") || value.includes("0123456789abcdefghijklmnopqrstuvwxyz") || value.includes("abcdefghijklmnopqrstuvwxyz0123456789") || value.includes("abcdefghijklmnopqrst");
|
|
6954
|
-
}
|
|
6955
|
-
function hasSuspiciousDependencies(repoPath, manifest) {
|
|
6956
|
-
if (!manifest.endsWith("package.json")) return false;
|
|
6957
|
-
const fullPath = join(repoPath, manifest);
|
|
6958
|
-
if (!isRegularFile(fullPath)) return false;
|
|
6959
|
-
const parsed = parseJsonObject(readFileSync(fullPath, "utf8"));
|
|
6960
|
-
if (!parsed) return false;
|
|
6961
|
-
const dependencies = isRecord(parsed.dependencies) ? parsed.dependencies : {};
|
|
6962
|
-
const devDependencies = isRecord(parsed.devDependencies) ? parsed.devDependencies : {};
|
|
6963
|
-
const names = [...Object.keys(dependencies), ...Object.keys(devDependencies)];
|
|
6964
|
-
return names.some(
|
|
6965
|
-
(name) => /^(todo|fake|placeholder|example)-|does-not-exist| hallucinated/i.test(name)
|
|
6966
|
-
);
|
|
6967
|
-
}
|
|
6968
|
-
function readRecentCommits(repoPath) {
|
|
6969
|
-
try {
|
|
6970
|
-
const output = execFileSync("git", ["log", "--max-count=12", "--format=%H%x00%s"], {
|
|
6971
|
-
cwd: repoPath,
|
|
6972
|
-
encoding: "utf8",
|
|
6973
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
6974
|
-
}).trim();
|
|
6975
|
-
if (!output) return [];
|
|
6976
|
-
return output.split("\n").map((line) => {
|
|
6977
|
-
const [sha = "", subject = ""] = line.split("\0");
|
|
6978
|
-
return { sha, subject };
|
|
6979
|
-
}).filter((commit) => commit.sha.length >= 7);
|
|
6980
|
-
} catch {
|
|
6981
|
-
return [];
|
|
6982
|
-
}
|
|
6983
|
-
}
|
|
6984
|
-
function readPackageScripts(packageJsonPath) {
|
|
6985
|
-
if (!isRegularFile(packageJsonPath)) return /* @__PURE__ */ new Map();
|
|
6986
|
-
const parsed = parseJsonObject(readFileSync(packageJsonPath, "utf8"));
|
|
6987
|
-
const scripts = parsed?.scripts;
|
|
6988
|
-
if (!isRecord(scripts)) return /* @__PURE__ */ new Map();
|
|
6989
|
-
return new Map(
|
|
6990
|
-
Object.entries(scripts).filter(
|
|
6991
|
-
(entry) => typeof entry[1] === "string"
|
|
6992
|
-
)
|
|
6993
|
-
);
|
|
6994
|
-
}
|
|
6995
|
-
function evidenceForRelative(repoPath, path, kind, label) {
|
|
6996
|
-
const fullPath = join(repoPath, path);
|
|
6997
|
-
const contents = isRegularFile(fullPath) ? readFileSync(fullPath, "utf8") : "";
|
|
6998
|
-
return {
|
|
6999
|
-
kind,
|
|
7000
|
-
label,
|
|
7001
|
-
path,
|
|
7002
|
-
...contents ? {
|
|
7003
|
-
line: firstMeaningfulLine(contents),
|
|
7004
|
-
contentHash: createHash("sha256").update(contents).digest("hex")
|
|
7005
|
-
} : {}
|
|
7006
|
-
};
|
|
7007
|
-
}
|
|
7008
|
-
function metric(name, label, value, max, weight, unit, description, kind) {
|
|
7009
|
-
return {
|
|
7010
|
-
name,
|
|
7011
|
-
label,
|
|
7012
|
-
value: Math.max(0, value),
|
|
7013
|
-
max,
|
|
7014
|
-
...kind ? { kind } : {},
|
|
7015
|
-
weight,
|
|
7016
|
-
unit,
|
|
7017
|
-
description
|
|
7018
|
-
};
|
|
7019
|
-
}
|
|
7020
|
-
function firstMeaningfulLine(contents) {
|
|
7021
|
-
const lines = contents.split("\n");
|
|
7022
|
-
const index = lines.findIndex((line) => line.trim().length > 0);
|
|
7023
|
-
return index === -1 ? 1 : index + 1;
|
|
7024
|
-
}
|
|
7025
|
-
function readGitHead(repoPath) {
|
|
8690
|
+
entries.push(entry);
|
|
8691
|
+
};
|
|
7026
8692
|
try {
|
|
7027
|
-
|
|
8693
|
+
const commits = execFileSync("git", ["rev-list", "--all"], {
|
|
7028
8694
|
cwd: repoPath,
|
|
7029
8695
|
encoding: "utf8",
|
|
7030
8696
|
stdio: ["ignore", "pipe", "ignore"]
|
|
7031
|
-
})
|
|
7032
|
-
} catch {
|
|
7033
|
-
return null;
|
|
7034
|
-
}
|
|
7035
|
-
}
|
|
7036
|
-
function hasEnvPathInGitHistory(repoPath) {
|
|
7037
|
-
try {
|
|
8697
|
+
});
|
|
7038
8698
|
const output = execFileSync(
|
|
7039
8699
|
"git",
|
|
7040
|
-
[
|
|
8700
|
+
[
|
|
8701
|
+
"diff-tree",
|
|
8702
|
+
"--stdin",
|
|
8703
|
+
"--root",
|
|
8704
|
+
"--name-only",
|
|
8705
|
+
"-r",
|
|
8706
|
+
"--diff-filter=AM",
|
|
8707
|
+
"--pretty=format:commit:%H"
|
|
8708
|
+
],
|
|
7041
8709
|
{
|
|
7042
8710
|
cwd: repoPath,
|
|
7043
8711
|
encoding: "utf8",
|
|
7044
|
-
|
|
7045
|
-
|
|
8712
|
+
input: commits,
|
|
8713
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
7046
8714
|
}
|
|
7047
|
-
)
|
|
7048
|
-
|
|
7049
|
-
|
|
8715
|
+
);
|
|
8716
|
+
let currentCommit = null;
|
|
8717
|
+
for (const line of output.split("\n")) {
|
|
8718
|
+
if (line.startsWith("commit:")) {
|
|
8719
|
+
currentCommit = line.slice("commit:".length);
|
|
8720
|
+
continue;
|
|
8721
|
+
}
|
|
8722
|
+
const path = line.trim();
|
|
8723
|
+
if (!currentCommit || !path) continue;
|
|
8724
|
+
if (!isCredentialHistoryPath(path)) continue;
|
|
8725
|
+
appendEntry({ commit: currentCommit, path });
|
|
8726
|
+
}
|
|
7050
8727
|
} catch {
|
|
7051
|
-
return false;
|
|
7052
8728
|
}
|
|
7053
|
-
|
|
7054
|
-
|
|
7055
|
-
// src/witan/rubric.ts
|
|
7056
|
-
var WITAN_RUBRIC = [
|
|
7057
|
-
{
|
|
7058
|
-
id: "A1",
|
|
7059
|
-
title: "Test integrity and regression signal",
|
|
7060
|
-
category: "code_trust"
|
|
7061
|
-
},
|
|
7062
|
-
{
|
|
7063
|
-
id: "A2",
|
|
7064
|
-
title: "Data-layer isolation and secrets posture",
|
|
7065
|
-
category: "code_trust"
|
|
7066
|
-
},
|
|
7067
|
-
{
|
|
7068
|
-
id: "A3",
|
|
7069
|
-
title: "Production readiness",
|
|
7070
|
-
category: "code_trust"
|
|
7071
|
-
},
|
|
7072
|
-
{
|
|
7073
|
-
id: "A4",
|
|
7074
|
-
title: "Dependency hygiene",
|
|
7075
|
-
category: "code_trust"
|
|
7076
|
-
},
|
|
7077
|
-
{
|
|
7078
|
-
id: "A5",
|
|
7079
|
-
title: "Claim-vs-reality reconciliation",
|
|
7080
|
-
category: "code_trust"
|
|
7081
|
-
},
|
|
7082
|
-
{
|
|
7083
|
-
id: "B1",
|
|
7084
|
-
title: "Dispatch trace completeness",
|
|
7085
|
-
category: "process_trust"
|
|
7086
|
-
},
|
|
7087
|
-
{
|
|
7088
|
-
id: "B2",
|
|
7089
|
-
title: "PR outcome traceability",
|
|
7090
|
-
category: "process_trust"
|
|
7091
|
-
},
|
|
7092
|
-
{
|
|
7093
|
-
id: "B3",
|
|
7094
|
-
title: "CI and QA discipline",
|
|
7095
|
-
category: "process_trust"
|
|
7096
|
-
},
|
|
7097
|
-
{
|
|
7098
|
-
id: "B4",
|
|
7099
|
-
title: "Audit trail and report-up completeness",
|
|
7100
|
-
category: "process_trust"
|
|
7101
|
-
},
|
|
7102
|
-
{
|
|
7103
|
-
id: "B5",
|
|
7104
|
-
title: "Verified learning trace",
|
|
7105
|
-
category: "process_trust"
|
|
7106
|
-
},
|
|
7107
|
-
{
|
|
7108
|
-
id: "B6",
|
|
7109
|
-
title: "Privileged-operation human gating",
|
|
7110
|
-
category: "process_trust"
|
|
8729
|
+
for (const entry of readDeletedCredentialHistoryEntries(repoPath)) {
|
|
8730
|
+
appendEntry(entry);
|
|
7111
8731
|
}
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
const
|
|
7118
|
-
const
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7122
|
-
|
|
7123
|
-
|
|
7124
|
-
bucket.push(signal);
|
|
7125
|
-
inputSignalsByDimension.set(signal.dimension, bucket);
|
|
8732
|
+
return entries;
|
|
8733
|
+
}
|
|
8734
|
+
function readDeletedCredentialHistoryEntries(repoPath) {
|
|
8735
|
+
const deletedPaths = readDeletedCredentialHistoryPaths(repoPath);
|
|
8736
|
+
const entries = [];
|
|
8737
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8738
|
+
for (const path of deletedPaths) {
|
|
8739
|
+
for (const commit of readHistoryCommitsForPath(repoPath, path)) {
|
|
8740
|
+
const key = `${commit}:${path}`;
|
|
8741
|
+
if (seen.has(key)) continue;
|
|
8742
|
+
seen.add(key);
|
|
8743
|
+
entries.push({ commit, path });
|
|
7126
8744
|
}
|
|
7127
8745
|
}
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
const
|
|
7133
|
-
|
|
7134
|
-
|
|
7135
|
-
|
|
7136
|
-
|
|
7137
|
-
|
|
7138
|
-
|
|
7139
|
-
|
|
7140
|
-
status: scored.status,
|
|
7141
|
-
evidence: scored.evidence,
|
|
7142
|
-
findings: scored.findings,
|
|
7143
|
-
metrics: scored.metrics,
|
|
7144
|
-
...signal?.notes ? { notes: signal.notes } : {}
|
|
7145
|
-
};
|
|
7146
|
-
}
|
|
7147
|
-
const { adjustedScore, adjustment, summaries } = applySignalAdjustment(
|
|
7148
|
-
scored.score,
|
|
7149
|
-
id,
|
|
7150
|
-
dimensionSignals
|
|
8746
|
+
return entries;
|
|
8747
|
+
}
|
|
8748
|
+
function readDeletedCredentialHistoryPaths(repoPath) {
|
|
8749
|
+
try {
|
|
8750
|
+
const output = execFileSync(
|
|
8751
|
+
"git",
|
|
8752
|
+
["log", "--all", "--diff-filter=D", "--name-status", "--format=commit:%H"],
|
|
8753
|
+
{
|
|
8754
|
+
cwd: repoPath,
|
|
8755
|
+
encoding: "utf8",
|
|
8756
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
8757
|
+
}
|
|
7151
8758
|
);
|
|
7152
|
-
|
|
7153
|
-
const
|
|
7154
|
-
const
|
|
7155
|
-
|
|
7156
|
-
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
status: finalStatus,
|
|
7162
|
-
evidence: scored.evidence,
|
|
7163
|
-
findings: scored.findings,
|
|
7164
|
-
metrics: scored.metrics,
|
|
7165
|
-
...signal?.notes ? { notes: signal.notes } : {}
|
|
7166
|
-
};
|
|
7167
|
-
});
|
|
7168
|
-
const categoryOrder = [];
|
|
7169
|
-
for (const rubricCriterion of rubric) {
|
|
7170
|
-
if (!categoryOrder.includes(rubricCriterion.category)) {
|
|
7171
|
-
categoryOrder.push(rubricCriterion.category);
|
|
8759
|
+
const paths = [];
|
|
8760
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8761
|
+
for (const line of output.split("\n")) {
|
|
8762
|
+
if (!line.startsWith("D ")) continue;
|
|
8763
|
+
const path = line.slice(2).trim();
|
|
8764
|
+
if (!path || seen.has(path)) continue;
|
|
8765
|
+
if (!isCredentialHistoryPath(path)) continue;
|
|
8766
|
+
seen.add(path);
|
|
8767
|
+
paths.push(path);
|
|
7172
8768
|
}
|
|
8769
|
+
return paths;
|
|
8770
|
+
} catch {
|
|
8771
|
+
return [];
|
|
7173
8772
|
}
|
|
7174
|
-
const categoryScoreMap = {};
|
|
7175
|
-
for (const category of categoryOrder) {
|
|
7176
|
-
categoryScoreMap[category] = averageScore(
|
|
7177
|
-
criteria.filter((criterion) => criterion.category === category)
|
|
7178
|
-
);
|
|
7179
|
-
}
|
|
7180
|
-
const firstCategory = categoryOrder[0];
|
|
7181
|
-
const secondCategory = categoryOrder[1] ?? firstCategory;
|
|
7182
|
-
const codeTrustScore = categoryScoreMap.code_trust ?? (firstCategory ? categoryScoreMap[firstCategory] : void 0) ?? 0;
|
|
7183
|
-
const processTrustScore = categoryScoreMap.process_trust ?? (secondCategory ? categoryScoreMap[secondCategory] : void 0) ?? 0;
|
|
7184
|
-
const overallScore = roundScore(
|
|
7185
|
-
categoryOrder.reduce((sum, category) => sum + (categoryScoreMap[category] ?? 0), 0) / Math.max(categoryOrder.length, 1)
|
|
7186
|
-
);
|
|
7187
|
-
return WitanReportSchema.parse({
|
|
7188
|
-
productSlug: parsedInput.productSlug,
|
|
7189
|
-
productDisplayName: parsedInput.productDisplayName,
|
|
7190
|
-
repo: parsedInput.repo,
|
|
7191
|
-
generatedAt: parsedInput.generatedAt,
|
|
7192
|
-
rubricVersion: parsedInput.rubricVersion,
|
|
7193
|
-
codeTrustScore,
|
|
7194
|
-
processTrustScore,
|
|
7195
|
-
overallScore,
|
|
7196
|
-
criteria,
|
|
7197
|
-
...consumedSignals.length > 0 ? { consumedSignals } : {},
|
|
7198
|
-
// Only surface the full per-category map for rubrics with more than two buckets —
|
|
7199
|
-
// the default two-category rubric is fully represented by codeTrustScore/processTrustScore.
|
|
7200
|
-
...categoryOrder.length > 2 ? { categoryScores: categoryScoreMap } : {},
|
|
7201
|
-
// Pass through repo-archetype metadata verbatim — createWitanReport does not compute or
|
|
7202
|
-
// alter it (see classifyRepoArchetype in repo-signals.ts); per-criterion scoring above is
|
|
7203
|
-
// unaffected by archetype, only presentation layers (badge/terminal/verdict) key off it.
|
|
7204
|
-
...parsedInput.archetype ? { archetype: parsedInput.archetype } : {},
|
|
7205
|
-
...parsedInput.insufficientSourceReason ? { insufficientSourceReason: parsedInput.insufficientSourceReason } : {}
|
|
7206
|
-
});
|
|
7207
8773
|
}
|
|
7208
|
-
function
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
);
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
source: signal.source,
|
|
7223
|
-
dimension,
|
|
7224
|
-
findingCount: signal.findings.length,
|
|
7225
|
-
severityBreakdown: { critical: criticalCount, warning: warningCount, info: infoCount },
|
|
7226
|
-
nativeScore,
|
|
7227
|
-
scoreAdjustment: -roundScore(Math.min(signalAdj, MAX_SIGNAL_ADJUSTMENT)),
|
|
7228
|
-
adjustedScore: roundScore(
|
|
7229
|
-
Math.max(0, nativeScore - Math.min(signalAdj, MAX_SIGNAL_ADJUSTMENT))
|
|
7230
|
-
),
|
|
7231
|
-
findings: [...signal.findings]
|
|
7232
|
-
});
|
|
8774
|
+
function readHistoryCommitsForPath(repoPath, path) {
|
|
8775
|
+
try {
|
|
8776
|
+
const output = execFileSync(
|
|
8777
|
+
"git",
|
|
8778
|
+
["log", "--all", "--diff-filter=AM", "--format=%H", "--", path],
|
|
8779
|
+
{
|
|
8780
|
+
cwd: repoPath,
|
|
8781
|
+
encoding: "utf8",
|
|
8782
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
8783
|
+
}
|
|
8784
|
+
);
|
|
8785
|
+
return output.split("\n").map((line) => line.trim()).filter((line) => /^[0-9a-f]{40}$/i.test(line));
|
|
8786
|
+
} catch {
|
|
8787
|
+
return [];
|
|
7233
8788
|
}
|
|
7234
|
-
|
|
7235
|
-
|
|
7236
|
-
|
|
7237
|
-
|
|
7238
|
-
|
|
8789
|
+
}
|
|
8790
|
+
function isCredentialHistoryPath(path) {
|
|
8791
|
+
if (isHardExcludedPath(path)) return false;
|
|
8792
|
+
const lowerPath = path.toLowerCase();
|
|
8793
|
+
const basename4 = lowerPath.split("/").at(-1) ?? lowerPath;
|
|
8794
|
+
if (/\.env(?:\.|$)/.test(basename4)) {
|
|
8795
|
+
return true;
|
|
7239
8796
|
}
|
|
7240
|
-
return
|
|
8797
|
+
return lowerPath.includes("secret") || lowerPath.includes("credential") || basename4.endsWith(".pem") || basename4.endsWith(".key") || basename4 === "id_rsa" || basename4.endsWith(".p12") || basename4.endsWith(".pfx");
|
|
7241
8798
|
}
|
|
7242
|
-
function
|
|
7243
|
-
if (
|
|
7244
|
-
|
|
7245
|
-
|
|
7246
|
-
if (score > 0) return "critical";
|
|
7247
|
-
return "critical";
|
|
8799
|
+
function isEnvHistoryPath(path) {
|
|
8800
|
+
if (isEnvTemplatePath(path)) return false;
|
|
8801
|
+
const basename4 = path.toLowerCase().split("/").at(-1) ?? path.toLowerCase();
|
|
8802
|
+
return /\.env(?:\.|$)/.test(basename4);
|
|
7248
8803
|
}
|
|
7249
|
-
function
|
|
7250
|
-
|
|
7251
|
-
|
|
7252
|
-
|
|
7253
|
-
|
|
7254
|
-
|
|
7255
|
-
|
|
7256
|
-
}
|
|
7257
|
-
merged.set(signal.criterionId, {
|
|
7258
|
-
criterionId: signal.criterionId,
|
|
7259
|
-
positiveEvidence: [...existing.positiveEvidence, ...signal.positiveEvidence],
|
|
7260
|
-
findings: [...existing.findings, ...signal.findings],
|
|
7261
|
-
metrics: [...existing.metrics ?? [], ...signal.metrics ?? []],
|
|
7262
|
-
notes: signal.notes ?? existing.notes,
|
|
7263
|
-
// N/A wins on merge: if either signal is N/A, the criterion is N/A.
|
|
7264
|
-
...existing.notApplicable === true || signal.notApplicable === true ? { notApplicable: true } : {}
|
|
8804
|
+
function readGitBlob(repoPath, commit, path) {
|
|
8805
|
+
try {
|
|
8806
|
+
return execFileSync("git", ["show", `${commit}:${path}`], {
|
|
8807
|
+
cwd: repoPath,
|
|
8808
|
+
encoding: "utf8",
|
|
8809
|
+
maxBuffer: 512e3,
|
|
8810
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
7265
8811
|
});
|
|
8812
|
+
} catch {
|
|
8813
|
+
return null;
|
|
7266
8814
|
}
|
|
7267
|
-
return merged;
|
|
7268
|
-
}
|
|
7269
|
-
function usesMetricScoring(rubricVersion) {
|
|
7270
|
-
return rubricVersion === WITAN_RUBRIC_VERSION_V1 || rubricVersion === WITAN_RUBRIC_VERSION_V2 || rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0;
|
|
7271
8815
|
}
|
|
7272
|
-
|
|
7273
|
-
|
|
8816
|
+
var ALL_CAPS_SNAKE_PLACEHOLDER_PATTERN = /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+$/;
|
|
8817
|
+
function isPlaceholderSecretValue(value) {
|
|
8818
|
+
const normalized = value.trim().toLowerCase();
|
|
8819
|
+
return PLACEHOLDER_SECRET_PATTERN.test(normalized) || normalized.includes("your-") || normalized.includes("example") || ALL_CAPS_SNAKE_PLACEHOLDER_PATTERN.test(value.trim()) || isSyntheticFixtureSecretValue(normalized) || isFillerRunSecretValue(normalized);
|
|
7274
8820
|
}
|
|
7275
|
-
function
|
|
7276
|
-
|
|
7277
|
-
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
evidence: [],
|
|
7281
|
-
findings: [],
|
|
7282
|
-
metrics: []
|
|
7283
|
-
};
|
|
7284
|
-
}
|
|
7285
|
-
if (signal.notApplicable === true) {
|
|
7286
|
-
return {
|
|
7287
|
-
score: 0,
|
|
7288
|
-
status: "not_applicable",
|
|
7289
|
-
evidence: [],
|
|
7290
|
-
findings: [],
|
|
7291
|
-
metrics: []
|
|
7292
|
-
};
|
|
7293
|
-
}
|
|
7294
|
-
const evidence = signal.positiveEvidence;
|
|
7295
|
-
const findings = signal.findings;
|
|
7296
|
-
const metrics = signal.metrics ?? [];
|
|
7297
|
-
const evidenceCount = evidence.length + findings.length;
|
|
7298
|
-
if (evidenceCount === 0) {
|
|
7299
|
-
if (!usesMetricScoring(rubricVersion) || metrics.length === 0) {
|
|
7300
|
-
return {
|
|
7301
|
-
score: 0,
|
|
7302
|
-
status: unmeasuredStatus(rubricVersion),
|
|
7303
|
-
evidence,
|
|
7304
|
-
findings,
|
|
7305
|
-
metrics
|
|
7306
|
-
};
|
|
7307
|
-
}
|
|
7308
|
-
}
|
|
7309
|
-
if (usesMetricScoring(rubricVersion)) {
|
|
7310
|
-
const measuredMetrics = metrics.length > 0 ? metrics : fallbackMetricsForEvidence(evidence, findings);
|
|
7311
|
-
const score = capScoreForFindings(scoreMetrics(measuredMetrics), findings);
|
|
7312
|
-
const status = statusForScoreAndFindings(score, findings);
|
|
7313
|
-
return {
|
|
7314
|
-
score,
|
|
7315
|
-
status,
|
|
7316
|
-
evidence,
|
|
7317
|
-
findings: ensureFindingsExplainStatus(signal.criterionId, score, status, findings, evidence),
|
|
7318
|
-
metrics: measuredMetrics
|
|
7319
|
-
};
|
|
7320
|
-
}
|
|
7321
|
-
if (findings.some((finding) => finding.severity === "critical")) {
|
|
7322
|
-
return {
|
|
7323
|
-
score: 1,
|
|
7324
|
-
status: "critical",
|
|
7325
|
-
evidence,
|
|
7326
|
-
findings,
|
|
7327
|
-
metrics
|
|
7328
|
-
};
|
|
7329
|
-
}
|
|
7330
|
-
if (findings.some((finding) => finding.severity === "warning")) {
|
|
7331
|
-
return {
|
|
7332
|
-
score: 2,
|
|
7333
|
-
status: "warning",
|
|
7334
|
-
evidence,
|
|
7335
|
-
findings,
|
|
7336
|
-
metrics
|
|
7337
|
-
};
|
|
8821
|
+
function isFillerRunSecretValue(value) {
|
|
8822
|
+
const candidates = [value];
|
|
8823
|
+
const sepIdx = Math.max(value.lastIndexOf("_"), value.lastIndexOf("-"));
|
|
8824
|
+
if (sepIdx > 0 && sepIdx < value.length - 1) {
|
|
8825
|
+
candidates.push(value.slice(sepIdx + 1));
|
|
7338
8826
|
}
|
|
7339
|
-
|
|
7340
|
-
|
|
7341
|
-
|
|
7342
|
-
|
|
7343
|
-
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
};
|
|
8827
|
+
for (const body of candidates) {
|
|
8828
|
+
if (body.length < 8) continue;
|
|
8829
|
+
const counts = /* @__PURE__ */ new Map();
|
|
8830
|
+
for (const ch of body) counts.set(ch, (counts.get(ch) ?? 0) + 1);
|
|
8831
|
+
const distinct = counts.size;
|
|
8832
|
+
const maxRun = Math.max(...counts.values());
|
|
8833
|
+
if (distinct <= 2 && maxRun / body.length >= 0.8) return true;
|
|
7347
8834
|
}
|
|
7348
|
-
return
|
|
7349
|
-
score: 4,
|
|
7350
|
-
status: "verified",
|
|
7351
|
-
evidence,
|
|
7352
|
-
findings,
|
|
7353
|
-
metrics
|
|
7354
|
-
};
|
|
8835
|
+
return false;
|
|
7355
8836
|
}
|
|
7356
|
-
function
|
|
7357
|
-
return
|
|
7358
|
-
{
|
|
7359
|
-
name: "evidence_depth",
|
|
7360
|
-
label: "Evidence depth",
|
|
7361
|
-
value: Math.min(evidence.length + findings.length + 1, 4),
|
|
7362
|
-
max: 4,
|
|
7363
|
-
weight: 1,
|
|
7364
|
-
unit: "signals",
|
|
7365
|
-
description: "Conservative v1 fallback for externally supplied evidence that has not provided criterion-specific depth metrics."
|
|
7366
|
-
}
|
|
7367
|
-
];
|
|
8837
|
+
function isSyntheticFixtureSecretValue(value) {
|
|
8838
|
+
return value.includes("abcdefghijklmnopqrstuvwxyz") || value.includes("0123456789abcdefghijklmnopqrstuvwxyz") || value.includes("abcdefghijklmnopqrstuvwxyz0123456789") || value.includes("abcdefghijklmnopqrst");
|
|
7368
8839
|
}
|
|
7369
|
-
function
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
8840
|
+
function hasSuspiciousDependencies(repoPath, manifest) {
|
|
8841
|
+
if (!manifest.endsWith("package.json")) return false;
|
|
8842
|
+
const fullPath = join3(repoPath, manifest);
|
|
8843
|
+
if (!isRegularFile(fullPath)) return false;
|
|
8844
|
+
const parsed = parseJsonObject(readFileSync6(fullPath, "utf8"));
|
|
8845
|
+
if (!parsed) return false;
|
|
8846
|
+
const dependencies = isRecord(parsed.dependencies) ? parsed.dependencies : {};
|
|
8847
|
+
const devDependencies = isRecord(parsed.devDependencies) ? parsed.devDependencies : {};
|
|
8848
|
+
const names = [...Object.keys(dependencies), ...Object.keys(devDependencies)];
|
|
8849
|
+
return names.some(
|
|
8850
|
+
(name) => /^(todo|fake|placeholder|example)-|does-not-exist| hallucinated/i.test(name)
|
|
8851
|
+
);
|
|
8852
|
+
}
|
|
8853
|
+
function readRecentCommits(repoPath) {
|
|
8854
|
+
try {
|
|
8855
|
+
const output = execFileSync("git", ["log", "--max-count=12", "--format=%H%x00%s"], {
|
|
8856
|
+
cwd: repoPath,
|
|
8857
|
+
encoding: "utf8",
|
|
8858
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
8859
|
+
}).trim();
|
|
8860
|
+
if (!output) return [];
|
|
8861
|
+
return output.split("\n").map((line) => {
|
|
8862
|
+
const [sha = "", subject = ""] = line.split("\0");
|
|
8863
|
+
return { sha, subject };
|
|
8864
|
+
}).filter((commit) => commit.sha.length >= 7);
|
|
8865
|
+
} catch {
|
|
8866
|
+
return [];
|
|
7376
8867
|
}
|
|
7377
|
-
if (totalWeight === 0) return 0;
|
|
7378
|
-
return roundScore(weightedTotal / totalWeight * 4);
|
|
7379
8868
|
}
|
|
7380
|
-
function
|
|
7381
|
-
if (
|
|
7382
|
-
|
|
7383
|
-
|
|
7384
|
-
return
|
|
8869
|
+
function readPackageScripts(packageJsonPath) {
|
|
8870
|
+
if (!isRegularFile(packageJsonPath)) return /* @__PURE__ */ new Map();
|
|
8871
|
+
const parsed = parseJsonObject(readFileSync6(packageJsonPath, "utf8"));
|
|
8872
|
+
const scripts = parsed?.scripts;
|
|
8873
|
+
if (!isRecord(scripts)) return /* @__PURE__ */ new Map();
|
|
8874
|
+
return new Map(
|
|
8875
|
+
Object.entries(scripts).filter(
|
|
8876
|
+
(entry) => typeof entry[1] === "string"
|
|
8877
|
+
)
|
|
8878
|
+
);
|
|
7385
8879
|
}
|
|
7386
|
-
function
|
|
7387
|
-
|
|
7388
|
-
|
|
7389
|
-
|
|
7390
|
-
|
|
7391
|
-
|
|
7392
|
-
|
|
8880
|
+
function evidenceForRelative(repoPath, path, kind, label) {
|
|
8881
|
+
const fullPath = join3(repoPath, path);
|
|
8882
|
+
const contents = isRegularFile(fullPath) ? readFileSync6(fullPath, "utf8") : "";
|
|
8883
|
+
return {
|
|
8884
|
+
kind,
|
|
8885
|
+
label,
|
|
8886
|
+
path,
|
|
8887
|
+
...contents ? {
|
|
8888
|
+
line: firstMeaningfulLine(contents),
|
|
8889
|
+
contentHash: createHash("sha256").update(contents).digest("hex")
|
|
8890
|
+
} : {}
|
|
8891
|
+
};
|
|
7393
8892
|
}
|
|
7394
|
-
function
|
|
7395
|
-
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
kind
|
|
7399
|
-
label
|
|
7400
|
-
path
|
|
8893
|
+
function evidenceForRelativeAtLine(repoPath, path, kind, label, line) {
|
|
8894
|
+
const fullPath = join3(repoPath, path);
|
|
8895
|
+
const contents = isRegularFile(fullPath) ? readFileSync6(fullPath, "utf8") : "";
|
|
8896
|
+
return {
|
|
8897
|
+
kind,
|
|
8898
|
+
label,
|
|
8899
|
+
path,
|
|
8900
|
+
line,
|
|
8901
|
+
...contents ? { contentHash: createHash("sha256").update(contents).digest("hex") } : {}
|
|
8902
|
+
};
|
|
8903
|
+
}
|
|
8904
|
+
function metric(name, label, value, max, weight, unit, description, kind) {
|
|
8905
|
+
return {
|
|
8906
|
+
name,
|
|
8907
|
+
label,
|
|
8908
|
+
value: Math.max(0, value),
|
|
8909
|
+
max,
|
|
8910
|
+
...kind ? { kind } : {},
|
|
8911
|
+
weight,
|
|
8912
|
+
unit,
|
|
8913
|
+
description
|
|
7401
8914
|
};
|
|
7402
|
-
return [
|
|
7403
|
-
{
|
|
7404
|
-
severity: status,
|
|
7405
|
-
summary: `${criterionId} metric-derived score is ${score.toFixed(1)}/4.0, in the ${status} band \u2014 no single finding drove this; it reflects the combined metric weighting below.`,
|
|
7406
|
-
evidence: anchor
|
|
7407
|
-
}
|
|
7408
|
-
];
|
|
7409
8915
|
}
|
|
7410
|
-
function
|
|
7411
|
-
const
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
if (applicable.length === 0) return 0;
|
|
7415
|
-
const total = applicable.reduce((sum, criterion) => sum + criterion.score, 0);
|
|
7416
|
-
return roundScore(total / applicable.length);
|
|
8916
|
+
function firstMeaningfulLine(contents) {
|
|
8917
|
+
const lines = contents.split("\n");
|
|
8918
|
+
const index = lines.findIndex((line) => line.trim().length > 0);
|
|
8919
|
+
return index === -1 ? 1 : index + 1;
|
|
7417
8920
|
}
|
|
7418
|
-
function
|
|
7419
|
-
|
|
8921
|
+
function readGitHead(repoPath) {
|
|
8922
|
+
try {
|
|
8923
|
+
return execFileSync("git", ["rev-parse", "HEAD"], {
|
|
8924
|
+
cwd: repoPath,
|
|
8925
|
+
encoding: "utf8",
|
|
8926
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
8927
|
+
}).trim();
|
|
8928
|
+
} catch {
|
|
8929
|
+
return null;
|
|
8930
|
+
}
|
|
8931
|
+
}
|
|
8932
|
+
function hasEnvPathInGitHistory(repoPath) {
|
|
8933
|
+
try {
|
|
8934
|
+
const output = execFileSync(
|
|
8935
|
+
"git",
|
|
8936
|
+
["log", "--all", "--diff-filter=AM", "--name-only", "--format="],
|
|
8937
|
+
{
|
|
8938
|
+
cwd: repoPath,
|
|
8939
|
+
encoding: "utf8",
|
|
8940
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
8941
|
+
maxBuffer: 512e3
|
|
8942
|
+
}
|
|
8943
|
+
).trim();
|
|
8944
|
+
if (!output) return false;
|
|
8945
|
+
return output.split("\n").some((p) => /(?:^|\/)\.env(?:\.|$)/i.test(p.trim()));
|
|
8946
|
+
} catch {
|
|
8947
|
+
return false;
|
|
8948
|
+
}
|
|
7420
8949
|
}
|
|
7421
8950
|
|
|
7422
|
-
// src/
|
|
7423
|
-
|
|
7424
|
-
var DIMENSION_RULES = [
|
|
7425
|
-
// A2 — injection / secrets / auth (high weight)
|
|
7426
|
-
{
|
|
7427
|
-
pattern: /sql[- _]?inject|cwe-89|sqli|command[- _]?inject|cwe-78|os[- _]?cmd|rce|remote[- _]?code/i,
|
|
7428
|
-
dimension: "A2",
|
|
7429
|
-
weight: 0.9
|
|
7430
|
-
},
|
|
7431
|
-
{
|
|
7432
|
-
pattern: /secret|credential|api[- _]?key|password[- _]?leak|hardcoded[- _]?(token|key|secret)|cwe-259|cwe-798/i,
|
|
7433
|
-
dimension: "A2",
|
|
7434
|
-
weight: 0.9
|
|
7435
|
-
},
|
|
8951
|
+
// ../witan/src/rubric.ts
|
|
8952
|
+
var WITAN_RUBRIC = [
|
|
7436
8953
|
{
|
|
7437
|
-
|
|
7438
|
-
|
|
7439
|
-
|
|
8954
|
+
id: "A1",
|
|
8955
|
+
title: "Test integrity and regression signal",
|
|
8956
|
+
category: "code_trust"
|
|
7440
8957
|
},
|
|
7441
8958
|
{
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
8959
|
+
id: "A2",
|
|
8960
|
+
title: "Data-layer isolation and secrets posture",
|
|
8961
|
+
category: "code_trust"
|
|
7445
8962
|
},
|
|
7446
8963
|
{
|
|
7447
|
-
|
|
7448
|
-
|
|
7449
|
-
|
|
8964
|
+
id: "A3",
|
|
8965
|
+
title: "Production readiness",
|
|
8966
|
+
category: "code_trust"
|
|
7450
8967
|
},
|
|
7451
8968
|
{
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
8969
|
+
id: "A4",
|
|
8970
|
+
title: "Dependency hygiene",
|
|
8971
|
+
category: "code_trust"
|
|
7455
8972
|
},
|
|
7456
8973
|
{
|
|
7457
|
-
|
|
7458
|
-
|
|
7459
|
-
|
|
8974
|
+
id: "A5",
|
|
8975
|
+
title: "Claim-vs-reality reconciliation",
|
|
8976
|
+
category: "code_trust"
|
|
7460
8977
|
},
|
|
7461
|
-
// A4 — dependency vulnerabilities
|
|
7462
8978
|
{
|
|
7463
|
-
|
|
7464
|
-
|
|
7465
|
-
|
|
8979
|
+
id: "B1",
|
|
8980
|
+
title: "Dispatch trace completeness",
|
|
8981
|
+
category: "process_trust"
|
|
7466
8982
|
},
|
|
7467
8983
|
{
|
|
7468
|
-
|
|
7469
|
-
|
|
7470
|
-
|
|
8984
|
+
id: "B2",
|
|
8985
|
+
title: "PR outcome traceability",
|
|
8986
|
+
category: "process_trust"
|
|
7471
8987
|
},
|
|
7472
|
-
// A3 — production readiness / insecure config
|
|
7473
8988
|
{
|
|
7474
|
-
|
|
7475
|
-
|
|
7476
|
-
|
|
8989
|
+
id: "B3",
|
|
8990
|
+
title: "CI and QA discipline",
|
|
8991
|
+
category: "process_trust"
|
|
7477
8992
|
},
|
|
7478
8993
|
{
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
8994
|
+
id: "B4",
|
|
8995
|
+
title: "Audit trail and report-up completeness",
|
|
8996
|
+
category: "process_trust"
|
|
7482
8997
|
},
|
|
7483
8998
|
{
|
|
7484
|
-
|
|
7485
|
-
|
|
7486
|
-
|
|
8999
|
+
id: "B5",
|
|
9000
|
+
title: "Verified learning trace",
|
|
9001
|
+
category: "process_trust"
|
|
7487
9002
|
},
|
|
7488
|
-
// A1 — test integrity (low weight; SARIF rarely surfaces this)
|
|
7489
9003
|
{
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
9004
|
+
id: "B6",
|
|
9005
|
+
title: "Privileged-operation human gating",
|
|
9006
|
+
category: "process_trust"
|
|
7493
9007
|
}
|
|
7494
9008
|
];
|
|
7495
|
-
|
|
7496
|
-
|
|
7497
|
-
var
|
|
7498
|
-
function
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
|
|
9009
|
+
|
|
9010
|
+
// ../witan/src/scoring.ts
|
|
9011
|
+
var MAX_SIGNAL_ADJUSTMENT = 0.8;
|
|
9012
|
+
function createWitanReport(input, inputSignals, rubric = WITAN_RUBRIC) {
|
|
9013
|
+
const parsedInput = WitanReportInputSchema.parse(input);
|
|
9014
|
+
const signalsByCriterion = mergeSignalsByCriterion(parsedInput.signals);
|
|
9015
|
+
const hasInputSignals = inputSignals != null && inputSignals.length > 0;
|
|
9016
|
+
const inputSignalsByDimension = /* @__PURE__ */ new Map();
|
|
9017
|
+
if (hasInputSignals && inputSignals) {
|
|
9018
|
+
for (const signal of inputSignals) {
|
|
9019
|
+
const bucket = inputSignalsByDimension.get(signal.dimension) ?? [];
|
|
9020
|
+
bucket.push(signal);
|
|
9021
|
+
inputSignalsByDimension.set(signal.dimension, bucket);
|
|
9022
|
+
}
|
|
9023
|
+
}
|
|
9024
|
+
const consumedSignals = [];
|
|
9025
|
+
const criteria = rubric.map((rubricCriterion) => {
|
|
9026
|
+
const id = rubricCriterion.id;
|
|
9027
|
+
const signal = signalsByCriterion.get(id);
|
|
9028
|
+
const scored = scoreCriterion(signal, parsedInput.rubricVersion);
|
|
9029
|
+
const dimensionSignals = inputSignalsByDimension.get(id);
|
|
9030
|
+
if (!dimensionSignals || dimensionSignals.length === 0) {
|
|
9031
|
+
return {
|
|
9032
|
+
id,
|
|
9033
|
+
title: rubricCriterion.title,
|
|
9034
|
+
category: rubricCriterion.category,
|
|
9035
|
+
score: scored.score,
|
|
9036
|
+
status: scored.status,
|
|
9037
|
+
evidence: scored.evidence,
|
|
9038
|
+
findings: scored.findings,
|
|
9039
|
+
metrics: scored.metrics,
|
|
9040
|
+
...signal?.notes ? { notes: signal.notes } : {}
|
|
9041
|
+
};
|
|
9042
|
+
}
|
|
9043
|
+
const { adjustedScore, adjustment, summaries } = applySignalAdjustment(
|
|
9044
|
+
scored.score,
|
|
9045
|
+
id,
|
|
9046
|
+
dimensionSignals
|
|
9047
|
+
);
|
|
9048
|
+
consumedSignals.push(...summaries);
|
|
9049
|
+
const finalScore = adjustment === 0 ? scored.score : adjustedScore;
|
|
9050
|
+
const finalStatus = adjustment === 0 ? scored.status : statusForScore(finalScore);
|
|
9051
|
+
return {
|
|
9052
|
+
id,
|
|
9053
|
+
title: rubricCriterion.title,
|
|
9054
|
+
category: rubricCriterion.category,
|
|
9055
|
+
score: finalScore,
|
|
9056
|
+
...adjustment !== 0 ? { nativeScore: scored.score } : {},
|
|
9057
|
+
status: finalStatus,
|
|
9058
|
+
evidence: scored.evidence,
|
|
9059
|
+
findings: scored.findings,
|
|
9060
|
+
metrics: scored.metrics,
|
|
9061
|
+
...signal?.notes ? { notes: signal.notes } : {}
|
|
9062
|
+
};
|
|
9063
|
+
});
|
|
9064
|
+
const categoryOrder = [];
|
|
9065
|
+
for (const rubricCriterion of rubric) {
|
|
9066
|
+
if (!categoryOrder.includes(rubricCriterion.category)) {
|
|
9067
|
+
categoryOrder.push(rubricCriterion.category);
|
|
7508
9068
|
}
|
|
7509
9069
|
}
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
const
|
|
7517
|
-
|
|
7518
|
-
|
|
9070
|
+
const categoryScoreMap = {};
|
|
9071
|
+
for (const category of categoryOrder) {
|
|
9072
|
+
categoryScoreMap[category] = averageScore(
|
|
9073
|
+
criteria.filter((criterion) => criterion.category === category)
|
|
9074
|
+
);
|
|
9075
|
+
}
|
|
9076
|
+
const firstCategory = categoryOrder[0];
|
|
9077
|
+
const secondCategory = categoryOrder[1] ?? firstCategory;
|
|
9078
|
+
const codeTrustScore = categoryScoreMap.code_trust ?? (firstCategory ? categoryScoreMap[firstCategory] : void 0) ?? 0;
|
|
9079
|
+
const processTrustScore = categoryScoreMap.process_trust ?? (secondCategory ? categoryScoreMap[secondCategory] : void 0) ?? 0;
|
|
9080
|
+
const overallScore = roundScore(
|
|
9081
|
+
categoryOrder.reduce((sum, category) => sum + (categoryScoreMap[category] ?? 0), 0) / Math.max(categoryOrder.length, 1)
|
|
9082
|
+
);
|
|
9083
|
+
return WitanReportSchema.parse({
|
|
9084
|
+
productSlug: parsedInput.productSlug,
|
|
9085
|
+
productDisplayName: parsedInput.productDisplayName,
|
|
9086
|
+
repo: parsedInput.repo,
|
|
9087
|
+
generatedAt: parsedInput.generatedAt,
|
|
9088
|
+
rubricVersion: parsedInput.rubricVersion,
|
|
9089
|
+
codeTrustScore,
|
|
9090
|
+
processTrustScore,
|
|
9091
|
+
overallScore,
|
|
9092
|
+
criteria,
|
|
9093
|
+
...consumedSignals.length > 0 ? { consumedSignals } : {},
|
|
9094
|
+
// Only surface the full per-category map for rubrics with more than two buckets —
|
|
9095
|
+
// the default two-category rubric is fully represented by codeTrustScore/processTrustScore.
|
|
9096
|
+
...categoryOrder.length > 2 ? { categoryScores: categoryScoreMap } : {},
|
|
9097
|
+
// Pass through repo-archetype metadata verbatim — createWitanReport does not compute or
|
|
9098
|
+
// alter it (see classifyRepoArchetype in repo-signals.ts); per-criterion scoring above is
|
|
9099
|
+
// unaffected by archetype, only presentation layers (badge/terminal/verdict) key off it.
|
|
9100
|
+
...parsedInput.archetype ? { archetype: parsedInput.archetype } : {},
|
|
9101
|
+
...parsedInput.insufficientSourceReason ? { insufficientSourceReason: parsedInput.insufficientSourceReason } : {}
|
|
9102
|
+
});
|
|
9103
|
+
}
|
|
9104
|
+
function applySignalAdjustment(nativeScore, dimension, signals) {
|
|
9105
|
+
const summaries = [];
|
|
9106
|
+
let totalRawAdj = 0;
|
|
9107
|
+
for (const signal of signals) {
|
|
9108
|
+
const criticalCount = signal.findings.filter((f) => f.severity === "critical").length;
|
|
9109
|
+
const warningCount = signal.findings.filter((f) => f.severity === "warning").length;
|
|
9110
|
+
const infoCount = signal.findings.filter((f) => f.severity === "info").length;
|
|
9111
|
+
const severityScore = Math.min(
|
|
9112
|
+
criticalCount * 0.2 + warningCount * 0.1 + infoCount * 0.02,
|
|
9113
|
+
1
|
|
9114
|
+
);
|
|
9115
|
+
const signalAdj = signal.weight * severityScore * MAX_SIGNAL_ADJUSTMENT;
|
|
9116
|
+
totalRawAdj += signalAdj;
|
|
9117
|
+
summaries.push({
|
|
9118
|
+
source: signal.source,
|
|
9119
|
+
dimension,
|
|
9120
|
+
findingCount: signal.findings.length,
|
|
9121
|
+
severityBreakdown: { critical: criticalCount, warning: warningCount, info: infoCount },
|
|
9122
|
+
nativeScore,
|
|
9123
|
+
scoreAdjustment: -roundScore(Math.min(signalAdj, MAX_SIGNAL_ADJUSTMENT)),
|
|
9124
|
+
adjustedScore: roundScore(
|
|
9125
|
+
Math.max(0, nativeScore - Math.min(signalAdj, MAX_SIGNAL_ADJUSTMENT))
|
|
9126
|
+
),
|
|
9127
|
+
findings: [...signal.findings]
|
|
9128
|
+
});
|
|
9129
|
+
}
|
|
9130
|
+
const totalAdj = Math.min(totalRawAdj, MAX_SIGNAL_ADJUSTMENT);
|
|
9131
|
+
const adjustedScore = roundScore(Math.max(0, nativeScore - totalAdj));
|
|
9132
|
+
for (const summary of summaries) {
|
|
9133
|
+
summary.adjustedScore = adjustedScore;
|
|
9134
|
+
summary.scoreAdjustment = -roundScore(totalAdj);
|
|
9135
|
+
}
|
|
9136
|
+
return { adjustedScore, adjustment: roundScore(totalAdj), summaries };
|
|
7519
9137
|
}
|
|
7520
|
-
function
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
return true;
|
|
7527
|
-
});
|
|
9138
|
+
function statusForScore(score) {
|
|
9139
|
+
if (score >= 3.5) return "verified";
|
|
9140
|
+
if (score >= 2.5) return "info";
|
|
9141
|
+
if (score >= 1.5) return "warning";
|
|
9142
|
+
if (score > 0) return "critical";
|
|
9143
|
+
return "critical";
|
|
7528
9144
|
}
|
|
7529
|
-
function
|
|
7530
|
-
|
|
7531
|
-
const
|
|
7532
|
-
|
|
7533
|
-
|
|
7534
|
-
|
|
7535
|
-
|
|
7536
|
-
const driverName = run.tool?.driver?.name ?? "unknown";
|
|
7537
|
-
const source = `sarif:${driverName}`;
|
|
7538
|
-
const ruleDefaultLevels = /* @__PURE__ */ new Map();
|
|
7539
|
-
for (const rule of run.tool?.driver?.rules ?? []) {
|
|
7540
|
-
if (rule.id && rule.defaultConfiguration?.level) {
|
|
7541
|
-
ruleDefaultLevels.set(rule.id, rule.defaultConfiguration.level);
|
|
7542
|
-
}
|
|
7543
|
-
}
|
|
7544
|
-
for (const result of run.results ?? []) {
|
|
7545
|
-
const ruleId = result.ruleId ?? "unknown";
|
|
7546
|
-
const effectiveLevel = result.level ?? ruleDefaultLevels.get(ruleId) ?? "warning";
|
|
7547
|
-
const severity = mapLevel(effectiveLevel);
|
|
7548
|
-
if (!severity) continue;
|
|
7549
|
-
const message = result.message?.text ?? ruleId;
|
|
7550
|
-
const location = renderLocation(result);
|
|
7551
|
-
const { dimension, weight } = mapRuleToDimension(ruleId, dimensionRules);
|
|
7552
|
-
const bucketKey = `${source}|${dimension}`;
|
|
7553
|
-
if (!buckets.has(bucketKey)) {
|
|
7554
|
-
buckets.set(bucketKey, { source, dimension, weight, findings: [] });
|
|
7555
|
-
}
|
|
7556
|
-
buckets.get(bucketKey)?.findings.push({ ruleId, severity, message, ...location ? { location } : {} });
|
|
9145
|
+
function mergeSignalsByCriterion(signals) {
|
|
9146
|
+
const merged = /* @__PURE__ */ new Map();
|
|
9147
|
+
for (const signal of signals) {
|
|
9148
|
+
const existing = merged.get(signal.criterionId);
|
|
9149
|
+
if (!existing) {
|
|
9150
|
+
merged.set(signal.criterionId, signal);
|
|
9151
|
+
continue;
|
|
7557
9152
|
}
|
|
9153
|
+
merged.set(signal.criterionId, {
|
|
9154
|
+
criterionId: signal.criterionId,
|
|
9155
|
+
positiveEvidence: [...existing.positiveEvidence, ...signal.positiveEvidence],
|
|
9156
|
+
findings: [...existing.findings, ...signal.findings],
|
|
9157
|
+
metrics: [...existing.metrics ?? [], ...signal.metrics ?? []],
|
|
9158
|
+
notes: signal.notes ?? existing.notes,
|
|
9159
|
+
// N/A wins on merge: if either signal is N/A, the criterion is N/A.
|
|
9160
|
+
...existing.notApplicable === true || signal.notApplicable === true ? { notApplicable: true } : {}
|
|
9161
|
+
});
|
|
7558
9162
|
}
|
|
7559
|
-
return
|
|
7560
|
-
source,
|
|
7561
|
-
dimension,
|
|
7562
|
-
weight,
|
|
7563
|
-
findings: dedupeFindings(findings)
|
|
7564
|
-
}));
|
|
9163
|
+
return merged;
|
|
7565
9164
|
}
|
|
7566
|
-
|
|
7567
|
-
|
|
7568
|
-
import { readFileSync as readFileSync3 } from "fs";
|
|
7569
|
-
var CHECK_RULES = {
|
|
7570
|
-
// B2 — PR outcome traceability
|
|
7571
|
-
"Branch-Protection": { dimension: "B2", weight: 0.8 },
|
|
7572
|
-
"Code-Review": { dimension: "B2", weight: 0.7 },
|
|
7573
|
-
// B3 — CI and QA discipline
|
|
7574
|
-
"Dangerous-Workflow": { dimension: "B3", weight: 0.9 },
|
|
7575
|
-
"Token-Permissions": { dimension: "B3", weight: 0.8 },
|
|
7576
|
-
"CI-Tests": { dimension: "B3", weight: 0.7 },
|
|
7577
|
-
Maintained: { dimension: "B3", weight: 0.3 },
|
|
7578
|
-
// B4 — audit trail / release integrity
|
|
7579
|
-
"Signed-Releases": { dimension: "B4", weight: 0.7 },
|
|
7580
|
-
Packaging: { dimension: "B4", weight: 0.4 },
|
|
7581
|
-
"Security-Policy": { dimension: "B4", weight: 0.4 },
|
|
7582
|
-
// A4 — dependency hygiene
|
|
7583
|
-
Vulnerabilities: { dimension: "A4", weight: 0.9 },
|
|
7584
|
-
"Pinned-Dependencies": { dimension: "A4", weight: 0.8 },
|
|
7585
|
-
"Dependency-Update-Tool": { dimension: "A4", weight: 0.6 },
|
|
7586
|
-
// A2 — data-layer / static analysis
|
|
7587
|
-
SAST: { dimension: "A2", weight: 0.7 },
|
|
7588
|
-
"Binary-Artifacts": { dimension: "A2", weight: 0.6 },
|
|
7589
|
-
// A1 — test integrity
|
|
7590
|
-
Fuzzing: { dimension: "A1", weight: 0.3 }
|
|
7591
|
-
};
|
|
7592
|
-
function mapScoreToSeverity(score) {
|
|
7593
|
-
if (score == null || Number.isNaN(score)) return null;
|
|
7594
|
-
if (score < 0) return null;
|
|
7595
|
-
if (score >= 10) return null;
|
|
7596
|
-
if (score <= 3) return "critical";
|
|
7597
|
-
if (score <= 6) return "warning";
|
|
7598
|
-
return "info";
|
|
9165
|
+
function usesMetricScoring(rubricVersion) {
|
|
9166
|
+
return rubricVersion === WITAN_RUBRIC_VERSION_V1 || rubricVersion === WITAN_RUBRIC_VERSION_V2 || rubricVersion === WITAN_RUBRIC_VERSION_V3 || rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0;
|
|
7599
9167
|
}
|
|
7600
|
-
function
|
|
7601
|
-
|
|
7602
|
-
return findings.filter((f) => {
|
|
7603
|
-
const key = `${f.ruleId}|${f.severity}|${f.location ?? ""}`;
|
|
7604
|
-
if (seen.has(key)) return false;
|
|
7605
|
-
seen.add(key);
|
|
7606
|
-
return true;
|
|
7607
|
-
});
|
|
9168
|
+
function unmeasuredStatus(rubricVersion) {
|
|
9169
|
+
return rubricVersion === WITAN_TRADING_RUBRIC_VERSION_V0 ? "unverified" : "insufficient_data";
|
|
7608
9170
|
}
|
|
7609
|
-
function
|
|
7610
|
-
if (!
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
if (!rule) continue;
|
|
7619
|
-
const severity = mapScoreToSeverity(check.score);
|
|
7620
|
-
if (!severity) continue;
|
|
7621
|
-
const scoreText = typeof check.score === "number" ? `${check.score}/10` : "n/a";
|
|
7622
|
-
const message = `${name} (Scorecard ${scoreText}): ${check.reason ?? "weakness detected"}`.slice(0, 500);
|
|
7623
|
-
const location = check.documentation?.url;
|
|
7624
|
-
const bucket = buckets.get(rule.dimension) ?? { weight: 0, findings: [] };
|
|
7625
|
-
bucket.weight = Math.max(bucket.weight, rule.weight);
|
|
7626
|
-
bucket.findings.push({
|
|
7627
|
-
ruleId: `scorecard:${name}`,
|
|
7628
|
-
severity,
|
|
7629
|
-
message,
|
|
7630
|
-
...location ? { location } : {}
|
|
7631
|
-
});
|
|
7632
|
-
buckets.set(rule.dimension, bucket);
|
|
9171
|
+
function scoreCriterion(signal, rubricVersion) {
|
|
9172
|
+
if (!signal) {
|
|
9173
|
+
return {
|
|
9174
|
+
score: 0,
|
|
9175
|
+
status: unmeasuredStatus(rubricVersion),
|
|
9176
|
+
evidence: [],
|
|
9177
|
+
findings: [],
|
|
9178
|
+
metrics: []
|
|
9179
|
+
};
|
|
7633
9180
|
}
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
|
|
7657
|
-
|
|
7658
|
-
|
|
7659
|
-
|
|
7660
|
-
|
|
7661
|
-
|
|
9181
|
+
if (signal.notApplicable === true) {
|
|
9182
|
+
return {
|
|
9183
|
+
score: 0,
|
|
9184
|
+
status: "not_applicable",
|
|
9185
|
+
evidence: [],
|
|
9186
|
+
findings: [],
|
|
9187
|
+
metrics: []
|
|
9188
|
+
};
|
|
9189
|
+
}
|
|
9190
|
+
const evidence = signal.positiveEvidence;
|
|
9191
|
+
const findings = signal.findings;
|
|
9192
|
+
const metrics = signal.metrics ?? [];
|
|
9193
|
+
const evidenceCount = evidence.length + findings.length;
|
|
9194
|
+
if (evidenceCount === 0) {
|
|
9195
|
+
if (!usesMetricScoring(rubricVersion) || metrics.length === 0) {
|
|
9196
|
+
return {
|
|
9197
|
+
score: 0,
|
|
9198
|
+
status: unmeasuredStatus(rubricVersion),
|
|
9199
|
+
evidence,
|
|
9200
|
+
findings,
|
|
9201
|
+
metrics
|
|
9202
|
+
};
|
|
9203
|
+
}
|
|
9204
|
+
}
|
|
9205
|
+
if (usesMetricScoring(rubricVersion)) {
|
|
9206
|
+
const measuredMetrics = metrics.length > 0 ? metrics : fallbackMetricsForEvidence(evidence, findings);
|
|
9207
|
+
const score = capScoreForFindings(scoreMetrics(measuredMetrics), findings);
|
|
9208
|
+
const status = statusForScoreAndFindings(score, findings);
|
|
9209
|
+
return {
|
|
9210
|
+
score,
|
|
9211
|
+
status,
|
|
9212
|
+
evidence,
|
|
9213
|
+
findings: ensureFindingsExplainStatus(signal.criterionId, score, status, findings, evidence),
|
|
9214
|
+
metrics: measuredMetrics
|
|
9215
|
+
};
|
|
9216
|
+
}
|
|
9217
|
+
if (findings.some((finding) => finding.severity === "critical")) {
|
|
9218
|
+
return {
|
|
9219
|
+
score: 1,
|
|
9220
|
+
status: "critical",
|
|
9221
|
+
evidence,
|
|
9222
|
+
findings,
|
|
9223
|
+
metrics
|
|
9224
|
+
};
|
|
9225
|
+
}
|
|
9226
|
+
if (findings.some((finding) => finding.severity === "warning")) {
|
|
9227
|
+
return {
|
|
9228
|
+
score: 2,
|
|
9229
|
+
status: "warning",
|
|
9230
|
+
evidence,
|
|
9231
|
+
findings,
|
|
9232
|
+
metrics
|
|
9233
|
+
};
|
|
9234
|
+
}
|
|
9235
|
+
if (findings.some((finding) => finding.severity === "info")) {
|
|
9236
|
+
return {
|
|
9237
|
+
score: 3,
|
|
9238
|
+
status: "info",
|
|
9239
|
+
evidence,
|
|
9240
|
+
findings,
|
|
9241
|
+
metrics
|
|
9242
|
+
};
|
|
9243
|
+
}
|
|
9244
|
+
return {
|
|
9245
|
+
score: 4,
|
|
9246
|
+
status: "verified",
|
|
9247
|
+
evidence,
|
|
9248
|
+
findings,
|
|
9249
|
+
metrics
|
|
9250
|
+
};
|
|
7662
9251
|
}
|
|
7663
|
-
function
|
|
7664
|
-
|
|
7665
|
-
|
|
7666
|
-
|
|
7667
|
-
|
|
7668
|
-
|
|
7669
|
-
|
|
7670
|
-
|
|
7671
|
-
|
|
7672
|
-
|
|
7673
|
-
const severity = finding.severity;
|
|
7674
|
-
if (!severity || !VALID_SEVERITIES.has(severity)) continue;
|
|
7675
|
-
const ruleId = finding.ruleId ?? "unknown";
|
|
7676
|
-
findings.push({
|
|
7677
|
-
ruleId,
|
|
7678
|
-
severity,
|
|
7679
|
-
message: finding.message ?? ruleId,
|
|
7680
|
-
...finding.location ? { location: finding.location } : {}
|
|
7681
|
-
});
|
|
9252
|
+
function fallbackMetricsForEvidence(evidence, findings) {
|
|
9253
|
+
return [
|
|
9254
|
+
{
|
|
9255
|
+
name: "evidence_depth",
|
|
9256
|
+
label: "Evidence depth",
|
|
9257
|
+
value: Math.min(evidence.length + findings.length + 1, 4),
|
|
9258
|
+
max: 4,
|
|
9259
|
+
weight: 1,
|
|
9260
|
+
unit: "signals",
|
|
9261
|
+
description: "Conservative v1 fallback for externally supplied evidence that has not provided criterion-specific depth metrics."
|
|
7682
9262
|
}
|
|
7683
|
-
|
|
7684
|
-
signals.push({ source, dimension, weight, findings });
|
|
7685
|
-
}
|
|
7686
|
-
return signals;
|
|
9263
|
+
];
|
|
7687
9264
|
}
|
|
7688
|
-
|
|
7689
|
-
|
|
7690
|
-
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
if (value.length <= max) return value;
|
|
7699
|
-
const ellipsis = "...";
|
|
7700
|
-
return `${value.slice(0, Math.max(max - ellipsis.length, 0))}${ellipsis}`;
|
|
9265
|
+
function scoreMetrics(metrics) {
|
|
9266
|
+
let weightedTotal = 0;
|
|
9267
|
+
let totalWeight = 0;
|
|
9268
|
+
for (const metric2 of metrics) {
|
|
9269
|
+
const normalized = metric2.max ? Math.min(metric2.value / metric2.max, 1) : Math.min(metric2.value, 1);
|
|
9270
|
+
weightedTotal += normalized * metric2.weight;
|
|
9271
|
+
totalWeight += metric2.weight;
|
|
9272
|
+
}
|
|
9273
|
+
if (totalWeight === 0) return 0;
|
|
9274
|
+
return roundScore(weightedTotal / totalWeight * 4);
|
|
7701
9275
|
}
|
|
7702
|
-
function
|
|
7703
|
-
return
|
|
7704
|
-
|
|
7705
|
-
|
|
7706
|
-
|
|
7707
|
-
...finding.location ? { location: clamp(finding.location, LOCATION_MAX) } : {}
|
|
7708
|
-
};
|
|
9276
|
+
function capScoreForFindings(score, findings) {
|
|
9277
|
+
if (findings.some((finding) => finding.severity === "critical")) return 1.4;
|
|
9278
|
+
if (findings.some((finding) => finding.severity === "warning")) return Math.min(score, 2.4);
|
|
9279
|
+
if (findings.some((finding) => finding.severity === "info")) return Math.min(score, 3.4);
|
|
9280
|
+
return score;
|
|
7709
9281
|
}
|
|
7710
|
-
|
|
7711
|
-
|
|
7712
|
-
|
|
7713
|
-
if (
|
|
7714
|
-
|
|
9282
|
+
function statusForScoreAndFindings(score, findings) {
|
|
9283
|
+
if (findings.some((finding) => finding.severity === "critical")) return "critical";
|
|
9284
|
+
if (findings.some((finding) => finding.severity === "warning")) return "warning";
|
|
9285
|
+
if (score >= 3.5 && findings.length === 0) return "verified";
|
|
9286
|
+
if (score >= 2.5) return "info";
|
|
9287
|
+
if (score >= 1.5) return "warning";
|
|
9288
|
+
return "critical";
|
|
7715
9289
|
}
|
|
7716
|
-
function
|
|
7717
|
-
if (
|
|
7718
|
-
|
|
9290
|
+
function ensureFindingsExplainStatus(criterionId, score, status, findings, evidence) {
|
|
9291
|
+
if (findings.length > 0) return [...findings];
|
|
9292
|
+
if (status !== "critical" && status !== "warning") return [...findings];
|
|
9293
|
+
const anchor = evidence[0] ?? {
|
|
9294
|
+
kind: "repository",
|
|
9295
|
+
label: `${criterionId} metric-derived score`,
|
|
9296
|
+
path: "."
|
|
9297
|
+
};
|
|
9298
|
+
return [
|
|
9299
|
+
{
|
|
9300
|
+
severity: status,
|
|
9301
|
+
summary: `${criterionId} metric-derived score is ${score.toFixed(1)}/4.0, in the ${status} band \u2014 no single finding drove this; it reflects the combined metric weighting below.`,
|
|
9302
|
+
evidence: anchor
|
|
9303
|
+
}
|
|
9304
|
+
];
|
|
7719
9305
|
}
|
|
7720
|
-
function
|
|
7721
|
-
const
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
}
|
|
7728
|
-
if (Array.isArray(obj.checks)) return obj.checks.length;
|
|
7729
|
-
if (Array.isArray(obj.signals)) {
|
|
7730
|
-
return obj.signals.reduce((sum, signal) => {
|
|
7731
|
-
const findings = signal.findings;
|
|
7732
|
-
return sum + (Array.isArray(findings) ? findings.length : 0);
|
|
7733
|
-
}, 0);
|
|
7734
|
-
}
|
|
7735
|
-
return 0;
|
|
9306
|
+
function averageScore(criteria) {
|
|
9307
|
+
const applicable = criteria.filter(
|
|
9308
|
+
(criterion) => criterion.status !== "not_applicable" && criterion.status !== "insufficient_data"
|
|
9309
|
+
);
|
|
9310
|
+
if (applicable.length === 0) return 0;
|
|
9311
|
+
const total = applicable.reduce((sum, criterion) => sum + criterion.score, 0);
|
|
9312
|
+
return roundScore(total / applicable.length);
|
|
7736
9313
|
}
|
|
7737
|
-
function
|
|
7738
|
-
|
|
7739
|
-
if (Array.isArray(obj.runs)) {
|
|
7740
|
-
const firstRun = obj.runs[0];
|
|
7741
|
-
return firstRun?.tool?.driver?.name ?? "unknown";
|
|
7742
|
-
}
|
|
7743
|
-
if (typeof obj.tool === "string" && obj.tool.length > 0) return obj.tool;
|
|
7744
|
-
return "scorecard";
|
|
9314
|
+
function roundScore(score) {
|
|
9315
|
+
return Math.round(score * 10) / 10;
|
|
7745
9316
|
}
|
|
7746
|
-
|
|
7747
|
-
|
|
7748
|
-
|
|
7749
|
-
|
|
7750
|
-
|
|
7751
|
-
|
|
7752
|
-
|
|
7753
|
-
|
|
7754
|
-
|
|
7755
|
-
|
|
7756
|
-
|
|
7757
|
-
else if (isGenericSignalDocument(raw)) signals = parseGenericJson(raw);
|
|
7758
|
-
if (!signals) {
|
|
7759
|
-
throw new Error(
|
|
7760
|
-
`Cejel: unrecognized ingest file format: ${filePath} \u2014 expected SARIF (a "runs" array), OpenSSF Scorecard JSON (a "checks" array), or the generic Cejel external-signal shape (a "tool" string + "signals" array). See the cejel README "Aggregate your scanners".`
|
|
7761
|
-
);
|
|
7762
|
-
}
|
|
7763
|
-
const rawCount = countRawEntries(raw);
|
|
7764
|
-
const mappedCount = signals.reduce((sum, signal) => sum + signal.findings.length, 0);
|
|
7765
|
-
if (rawCount > 0 && mappedCount === 0) {
|
|
7766
|
-
process.stderr.write(
|
|
7767
|
-
`Cejel: ${rawCount} findings from ${rawToolName(raw)} (${filePath}), 0 mapped to trust criteria
|
|
7768
|
-
`
|
|
7769
|
-
);
|
|
7770
|
-
}
|
|
7771
|
-
return signals.map((signal) => ({
|
|
7772
|
-
...signal,
|
|
7773
|
-
findings: signal.findings.map(clampFinding)
|
|
7774
|
-
}));
|
|
9317
|
+
|
|
9318
|
+
// ../witan/src/public-scan.ts
|
|
9319
|
+
function scoreRepoWithPublicCejel(options) {
|
|
9320
|
+
const input = buildWitanInputFromRepo({
|
|
9321
|
+
productSlug: options.productSlug,
|
|
9322
|
+
productDisplayName: options.productDisplayName,
|
|
9323
|
+
repoPath: options.repoPath,
|
|
9324
|
+
...options.generatedAt ? { generatedAt: options.generatedAt } : {}
|
|
9325
|
+
});
|
|
9326
|
+
const inputSignals = resolvePublicIngestSignals(options);
|
|
9327
|
+
return createWitanReport(input, inputSignals.length > 0 ? inputSignals : void 0);
|
|
7775
9328
|
}
|
|
7776
|
-
function
|
|
7777
|
-
|
|
7778
|
-
const
|
|
7779
|
-
const
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
9329
|
+
function resolvePublicIngestSignals(options) {
|
|
9330
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9331
|
+
const files = [];
|
|
9332
|
+
for (const pattern of options.ingestPatterns ?? []) {
|
|
9333
|
+
const matches = expandIngestPattern(pattern);
|
|
9334
|
+
if (matches.length === 0 && options.warnOnEmptyIngestMatch) {
|
|
9335
|
+
process.stderr.write(`Cejel: --ingest pattern matched no files: ${pattern}
|
|
9336
|
+
`);
|
|
9337
|
+
}
|
|
9338
|
+
for (const match of matches) {
|
|
9339
|
+
const resolved = resolve2(match);
|
|
9340
|
+
if (seen.has(resolved)) continue;
|
|
9341
|
+
seen.add(resolved);
|
|
9342
|
+
files.push(match);
|
|
9343
|
+
}
|
|
7788
9344
|
}
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
try {
|
|
7795
|
-
entries = readdirSync2(inputsDir);
|
|
7796
|
-
} catch {
|
|
7797
|
-
return [];
|
|
9345
|
+
for (const discovered of discoverIngestInputs(options.repoPath)) {
|
|
9346
|
+
const resolved = resolve2(discovered);
|
|
9347
|
+
if (seen.has(resolved)) continue;
|
|
9348
|
+
seen.add(resolved);
|
|
9349
|
+
files.push(discovered);
|
|
7798
9350
|
}
|
|
7799
|
-
return
|
|
9351
|
+
return files.flatMap((file) => parseIngestFile(file));
|
|
7800
9352
|
}
|
|
7801
9353
|
|
|
7802
|
-
// src/
|
|
7803
|
-
import {
|
|
9354
|
+
// ../witan/src/repo-clone.ts
|
|
9355
|
+
import { execFileSync as execFileSync2 } from "child_process";
|
|
9356
|
+
import { mkdirSync, rmSync } from "fs";
|
|
9357
|
+
import { tmpdir } from "os";
|
|
9358
|
+
import { join as join4 } from "path";
|
|
9359
|
+
|
|
9360
|
+
// ../witan/src/cejel-package-name.ts
|
|
9361
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
9362
|
+
import { fileURLToPath } from "url";
|
|
9363
|
+
|
|
9364
|
+
// ../witan/src/leaderboard.ts
|
|
9365
|
+
var RESERVED_CORPUS_SLUGS = ["biome", "tsconfig", "package"];
|
|
9366
|
+
var LeaderboardCorpusEntrySchema = external_exports.object({
|
|
9367
|
+
// Also the evidence-report slug (reports/<name>.{json,md,svg}) — min length 3
|
|
9368
|
+
// to satisfy the WitanReport productSlug pattern.
|
|
9369
|
+
name: external_exports.string().regex(/^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/).refine((value) => !RESERVED_CORPUS_SLUGS.includes(value), {
|
|
9370
|
+
message: "Corpus entry name collides with a tool config filename (reports/<name>.json would be discovered by that tool) \u2014 pick a different slug, e.g. biomejs."
|
|
9371
|
+
}),
|
|
9372
|
+
category: external_exports.string().min(1).max(80),
|
|
9373
|
+
expectedArchetype: external_exports.string().min(1).max(40),
|
|
9374
|
+
license: external_exports.string().min(1).max(80),
|
|
9375
|
+
/**
|
|
9376
|
+
* Repository visibility — the redaction policy's first-class input
|
|
9377
|
+
* (goal_cejel_redaction_policy_is_verifiability_2026-07-12): a path is
|
|
9378
|
+
* published exactly when the reader can check it (public), and withheld
|
|
9379
|
+
* entirely when they can't (private). FAIL CLOSED: absent or unrecognized
|
|
9380
|
+
* resolves to 'private' via `.catch` rather than throwing or defaulting
|
|
9381
|
+
* open, so a corpus entry can never accidentally publish paths by omission.
|
|
9382
|
+
*/
|
|
9383
|
+
visibility: external_exports.enum(["public", "private"]).catch("private"),
|
|
9384
|
+
url: external_exports.string().url().optional(),
|
|
9385
|
+
/**
|
|
9386
|
+
* Immutable source snapshot for URL entries. A rubric rescore always uses
|
|
9387
|
+
* the same commits; changing one is a separate corpus update.
|
|
9388
|
+
*/
|
|
9389
|
+
commit: external_exports.string().regex(/^[0-9a-f]{40}$/).optional(),
|
|
9390
|
+
self: external_exports.literal(true).optional(),
|
|
9391
|
+
/**
|
|
9392
|
+
* A directory inside THIS repository (relative to its root), for internal
|
|
9393
|
+
* entries that are a sub-package rather than the whole repo (e.g. the public
|
|
9394
|
+
* cejel CLI at packages/witan-cli). Scored locally like "self".
|
|
9395
|
+
*/
|
|
9396
|
+
path: external_exports.string().min(1).max(200).regex(/^[A-Za-z0-9._/-]+$/).refine((value) => !value.startsWith("/") && !value.split("/").includes(".."), {
|
|
9397
|
+
message: 'Corpus entry "path" must be relative and must not traverse upward.'
|
|
9398
|
+
}).optional()
|
|
9399
|
+
}).strict().refine((entry) => (entry.url ? 1 : 0) + (entry.self ? 1 : 0) + (entry.path ? 1 : 0) === 1, {
|
|
9400
|
+
message: 'Corpus entry must have exactly one of "url", "self", or "path".'
|
|
9401
|
+
}).refine((entry) => entry.url ? entry.commit !== void 0 : entry.commit === void 0, {
|
|
9402
|
+
message: 'Every URL corpus entry must declare exactly one immutable 40-character "commit".'
|
|
9403
|
+
});
|
|
9404
|
+
var LeaderboardCorpusSchema = external_exports.object({
|
|
9405
|
+
comment: external_exports.string().min(1),
|
|
9406
|
+
entries: external_exports.array(LeaderboardCorpusEntrySchema).min(1)
|
|
9407
|
+
}).strict().refine(
|
|
9408
|
+
(corpus) => new Set(corpus.entries.map((entry) => entry.name)).size === corpus.entries.length,
|
|
9409
|
+
{ message: "Corpus entry names must be unique." }
|
|
9410
|
+
);
|
|
9411
|
+
|
|
9412
|
+
// ../witan/src/quant-integrity.ts
|
|
9413
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
9414
|
+
import { join as join8 } from "path";
|
|
9415
|
+
|
|
9416
|
+
// ../witan/src/quant-metrics-grading.ts
|
|
9417
|
+
import { createHash as createHash2 } from "crypto";
|
|
9418
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
9419
|
+
import { join as join7 } from "path";
|
|
9420
|
+
|
|
9421
|
+
// ../witan/src/quant-run-tier-grading.ts
|
|
9422
|
+
import { createHash as createHash3 } from "crypto";
|
|
7804
9423
|
|
|
7805
9424
|
// src/product-identity.ts
|
|
7806
|
-
import { existsSync, readFileSync as
|
|
7807
|
-
import { basename as
|
|
9425
|
+
import { existsSync as existsSync3, readFileSync as readFileSync11 } from "fs";
|
|
9426
|
+
import { basename as basename3, join as join9 } from "path";
|
|
7808
9427
|
var SLUG_PATTERN = /^[a-z0-9][a-z0-9-]{1,62}[a-z0-9]$/;
|
|
7809
9428
|
var FALLBACK_SLUG = "repo";
|
|
7810
9429
|
var FALLBACK_DISPLAY_NAME = "Repository";
|
|
7811
9430
|
function deriveProductIdentity(repoPath) {
|
|
7812
|
-
const packageJsonPath =
|
|
7813
|
-
const raw = readPackageName(packageJsonPath) ??
|
|
9431
|
+
const packageJsonPath = join9(repoPath, "package.json");
|
|
9432
|
+
const raw = readPackageName(packageJsonPath) ?? basename3(repoPath);
|
|
7814
9433
|
const displayName = raw.trim().length > 0 ? raw.trim() : FALLBACK_DISPLAY_NAME;
|
|
7815
9434
|
return {
|
|
7816
9435
|
productSlug: slugify(raw),
|
|
@@ -7818,9 +9437,9 @@ function deriveProductIdentity(repoPath) {
|
|
|
7818
9437
|
};
|
|
7819
9438
|
}
|
|
7820
9439
|
function readPackageName(packageJsonPath) {
|
|
7821
|
-
if (!
|
|
9440
|
+
if (!existsSync3(packageJsonPath)) return void 0;
|
|
7822
9441
|
try {
|
|
7823
|
-
const parsed = JSON.parse(
|
|
9442
|
+
const parsed = JSON.parse(readFileSync11(packageJsonPath, "utf8"));
|
|
7824
9443
|
if (typeof parsed === "object" && parsed !== null && "name" in parsed) {
|
|
7825
9444
|
const name = parsed.name;
|
|
7826
9445
|
if (typeof name === "string" && name.trim().length > 0) return name;
|
|
@@ -7881,52 +9500,28 @@ function buildWitanCliSummary(report) {
|
|
|
7881
9500
|
// src/scan.ts
|
|
7882
9501
|
function runCejelScan(options) {
|
|
7883
9502
|
const identity = deriveProductIdentity(options.repoPath);
|
|
7884
|
-
const
|
|
9503
|
+
const report = scoreRepoWithPublicCejel({
|
|
7885
9504
|
productSlug: identity.productSlug,
|
|
7886
9505
|
productDisplayName: identity.productDisplayName,
|
|
7887
|
-
repoPath: options.repoPath
|
|
9506
|
+
repoPath: options.repoPath,
|
|
9507
|
+
ingestPatterns: options.ingestPatterns,
|
|
9508
|
+
warnOnEmptyIngestMatch: options.warnOnEmptyIngestMatch
|
|
7888
9509
|
});
|
|
7889
|
-
const inputSignals = resolveIngestSignals(options);
|
|
7890
|
-
const report = createWitanReport(input, inputSignals.length > 0 ? inputSignals : void 0);
|
|
7891
9510
|
const summary = buildWitanCliSummary(report);
|
|
7892
9511
|
return { report, summary };
|
|
7893
9512
|
}
|
|
7894
|
-
function resolveIngestSignals(options) {
|
|
7895
|
-
const seen = /* @__PURE__ */ new Set();
|
|
7896
|
-
const files = [];
|
|
7897
|
-
for (const pattern of options.ingestPatterns ?? []) {
|
|
7898
|
-
const matches = expandIngestPattern(pattern);
|
|
7899
|
-
if (matches.length === 0 && options.warnOnEmptyIngestMatch) {
|
|
7900
|
-
process.stderr.write(`Cejel: --ingest pattern matched no files: ${pattern}
|
|
7901
|
-
`);
|
|
7902
|
-
}
|
|
7903
|
-
for (const match of matches) {
|
|
7904
|
-
const resolved = resolve2(match);
|
|
7905
|
-
if (seen.has(resolved)) continue;
|
|
7906
|
-
seen.add(resolved);
|
|
7907
|
-
files.push(match);
|
|
7908
|
-
}
|
|
7909
|
-
}
|
|
7910
|
-
for (const discovered of discoverIngestInputs(options.repoPath)) {
|
|
7911
|
-
const resolved = resolve2(discovered);
|
|
7912
|
-
if (seen.has(resolved)) continue;
|
|
7913
|
-
seen.add(resolved);
|
|
7914
|
-
files.push(discovered);
|
|
7915
|
-
}
|
|
7916
|
-
return files.flatMap((file) => parseIngestFile(file));
|
|
7917
|
-
}
|
|
7918
9513
|
|
|
7919
9514
|
export {
|
|
7920
9515
|
__commonJS,
|
|
7921
9516
|
__export,
|
|
7922
9517
|
__toESM,
|
|
7923
|
-
ZodOptional,
|
|
7924
|
-
ZodFirstPartyTypeKind,
|
|
7925
|
-
objectType,
|
|
7926
|
-
external_exports,
|
|
7927
9518
|
formatExternalSourceLine,
|
|
7928
9519
|
renderWitanHtmlReport,
|
|
7929
9520
|
renderWitanBadgeEndpoint,
|
|
7930
9521
|
renderWitanBadgeSvg,
|
|
9522
|
+
ZodOptional,
|
|
9523
|
+
ZodFirstPartyTypeKind,
|
|
9524
|
+
objectType,
|
|
9525
|
+
external_exports,
|
|
7931
9526
|
runCejelScan
|
|
7932
9527
|
};
|