witnora 0.8.1 → 0.9.0
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 +275 -12
- package/dist/artifact-manifest.js +37 -0
- package/dist/artifact-validation.js +102 -0
- package/dist/badge.js +31 -0
- package/dist/browser-adapter.js +156 -0
- package/dist/bundle.js +100 -0
- package/dist/cli.js +971 -0
- package/dist/command-help.js +71 -0
- package/dist/companion-artifacts.js +170 -0
- package/dist/conformance.js +115 -0
- package/dist/control-plane.js +409 -0
- package/dist/corpus-governance.js +126 -0
- package/dist/corpus-store.js +239 -0
- package/dist/corpus.js +438 -0
- package/dist/credentials.js +127 -0
- package/dist/evidence-signing.js +85 -0
- package/dist/failure-review.js +188 -0
- package/dist/guided-setup.js +101 -0
- package/dist/index.js +16 -0
- package/dist/lab.js +323 -0
- package/dist/local-server.js +491 -0
- package/dist/monitor.js +100 -0
- package/dist/normalizers.js +265 -0
- package/dist/onboarding-templates.js +158 -0
- package/dist/release-gate.js +457 -0
- package/dist/report.js +165 -0
- package/dist/runner.js +349 -0
- package/dist/sandbox.js +424 -0
- package/dist/schema-validator.js +503 -0
- package/dist/try.js +135 -0
- package/dist/types.js +3 -0
- package/dist/vendor/onegent-runtime/browser-adapter-kit.d.ts +107 -0
- package/dist/vendor/onegent-runtime/browser-adapter-kit.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/browser-adapter-kit.js +187 -0
- package/dist/vendor/onegent-runtime/browser-enforcement-runtime.d.ts +183 -0
- package/dist/vendor/onegent-runtime/browser-enforcement-runtime.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/browser-enforcement-runtime.js +344 -0
- package/dist/vendor/onegent-runtime/controlled-adapter.d.ts +6 -0
- package/dist/vendor/onegent-runtime/controlled-adapter.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/controlled-adapter.js +40 -0
- package/dist/vendor/onegent-runtime/mock-procurement.d.ts +6 -0
- package/dist/vendor/onegent-runtime/mock-procurement.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/mock-procurement.js +33 -0
- package/dist/vendor/onegent-runtime/policies.d.ts +6 -0
- package/dist/vendor/onegent-runtime/policies.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/policies.js +109 -0
- package/dist/vendor/onegent-runtime/risk.d.ts +3 -0
- package/dist/vendor/onegent-runtime/risk.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/risk.js +54 -0
- package/dist/vendor/onegent-runtime/sandbox-adapter-kit.d.ts +45 -0
- package/dist/vendor/onegent-runtime/sandbox-adapter-kit.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/sandbox-adapter-kit.js +148 -0
- package/dist/vendor/onegent-runtime/sandbox-harness.d.ts +167 -0
- package/dist/vendor/onegent-runtime/sandbox-harness.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/sandbox-harness.js +729 -0
- package/dist/vendor/onegent-runtime/sandbox-hosted.d.ts +77 -0
- package/dist/vendor/onegent-runtime/sandbox-hosted.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/sandbox-hosted.js +152 -0
- package/dist/vendor/onegent-runtime/sdk.d.ts +29 -0
- package/dist/vendor/onegent-runtime/sdk.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/sdk.js +140 -0
- package/dist/vendor/onegent-runtime/service.d.ts +27 -0
- package/dist/vendor/onegent-runtime/service.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/service.js +423 -0
- package/dist/vendor/onegent-runtime/store.d.ts +16 -0
- package/dist/vendor/onegent-runtime/store.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/store.js +29 -0
- package/dist/vendor/onegent-runtime/stripe-test-readonly.d.ts +79 -0
- package/dist/vendor/onegent-runtime/stripe-test-readonly.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/stripe-test-readonly.js +163 -0
- package/dist/vendor/onegent-runtime/trust-crypto.d.ts +11 -0
- package/dist/vendor/onegent-runtime/trust-crypto.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/trust-crypto.js +70 -0
- package/dist/vendor/onegent-runtime/trust-types.d.ts +163 -0
- package/dist/vendor/onegent-runtime/trust-types.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/trust-types.js +7 -0
- package/dist/vendor/onegent-runtime/trusted-recorder.d.ts +49 -0
- package/dist/vendor/onegent-runtime/trusted-recorder.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/trusted-recorder.js +347 -0
- package/dist/vendor/onegent-runtime/types.d.ts +287 -0
- package/dist/vendor/onegent-runtime/types.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/types.js +1 -0
- package/dist/vendor/onegent-runtime/vendor-sandbox-egress.d.ts +49 -0
- package/dist/vendor/onegent-runtime/vendor-sandbox-egress.d.ts.map +1 -0
- package/dist/vendor/onegent-runtime/vendor-sandbox-egress.js +152 -0
- package/package.json +33 -13
- package/bin/witnora.js +0 -3
|
@@ -0,0 +1,503 @@
|
|
|
1
|
+
import { AGENTCERT_EVIDENCE_SCHEMA_SEMVER, AGENTCERT_EVIDENCE_SCHEMA_VERSION } from "./types.js";
|
|
2
|
+
import { validateEvidenceSignature } from "./evidence-signing.js";
|
|
3
|
+
import { validateReleaseGateReport } from "./release-gate.js";
|
|
4
|
+
export function parseSchemaId(input) {
|
|
5
|
+
const value = input ?? "evidence-bundle";
|
|
6
|
+
if (value === "evidence-bundle" ||
|
|
7
|
+
value === "result" ||
|
|
8
|
+
value === "corpus-record" ||
|
|
9
|
+
value === "failure-review" ||
|
|
10
|
+
value === "classifier-eval" ||
|
|
11
|
+
value === "monitor-snapshot" ||
|
|
12
|
+
value === "robustness-lab" ||
|
|
13
|
+
value === "release-gate" ||
|
|
14
|
+
value === "assurance-report" ||
|
|
15
|
+
value === "assurance-delivery" ||
|
|
16
|
+
value === "assurance-scope" ||
|
|
17
|
+
value === "evidence-signature" ||
|
|
18
|
+
value === "evidence-strength" ||
|
|
19
|
+
value === "action-mandate" ||
|
|
20
|
+
value === "trusted-action-record" ||
|
|
21
|
+
value === "trusted-run-receipt") {
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
throw new Error(`Unsupported schema "${value}". Use evidence-bundle, result, corpus-record, failure-review, classifier-eval, monitor-snapshot, robustness-lab, release-gate, assurance-report, assurance-delivery, assurance-scope, evidence-signature, evidence-strength, action-mandate, trusted-action-record, or trusted-run-receipt.`);
|
|
25
|
+
}
|
|
26
|
+
export function validateAgentCertSchema(schema, input) {
|
|
27
|
+
const errors = [];
|
|
28
|
+
if (schema === "release-gate") {
|
|
29
|
+
errors.push(...validateReleaseGateReport(input));
|
|
30
|
+
return { schema, valid: errors.length === 0, errors };
|
|
31
|
+
}
|
|
32
|
+
if (schema === "evidence-signature") {
|
|
33
|
+
errors.push(...validateEvidenceSignature(input));
|
|
34
|
+
return { schema, valid: errors.length === 0, errors };
|
|
35
|
+
}
|
|
36
|
+
const value = object(input, "$", errors);
|
|
37
|
+
if (value) {
|
|
38
|
+
if (schema === "evidence-bundle")
|
|
39
|
+
validateEvidenceBundle(value, errors);
|
|
40
|
+
if (schema === "result")
|
|
41
|
+
validateResult(value, errors);
|
|
42
|
+
if (schema === "corpus-record")
|
|
43
|
+
validateCorpusRecord(value, errors);
|
|
44
|
+
if (schema === "failure-review")
|
|
45
|
+
validateFailureReview(value, errors);
|
|
46
|
+
if (schema === "classifier-eval")
|
|
47
|
+
validateClassifierEval(value, errors);
|
|
48
|
+
if (schema === "monitor-snapshot")
|
|
49
|
+
validateMonitorSnapshot(value, errors);
|
|
50
|
+
if (schema === "robustness-lab")
|
|
51
|
+
validateRobustnessLab(value, errors);
|
|
52
|
+
if (schema === "assurance-report")
|
|
53
|
+
validateAssuranceReport(value, errors);
|
|
54
|
+
if (schema === "assurance-delivery")
|
|
55
|
+
validateAssuranceDelivery(value, errors);
|
|
56
|
+
if (schema === "assurance-scope")
|
|
57
|
+
validateAssuranceScope(value, errors);
|
|
58
|
+
if (schema === "evidence-strength")
|
|
59
|
+
validateEvidenceStrength(value, errors);
|
|
60
|
+
if (schema === "action-mandate")
|
|
61
|
+
validateActionMandate(value, errors);
|
|
62
|
+
if (schema === "trusted-action-record")
|
|
63
|
+
validateTrustedActionRecord(value, errors);
|
|
64
|
+
if (schema === "trusted-run-receipt")
|
|
65
|
+
validateTrustedRunReceipt(value, errors);
|
|
66
|
+
}
|
|
67
|
+
return { schema, valid: errors.length === 0, errors };
|
|
68
|
+
}
|
|
69
|
+
function validateEvidenceBundle(value, errors) {
|
|
70
|
+
requiredConst(value, "schemaName", "agentcert.evidence_bundle", errors);
|
|
71
|
+
requiredConst(value, "schemaVersion", AGENTCERT_EVIDENCE_SCHEMA_VERSION, errors);
|
|
72
|
+
requiredConst(value, "schemaSemver", AGENTCERT_EVIDENCE_SCHEMA_SEMVER, errors);
|
|
73
|
+
requiredConst(value, "kind", "agentcert.evidence_bundle", errors);
|
|
74
|
+
requiredString(value, "runId", errors);
|
|
75
|
+
requiredString(value, "generatedAt", errors);
|
|
76
|
+
requiredObject(value, "subject", errors);
|
|
77
|
+
requiredObject(value, "verdict", errors);
|
|
78
|
+
requiredObject(value, "summary", errors);
|
|
79
|
+
requiredArray(value, "results", errors);
|
|
80
|
+
requiredArray(value, "evidence", errors);
|
|
81
|
+
requiredObject(value, "artifacts", errors);
|
|
82
|
+
requiredArray(value, "standards", errors);
|
|
83
|
+
if (value.evidenceStrength !== undefined) {
|
|
84
|
+
const strength = recordValue(value.evidenceStrength);
|
|
85
|
+
if (!strength)
|
|
86
|
+
errors.push("evidenceStrength must be an object.");
|
|
87
|
+
else
|
|
88
|
+
validateEvidenceStrength(strength, errors, "evidenceStrength.");
|
|
89
|
+
}
|
|
90
|
+
const subject = recordValue(value.subject);
|
|
91
|
+
if (subject) {
|
|
92
|
+
requiredStringAt(subject, "name", "subject.name", errors);
|
|
93
|
+
requiredEnumAt(subject, "type", ["agent", "mcp-server", "tool", "application", "unknown"], "subject.type", errors);
|
|
94
|
+
}
|
|
95
|
+
const verdict = recordValue(value.verdict);
|
|
96
|
+
if (verdict) {
|
|
97
|
+
requiredBooleanAt(verdict, "passed", "verdict.passed", errors);
|
|
98
|
+
requiredNumberRange(verdict, "score", "verdict.score", 0, 100, errors);
|
|
99
|
+
requiredStringAt(verdict, "level", "verdict.level", errors);
|
|
100
|
+
}
|
|
101
|
+
const summary = recordValue(value.summary);
|
|
102
|
+
if (summary) {
|
|
103
|
+
stringArray(summary.products, "summary.products", errors);
|
|
104
|
+
requiredNonNegativeInteger(summary, "criticalEvidence", "summary.criticalEvidence", errors);
|
|
105
|
+
requiredNonNegativeInteger(summary, "highEvidence", "summary.highEvidence", errors);
|
|
106
|
+
requiredNonNegativeInteger(summary, "totalEvidence", "summary.totalEvidence", errors);
|
|
107
|
+
}
|
|
108
|
+
validateTimestamp(value.generatedAt, "generatedAt", errors);
|
|
109
|
+
validateArtifactMap(value.artifacts, "artifacts", errors);
|
|
110
|
+
validateResultArray(value.results, "results", errors);
|
|
111
|
+
validateEvidenceArray(value.evidence, "evidence", errors);
|
|
112
|
+
validateStandards(value.standards, errors);
|
|
113
|
+
}
|
|
114
|
+
const EVIDENCE_LEVELS = ["reported", "recorded", "enforced", "outcome_verified", "independently_reviewed"];
|
|
115
|
+
const ACTION_TYPES = ["SUBMIT", "PAY", "SEND", "UPDATE"];
|
|
116
|
+
function validateEvidenceStrength(value, errors, prefix = "") {
|
|
117
|
+
requiredConst(value, "schemaVersion", "agentcert.evidence_strength.v0.1", errors);
|
|
118
|
+
requiredEnumAt(value, "level", EVIDENCE_LEVELS, `${prefix}level`, errors);
|
|
119
|
+
requiredArray(value, "claims", errors);
|
|
120
|
+
requiredArray(value, "limitations", errors);
|
|
121
|
+
stringArray(value.claims, `${prefix}claims`, errors);
|
|
122
|
+
stringArray(value.limitations, `${prefix}limitations`, errors);
|
|
123
|
+
}
|
|
124
|
+
function validateActionMandate(value, errors) {
|
|
125
|
+
requiredConst(value, "schemaVersion", "agentcert.action_mandate.v0.1", errors);
|
|
126
|
+
for (const field of ["mandateId", "policySha256", "validFrom", "expiresAt", "issuedAt", "digestSha256"])
|
|
127
|
+
requiredString(value, field, errors);
|
|
128
|
+
requiredObject(value, "issuer", errors);
|
|
129
|
+
requiredObject(value, "subject", errors);
|
|
130
|
+
requiredObject(value, "scope", errors);
|
|
131
|
+
requiredObject(value, "sourceSignature", errors);
|
|
132
|
+
sha256Field(value, "policySha256", errors);
|
|
133
|
+
sha256Field(value, "digestSha256", errors);
|
|
134
|
+
for (const field of ["validFrom", "expiresAt", "issuedAt"])
|
|
135
|
+
validateTimestamp(value[field], field, errors);
|
|
136
|
+
const scope = recordValue(value.scope);
|
|
137
|
+
if (scope) {
|
|
138
|
+
requiredArray(scope, "actionTypes", errors);
|
|
139
|
+
requiredArray(scope, "targetSystems", errors);
|
|
140
|
+
requiredArray(scope, "permissions", errors);
|
|
141
|
+
if (Array.isArray(scope.actionTypes))
|
|
142
|
+
scope.actionTypes.forEach((item, index) => {
|
|
143
|
+
if (!ACTION_TYPES.includes(String(item)))
|
|
144
|
+
errors.push(`scope.actionTypes[${index}] is not supported.`);
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
validateSourceSignature(value.sourceSignature, "sourceSignature", errors);
|
|
148
|
+
}
|
|
149
|
+
function validateTrustedActionRecord(value, errors) {
|
|
150
|
+
requiredConst(value, "schemaVersion", "agentcert.trusted_action_record.v0.1", errors);
|
|
151
|
+
for (const field of ["recordId", "runId", "occurredAt", "type", "payloadSha256", "eventHash"])
|
|
152
|
+
requiredString(value, field, errors);
|
|
153
|
+
requiredNonNegativeInteger(value, "sequence", "sequence", errors);
|
|
154
|
+
requiredObject(value, "collector", errors);
|
|
155
|
+
requiredObject(value, "payload", errors);
|
|
156
|
+
requiredObject(value, "sourceSignature", errors);
|
|
157
|
+
sha256Field(value, "payloadSha256", errors);
|
|
158
|
+
sha256Field(value, "eventHash", errors);
|
|
159
|
+
if (value.previousEventHash !== undefined)
|
|
160
|
+
sha256Field(value, "previousEventHash", errors);
|
|
161
|
+
validateTimestamp(value.occurredAt, "occurredAt", errors);
|
|
162
|
+
validateSourceSignature(value.sourceSignature, "sourceSignature", errors);
|
|
163
|
+
}
|
|
164
|
+
function validateTrustedRunReceipt(value, errors) {
|
|
165
|
+
requiredConst(value, "schemaVersion", "agentcert.trusted_run_receipt.v0.1", errors);
|
|
166
|
+
for (const field of ["runId", "startedAt", "completedAt", "firstEventHash", "lastEventHash", "sourcePublicKeyPem", "receiptSha256"])
|
|
167
|
+
requiredString(value, field, errors);
|
|
168
|
+
for (const field of ["eventCount", "droppedEventCount"])
|
|
169
|
+
requiredNonNegativeInteger(value, field, field, errors);
|
|
170
|
+
requiredObject(value, "collector", errors);
|
|
171
|
+
requiredArray(value, "mandateDigests", errors);
|
|
172
|
+
requiredArray(value, "actionIds", errors);
|
|
173
|
+
requiredObject(value, "journal", errors);
|
|
174
|
+
requiredObject(value, "evidenceStrength", errors);
|
|
175
|
+
requiredObject(value, "sourceSignature", errors);
|
|
176
|
+
for (const field of ["firstEventHash", "lastEventHash", "receiptSha256"])
|
|
177
|
+
sha256Field(value, field, errors);
|
|
178
|
+
const strength = recordValue(value.evidenceStrength);
|
|
179
|
+
if (strength)
|
|
180
|
+
validateEvidenceStrength(strength, errors, "evidenceStrength.");
|
|
181
|
+
validateSourceSignature(value.sourceSignature, "sourceSignature", errors);
|
|
182
|
+
}
|
|
183
|
+
function sha256Field(value, field, errors) {
|
|
184
|
+
if (typeof value[field] === "string" && !/^[0-9a-f]{64}$/.test(value[field]))
|
|
185
|
+
errors.push(`${field} must be a lowercase SHA-256 digest.`);
|
|
186
|
+
}
|
|
187
|
+
function validateSourceSignature(value, path, errors) {
|
|
188
|
+
const signature = recordValue(value);
|
|
189
|
+
if (!signature)
|
|
190
|
+
return;
|
|
191
|
+
if (signature.algorithm !== "Ed25519")
|
|
192
|
+
errors.push(`${path}.algorithm must equal Ed25519.`);
|
|
193
|
+
requiredStringAt(signature, "keyId", `${path}.keyId`, errors);
|
|
194
|
+
requiredStringAt(signature, "signature", `${path}.signature`, errors);
|
|
195
|
+
}
|
|
196
|
+
function validateResult(value, errors) {
|
|
197
|
+
requiredConst(value, "schemaVersion", "1", errors);
|
|
198
|
+
requiredString(value, "product", errors);
|
|
199
|
+
requiredString(value, "runId", errors);
|
|
200
|
+
requiredString(value, "timestamp", errors);
|
|
201
|
+
requiredEnum(value, "phase", ["pre-release", "runtime"], errors);
|
|
202
|
+
requiredNumber(value, "score", errors);
|
|
203
|
+
requiredBoolean(value, "passed", errors);
|
|
204
|
+
requiredObject(value, "artifacts", errors);
|
|
205
|
+
requiredArray(value, "evidence", errors);
|
|
206
|
+
requiredNumberRange(value, "score", "score", 0, 100, errors);
|
|
207
|
+
validateTimestamp(value.timestamp, "timestamp", errors);
|
|
208
|
+
validateArtifactMap(value.artifacts, "artifacts", errors);
|
|
209
|
+
validateEvidenceArray(value.evidence, "evidence", errors);
|
|
210
|
+
}
|
|
211
|
+
function validateResultArray(input, path, errors) {
|
|
212
|
+
if (!Array.isArray(input))
|
|
213
|
+
return;
|
|
214
|
+
input.forEach((item, index) => {
|
|
215
|
+
const value = object(item, `${path}[${index}]`, errors);
|
|
216
|
+
if (!value)
|
|
217
|
+
return;
|
|
218
|
+
const nested = [];
|
|
219
|
+
validateResult(value, nested);
|
|
220
|
+
errors.push(...nested.map((error) => `${path}[${index}].${error}`));
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
function validateEvidenceArray(input, path, errors) {
|
|
224
|
+
if (!Array.isArray(input))
|
|
225
|
+
return;
|
|
226
|
+
input.forEach((item, index) => {
|
|
227
|
+
const value = object(item, `${path}[${index}]`, errors);
|
|
228
|
+
if (!value)
|
|
229
|
+
return;
|
|
230
|
+
requiredStringAt(value, "id", `${path}[${index}].id`, errors);
|
|
231
|
+
requiredStringAt(value, "kind", `${path}[${index}].kind`, errors);
|
|
232
|
+
requiredEnumAt(value, "severity", ["critical", "high", "medium", "low", "info"], `${path}[${index}].severity`, errors);
|
|
233
|
+
requiredStringAt(value, "message", `${path}[${index}].message`, errors);
|
|
234
|
+
for (const field of ["source", "artifactPath", "suggestedFix"]) {
|
|
235
|
+
if (value[field] !== undefined && typeof value[field] !== "string")
|
|
236
|
+
errors.push(`${path}[${index}].${field} must be a string.`);
|
|
237
|
+
}
|
|
238
|
+
if (value.metadata !== undefined && !recordValue(value.metadata))
|
|
239
|
+
errors.push(`${path}[${index}].metadata must be an object.`);
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function validateArtifactMap(input, path, errors) {
|
|
243
|
+
const value = recordValue(input);
|
|
244
|
+
if (!value)
|
|
245
|
+
return;
|
|
246
|
+
for (const [key, item] of Object.entries(value))
|
|
247
|
+
if (typeof item !== "string")
|
|
248
|
+
errors.push(`${path}.${key} must be a string.`);
|
|
249
|
+
}
|
|
250
|
+
function validateStandards(input, errors) {
|
|
251
|
+
if (!Array.isArray(input))
|
|
252
|
+
return;
|
|
253
|
+
input.forEach((item, index) => {
|
|
254
|
+
const value = object(item, `standards[${index}]`, errors);
|
|
255
|
+
if (!value)
|
|
256
|
+
return;
|
|
257
|
+
requiredStringAt(value, "id", `standards[${index}].id`, errors);
|
|
258
|
+
requiredStringAt(value, "name", `standards[${index}].name`, errors);
|
|
259
|
+
requiredEnumAt(value, "status", ["mapped", "planned"], `standards[${index}].status`, errors);
|
|
260
|
+
requiredStringAt(value, "note", `standards[${index}].note`, errors);
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
function validateCorpusRecord(value, errors) {
|
|
264
|
+
requiredConst(value, "schemaVersion", "1", errors);
|
|
265
|
+
requiredEnum(value, "kind", ["product_run", "scenario_run"], errors);
|
|
266
|
+
requiredString(value, "id", errors);
|
|
267
|
+
requiredString(value, "subject", errors);
|
|
268
|
+
requiredString(value, "agentName", errors);
|
|
269
|
+
requiredString(value, "agentVersion", errors);
|
|
270
|
+
requiredString(value, "runId", errors);
|
|
271
|
+
requiredBoolean(value, "passed", errors);
|
|
272
|
+
requiredArray(value, "failurePatterns", errors);
|
|
273
|
+
if (value.governance !== undefined) {
|
|
274
|
+
const governance = recordValue(value.governance);
|
|
275
|
+
if (!governance)
|
|
276
|
+
errors.push("governance must be an object.");
|
|
277
|
+
else {
|
|
278
|
+
requiredConst(governance, "schemaVersion", "agentcert.corpus_governance.v0.1", errors);
|
|
279
|
+
requiredEnum(governance, "consent", ["private", "anonymous", "public", "denied"], errors);
|
|
280
|
+
requiredString(governance, "consentSource", errors);
|
|
281
|
+
requiredString(governance, "consentRecordedAt", errors);
|
|
282
|
+
requiredObject(governance, "provenance", errors);
|
|
283
|
+
requiredObject(governance, "redaction", errors);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
function validateAssuranceReport(value, errors) {
|
|
288
|
+
requiredConst(value, "schemaVersion", "agentcert.assurance_report.v0.1", errors);
|
|
289
|
+
for (const key of ["assuranceCaseId", "projectId", "policyPackVersion", "evaluationPlanSha256", "reviewerId", "issuedAt", "expiresAt", "statement"])
|
|
290
|
+
requiredString(value, key, errors);
|
|
291
|
+
requiredObject(value, "subject", errors);
|
|
292
|
+
requiredArray(value, "evidence", errors);
|
|
293
|
+
requiredConst(value, "decision", "issued", errors);
|
|
294
|
+
requiredArray(value, "limitations", errors);
|
|
295
|
+
if (!/^[0-9a-f]{64}$/.test(String(value.evaluationPlanSha256 ?? "")))
|
|
296
|
+
errors.push("evaluationPlanSha256 must be a lowercase SHA-256 digest.");
|
|
297
|
+
validateTimestamp(value.issuedAt, "issuedAt", errors);
|
|
298
|
+
validateTimestamp(value.expiresAt, "expiresAt", errors);
|
|
299
|
+
validateAssuranceContinuity(value.continuousAssurance, errors);
|
|
300
|
+
}
|
|
301
|
+
function validateAssuranceDelivery(value, errors) {
|
|
302
|
+
requiredConst(value, "schemaVersion", "agentcert.assurance_delivery.v0.1", errors);
|
|
303
|
+
for (const key of ["engagementId", "projectId", "assuranceCaseId", "dueAt", "deliveredAt", "evaluationPlanSha256", "statement"])
|
|
304
|
+
requiredString(value, key, errors);
|
|
305
|
+
for (const key of ["customer", "subject", "sandbox", "workflow", "terms", "decision", "integration", "evidenceStrength", "attestation"])
|
|
306
|
+
requiredObject(value, key, errors);
|
|
307
|
+
for (const key of ["baselineEvidence", "remediationItems", "retestEvidence"])
|
|
308
|
+
requiredArray(value, key, errors);
|
|
309
|
+
if (!/^[0-9a-f]{64}$/.test(String(value.evaluationPlanSha256 ?? "")))
|
|
310
|
+
errors.push("evaluationPlanSha256 must be a lowercase SHA-256 digest.");
|
|
311
|
+
validateTimestamp(value.dueAt, "dueAt", errors);
|
|
312
|
+
validateTimestamp(value.deliveredAt, "deliveredAt", errors);
|
|
313
|
+
const terms = recordValue(value.terms);
|
|
314
|
+
if (terms) {
|
|
315
|
+
if (terms.priceUsd !== 5000)
|
|
316
|
+
errors.push("terms.priceUsd must equal 5000.");
|
|
317
|
+
if (terms.workflowCount !== 1)
|
|
318
|
+
errors.push("terms.workflowCount must equal 1.");
|
|
319
|
+
if (terms.includedRetests !== 1)
|
|
320
|
+
errors.push("terms.includedRetests must equal 1.");
|
|
321
|
+
if (terms.privacy !== "private_by_default")
|
|
322
|
+
errors.push("terms.privacy must equal private_by_default.");
|
|
323
|
+
}
|
|
324
|
+
const decision = recordValue(value.decision);
|
|
325
|
+
if (decision)
|
|
326
|
+
requiredEnum(decision, "verdict", ["RELEASE", "RELEASE_WITH_CONTROLS", "BLOCK"], errors);
|
|
327
|
+
validateAssuranceContinuity(value.continuousAssurance, errors);
|
|
328
|
+
}
|
|
329
|
+
function validateAssuranceContinuity(input, errors) {
|
|
330
|
+
if (input === undefined)
|
|
331
|
+
return;
|
|
332
|
+
const value = recordValue(input);
|
|
333
|
+
if (!value) {
|
|
334
|
+
errors.push("continuousAssurance must be an object.");
|
|
335
|
+
return;
|
|
336
|
+
}
|
|
337
|
+
requiredConst(value, "schemaVersion", "agentcert.assurance_continuity.v0.1", errors);
|
|
338
|
+
requiredObject(value, "scope", errors);
|
|
339
|
+
requiredSha256At(value, "scopeFingerprintSha256", "continuousAssurance.scopeFingerprintSha256", errors);
|
|
340
|
+
requiredConst(value, "freshnessAtIssuance", "CURRENT", errors);
|
|
341
|
+
requiredArray(value, "revalidationRequiredWhen", errors);
|
|
342
|
+
stringArray(value.revalidationRequiredWhen, "continuousAssurance.revalidationRequiredWhen", errors);
|
|
343
|
+
const scope = recordValue(value.scope);
|
|
344
|
+
if (scope) {
|
|
345
|
+
const nested = [];
|
|
346
|
+
validateAssuranceScope(scope, nested);
|
|
347
|
+
errors.push(...nested.map((error) => `continuousAssurance.scope.${error}`));
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
function validateAssuranceScope(value, errors) {
|
|
351
|
+
requiredConst(value, "schemaVersion", "agentcert.assurance_scope.v0.1", errors);
|
|
352
|
+
for (const key of ["agent", "model", "prompt", "tools", "policy", "scenarioSuite"])
|
|
353
|
+
requiredObject(value, key, errors);
|
|
354
|
+
const agent = recordValue(value.agent);
|
|
355
|
+
const model = recordValue(value.model);
|
|
356
|
+
const prompt = recordValue(value.prompt);
|
|
357
|
+
const tools = recordValue(value.tools);
|
|
358
|
+
const policy = recordValue(value.policy);
|
|
359
|
+
const suite = recordValue(value.scenarioSuite);
|
|
360
|
+
if (agent) {
|
|
361
|
+
requiredStringAt(agent, "id", "agent.id", errors);
|
|
362
|
+
requiredStringAt(agent, "version", "agent.version", errors);
|
|
363
|
+
optionalSha256At(agent, "artifactSha256", "agent.artifactSha256", errors);
|
|
364
|
+
}
|
|
365
|
+
if (model)
|
|
366
|
+
for (const key of ["provider", "name", "version"])
|
|
367
|
+
requiredStringAt(model, key, `model.${key}`, errors);
|
|
368
|
+
if (prompt)
|
|
369
|
+
requiredSha256At(prompt, "sha256", "prompt.sha256", errors);
|
|
370
|
+
if (tools)
|
|
371
|
+
requiredSha256At(tools, "manifestSha256", "tools.manifestSha256", errors);
|
|
372
|
+
if (policy) {
|
|
373
|
+
requiredStringAt(policy, "id", "policy.id", errors);
|
|
374
|
+
requiredStringAt(policy, "version", "policy.version", errors);
|
|
375
|
+
optionalSha256At(policy, "sha256", "policy.sha256", errors);
|
|
376
|
+
}
|
|
377
|
+
if (suite) {
|
|
378
|
+
requiredStringAt(suite, "id", "scenarioSuite.id", errors);
|
|
379
|
+
requiredStringAt(suite, "version", "scenarioSuite.version", errors);
|
|
380
|
+
requiredSha256At(suite, "sha256", "scenarioSuite.sha256", errors);
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
function requiredSha256At(value, key, path, errors) {
|
|
384
|
+
if (typeof value[key] !== "string" || !/^[0-9a-f]{64}$/.test(value[key]))
|
|
385
|
+
errors.push(`${path} must be a lowercase SHA-256 digest.`);
|
|
386
|
+
}
|
|
387
|
+
function optionalSha256At(value, key, path, errors) {
|
|
388
|
+
if (value[key] !== undefined && (typeof value[key] !== "string" || !/^[0-9a-f]{64}$/.test(value[key])))
|
|
389
|
+
errors.push(`${path} must be a lowercase SHA-256 digest.`);
|
|
390
|
+
}
|
|
391
|
+
function validateFailureReview(value, errors) {
|
|
392
|
+
requiredConst(value, "schemaVersion", "1", errors);
|
|
393
|
+
requiredConst(value, "kind", "agentcert.failure_review", errors);
|
|
394
|
+
requiredString(value, "id", errors);
|
|
395
|
+
requiredString(value, "reviewedAt", errors);
|
|
396
|
+
requiredString(value, "reviewer", errors);
|
|
397
|
+
requiredEnum(value, "status", ["confirmed", "corrected"], errors);
|
|
398
|
+
requiredObject(value, "target", errors);
|
|
399
|
+
requiredString(value, "type", errors);
|
|
400
|
+
}
|
|
401
|
+
function validateClassifierEval(value, errors) {
|
|
402
|
+
requiredConst(value, "schemaVersion", "1", errors);
|
|
403
|
+
requiredConst(value, "kind", "agentcert.failure_classifier_evaluation", errors);
|
|
404
|
+
requiredNumber(value, "reviewedRows", errors);
|
|
405
|
+
requiredNumber(value, "correctRows", errors);
|
|
406
|
+
requiredNumber(value, "incorrectRows", errors);
|
|
407
|
+
requiredNumber(value, "precision", errors);
|
|
408
|
+
requiredNumber(value, "coverage", errors);
|
|
409
|
+
requiredArray(value, "byType", errors);
|
|
410
|
+
requiredArray(value, "confusion", errors);
|
|
411
|
+
}
|
|
412
|
+
function validateMonitorSnapshot(value, errors) {
|
|
413
|
+
requiredConst(value, "schemaVersion", "1", errors);
|
|
414
|
+
requiredConst(value, "kind", "agentcert.monitor_snapshot", errors);
|
|
415
|
+
requiredString(value, "generatedAt", errors);
|
|
416
|
+
requiredString(value, "subject", errors);
|
|
417
|
+
requiredObject(value, "summary", errors);
|
|
418
|
+
requiredObject(value, "filters", errors);
|
|
419
|
+
requiredArray(value, "lifecycle", errors);
|
|
420
|
+
requiredArray(value, "recentRuns", errors);
|
|
421
|
+
requiredArray(value, "failurePatterns", errors);
|
|
422
|
+
}
|
|
423
|
+
function validateRobustnessLab(value, errors) {
|
|
424
|
+
requiredConst(value, "schemaVersion", "1", errors);
|
|
425
|
+
requiredConst(value, "kind", "agentcert.real_agent_robustness_lab", errors);
|
|
426
|
+
requiredString(value, "generatedAt", errors);
|
|
427
|
+
requiredString(value, "name", errors);
|
|
428
|
+
requiredObject(value, "summary", errors);
|
|
429
|
+
requiredArray(value, "agents", errors);
|
|
430
|
+
requiredArray(value, "faults", errors);
|
|
431
|
+
requiredArray(value, "matrix", errors);
|
|
432
|
+
requiredArray(value, "limitations", errors);
|
|
433
|
+
}
|
|
434
|
+
function object(input, path, errors) {
|
|
435
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
436
|
+
errors.push(`${path} must be an object.`);
|
|
437
|
+
return undefined;
|
|
438
|
+
}
|
|
439
|
+
return input;
|
|
440
|
+
}
|
|
441
|
+
function requiredConst(input, key, expected, errors) {
|
|
442
|
+
if (input[key] !== expected)
|
|
443
|
+
errors.push(`${key} must be ${JSON.stringify(expected)}.`);
|
|
444
|
+
}
|
|
445
|
+
function requiredString(input, key, errors) {
|
|
446
|
+
if (typeof input[key] !== "string" || input[key] === "")
|
|
447
|
+
errors.push(`${key} must be a non-empty string.`);
|
|
448
|
+
}
|
|
449
|
+
function requiredNumber(input, key, errors) {
|
|
450
|
+
if (typeof input[key] !== "number" || !Number.isFinite(input[key]))
|
|
451
|
+
errors.push(`${key} must be a finite number.`);
|
|
452
|
+
}
|
|
453
|
+
function requiredBoolean(input, key, errors) {
|
|
454
|
+
if (typeof input[key] !== "boolean")
|
|
455
|
+
errors.push(`${key} must be a boolean.`);
|
|
456
|
+
}
|
|
457
|
+
function requiredArray(input, key, errors) {
|
|
458
|
+
if (!Array.isArray(input[key]))
|
|
459
|
+
errors.push(`${key} must be an array.`);
|
|
460
|
+
}
|
|
461
|
+
function requiredObject(input, key, errors) {
|
|
462
|
+
if (!input[key] || typeof input[key] !== "object" || Array.isArray(input[key]))
|
|
463
|
+
errors.push(`${key} must be an object.`);
|
|
464
|
+
}
|
|
465
|
+
function requiredEnum(input, key, values, errors) {
|
|
466
|
+
if (typeof input[key] !== "string" || !values.includes(input[key])) {
|
|
467
|
+
errors.push(`${key} must be one of: ${values.join(", ")}.`);
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
function recordValue(input) {
|
|
471
|
+
return input && typeof input === "object" && !Array.isArray(input) ? input : undefined;
|
|
472
|
+
}
|
|
473
|
+
function requiredStringAt(input, key, path, errors) {
|
|
474
|
+
if (typeof input[key] !== "string" || input[key] === "")
|
|
475
|
+
errors.push(`${path} must be a non-empty string.`);
|
|
476
|
+
}
|
|
477
|
+
function requiredBooleanAt(input, key, path, errors) {
|
|
478
|
+
if (typeof input[key] !== "boolean")
|
|
479
|
+
errors.push(`${path} must be a boolean.`);
|
|
480
|
+
}
|
|
481
|
+
function requiredEnumAt(input, key, values, path, errors) {
|
|
482
|
+
if (typeof input[key] !== "string" || !values.includes(input[key]))
|
|
483
|
+
errors.push(`${path} must be one of: ${values.join(", ")}.`);
|
|
484
|
+
}
|
|
485
|
+
function requiredNumberRange(input, key, path, minimum, maximum, errors) {
|
|
486
|
+
const value = input[key];
|
|
487
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value < minimum || value > maximum) {
|
|
488
|
+
errors.push(`${path} must be a finite number from ${minimum} to ${maximum}.`);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
function requiredNonNegativeInteger(input, key, path, errors) {
|
|
492
|
+
const value = input[key];
|
|
493
|
+
if (!Number.isInteger(value) || value < 0)
|
|
494
|
+
errors.push(`${path} must be a non-negative integer.`);
|
|
495
|
+
}
|
|
496
|
+
function stringArray(input, path, errors) {
|
|
497
|
+
if (!Array.isArray(input) || input.some((item) => typeof item !== "string"))
|
|
498
|
+
errors.push(`${path} must be an array of strings.`);
|
|
499
|
+
}
|
|
500
|
+
function validateTimestamp(input, path, errors) {
|
|
501
|
+
if (typeof input === "string" && !Number.isFinite(Date.parse(input)))
|
|
502
|
+
errors.push(`${path} must be a valid date-time string.`);
|
|
503
|
+
}
|
package/dist/try.js
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import { relative, resolve } from "node:path";
|
|
4
|
+
import { renderAgentCertBadge } from "./badge.js";
|
|
5
|
+
import { buildEvidenceBundle } from "./bundle.js";
|
|
6
|
+
import { renderHtmlReport, renderMarkdownReport } from "./report.js";
|
|
7
|
+
const TEMPLATE_STEPS = {
|
|
8
|
+
browser: [
|
|
9
|
+
{ type: "task.started", status: "recorded", observed: "A synthetic browser task started." },
|
|
10
|
+
{ type: "navigation.observed", status: "recorded", observed: "The sample reached the expected local route." },
|
|
11
|
+
{ type: "outcome.verified", status: "verified", observed: "Expected and observed sample states matched." },
|
|
12
|
+
],
|
|
13
|
+
coding: [
|
|
14
|
+
{ type: "change.proposed", status: "recorded", observed: "A synthetic repository change was proposed." },
|
|
15
|
+
{ type: "tests.observed", status: "recorded", observed: "The deterministic sample test completed." },
|
|
16
|
+
{ type: "outcome.verified", status: "verified", observed: "The sample workspace remained unchanged." },
|
|
17
|
+
],
|
|
18
|
+
mcp: [
|
|
19
|
+
{ type: "tool.discovered", status: "recorded", observed: "A synthetic read-only tool was discovered." },
|
|
20
|
+
{ type: "tool.invoked", status: "recorded", observed: "The deterministic tool fixture returned its declared response." },
|
|
21
|
+
{ type: "outcome.verified", status: "verified", observed: "The response matched the sample contract." },
|
|
22
|
+
],
|
|
23
|
+
workflow: [
|
|
24
|
+
{ type: "workflow.started", status: "recorded", observed: "A synthetic claim workflow started." },
|
|
25
|
+
{ type: "policy.evaluated", status: "recorded", observed: "The sample required approval before its mock action." },
|
|
26
|
+
{ type: "approval.recorded", status: "recorded", observed: "A fixture approval was recorded." },
|
|
27
|
+
{ type: "mock_action.executed", status: "recorded", observed: "Only local sample state changed." },
|
|
28
|
+
{ type: "outcome.verified", status: "verified", observed: "Expected SUBMITTED matched observed SUBMITTED." },
|
|
29
|
+
],
|
|
30
|
+
data: [
|
|
31
|
+
{ type: "query.planned", status: "recorded", observed: "A synthetic read-only query was planned." },
|
|
32
|
+
{ type: "query.executed", status: "recorded", observed: "The local fixture returned three rows." },
|
|
33
|
+
{ type: "outcome.verified", status: "verified", observed: "The result count and schema matched expectations." },
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
export async function writeTryEvidence(options) {
|
|
37
|
+
const outDir = resolve(options.outDir);
|
|
38
|
+
const now = options.now ?? new Date();
|
|
39
|
+
const id = options.id ?? randomUUID();
|
|
40
|
+
const runId = `agentcert_try_${id}`;
|
|
41
|
+
const timestamp = now.toISOString();
|
|
42
|
+
const tracePath = resolve(outDir, "sample-trace.json");
|
|
43
|
+
const evidencePath = resolve(outDir, "agentcert-evidence.json");
|
|
44
|
+
const reportPath = resolve(outDir, "agentcert-report.html");
|
|
45
|
+
const markdownPath = resolve(outDir, "agentcert-report.md");
|
|
46
|
+
const badgePath = resolve(outDir, "badge.svg");
|
|
47
|
+
const artifactPath = portablePath(relative(process.cwd(), tracePath));
|
|
48
|
+
const steps = TEMPLATE_STEPS[options.template].map((step, index) => ({ sequence: index + 1, ...step }));
|
|
49
|
+
const trace = {
|
|
50
|
+
schemaVersion: "agentcert.synthetic_trace.v0.1",
|
|
51
|
+
synthetic: true,
|
|
52
|
+
purpose: "onboarding_only",
|
|
53
|
+
runId,
|
|
54
|
+
template: options.template,
|
|
55
|
+
subject: options.subject,
|
|
56
|
+
startedAt: timestamp,
|
|
57
|
+
completedAt: timestamp,
|
|
58
|
+
steps,
|
|
59
|
+
outcome: {
|
|
60
|
+
success: true,
|
|
61
|
+
expected: sampleExpectedOutcome(options.template),
|
|
62
|
+
observed: sampleExpectedOutcome(options.template),
|
|
63
|
+
},
|
|
64
|
+
limitations: [
|
|
65
|
+
"No customer agent, model, tool, credential, or production system was executed.",
|
|
66
|
+
"This sample cannot establish a CURRENT assurance contract or independent certification.",
|
|
67
|
+
],
|
|
68
|
+
};
|
|
69
|
+
const result = {
|
|
70
|
+
schemaVersion: "1",
|
|
71
|
+
product: "agentcert-cli",
|
|
72
|
+
runId,
|
|
73
|
+
timestamp,
|
|
74
|
+
phase: "pre-release",
|
|
75
|
+
score: 100,
|
|
76
|
+
passed: true,
|
|
77
|
+
certLevel: "synthetic-onboarding-sample",
|
|
78
|
+
summary: `Synthetic ${options.template} onboarding sample completed. This validates the Witnora evidence path, not a customer agent.`,
|
|
79
|
+
evidenceStrength: {
|
|
80
|
+
schemaVersion: "agentcert.evidence_strength.v0.1",
|
|
81
|
+
level: "reported",
|
|
82
|
+
claims: ["Witnora recorded a deterministic local onboarding sample and its expected outcome."],
|
|
83
|
+
limitations: [
|
|
84
|
+
"No customer agent behavior was evaluated.",
|
|
85
|
+
"No execution boundary or independent reviewer attested this sample.",
|
|
86
|
+
"A passing sample cannot establish CURRENT assurance for a real agent.",
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
artifacts: { sampleTrace: artifactPath },
|
|
90
|
+
evidence: [{
|
|
91
|
+
id: `synthetic_onboarding_${id}`,
|
|
92
|
+
kind: "synthetic_onboarding",
|
|
93
|
+
severity: "info",
|
|
94
|
+
message: `Deterministic ${options.template} sample passed. Replace it with evidence from the real agent boundary before making a release decision.`,
|
|
95
|
+
source: "agentcert try",
|
|
96
|
+
artifactPath,
|
|
97
|
+
metadata: { synthetic: true, template: options.template, purpose: "onboarding_only" },
|
|
98
|
+
}],
|
|
99
|
+
};
|
|
100
|
+
const bundle = buildEvidenceBundle([result], options.subject, "agent");
|
|
101
|
+
bundle.runId = runId;
|
|
102
|
+
bundle.generatedAt = timestamp;
|
|
103
|
+
await mkdir(outDir, { recursive: true });
|
|
104
|
+
await writeFile(tracePath, `${JSON.stringify(trace, null, 2)}\n`, "utf8");
|
|
105
|
+
await writeFile(evidencePath, `${JSON.stringify(bundle, null, 2)}\n`, "utf8");
|
|
106
|
+
await writeFile(reportPath, renderHtmlReport(bundle), "utf8");
|
|
107
|
+
await writeFile(markdownPath, renderMarkdownReport(bundle), "utf8");
|
|
108
|
+
await writeFile(badgePath, renderAgentCertBadge(bundle), "utf8");
|
|
109
|
+
return { bundle, evidencePath, reportPath, markdownPath, badgePath, tracePath };
|
|
110
|
+
}
|
|
111
|
+
export function renderTrySummary(outcome) {
|
|
112
|
+
return `Synthetic onboarding sample: PASS\n` +
|
|
113
|
+
`Evidence: ${outcome.evidencePath}\n` +
|
|
114
|
+
`Report: ${outcome.reportPath}\n` +
|
|
115
|
+
`Trace: ${outcome.tracePath}\n\n` +
|
|
116
|
+
`This proves the local Witnora evidence path works. It does not evaluate a real agent or establish CURRENT assurance.\n\n` +
|
|
117
|
+
`Next:\n` +
|
|
118
|
+
` 1. Open the HTML report.\n` +
|
|
119
|
+
` 2. To retain this sample in Hosted, connect a project and re-run with --push.\n` +
|
|
120
|
+
` 3. When ready, run witnora init --template <type> inside the real agent repository.\n`;
|
|
121
|
+
}
|
|
122
|
+
function sampleExpectedOutcome(template) {
|
|
123
|
+
if (template === "browser")
|
|
124
|
+
return "task_completed";
|
|
125
|
+
if (template === "coding")
|
|
126
|
+
return "workspace_unchanged";
|
|
127
|
+
if (template === "mcp")
|
|
128
|
+
return "contract_response_valid";
|
|
129
|
+
if (template === "data")
|
|
130
|
+
return "three_valid_rows";
|
|
131
|
+
return "SUBMITTED";
|
|
132
|
+
}
|
|
133
|
+
function portablePath(path) {
|
|
134
|
+
return path.replaceAll("\\", "/");
|
|
135
|
+
}
|
package/dist/types.js
ADDED