archctx-contracts 0.1.5
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/fixtures/boundary/agent-job-expired.json +33 -0
- package/fixtures/boundary/architecture-event-extension.json +41 -0
- package/fixtures/boundary/architecture-node-extension.json +13 -0
- package/fixtures/boundary/attestation-v2-error.json +43 -0
- package/fixtures/boundary/check-delivery-dead-letter.json +14 -0
- package/fixtures/boundary/evidence-binding-context-only.json +20 -0
- package/fixtures/boundary/practice-disabled-overlay.json +59 -0
- package/fixtures/boundary/recommendation-deferred.json +19 -0
- package/fixtures/boundary/review-challenge-v2-organization.json +15 -0
- package/fixtures/boundary/runner-identity-organization-scope.json +16 -0
- package/fixtures/invalid/adapter-fidelity-reverse-sync.json +9 -0
- package/fixtures/invalid/agent-job-direct-mutation.json +32 -0
- package/fixtures/invalid/architecture-event-source-body-field.json +39 -0
- package/fixtures/invalid/architecture-snapshot-unknown-mode.json +29 -0
- package/fixtures/invalid/attestation-v2-finding-field.json +39 -0
- package/fixtures/invalid/check-delivery-legacy-check-name.json +14 -0
- package/fixtures/invalid/cloud-egress-envelope-private-field.json +12 -0
- package/fixtures/invalid/compatibility-illegal-reason.json +17 -0
- package/fixtures/invalid/evidence-binding-summary-substring-authority.json +17 -0
- package/fixtures/invalid/evidence-item-source-body-field.json +27 -0
- package/fixtures/invalid/explorer-projection-write-field.json +21 -0
- package/fixtures/invalid/investigation-report-direct-mutation.json +38 -0
- package/fixtures/invalid/investigation-report-missing-proposed-delta.json +19 -0
- package/fixtures/invalid/node-unknown-field.json +10 -0
- package/fixtures/invalid/notification-event-code-field.json +11 -0
- package/fixtures/invalid/practice-policy-empty-test-evidence.json +15 -0
- package/fixtures/invalid/practice-policy-negative-recommendation-budget.json +10 -0
- package/fixtures/invalid/practice-unknown-field.json +56 -0
- package/fixtures/invalid/projection-target-invalid-ownership.json +18 -0
- package/fixtures/invalid/recommendation-feedback-implicit-acceptance.json +29 -0
- package/fixtures/invalid/recommendation-run-raw-input-field.json +33 -0
- package/fixtures/invalid/recommendation-source-body-field.json +17 -0
- package/fixtures/invalid/review-challenge-v2-private-field.json +16 -0
- package/fixtures/valid/adapter-fidelity.json +9 -0
- package/fixtures/valid/agent-job.json +33 -0
- package/fixtures/valid/architecture-candidate-delta-policy.json +45 -0
- package/fixtures/valid/architecture-candidate-delta.json +188 -0
- package/fixtures/valid/architecture-event.json +39 -0
- package/fixtures/valid/architecture-intervention.json +36 -0
- package/fixtures/valid/architecture-node.json +25 -0
- package/fixtures/valid/architecture-relation.json +14 -0
- package/fixtures/valid/architecture-snapshot.json +31 -0
- package/fixtures/valid/architecture-subject-selector.json +9 -0
- package/fixtures/valid/attestation-v2.json +38 -0
- package/fixtures/valid/attestation.json +25 -0
- package/fixtures/valid/changeset.json +30 -0
- package/fixtures/valid/chatgpt-ga-tool.json +9 -0
- package/fixtures/valid/check-delivery.json +14 -0
- package/fixtures/valid/cloud-egress-envelope.json +11 -0
- package/fixtures/valid/compatibility-contract.json +19 -0
- package/fixtures/valid/constraint.json +22 -0
- package/fixtures/valid/cross-repo-relation.json +23 -0
- package/fixtures/valid/device-identity.json +10 -0
- package/fixtures/valid/entitlement.json +12 -0
- package/fixtures/valid/evidence-binding.json +17 -0
- package/fixtures/valid/evidence-item.json +29 -0
- package/fixtures/valid/explorer-projection.json +53 -0
- package/fixtures/valid/explorer-service.json +11 -0
- package/fixtures/valid/external-document-resource.json +29 -0
- package/fixtures/valid/governance-key-status.json +11 -0
- package/fixtures/valid/investigation-report.json +38 -0
- package/fixtures/valid/landscape.json +36 -0
- package/fixtures/valid/likec4-mapping.json +14 -0
- package/fixtures/valid/notification-event.json +10 -0
- package/fixtures/valid/notification-provider.json +12 -0
- package/fixtures/valid/org-runner-identity.json +10 -0
- package/fixtures/valid/practice-catalog-manifest.json +16 -0
- package/fixtures/valid/practice-check-result.json +17 -0
- package/fixtures/valid/practice-checkpoint.json +94 -0
- package/fixtures/valid/practice-guidance.json +42 -0
- package/fixtures/valid/practice-match.json +23 -0
- package/fixtures/valid/practice-policy.json +33 -0
- package/fixtures/valid/practice-profile.json +22 -0
- package/fixtures/valid/practice-source.json +19 -0
- package/fixtures/valid/practice-waiver.json +14 -0
- package/fixtures/valid/practice.json +93 -0
- package/fixtures/valid/product-version-manifest.json +51 -0
- package/fixtures/valid/projection-target.json +18 -0
- package/fixtures/valid/recommendation-feedback.json +29 -0
- package/fixtures/valid/recommendation-run.json +33 -0
- package/fixtures/valid/recommendation.json +17 -0
- package/fixtures/valid/retrieval-config.json +20 -0
- package/fixtures/valid/retrieval-decision.json +26 -0
- package/fixtures/valid/retrieval-eval.json +14 -0
- package/fixtures/valid/review-challenge-v2.json +15 -0
- package/fixtures/valid/review-result.json +32 -0
- package/fixtures/valid/runner-identity.json +13 -0
- package/fixtures/valid/structurizr-mapping.json +15 -0
- package/fixtures/valid/task-context.json +23 -0
- package/package.json +17 -0
- package/src/control-plane-routes.ts +35 -0
- package/src/external-docs.ts +137 -0
- package/src/github-governance.ts +850 -0
- package/src/index.ts +9 -0
- package/src/ledger.ts +649 -0
- package/src/ports.ts +385 -0
- package/src/practices.ts +433 -0
- package/src/product-version.ts +108 -0
- package/src/schema.ts +145 -0
- package/src/validator.ts +95 -0
package/src/validator.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { Json } from "./schema";
|
|
2
|
+
|
|
3
|
+
export interface ValidationIssue {
|
|
4
|
+
path: string;
|
|
5
|
+
message: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export interface ValidationResult {
|
|
9
|
+
valid: boolean;
|
|
10
|
+
issues: ValidationIssue[];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type JsonSchema = {
|
|
14
|
+
type?: string | string[];
|
|
15
|
+
const?: Json;
|
|
16
|
+
enum?: Json[];
|
|
17
|
+
pattern?: string;
|
|
18
|
+
required?: string[];
|
|
19
|
+
properties?: Record<string, JsonSchema>;
|
|
20
|
+
items?: JsonSchema;
|
|
21
|
+
oneOf?: JsonSchema[];
|
|
22
|
+
additionalProperties?: boolean | JsonSchema;
|
|
23
|
+
minItems?: number;
|
|
24
|
+
minimum?: number;
|
|
25
|
+
maximum?: number;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export function validateJsonSchema(schema: JsonSchema, value: Json): ValidationResult {
|
|
29
|
+
const issues: ValidationIssue[] = [];
|
|
30
|
+
visit(schema, value, "$", issues);
|
|
31
|
+
return { valid: issues.length === 0, issues };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function visit(schema: JsonSchema, value: Json, path: string, issues: ValidationIssue[]): void {
|
|
35
|
+
if (schema.oneOf) {
|
|
36
|
+
const matched = schema.oneOf.filter((candidate) => {
|
|
37
|
+
const candidateIssues: ValidationIssue[] = [];
|
|
38
|
+
visit(candidate, value, path, candidateIssues);
|
|
39
|
+
return candidateIssues.length === 0;
|
|
40
|
+
}).length;
|
|
41
|
+
if (matched !== 1) {
|
|
42
|
+
issues.push({ path, message: `expected exactly one matching schema, got ${matched}` });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
if (schema.const !== undefined && JSON.stringify(value) !== JSON.stringify(schema.const)) {
|
|
47
|
+
issues.push({ path, message: `expected const ${JSON.stringify(schema.const)}` });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (schema.enum && !schema.enum.some((item) => JSON.stringify(item) === JSON.stringify(value))) {
|
|
51
|
+
issues.push({ path, message: `expected one of ${schema.enum.map(String).join(", ")}` });
|
|
52
|
+
}
|
|
53
|
+
if (schema.type && !matchesType(schema.type, value)) {
|
|
54
|
+
issues.push({ path, message: `expected type ${Array.isArray(schema.type) ? schema.type.join("|") : schema.type}` });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (typeof value === "string" && schema.pattern && !new RegExp(schema.pattern).test(value)) {
|
|
58
|
+
issues.push({ path, message: `does not match ${schema.pattern}` });
|
|
59
|
+
}
|
|
60
|
+
if (typeof value === "number") {
|
|
61
|
+
if (schema.minimum !== undefined && value < schema.minimum) issues.push({ path, message: `below minimum ${schema.minimum}` });
|
|
62
|
+
if (schema.maximum !== undefined && value > schema.maximum) issues.push({ path, message: `above maximum ${schema.maximum}` });
|
|
63
|
+
}
|
|
64
|
+
if (Array.isArray(value)) {
|
|
65
|
+
if (schema.minItems !== undefined && value.length < schema.minItems) {
|
|
66
|
+
issues.push({ path, message: `expected at least ${schema.minItems} items` });
|
|
67
|
+
}
|
|
68
|
+
if (schema.items) value.forEach((item, index) => visit(schema.items!, item, `${path}[${index}]`, issues));
|
|
69
|
+
}
|
|
70
|
+
if (value !== null && typeof value === "object" && !Array.isArray(value)) {
|
|
71
|
+
const objectValue = value as Record<string, Json>;
|
|
72
|
+
for (const key of schema.required ?? []) {
|
|
73
|
+
if (!(key in objectValue)) issues.push({ path: `${path}.${key}`, message: "required" });
|
|
74
|
+
}
|
|
75
|
+
for (const [key, child] of Object.entries(schema.properties ?? {})) {
|
|
76
|
+
if (key in objectValue) visit(child, objectValue[key], `${path}.${key}`, issues);
|
|
77
|
+
}
|
|
78
|
+
if (schema.additionalProperties === false && schema.properties) {
|
|
79
|
+
for (const key of Object.keys(objectValue)) {
|
|
80
|
+
if (!(key in schema.properties)) issues.push({ path: `${path}.${key}`, message: "additional property denied" });
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function matchesType(type: string | string[], value: Json): boolean {
|
|
87
|
+
const allowed = Array.isArray(type) ? type : [type];
|
|
88
|
+
return allowed.some((candidate) => {
|
|
89
|
+
if (candidate === "array") return Array.isArray(value);
|
|
90
|
+
if (candidate === "null") return value === null;
|
|
91
|
+
if (candidate === "object") return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
92
|
+
if (candidate === "integer") return Number.isInteger(value);
|
|
93
|
+
return typeof value === candidate;
|
|
94
|
+
});
|
|
95
|
+
}
|