@noeos/verification-engine 0.0.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/CHANGELOG.md +8 -0
- package/LICENSE +201 -0
- package/NOTICE +11 -0
- package/README.md +7 -0
- package/dist/cjs/api/engine.js +271 -0
- package/dist/cjs/api/types.js +10 -0
- package/dist/cjs/chains/chain-builder.js +541 -0
- package/dist/cjs/chains/duplicate-detector.js +208 -0
- package/dist/cjs/chains/verify-chain.js +656 -0
- package/dist/cjs/contracts/generated.js +512 -0
- package/dist/cjs/contracts/schema-assets.js +6 -0
- package/dist/cjs/contracts/vector-assets.js +6 -0
- package/dist/cjs/domain/algorithm-id.js +5 -0
- package/dist/cjs/domain/byte-view.js +7 -0
- package/dist/cjs/domain/chain.js +3 -0
- package/dist/cjs/domain/diagnostic.js +6 -0
- package/dist/cjs/domain/digest.js +37 -0
- package/dist/cjs/domain/duplicate-policy.js +3 -0
- package/dist/cjs/domain/evidence.js +10 -0
- package/dist/cjs/domain/identifiers.js +52 -0
- package/dist/cjs/domain/json-value.js +3 -0
- package/dist/cjs/domain/limits.js +24 -0
- package/dist/cjs/domain/operation-result.js +19 -0
- package/dist/cjs/domain/position.js +16 -0
- package/dist/cjs/domain/protocol-version.js +5 -0
- package/dist/cjs/domain/rule.js +3 -0
- package/dist/cjs/domain/stream.js +3 -0
- package/dist/cjs/domain/version.js +16 -0
- package/dist/cjs/evidence/digest-evidence.js +22 -0
- package/dist/cjs/evidence/evidence-parser.js +288 -0
- package/dist/cjs/framing/frame-builders.js +124 -0
- package/dist/cjs/framing/frame-encoder.js +238 -0
- package/dist/cjs/framing/frame-parser.js +173 -0
- package/dist/cjs/framing/frame-types.js +3 -0
- package/dist/cjs/hashing/hash-adapter.js +90 -0
- package/dist/cjs/hashing/hash-frame.js +16 -0
- package/dist/cjs/index.js +16 -0
- package/dist/cjs/normalization/byte-sink.js +70 -0
- package/dist/cjs/normalization/jcs-profile.js +154 -0
- package/dist/cjs/normalization/normalize.js +56 -0
- package/dist/cjs/normalization/profile-registry.js +66 -0
- package/dist/cjs/normalization/profile.js +3 -0
- package/dist/cjs/normalization/raw-bytes-profile.js +27 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/profiles.js +9 -0
- package/dist/cjs/records/record-service.js +278 -0
- package/dist/cjs/rules/rule-set.js +211 -0
- package/dist/cjs/schemas.js +6 -0
- package/dist/cjs/validation/algorithm-validation.js +12 -0
- package/dist/cjs/validation/diagnostic-collector.js +159 -0
- package/dist/cjs/validation/digest-validation.js +48 -0
- package/dist/cjs/validation/identifier-validation.js +33 -0
- package/dist/cjs/validation/json-text-parser.js +297 -0
- package/dist/cjs/validation/json-value-validation.js +155 -0
- package/dist/cjs/validation/limit-validation.js +75 -0
- package/dist/cjs/validation/object-inspection.js +60 -0
- package/dist/cjs/validation/position-validation.js +13 -0
- package/dist/cjs/validation/result-helpers.js +9 -0
- package/dist/cjs/validation/utf8-validation.js +69 -0
- package/dist/cjs/validation/version-validation.js +31 -0
- package/dist/cjs/vectors.js +6 -0
- package/dist/esm/api/engine.js +266 -0
- package/dist/esm/api/types.js +4 -0
- package/dist/esm/chains/chain-builder.js +536 -0
- package/dist/esm/chains/duplicate-detector.js +204 -0
- package/dist/esm/chains/verify-chain.js +652 -0
- package/dist/esm/contracts/generated.js +509 -0
- package/dist/esm/contracts/schema-assets.js +2 -0
- package/dist/esm/contracts/vector-assets.js +2 -0
- package/dist/esm/domain/algorithm-id.js +2 -0
- package/dist/esm/domain/byte-view.js +4 -0
- package/dist/esm/domain/chain.js +2 -0
- package/dist/esm/domain/diagnostic.js +3 -0
- package/dist/esm/domain/digest.js +32 -0
- package/dist/esm/domain/duplicate-policy.js +2 -0
- package/dist/esm/domain/evidence.js +7 -0
- package/dist/esm/domain/identifiers.js +45 -0
- package/dist/esm/domain/json-value.js +2 -0
- package/dist/esm/domain/limits.js +21 -0
- package/dist/esm/domain/operation-result.js +15 -0
- package/dist/esm/domain/position.js +12 -0
- package/dist/esm/domain/protocol-version.js +2 -0
- package/dist/esm/domain/rule.js +2 -0
- package/dist/esm/domain/stream.js +2 -0
- package/dist/esm/domain/version.js +12 -0
- package/dist/esm/evidence/digest-evidence.js +19 -0
- package/dist/esm/evidence/evidence-parser.js +281 -0
- package/dist/esm/framing/frame-builders.js +114 -0
- package/dist/esm/framing/frame-encoder.js +234 -0
- package/dist/esm/framing/frame-parser.js +170 -0
- package/dist/esm/framing/frame-types.js +2 -0
- package/dist/esm/hashing/hash-adapter.js +84 -0
- package/dist/esm/hashing/hash-frame.js +12 -0
- package/dist/esm/index.js +5 -0
- package/dist/esm/normalization/byte-sink.js +66 -0
- package/dist/esm/normalization/jcs-profile.js +151 -0
- package/dist/esm/normalization/normalize.js +52 -0
- package/dist/esm/normalization/profile-registry.js +62 -0
- package/dist/esm/normalization/profile.js +2 -0
- package/dist/esm/normalization/raw-bytes-profile.js +24 -0
- package/dist/esm/profiles.js +6 -0
- package/dist/esm/records/record-service.js +270 -0
- package/dist/esm/rules/rule-set.js +206 -0
- package/dist/esm/schemas.js +2 -0
- package/dist/esm/validation/algorithm-validation.js +9 -0
- package/dist/esm/validation/diagnostic-collector.js +154 -0
- package/dist/esm/validation/digest-validation.js +43 -0
- package/dist/esm/validation/identifier-validation.js +27 -0
- package/dist/esm/validation/json-text-parser.js +294 -0
- package/dist/esm/validation/json-value-validation.js +152 -0
- package/dist/esm/validation/limit-validation.js +71 -0
- package/dist/esm/validation/object-inspection.js +54 -0
- package/dist/esm/validation/position-validation.js +10 -0
- package/dist/esm/validation/result-helpers.js +6 -0
- package/dist/esm/validation/utf8-validation.js +63 -0
- package/dist/esm/validation/version-validation.js +26 -0
- package/dist/esm/vectors.js +2 -0
- package/dist/types/api/engine.d.ts +8 -0
- package/dist/types/api/types.d.ts +124 -0
- package/dist/types/chains/chain-builder.d.ts +42 -0
- package/dist/types/chains/duplicate-detector.d.ts +18 -0
- package/dist/types/chains/verify-chain.d.ts +9 -0
- package/dist/types/contracts/generated.d.ts +442 -0
- package/dist/types/contracts/schema-assets.d.ts +2 -0
- package/dist/types/contracts/vector-assets.d.ts +2 -0
- package/dist/types/domain/algorithm-id.d.ts +4 -0
- package/dist/types/domain/byte-view.d.ts +1 -0
- package/dist/types/domain/chain.d.ts +43 -0
- package/dist/types/domain/diagnostic.d.ts +23 -0
- package/dist/types/domain/digest.d.ts +12 -0
- package/dist/types/domain/duplicate-policy.d.ts +26 -0
- package/dist/types/domain/evidence.d.ts +100 -0
- package/dist/types/domain/identifiers.d.ts +29 -0
- package/dist/types/domain/json-value.d.ts +6 -0
- package/dist/types/domain/limits.d.ts +13 -0
- package/dist/types/domain/operation-result.d.ts +12 -0
- package/dist/types/domain/position.d.ts +8 -0
- package/dist/types/domain/protocol-version.d.ts +2 -0
- package/dist/types/domain/rule.d.ts +34 -0
- package/dist/types/domain/stream.d.ts +5 -0
- package/dist/types/domain/version.d.ts +8 -0
- package/dist/types/evidence/digest-evidence.d.ts +4 -0
- package/dist/types/evidence/evidence-parser.d.ts +8 -0
- package/dist/types/framing/frame-builders.d.ts +40 -0
- package/dist/types/framing/frame-encoder.d.ts +6 -0
- package/dist/types/framing/frame-parser.d.ts +4 -0
- package/dist/types/framing/frame-types.d.ts +27 -0
- package/dist/types/hashing/hash-adapter.d.ts +12 -0
- package/dist/types/hashing/hash-frame.d.ts +6 -0
- package/dist/types/index.d.ts +8 -0
- package/dist/types/normalization/byte-sink.d.ts +19 -0
- package/dist/types/normalization/jcs-profile.d.ts +3 -0
- package/dist/types/normalization/normalize.d.ts +11 -0
- package/dist/types/normalization/profile-registry.d.ts +26 -0
- package/dist/types/normalization/profile.d.ts +22 -0
- package/dist/types/normalization/raw-bytes-profile.d.ts +2 -0
- package/dist/types/profiles.d.ts +8 -0
- package/dist/types/records/record-service.d.ts +38 -0
- package/dist/types/rules/rule-set.d.ts +13 -0
- package/dist/types/schemas.d.ts +2 -0
- package/dist/types/validation/algorithm-validation.d.ts +3 -0
- package/dist/types/validation/diagnostic-collector.d.ts +24 -0
- package/dist/types/validation/digest-validation.d.ts +6 -0
- package/dist/types/validation/identifier-validation.d.ts +6 -0
- package/dist/types/validation/json-text-parser.d.ts +4 -0
- package/dist/types/validation/json-value-validation.d.ts +4 -0
- package/dist/types/validation/limit-validation.d.ts +4 -0
- package/dist/types/validation/object-inspection.d.ts +11 -0
- package/dist/types/validation/position-validation.d.ts +3 -0
- package/dist/types/validation/result-helpers.d.ts +3 -0
- package/dist/types/validation/utf8-validation.d.ts +5 -0
- package/dist/types/validation/version-validation.d.ts +9 -0
- package/dist/types/vectors.d.ts +2 -0
- package/package.json +61 -0
- package/schemas/chain-summary.v1.schema.json +156 -0
- package/schemas/diagnostic.v1.schema.json +107 -0
- package/schemas/link-evidence.v1.schema.json +165 -0
- package/schemas/record-evidence.v1.schema.json +91 -0
- package/schemas/vector-set.v1.schema.json +52 -0
- package/vectors/evidence.json +26 -0
- package/vectors/framing.json +136 -0
- package/vectors/hashing.json +58 -0
- package/vectors/invalid.json +56 -0
- package/vectors/manifest.json +46 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.RuleSet = void 0;
|
|
5
|
+
exports.createReadonlyByteView = createReadonlyByteView;
|
|
6
|
+
const operation_result_js_1 = require("../domain/operation-result.js");
|
|
7
|
+
const diagnostic_collector_js_1 = require("../validation/diagnostic-collector.js");
|
|
8
|
+
const object_inspection_js_1 = require("../validation/object-inspection.js");
|
|
9
|
+
const version_validation_js_1 = require("../validation/version-validation.js");
|
|
10
|
+
const ruleIdPattern = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/u;
|
|
11
|
+
const EMPTY_DIAGNOSTICS = Object.freeze([]);
|
|
12
|
+
class RuleSet {
|
|
13
|
+
rules;
|
|
14
|
+
constructor(rules) {
|
|
15
|
+
this.rules = rules;
|
|
16
|
+
Object.freeze(this);
|
|
17
|
+
}
|
|
18
|
+
static create(value, limits) {
|
|
19
|
+
if (value === undefined)
|
|
20
|
+
return (0, operation_result_js_1.success)(new RuleSet(Object.freeze([])));
|
|
21
|
+
if (!Array.isArray(value))
|
|
22
|
+
return ruleFailure("RULE_VERSION_CONFLICT", limits);
|
|
23
|
+
const rules = [];
|
|
24
|
+
const keys = new Set();
|
|
25
|
+
for (const candidate of value) {
|
|
26
|
+
const validated = validateRule(candidate, limits);
|
|
27
|
+
if (!validated.ok)
|
|
28
|
+
return validated;
|
|
29
|
+
const key = `${validated.value.id}\u0000${validated.value.version}`;
|
|
30
|
+
if (keys.has(key))
|
|
31
|
+
return ruleFailure("RULE_VERSION_CONFLICT", limits);
|
|
32
|
+
keys.add(key);
|
|
33
|
+
rules.push(validated.value);
|
|
34
|
+
}
|
|
35
|
+
rules.sort((left, right) => compareText(left.id, right.id) || compareText(left.version, right.version));
|
|
36
|
+
return (0, operation_result_js_1.success)(new RuleSet(Object.freeze(rules)));
|
|
37
|
+
}
|
|
38
|
+
evaluate(context, limits) {
|
|
39
|
+
if (this.rules.length === 0)
|
|
40
|
+
return EMPTY_DIAGNOSTICS;
|
|
41
|
+
const collector = new diagnostic_collector_js_1.DiagnosticCollector(limits);
|
|
42
|
+
for (const rule of this.rules) {
|
|
43
|
+
if (!rule.phases.includes(context.phase))
|
|
44
|
+
continue;
|
|
45
|
+
try {
|
|
46
|
+
const findings = rule.evaluate(context);
|
|
47
|
+
if (!Array.isArray(findings)) {
|
|
48
|
+
collector.addCode("RULE_EXECUTION_FAILED", context.phase, failureOptions(context, "RULE_RESULT_INVALID"));
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
for (const finding of findings) {
|
|
52
|
+
const diagnostic = toDiagnostic(rule, finding, context);
|
|
53
|
+
if (diagnostic === undefined) {
|
|
54
|
+
collector.addCode("RULE_EXECUTION_FAILED", context.phase, failureOptions(context, "RULE_RESULT_INVALID"));
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
collector.add(diagnostic);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
collector.addCode("RULE_EXECUTION_FAILED", context.phase, failureOptions(context, "RULE_EVALUATION_FAILED"));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return collector.finish();
|
|
66
|
+
}
|
|
67
|
+
hasRules() {
|
|
68
|
+
return this.rules.length !== 0;
|
|
69
|
+
}
|
|
70
|
+
toArray() {
|
|
71
|
+
return this.rules;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
exports.RuleSet = RuleSet;
|
|
75
|
+
function createReadonlyByteView(bytes) {
|
|
76
|
+
const copy = Uint8Array.from(bytes);
|
|
77
|
+
return Object.freeze({
|
|
78
|
+
byteLength: copy.length,
|
|
79
|
+
copySlice(start, end) {
|
|
80
|
+
return Uint8Array.from(copy.slice(start, end));
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function validateRule(value, limits) {
|
|
85
|
+
const entries = (0, object_inspection_js_1.inspectPlainObject)(value);
|
|
86
|
+
if (entries === undefined)
|
|
87
|
+
return ruleFailure("RULE_VERSION_CONFLICT", limits);
|
|
88
|
+
const fields = new Map(entries);
|
|
89
|
+
if (fields.size !== 5 ||
|
|
90
|
+
!fields.has("id") ||
|
|
91
|
+
!fields.has("version") ||
|
|
92
|
+
!fields.has("phases") ||
|
|
93
|
+
!fields.has("defaultSeverity") ||
|
|
94
|
+
!fields.has("evaluate")) {
|
|
95
|
+
return ruleFailure("RULE_VERSION_CONFLICT", limits);
|
|
96
|
+
}
|
|
97
|
+
const id = fields.get("id");
|
|
98
|
+
const version = fields.get("version");
|
|
99
|
+
const phases = fields.get("phases");
|
|
100
|
+
const defaultSeverity = fields.get("defaultSeverity");
|
|
101
|
+
const evaluate = fields.get("evaluate");
|
|
102
|
+
if (typeof id !== "string" || !ruleIdPattern.test(id) || id.length > 128) {
|
|
103
|
+
return ruleFailure("RULE_VERSION_CONFLICT", limits);
|
|
104
|
+
}
|
|
105
|
+
const validatedVersion = (0, version_validation_js_1.validateProfileVersion)(version);
|
|
106
|
+
if (!validatedVersion.ok || !Array.isArray(phases) || typeof evaluate !== "function") {
|
|
107
|
+
return ruleFailure("RULE_VERSION_CONFLICT", limits);
|
|
108
|
+
}
|
|
109
|
+
if (defaultSeverity !== "error" && defaultSeverity !== "warning" && defaultSeverity !== "info") {
|
|
110
|
+
return ruleFailure("RULE_VERSION_CONFLICT", limits);
|
|
111
|
+
}
|
|
112
|
+
const normalizedPhases = [];
|
|
113
|
+
for (const phase of phases) {
|
|
114
|
+
if (!isRulePhase(phase) || normalizedPhases.includes(phase)) {
|
|
115
|
+
return ruleFailure("RULE_VERSION_CONFLICT", limits);
|
|
116
|
+
}
|
|
117
|
+
normalizedPhases.push(phase);
|
|
118
|
+
}
|
|
119
|
+
if (normalizedPhases.length === 0)
|
|
120
|
+
return ruleFailure("RULE_VERSION_CONFLICT", limits);
|
|
121
|
+
return (0, operation_result_js_1.success)(Object.freeze({
|
|
122
|
+
id,
|
|
123
|
+
version: validatedVersion.value.value,
|
|
124
|
+
phases: Object.freeze([...normalizedPhases]),
|
|
125
|
+
defaultSeverity,
|
|
126
|
+
evaluate(context) {
|
|
127
|
+
return Reflect.apply(evaluate, undefined, [context]);
|
|
128
|
+
},
|
|
129
|
+
}));
|
|
130
|
+
}
|
|
131
|
+
function toDiagnostic(rule, value, context) {
|
|
132
|
+
const entries = (0, object_inspection_js_1.inspectPlainObject)(value);
|
|
133
|
+
if (entries === undefined)
|
|
134
|
+
return undefined;
|
|
135
|
+
const fields = new Map(entries);
|
|
136
|
+
for (const key of fields.keys()) {
|
|
137
|
+
if (key !== "messageKey" && key !== "path" && key !== "details" && key !== "severity")
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
const messageKey = fields.get("messageKey");
|
|
141
|
+
const path = fields.get("path");
|
|
142
|
+
const details = fields.get("details");
|
|
143
|
+
const severity = fields.get("severity");
|
|
144
|
+
if (typeof messageKey !== "string")
|
|
145
|
+
return undefined;
|
|
146
|
+
if (path !== undefined && typeof path !== "string")
|
|
147
|
+
return undefined;
|
|
148
|
+
if (severity !== undefined &&
|
|
149
|
+
severity !== "error" &&
|
|
150
|
+
severity !== "warning" &&
|
|
151
|
+
severity !== "info") {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
const ruleDetails = {
|
|
155
|
+
"rule-id": rule.id,
|
|
156
|
+
"rule-version": rule.version,
|
|
157
|
+
};
|
|
158
|
+
if (details !== undefined) {
|
|
159
|
+
const detailEntries = (0, object_inspection_js_1.inspectPlainObject)(details);
|
|
160
|
+
if (detailEntries === undefined)
|
|
161
|
+
return undefined;
|
|
162
|
+
for (const [key, item] of detailEntries) {
|
|
163
|
+
if (key === "rule-id" || key === "rule-version")
|
|
164
|
+
return undefined;
|
|
165
|
+
if (item !== null &&
|
|
166
|
+
typeof item !== "string" &&
|
|
167
|
+
typeof item !== "number" &&
|
|
168
|
+
typeof item !== "boolean") {
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
ruleDetails[key] = item;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return (0, diagnostic_collector_js_1.createDiagnostic)("RULE_FAILED", context.phase, {
|
|
175
|
+
messageKey,
|
|
176
|
+
details: ruleDetails,
|
|
177
|
+
severity: severity ?? rule.defaultSeverity,
|
|
178
|
+
...optionalDiagnosticFields(context, path),
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
function isRulePhase(value) {
|
|
182
|
+
return (value === "input" ||
|
|
183
|
+
value === "normalization" ||
|
|
184
|
+
value === "record" ||
|
|
185
|
+
value === "link" ||
|
|
186
|
+
value === "chain");
|
|
187
|
+
}
|
|
188
|
+
function ruleFailure(code, limits) {
|
|
189
|
+
void limits;
|
|
190
|
+
return (0, operation_result_js_1.failure)([(0, diagnostic_collector_js_1.createDiagnostic)(code, "input")]);
|
|
191
|
+
}
|
|
192
|
+
function failureOptions(context, causeCode) {
|
|
193
|
+
return {
|
|
194
|
+
causeCode,
|
|
195
|
+
...optionalDiagnosticFields(context),
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
function optionalDiagnosticFields(context, path) {
|
|
199
|
+
return {
|
|
200
|
+
...(path === undefined ? {} : { path }),
|
|
201
|
+
...(context.recordId === undefined ? {} : { recordId: context.recordId }),
|
|
202
|
+
...(context.position === undefined ? {} : { position: context.position }),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function compareText(left, right) {
|
|
206
|
+
if (left < right)
|
|
207
|
+
return -1;
|
|
208
|
+
if (left > right)
|
|
209
|
+
return 1;
|
|
210
|
+
return 0;
|
|
211
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.SCHEMA_ASSETS = void 0;
|
|
5
|
+
var schema_assets_js_1 = require("./contracts/schema-assets.js");
|
|
6
|
+
Object.defineProperty(exports, "SCHEMA_ASSETS", { enumerable: true, get: function () { return schema_assets_js_1.SCHEMA_ASSETS; } });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.validateAlgorithmId = validateAlgorithmId;
|
|
5
|
+
const operation_result_js_1 = require("../domain/operation-result.js");
|
|
6
|
+
const result_helpers_js_1 = require("./result-helpers.js");
|
|
7
|
+
function validateAlgorithmId(value) {
|
|
8
|
+
if (value === "sha-256" || value === "sha-384" || value === "sha-512") {
|
|
9
|
+
return (0, operation_result_js_1.success)(value);
|
|
10
|
+
}
|
|
11
|
+
return (0, result_helpers_js_1.failureWithCode)("ALGORITHM_UNKNOWN", "input");
|
|
12
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.DiagnosticCollector = void 0;
|
|
5
|
+
exports.createDiagnostic = createDiagnostic;
|
|
6
|
+
const generated_js_1 = require("../contracts/generated.js");
|
|
7
|
+
const diagnostic_js_1 = require("../domain/diagnostic.js");
|
|
8
|
+
const object_inspection_js_1 = require("./object-inspection.js");
|
|
9
|
+
function createDiagnostic(code, phase, options = {}) {
|
|
10
|
+
const metadata = generated_js_1.DIAGNOSTIC_CODES.find((entry) => entry.code === code);
|
|
11
|
+
if (metadata === undefined) {
|
|
12
|
+
throw new Error(`Unknown generated diagnostic code: ${code}`);
|
|
13
|
+
}
|
|
14
|
+
const details = options.details === undefined ? undefined : tryCopyDetails(options.details);
|
|
15
|
+
const path = safePath(options.path);
|
|
16
|
+
const recordId = safeString(options.recordId, /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/u, 128);
|
|
17
|
+
const causeCode = safeString(options.causeCode, /^[A-Z][A-Z0-9_]{1,127}$/u, 128);
|
|
18
|
+
const position = safePosition(options.position);
|
|
19
|
+
const diagnostic = {
|
|
20
|
+
$schema: diagnostic_js_1.DIAGNOSTIC_SCHEMA,
|
|
21
|
+
code,
|
|
22
|
+
severity: code === "RULE_FAILED" && options.severity !== undefined
|
|
23
|
+
? options.severity
|
|
24
|
+
: metadata.severity,
|
|
25
|
+
phase,
|
|
26
|
+
messageKey: safeString(options.messageKey, /^[a-z][a-z0-9.-]{0,127}$/u, 128) ??
|
|
27
|
+
code.toLowerCase().replaceAll("_", "."),
|
|
28
|
+
...(path === undefined ? {} : { path }),
|
|
29
|
+
...(recordId === undefined ? {} : { recordId }),
|
|
30
|
+
...(position === undefined ? {} : { position }),
|
|
31
|
+
...(details === undefined ? {} : { details }),
|
|
32
|
+
...(causeCode === undefined ? {} : { causeCode }),
|
|
33
|
+
};
|
|
34
|
+
return Object.freeze(diagnostic);
|
|
35
|
+
}
|
|
36
|
+
function tryCopyDetails(value) {
|
|
37
|
+
try {
|
|
38
|
+
return copyDetails(value);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function safeString(value, pattern, maxLength) {
|
|
45
|
+
return typeof value === "string" && value.length <= maxLength && pattern.test(value)
|
|
46
|
+
? value
|
|
47
|
+
: undefined;
|
|
48
|
+
}
|
|
49
|
+
function safePath(value) {
|
|
50
|
+
if (typeof value !== "string" || value.length > 512) {
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
if (value === "" || /^[a-z][a-z0-9.-]{0,127}$/u.test(value)) {
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
if (!value.startsWith("/")) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
const segments = value.split("/");
|
|
60
|
+
return segments.slice(1).every(isJsonPointerSegment) ? value : undefined;
|
|
61
|
+
}
|
|
62
|
+
function isJsonPointerSegment(segment) {
|
|
63
|
+
if (segment.length === 0) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
for (let index = 0; index < segment.length; index += 1) {
|
|
67
|
+
const character = segment[index];
|
|
68
|
+
if (character === "~") {
|
|
69
|
+
const escape = segment[index + 1];
|
|
70
|
+
if (escape !== "0" && escape !== "1") {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
index += 1;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (character === undefined || !/[A-Za-z0-9._~-]/u.test(character)) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
function safePosition(value) {
|
|
83
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : undefined;
|
|
84
|
+
}
|
|
85
|
+
function copyDetails(value) {
|
|
86
|
+
const keys = Object.keys(value);
|
|
87
|
+
if (Object.getOwnPropertySymbols(value).length !== 0 || keys.length > 32) {
|
|
88
|
+
throw new Error("invalid diagnostic details");
|
|
89
|
+
}
|
|
90
|
+
const output = {};
|
|
91
|
+
for (const key of keys) {
|
|
92
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
93
|
+
if (!/^[a-z][a-z0-9.-]{0,63}$/u.test(key) ||
|
|
94
|
+
descriptor === undefined ||
|
|
95
|
+
!(0, object_inspection_js_1.isDataPropertyDescriptor)(descriptor)) {
|
|
96
|
+
throw new Error("invalid diagnostic details");
|
|
97
|
+
}
|
|
98
|
+
const detail = descriptor.value;
|
|
99
|
+
if (detail !== null &&
|
|
100
|
+
typeof detail !== "boolean" &&
|
|
101
|
+
(typeof detail !== "number" || !Number.isFinite(detail)) &&
|
|
102
|
+
(typeof detail !== "string" || detail.length > 256)) {
|
|
103
|
+
throw new Error("invalid diagnostic details");
|
|
104
|
+
}
|
|
105
|
+
Object.defineProperty(output, key, {
|
|
106
|
+
configurable: false,
|
|
107
|
+
enumerable: true,
|
|
108
|
+
value: detail,
|
|
109
|
+
writable: false,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return Object.freeze(output);
|
|
113
|
+
}
|
|
114
|
+
class DiagnosticCollector {
|
|
115
|
+
limits;
|
|
116
|
+
entries = [];
|
|
117
|
+
truncated = false;
|
|
118
|
+
constructor(limits) {
|
|
119
|
+
this.limits = limits;
|
|
120
|
+
}
|
|
121
|
+
add(diagnostic) {
|
|
122
|
+
if (this.entries.length < this.limits.maxDiagnostics) {
|
|
123
|
+
this.entries.push(diagnostic);
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
if (!this.truncated) {
|
|
127
|
+
this.truncated = true;
|
|
128
|
+
this.entries[this.entries.length - 1] = createDiagnostic("DIAGNOSTIC_LIMIT_REACHED", "output");
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
addCode(code, phase, options) {
|
|
132
|
+
this.add(createDiagnostic(code, phase, options));
|
|
133
|
+
}
|
|
134
|
+
hasErrors() {
|
|
135
|
+
return this.entries.some(({ severity }) => severity === "error");
|
|
136
|
+
}
|
|
137
|
+
finish() {
|
|
138
|
+
if (this.entries.length === 0)
|
|
139
|
+
return Object.freeze([]);
|
|
140
|
+
const sorted = [...this.entries].sort(compareDiagnostics);
|
|
141
|
+
return Object.freeze(sorted);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
exports.DiagnosticCollector = DiagnosticCollector;
|
|
145
|
+
function compareDiagnostics(left, right) {
|
|
146
|
+
const leftPosition = left.position ?? Number.MAX_SAFE_INTEGER;
|
|
147
|
+
const rightPosition = right.position ?? Number.MAX_SAFE_INTEGER;
|
|
148
|
+
return (leftPosition - rightPosition ||
|
|
149
|
+
compareText(left.phase, right.phase) ||
|
|
150
|
+
compareText(left.code, right.code) ||
|
|
151
|
+
compareText(left.path ?? "", right.path ?? ""));
|
|
152
|
+
}
|
|
153
|
+
function compareText(left, right) {
|
|
154
|
+
if (left < right)
|
|
155
|
+
return -1;
|
|
156
|
+
if (left > right)
|
|
157
|
+
return 1;
|
|
158
|
+
return 0;
|
|
159
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.digestLength = digestLength;
|
|
5
|
+
exports.validateDigest = validateDigest;
|
|
6
|
+
exports.equalDigest = equalDigest;
|
|
7
|
+
const digest_js_1 = require("../domain/digest.js");
|
|
8
|
+
const operation_result_js_1 = require("../domain/operation-result.js");
|
|
9
|
+
const result_helpers_js_1 = require("./result-helpers.js");
|
|
10
|
+
const algorithm_validation_js_1 = require("./algorithm-validation.js");
|
|
11
|
+
const digestLengths = Object.freeze({
|
|
12
|
+
"sha-256": 32,
|
|
13
|
+
"sha-384": 48,
|
|
14
|
+
"sha-512": 64,
|
|
15
|
+
});
|
|
16
|
+
function digestLength(algorithm) {
|
|
17
|
+
return digestLengths[algorithm];
|
|
18
|
+
}
|
|
19
|
+
function validateDigest(value, algorithm) {
|
|
20
|
+
const algorithmResult = (0, algorithm_validation_js_1.validateAlgorithmId)(algorithm);
|
|
21
|
+
if (!algorithmResult.ok)
|
|
22
|
+
return algorithmResult;
|
|
23
|
+
if (typeof value !== "string" || !/^(?:[0-9a-f]{2})+$/u.test(value)) {
|
|
24
|
+
return (0, result_helpers_js_1.failureWithCode)("DIGEST_ENCODING_INVALID", "input");
|
|
25
|
+
}
|
|
26
|
+
const expectedLength = digestLength(algorithmResult.value) * 2;
|
|
27
|
+
if (value.length !== expectedLength) {
|
|
28
|
+
return (0, result_helpers_js_1.failureWithCode)("DIGEST_LENGTH_INVALID", "input");
|
|
29
|
+
}
|
|
30
|
+
const bytes = new Uint8Array(expectedLength / 2);
|
|
31
|
+
for (let index = 0; index < bytes.length; index += 1) {
|
|
32
|
+
bytes[index] = Number.parseInt(value.slice(index * 2, index * 2 + 2), 16);
|
|
33
|
+
}
|
|
34
|
+
return (0, operation_result_js_1.success)(digest_js_1.Digest.fromValidated(algorithmResult.value, bytes));
|
|
35
|
+
}
|
|
36
|
+
function equalDigest(left, right) {
|
|
37
|
+
if (left.algorithm !== right.algorithm)
|
|
38
|
+
return false;
|
|
39
|
+
const leftBytes = left.toBytes();
|
|
40
|
+
const rightBytes = right.toBytes();
|
|
41
|
+
const leftView = new DataView(leftBytes.buffer, leftBytes.byteOffset, leftBytes.byteLength);
|
|
42
|
+
const rightView = new DataView(rightBytes.buffer, rightBytes.byteOffset, rightBytes.byteLength);
|
|
43
|
+
let difference = 0;
|
|
44
|
+
for (let index = 0; index < leftBytes.length; index += 1) {
|
|
45
|
+
difference |= leftView.getUint8(index) ^ rightView.getUint8(index);
|
|
46
|
+
}
|
|
47
|
+
return difference === 0;
|
|
48
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.validateRecordId = validateRecordId;
|
|
5
|
+
exports.validateSequenceId = validateSequenceId;
|
|
6
|
+
exports.validateContextId = validateContextId;
|
|
7
|
+
exports.validateProfileId = validateProfileId;
|
|
8
|
+
const identifiers_js_1 = require("../domain/identifiers.js");
|
|
9
|
+
const operation_result_js_1 = require("../domain/operation-result.js");
|
|
10
|
+
const result_helpers_js_1 = require("./result-helpers.js");
|
|
11
|
+
const identifierPattern = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/u;
|
|
12
|
+
const profilePattern = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/u;
|
|
13
|
+
function validateRecordId(value) {
|
|
14
|
+
return validateIdentifier(value, (input) => identifiers_js_1.RecordId.fromValidated(input));
|
|
15
|
+
}
|
|
16
|
+
function validateSequenceId(value) {
|
|
17
|
+
return validateIdentifier(value, (input) => identifiers_js_1.SequenceId.fromValidated(input));
|
|
18
|
+
}
|
|
19
|
+
function validateContextId(value) {
|
|
20
|
+
return validateIdentifier(value, (input) => identifiers_js_1.ContextId.fromValidated(input));
|
|
21
|
+
}
|
|
22
|
+
function validateProfileId(value) {
|
|
23
|
+
if (typeof value !== "string" || !profilePattern.test(value) || value.length > 128) {
|
|
24
|
+
return (0, result_helpers_js_1.failureWithCode)("IDENTIFIER_INVALID", "input");
|
|
25
|
+
}
|
|
26
|
+
return (0, operation_result_js_1.success)(identifiers_js_1.ProfileId.fromValidated(value));
|
|
27
|
+
}
|
|
28
|
+
function validateIdentifier(value, create) {
|
|
29
|
+
if (typeof value !== "string" || !identifierPattern.test(value) || value.length > 128) {
|
|
30
|
+
return (0, result_helpers_js_1.failureWithCode)("IDENTIFIER_INVALID", "input");
|
|
31
|
+
}
|
|
32
|
+
return (0, operation_result_js_1.success)(create(value));
|
|
33
|
+
}
|