@openauditmodel/cli 0.1.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.
Files changed (134) hide show
  1. package/LICENSE +215 -0
  2. package/README.md +647 -0
  3. package/dist/conformance/src/cli.d.ts +20 -0
  4. package/dist/conformance/src/cli.js +560 -0
  5. package/dist/conformance/src/cli.js.map +1 -0
  6. package/dist/conformance/src/format-errors.d.ts +20 -0
  7. package/dist/conformance/src/format-errors.js +116 -0
  8. package/dist/conformance/src/format-errors.js.map +1 -0
  9. package/dist/conformance/src/integrity/canonicalize.d.ts +25 -0
  10. package/dist/conformance/src/integrity/canonicalize.js +100 -0
  11. package/dist/conformance/src/integrity/canonicalize.js.map +1 -0
  12. package/dist/conformance/src/integrity/digest.d.ts +54 -0
  13. package/dist/conformance/src/integrity/digest.js +126 -0
  14. package/dist/conformance/src/integrity/digest.js.map +1 -0
  15. package/dist/conformance/src/integrity/types.d.ts +86 -0
  16. package/dist/conformance/src/integrity/types.js +36 -0
  17. package/dist/conformance/src/integrity/types.js.map +1 -0
  18. package/dist/conformance/src/integrity/verify-chain.d.ts +23 -0
  19. package/dist/conformance/src/integrity/verify-chain.js +235 -0
  20. package/dist/conformance/src/integrity/verify-chain.js.map +1 -0
  21. package/dist/conformance/src/integrity/verify-event.d.ts +29 -0
  22. package/dist/conformance/src/integrity/verify-event.js +140 -0
  23. package/dist/conformance/src/integrity/verify-event.js.map +1 -0
  24. package/dist/conformance/src/privacy/entropy.d.ts +14 -0
  25. package/dist/conformance/src/privacy/entropy.js +86 -0
  26. package/dist/conformance/src/privacy/entropy.js.map +1 -0
  27. package/dist/conformance/src/privacy/field-names.d.ts +36 -0
  28. package/dist/conformance/src/privacy/field-names.js +121 -0
  29. package/dist/conformance/src/privacy/field-names.js.map +1 -0
  30. package/dist/conformance/src/privacy/lint-event.d.ts +18 -0
  31. package/dist/conformance/src/privacy/lint-event.js +272 -0
  32. package/dist/conformance/src/privacy/lint-event.js.map +1 -0
  33. package/dist/conformance/src/privacy/rules.d.ts +44 -0
  34. package/dist/conformance/src/privacy/rules.js +161 -0
  35. package/dist/conformance/src/privacy/rules.js.map +1 -0
  36. package/dist/conformance/src/privacy/safe-formats.d.ts +32 -0
  37. package/dist/conformance/src/privacy/safe-formats.js +118 -0
  38. package/dist/conformance/src/privacy/safe-formats.js.map +1 -0
  39. package/dist/conformance/src/privacy/size-analysis.d.ts +36 -0
  40. package/dist/conformance/src/privacy/size-analysis.js +87 -0
  41. package/dist/conformance/src/privacy/size-analysis.js.map +1 -0
  42. package/dist/conformance/src/privacy/token-patterns.d.ts +24 -0
  43. package/dist/conformance/src/privacy/token-patterns.js +126 -0
  44. package/dist/conformance/src/privacy/token-patterns.js.map +1 -0
  45. package/dist/conformance/src/privacy/traverse.d.ts +33 -0
  46. package/dist/conformance/src/privacy/traverse.js +61 -0
  47. package/dist/conformance/src/privacy/traverse.js.map +1 -0
  48. package/dist/conformance/src/privacy/types.d.ts +58 -0
  49. package/dist/conformance/src/privacy/types.js +32 -0
  50. package/dist/conformance/src/privacy/types.js.map +1 -0
  51. package/dist/conformance/src/privacy/url-analysis.d.ts +40 -0
  52. package/dist/conformance/src/privacy/url-analysis.js +148 -0
  53. package/dist/conformance/src/privacy/url-analysis.js.map +1 -0
  54. package/dist/conformance/src/profiles/check-profile.d.ts +22 -0
  55. package/dist/conformance/src/profiles/check-profile.js +72 -0
  56. package/dist/conformance/src/profiles/check-profile.js.map +1 -0
  57. package/dist/conformance/src/profiles/evaluate-rule.d.ts +27 -0
  58. package/dist/conformance/src/profiles/evaluate-rule.js +87 -0
  59. package/dist/conformance/src/profiles/evaluate-rule.js.map +1 -0
  60. package/dist/conformance/src/profiles/load-profile.d.ts +30 -0
  61. package/dist/conformance/src/profiles/load-profile.js +95 -0
  62. package/dist/conformance/src/profiles/load-profile.js.map +1 -0
  63. package/dist/conformance/src/profiles/resolve-pointer.d.ts +44 -0
  64. package/dist/conformance/src/profiles/resolve-pointer.js +123 -0
  65. package/dist/conformance/src/profiles/resolve-pointer.js.map +1 -0
  66. package/dist/conformance/src/profiles/select-rules.d.ts +13 -0
  67. package/dist/conformance/src/profiles/select-rules.js +42 -0
  68. package/dist/conformance/src/profiles/select-rules.js.map +1 -0
  69. package/dist/conformance/src/profiles/types.d.ts +101 -0
  70. package/dist/conformance/src/profiles/types.js +31 -0
  71. package/dist/conformance/src/profiles/types.js.map +1 -0
  72. package/dist/conformance/src/profiles/validate-profile-definition.d.ts +12 -0
  73. package/dist/conformance/src/profiles/validate-profile-definition.js +47 -0
  74. package/dist/conformance/src/profiles/validate-profile-definition.js.map +1 -0
  75. package/dist/conformance/src/sources.d.ts +53 -0
  76. package/dist/conformance/src/sources.js +153 -0
  77. package/dist/conformance/src/sources.js.map +1 -0
  78. package/dist/conformance/src/validate-core.d.ts +30 -0
  79. package/dist/conformance/src/validate-core.js +62 -0
  80. package/dist/conformance/src/validate-core.js.map +1 -0
  81. package/dist/conformance/src/validate.d.ts +34 -0
  82. package/dist/conformance/src/validate.js +62 -0
  83. package/dist/conformance/src/validate.js.map +1 -0
  84. package/dist/conformance/src/validator-interface.d.ts +35 -0
  85. package/dist/conformance/src/validator-interface.js +19 -0
  86. package/dist/conformance/src/validator-interface.js.map +1 -0
  87. package/package.json +85 -0
  88. package/profiles/README.md +201 -0
  89. package/profiles/api-and-integration-management/README.md +271 -0
  90. package/profiles/api-and-integration-management/profile.json +258 -0
  91. package/profiles/backup-and-recovery/README.md +318 -0
  92. package/profiles/backup-and-recovery/profile.json +178 -0
  93. package/profiles/customer-and-account-management/README.md +340 -0
  94. package/profiles/customer-and-account-management/profile.json +237 -0
  95. package/profiles/deployment-and-change-management/README.md +359 -0
  96. package/profiles/deployment-and-change-management/profile.json +298 -0
  97. package/profiles/document-management/README.md +120 -0
  98. package/profiles/document-management/profile.json +170 -0
  99. package/profiles/financial-transaction-management/README.md +339 -0
  100. package/profiles/financial-transaction-management/profile.json +247 -0
  101. package/profiles/identity-and-access-management/README.md +112 -0
  102. package/profiles/identity-and-access-management/profile.json +120 -0
  103. package/profiles/incident-management/README.md +338 -0
  104. package/profiles/incident-management/profile.json +256 -0
  105. package/profiles/message-broker-management/README.md +344 -0
  106. package/profiles/message-broker-management/profile.json +399 -0
  107. package/profiles/profile-definition.schema.json +213 -0
  108. package/profiles/secrets-and-key-management/README.md +331 -0
  109. package/profiles/secrets-and-key-management/profile.json +219 -0
  110. package/schemas/v0.1/audit-event.schema.json +911 -0
  111. package/semantic-conventions/README.md +52 -0
  112. package/semantic-conventions/authentication.md +111 -0
  113. package/semantic-conventions/configuration-and-change.md +122 -0
  114. package/semantic-conventions/correlation-and-tracing.md +387 -0
  115. package/semantic-conventions/data-access.md +115 -0
  116. package/semantic-conventions/event-naming.md +114 -0
  117. package/semantic-conventions/identity-and-access.md +112 -0
  118. package/semantic-conventions/privileged-operations.md +110 -0
  119. package/semantic-conventions/workflow-and-approval.md +109 -0
  120. package/specification/actor-model.md +135 -0
  121. package/specification/approval-and-delegation.md +150 -0
  122. package/specification/authentication.md +116 -0
  123. package/specification/authorization.md +117 -0
  124. package/specification/change-model.md +134 -0
  125. package/specification/delivery.md +136 -0
  126. package/specification/design-principles.md +137 -0
  127. package/specification/event-model.md +387 -0
  128. package/specification/evidence-model.md +109 -0
  129. package/specification/extension-model.md +159 -0
  130. package/specification/integrity.md +314 -0
  131. package/specification/overview.md +172 -0
  132. package/specification/privacy.md +386 -0
  133. package/specification/resource-model.md +116 -0
  134. package/specification/terminology.md +135 -0
@@ -0,0 +1,116 @@
1
+ function paramsOf(error) {
2
+ return (error.params ?? {});
3
+ }
4
+ function asString(value) {
5
+ return typeof value === "string" ? value : undefined;
6
+ }
7
+ /** Escapes a property name so that it is a legal JSON Pointer reference token. */
8
+ function pointerSegment(property) {
9
+ return property.replaceAll("~", "~0").replaceAll("/", "~1");
10
+ }
11
+ function joinPointer(base, property) {
12
+ const pointer = property === undefined ? base : `${base}/${pointerSegment(property)}`;
13
+ return pointer === "" ? "/" : pointer;
14
+ }
15
+ function describe(error) {
16
+ const params = paramsOf(error);
17
+ const fallback = error.message ?? "failed validation";
18
+ switch (error.keyword) {
19
+ case "required":
20
+ return { message: `missing required property "${String(params["missingProperty"])}"` };
21
+ case "dependentRequired":
22
+ return {
23
+ message: `missing property "${String(params["missingProperty"])}", which is required when "${String(params["property"])}" is present`,
24
+ };
25
+ case "additionalProperties":
26
+ return {
27
+ message: `unknown property "${String(params["additionalProperty"])}" is not permitted here`,
28
+ detail: "core objects reject unknown properties; use metadata, extensions or attributes instead",
29
+ };
30
+ case "propertyNames":
31
+ return {
32
+ message: `property name "${String(params["propertyName"])}" does not follow the required naming rule`,
33
+ };
34
+ case "enum": {
35
+ const allowed = Array.isArray(params["allowedValues"])
36
+ ? params["allowedValues"].map((value) => JSON.stringify(value)).join(", ")
37
+ : undefined;
38
+ return {
39
+ message: "value is not one of the permitted values",
40
+ ...(allowed === undefined ? {} : { detail: `allowed: ${allowed}` }),
41
+ };
42
+ }
43
+ case "const":
44
+ return {
45
+ message: "value does not equal the required constant",
46
+ detail: `expected: ${JSON.stringify(params["allowedValue"])}`,
47
+ };
48
+ case "pattern":
49
+ return {
50
+ message: "value does not match the required pattern",
51
+ detail: `pattern: ${String(params["pattern"])}`,
52
+ };
53
+ case "format":
54
+ return {
55
+ message: `value is not a valid "${String(params["format"])}" value`,
56
+ };
57
+ case "if":
58
+ return {
59
+ message: "value does not satisfy a conditional requirement of the schema",
60
+ detail: "see the accompanying issues for the specific requirement",
61
+ };
62
+ case "not":
63
+ return { message: "value is explicitly forbidden by the schema" };
64
+ default:
65
+ return { message: fallback };
66
+ }
67
+ }
68
+ /** Converts validator errors into issues, deduplicating identical entries. */
69
+ export function toIssues(errors) {
70
+ if (!errors || errors.length === 0) {
71
+ return [];
72
+ }
73
+ const seen = new Set();
74
+ const issues = [];
75
+ for (const error of errors) {
76
+ const params = paramsOf(error);
77
+ const base = error.instancePath;
78
+ // `propertyNames` failures report the offending key either on the error
79
+ // itself (for the nested constraint that failed) or in its parameters.
80
+ const propertyName = asString(error.propertyName) ??
81
+ (error.keyword === "propertyNames" ? asString(params["propertyName"]) : undefined);
82
+ let path;
83
+ if (error.keyword === "required" || error.keyword === "dependentRequired") {
84
+ path = joinPointer(base, asString(params["missingProperty"]));
85
+ }
86
+ else if (error.keyword === "additionalProperties") {
87
+ path = joinPointer(base, asString(params["additionalProperty"]));
88
+ }
89
+ else {
90
+ path = joinPointer(base, propertyName);
91
+ }
92
+ const { message, detail } = describe(error);
93
+ const key = `${path}|${error.keyword}|${message}|${detail ?? ""}`;
94
+ if (seen.has(key)) {
95
+ continue;
96
+ }
97
+ seen.add(key);
98
+ issues.push({
99
+ path,
100
+ message,
101
+ keyword: error.keyword,
102
+ ...(detail === undefined ? {} : { detail }),
103
+ });
104
+ }
105
+ return issues;
106
+ }
107
+ /** Renders issues as indented report lines. */
108
+ export function formatIssues(issues, indent = " ") {
109
+ return issues
110
+ .map((issue) => {
111
+ const detail = issue.detail === undefined ? "" : `\n${indent} ${issue.detail}`;
112
+ return `${indent}${issue.path} ${issue.message} [${issue.keyword}]${detail}`;
113
+ })
114
+ .join("\n");
115
+ }
116
+ //# sourceMappingURL=format-errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-errors.js","sourceRoot":"","sources":["../../../conformance/src/format-errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { CANONICALIZATION_RFC8785 } from "./types.js";
2
+ /**
3
+ * Deepest structure accepted for canonicalization. Canonicalization is
4
+ * recursive, so an arbitrarily deep document would exhaust the stack; audit
5
+ * events are shallow and this bound is far above any realistic event.
6
+ */
7
+ export declare const MAX_JSON_DEPTH = 200;
8
+ export declare class CanonicalizationError extends Error {
9
+ constructor(message: string);
10
+ }
11
+ /**
12
+ * Rejects anything that is not a value `JSON.parse` could have produced.
13
+ *
14
+ * The pointer in the error identifies *where* the problem is, never what the
15
+ * value was, so that a malformed event cannot leak its content through an error
16
+ * message.
17
+ */
18
+ export declare function assertJsonValue(value: unknown, pointer?: string, depth?: number): void;
19
+ /** Returns the RFC 8785 canonical form of a JSON value. */
20
+ export declare function canonicalize(value: unknown): string;
21
+ /** Returns the UTF-8 encoding of the RFC 8785 canonical form. */
22
+ export declare function canonicalBytes(value: unknown): Buffer;
23
+ /** True when this verifier implements the declared canonicalization. */
24
+ export declare function isSupportedCanonicalization(identifier: string): boolean;
25
+ export { CANONICALIZATION_RFC8785 };
@@ -0,0 +1,100 @@
1
+ /**
2
+ * RFC 8785 JSON Canonicalization Scheme.
3
+ *
4
+ * Canonicalization is delegated to the `canonicalize` package (Apache-2.0, no
5
+ * dependencies), which implements the scheme by sorting object keys with the
6
+ * ECMAScript default string comparison — UTF-16 code unit order, as RFC 8785
7
+ * §3.2.3 requires — and serialising primitives with `JSON.stringify`, whose
8
+ * number and string handling is the behaviour RFC 8785 §3.2.2.2 and §3.2.2.3
9
+ * are defined against.
10
+ *
11
+ * The guard in this module exists because that package is permissive with
12
+ * values JSON cannot represent: it maps `undefined` inside an array to `null`,
13
+ * drops `undefined` object members, and calls `toJSON` on anything that has it.
14
+ * Silently reinterpreting an input would produce a digest over something other
15
+ * than what the caller passed, so those inputs are rejected instead.
16
+ */
17
+ import canonicalizeValue from "canonicalize";
18
+ import { CANONICALIZATION_RFC8785, SUPPORTED_CANONICALIZATIONS } from "./types.js";
19
+ /**
20
+ * Deepest structure accepted for canonicalization. Canonicalization is
21
+ * recursive, so an arbitrarily deep document would exhaust the stack; audit
22
+ * events are shallow and this bound is far above any realistic event.
23
+ */
24
+ export const MAX_JSON_DEPTH = 200;
25
+ export class CanonicalizationError extends Error {
26
+ constructor(message) {
27
+ super(message);
28
+ this.name = "CanonicalizationError";
29
+ }
30
+ }
31
+ function describePointer(pointer) {
32
+ return pointer === "" ? "the document root" : pointer;
33
+ }
34
+ function isPlainObject(value) {
35
+ const prototype = Object.getPrototypeOf(value);
36
+ return prototype === Object.prototype || prototype === null;
37
+ }
38
+ /**
39
+ * Rejects anything that is not a value `JSON.parse` could have produced.
40
+ *
41
+ * The pointer in the error identifies *where* the problem is, never what the
42
+ * value was, so that a malformed event cannot leak its content through an error
43
+ * message.
44
+ */
45
+ export function assertJsonValue(value, pointer = "", depth = 0) {
46
+ if (depth > MAX_JSON_DEPTH) {
47
+ throw new CanonicalizationError(`structure is nested more than ${MAX_JSON_DEPTH} levels deep at ${describePointer(pointer)}`);
48
+ }
49
+ if (value === null) {
50
+ return;
51
+ }
52
+ switch (typeof value) {
53
+ case "boolean":
54
+ case "string":
55
+ return;
56
+ case "number":
57
+ if (!Number.isFinite(value)) {
58
+ throw new CanonicalizationError(`number at ${describePointer(pointer)} is not finite and cannot be canonicalized`);
59
+ }
60
+ return;
61
+ case "object":
62
+ break;
63
+ default:
64
+ throw new CanonicalizationError(`value at ${describePointer(pointer)} has type "${typeof value}", which JSON cannot represent`);
65
+ }
66
+ if (Array.isArray(value)) {
67
+ for (const [index, item] of value.entries()) {
68
+ assertJsonValue(item, `${pointer}/${index}`, depth + 1);
69
+ }
70
+ return;
71
+ }
72
+ if (!isPlainObject(value)) {
73
+ throw new CanonicalizationError(`value at ${describePointer(pointer)} is not a plain JSON object`);
74
+ }
75
+ for (const [key, member] of Object.entries(value)) {
76
+ if (member === undefined) {
77
+ throw new CanonicalizationError(`member "${key}" at ${describePointer(pointer)} is undefined, which JSON cannot represent`);
78
+ }
79
+ assertJsonValue(member, `${pointer}/${key.replaceAll("~", "~0").replaceAll("/", "~1")}`, depth + 1);
80
+ }
81
+ }
82
+ /** Returns the RFC 8785 canonical form of a JSON value. */
83
+ export function canonicalize(value) {
84
+ assertJsonValue(value);
85
+ const canonical = canonicalizeValue(value);
86
+ if (typeof canonical !== "string") {
87
+ throw new CanonicalizationError("value could not be canonicalized");
88
+ }
89
+ return canonical;
90
+ }
91
+ /** Returns the UTF-8 encoding of the RFC 8785 canonical form. */
92
+ export function canonicalBytes(value) {
93
+ return Buffer.from(canonicalize(value), "utf8");
94
+ }
95
+ /** True when this verifier implements the declared canonicalization. */
96
+ export function isSupportedCanonicalization(identifier) {
97
+ return SUPPORTED_CANONICALIZATIONS.includes(identifier);
98
+ }
99
+ export { CANONICALIZATION_RFC8785 };
100
+ //# sourceMappingURL=canonicalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonicalize.js","sourceRoot":"","sources":["../../../../conformance/src/integrity/canonicalize.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { SUPPORTED_HASH_ALGORITHMS, type SupportedHashAlgorithm } from "./types.js";
2
+ /**
3
+ * True when this verifier implements the declared algorithm. Matching is
4
+ * case-sensitive: `sha256` is not `SHA-256`, and reinterpreting it would mean
5
+ * guessing at what a producer meant.
6
+ */
7
+ export declare function isSupportedHashAlgorithm(algorithm: string): algorithm is SupportedHashAlgorithm;
8
+ /** Digest length in bytes for a supported algorithm. */
9
+ export declare function digestByteLength(algorithm: SupportedHashAlgorithm): number;
10
+ /** True when a value is a well-formed lowercase hexadecimal digest. */
11
+ export declare function isHexDigest(value: unknown): value is string;
12
+ /**
13
+ * Builds the digest input: a deep clone of the event with the self-referential
14
+ * integrity members removed.
15
+ *
16
+ * Exactly two JSON Pointers are removed, `/integrity/hash` and
17
+ * `/integrity/signature`. No other member is removed and no empty container is
18
+ * pruned, so an `integrity` object left with no members is serialised as `{}`.
19
+ * That rule is arbitrary but it must be fixed, because a producer that pruned
20
+ * it and a verifier that did not would compute different digests.
21
+ *
22
+ * The input event is never mutated.
23
+ */
24
+ export declare function buildDigestInput(event: unknown): unknown;
25
+ /** Returns the RFC 8785 canonical form of the digest input, for diagnostics and tests. */
26
+ export declare function canonicalDigestInput(event: unknown): string;
27
+ /**
28
+ * Calculates an event's digest and returns it as lowercase hexadecimal.
29
+ *
30
+ * Throws for an algorithm this verifier does not implement; callers that need
31
+ * to report rather than throw should check `isSupportedHashAlgorithm` first.
32
+ */
33
+ export declare function calculateDigest(event: unknown, algorithm: string): string;
34
+ /**
35
+ * Returns a copy of an event with `integrity.hash` set to its calculated
36
+ * digest.
37
+ *
38
+ * The event must already declare `integrity.canonicalization` and
39
+ * `integrity.hashAlgorithm`, because both are part of the digest input: a
40
+ * producer that let the tooling choose them would be sealing a claim it never
41
+ * made. This is a producer-side convenience for tests, fixtures and future
42
+ * libraries; it performs no signing and touches no key material.
43
+ */
44
+ export declare function sealEvent<T>(event: T): T;
45
+ /**
46
+ * Compares two digests as bytes, in constant time for equal-length inputs.
47
+ *
48
+ * A digest is not a secret, so this is defence in depth rather than a
49
+ * requirement; what matters more is that a malformed value is rejected instead
50
+ * of being coerced. `Buffer.from(value, "hex")` truncates silently on invalid
51
+ * input, so both values are checked against the accepted encoding first.
52
+ */
53
+ export declare function digestsEqual(left: string, right: string): boolean;
54
+ export { SUPPORTED_HASH_ALGORITHMS, type SupportedHashAlgorithm };
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Event digest calculation and comparison.
3
+ *
4
+ * The procedure implemented here is normative and is specified in
5
+ * specification/integrity.md §4. It is deterministic: the same event produces
6
+ * the same digest in any conforming implementation, in any language.
7
+ */
8
+ import { createHash, timingSafeEqual } from "node:crypto";
9
+ import { canonicalBytes, canonicalize } from "./canonicalize.js";
10
+ import { DIGEST_BYTE_LENGTHS, DIGEST_EXCLUDED_POINTERS, SUPPORTED_HASH_ALGORITHMS, } from "./types.js";
11
+ /** Lowercase hexadecimal, an even number of digits. The only accepted digest encoding. */
12
+ const HEX_DIGEST = /^([0-9a-f]{2})+$/;
13
+ /** Node's digest name for each normative OpenAuditModel algorithm identifier. */
14
+ const NODE_HASH_NAMES = {
15
+ "SHA-256": "sha256",
16
+ "SHA-384": "sha384",
17
+ "SHA-512": "sha512",
18
+ };
19
+ /**
20
+ * True when this verifier implements the declared algorithm. Matching is
21
+ * case-sensitive: `sha256` is not `SHA-256`, and reinterpreting it would mean
22
+ * guessing at what a producer meant.
23
+ */
24
+ export function isSupportedHashAlgorithm(algorithm) {
25
+ return SUPPORTED_HASH_ALGORITHMS.includes(algorithm);
26
+ }
27
+ /** Digest length in bytes for a supported algorithm. */
28
+ export function digestByteLength(algorithm) {
29
+ return DIGEST_BYTE_LENGTHS[algorithm];
30
+ }
31
+ /** True when a value is a well-formed lowercase hexadecimal digest. */
32
+ export function isHexDigest(value) {
33
+ return typeof value === "string" && HEX_DIGEST.test(value);
34
+ }
35
+ /**
36
+ * Builds the digest input: a deep clone of the event with the self-referential
37
+ * integrity members removed.
38
+ *
39
+ * Exactly two JSON Pointers are removed, `/integrity/hash` and
40
+ * `/integrity/signature`. No other member is removed and no empty container is
41
+ * pruned, so an `integrity` object left with no members is serialised as `{}`.
42
+ * That rule is arbitrary but it must be fixed, because a producer that pruned
43
+ * it and a verifier that did not would compute different digests.
44
+ *
45
+ * The input event is never mutated.
46
+ */
47
+ export function buildDigestInput(event) {
48
+ const clone = structuredClone(event);
49
+ if (clone !== null && typeof clone === "object" && !Array.isArray(clone)) {
50
+ const record = clone;
51
+ const integrity = record["integrity"];
52
+ if (integrity !== null && typeof integrity === "object" && !Array.isArray(integrity)) {
53
+ const integrityRecord = integrity;
54
+ for (const pointer of DIGEST_EXCLUDED_POINTERS) {
55
+ const member = pointer.slice("/integrity/".length);
56
+ delete integrityRecord[member];
57
+ }
58
+ }
59
+ }
60
+ return clone;
61
+ }
62
+ /** Returns the RFC 8785 canonical form of the digest input, for diagnostics and tests. */
63
+ export function canonicalDigestInput(event) {
64
+ return canonicalize(buildDigestInput(event));
65
+ }
66
+ /**
67
+ * Calculates an event's digest and returns it as lowercase hexadecimal.
68
+ *
69
+ * Throws for an algorithm this verifier does not implement; callers that need
70
+ * to report rather than throw should check `isSupportedHashAlgorithm` first.
71
+ */
72
+ export function calculateDigest(event, algorithm) {
73
+ if (!isSupportedHashAlgorithm(algorithm)) {
74
+ throw new Error(`unsupported hash algorithm "${algorithm}"; this verifier implements ${SUPPORTED_HASH_ALGORITHMS.join(", ")}`);
75
+ }
76
+ const bytes = canonicalBytes(buildDigestInput(event));
77
+ return createHash(NODE_HASH_NAMES[algorithm]).update(bytes).digest("hex");
78
+ }
79
+ /**
80
+ * Returns a copy of an event with `integrity.hash` set to its calculated
81
+ * digest.
82
+ *
83
+ * The event must already declare `integrity.canonicalization` and
84
+ * `integrity.hashAlgorithm`, because both are part of the digest input: a
85
+ * producer that let the tooling choose them would be sealing a claim it never
86
+ * made. This is a producer-side convenience for tests, fixtures and future
87
+ * libraries; it performs no signing and touches no key material.
88
+ */
89
+ export function sealEvent(event) {
90
+ const integrity = event?.["integrity"];
91
+ if (integrity === null || typeof integrity !== "object" || Array.isArray(integrity)) {
92
+ throw new Error("cannot seal an event that declares no integrity object");
93
+ }
94
+ const record = integrity;
95
+ const canonicalization = record["canonicalization"];
96
+ const algorithm = record["hashAlgorithm"];
97
+ if (typeof canonicalization !== "string") {
98
+ throw new Error("cannot seal an event that declares no integrity.canonicalization");
99
+ }
100
+ if (typeof algorithm !== "string") {
101
+ throw new Error("cannot seal an event that declares no integrity.hashAlgorithm");
102
+ }
103
+ const hash = calculateDigest(event, algorithm);
104
+ return { ...event, integrity: { ...record, hash } };
105
+ }
106
+ /**
107
+ * Compares two digests as bytes, in constant time for equal-length inputs.
108
+ *
109
+ * A digest is not a secret, so this is defence in depth rather than a
110
+ * requirement; what matters more is that a malformed value is rejected instead
111
+ * of being coerced. `Buffer.from(value, "hex")` truncates silently on invalid
112
+ * input, so both values are checked against the accepted encoding first.
113
+ */
114
+ export function digestsEqual(left, right) {
115
+ if (!isHexDigest(left) || !isHexDigest(right)) {
116
+ return false;
117
+ }
118
+ const leftBytes = Buffer.from(left, "hex");
119
+ const rightBytes = Buffer.from(right, "hex");
120
+ if (leftBytes.length !== rightBytes.length) {
121
+ return false;
122
+ }
123
+ return timingSafeEqual(leftBytes, rightBytes);
124
+ }
125
+ export { SUPPORTED_HASH_ALGORITHMS };
126
+ //# sourceMappingURL=digest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"digest.js","sourceRoot":"","sources":["../../../../conformance/src/integrity/digest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Shared types and constants for tamper-evidence verification.
3
+ *
4
+ * The tooling detects specific integrity failures. It does not prevent deletion
5
+ * or modification, and it makes no claim that an event is immutable,
6
+ * tamper-proof, legally binding or non-repudiable.
7
+ */
8
+ /** Canonicalization identifier the v0.1 verifier implements: RFC 8785 JCS. */
9
+ export declare const CANONICALIZATION_RFC8785 = "RFC8785";
10
+ /** Canonicalization identifiers this verifier can execute. Matching is case-sensitive. */
11
+ export declare const SUPPORTED_CANONICALIZATIONS: readonly ["RFC8785"];
12
+ /**
13
+ * Hash algorithms this verifier can execute, as normative identifiers.
14
+ *
15
+ * The schema keeps `integrity.hashAlgorithm` an open vocabulary so that new
16
+ * algorithms can be adopted without a specification change. An identifier the
17
+ * schema accepts is therefore not necessarily one this verifier implements: an
18
+ * event declaring an algorithm outside this list is reported as
19
+ * `unsupported-algorithm` rather than silently treated as verified.
20
+ */
21
+ export declare const SUPPORTED_HASH_ALGORITHMS: readonly ["SHA-256", "SHA-384", "SHA-512"];
22
+ export type SupportedHashAlgorithm = (typeof SUPPORTED_HASH_ALGORITHMS)[number];
23
+ /** Digest length in bytes for each supported algorithm. */
24
+ export declare const DIGEST_BYTE_LENGTHS: Readonly<Record<SupportedHashAlgorithm, number>>;
25
+ /**
26
+ * JSON Pointers removed from an event before its digest is calculated.
27
+ *
28
+ * Everything else, including `sequence`, `integrity.previousHash`,
29
+ * `integrity.chainId`, `integrity.batchId`, `integrity.hashAlgorithm` and
30
+ * `integrity.canonicalization`, is part of the digest input.
31
+ */
32
+ export declare const DIGEST_EXCLUDED_POINTERS: readonly ["/integrity/hash", "/integrity/signature"];
33
+ /** Why a single event failed verification. */
34
+ export type EventFindingKind = "schema-invalid" | "integrity-missing" | "hash-missing" | "hash-algorithm-missing" | "canonicalization-missing" | "unsupported-canonicalization" | "unsupported-algorithm" | "malformed-hash" | "digest-length-mismatch" | "hash-mismatch" | "canonicalization-failed";
35
+ /** Why a chain failed verification. */
36
+ export type ChainFindingKind = "chain-id-missing" | "sequence-missing" | "duplicate-sequence" | "previous-hash-missing" | "broken-link" | "algorithm-mismatch";
37
+ export type FindingKind = EventFindingKind | ChainFindingKind;
38
+ /** A single reason verification did not succeed. */
39
+ export interface Finding {
40
+ readonly kind: FindingKind;
41
+ /** One line, safe to print. Never contains event content. */
42
+ readonly message: string;
43
+ /** Ordered detail lines, such as the declared and calculated digests. */
44
+ readonly detail?: readonly string[];
45
+ /** Where the problem was found, when it applies to one event. */
46
+ readonly label?: string;
47
+ }
48
+ /** An informational observation that does not by itself fail verification. */
49
+ export interface Note {
50
+ readonly message: string;
51
+ readonly detail?: readonly string[];
52
+ }
53
+ /** A check that passed, reported so that a successful run says what it proved. */
54
+ export interface PassedCheck {
55
+ readonly message: string;
56
+ }
57
+ /** Outcome of verifying one event's own digest. */
58
+ export interface EventVerificationResult {
59
+ readonly label: string;
60
+ readonly verified: boolean;
61
+ readonly checks: readonly PassedCheck[];
62
+ readonly findings: readonly Finding[];
63
+ readonly canonicalization?: string;
64
+ readonly hashAlgorithm?: string;
65
+ readonly declaredHash?: string;
66
+ readonly calculatedHash?: string;
67
+ }
68
+ /** Outcome of verifying one chain. */
69
+ export interface ChainVerificationResult {
70
+ readonly chainId: string;
71
+ readonly eventCount: number;
72
+ readonly firstSequence?: number;
73
+ readonly lastSequence?: number;
74
+ readonly intact: boolean;
75
+ readonly checks: readonly PassedCheck[];
76
+ readonly findings: readonly Finding[];
77
+ readonly notes: readonly Note[];
78
+ }
79
+ /** Outcome of verifying every chain in a supplied set of events. */
80
+ export interface ChainReport {
81
+ readonly chains: readonly ChainVerificationResult[];
82
+ /** Events that could not be assigned to a chain at all. */
83
+ readonly unassigned: readonly Finding[];
84
+ readonly eventCount: number;
85
+ readonly intact: boolean;
86
+ }
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Shared types and constants for tamper-evidence verification.
3
+ *
4
+ * The tooling detects specific integrity failures. It does not prevent deletion
5
+ * or modification, and it makes no claim that an event is immutable,
6
+ * tamper-proof, legally binding or non-repudiable.
7
+ */
8
+ /** Canonicalization identifier the v0.1 verifier implements: RFC 8785 JCS. */
9
+ export const CANONICALIZATION_RFC8785 = "RFC8785";
10
+ /** Canonicalization identifiers this verifier can execute. Matching is case-sensitive. */
11
+ export const SUPPORTED_CANONICALIZATIONS = [CANONICALIZATION_RFC8785];
12
+ /**
13
+ * Hash algorithms this verifier can execute, as normative identifiers.
14
+ *
15
+ * The schema keeps `integrity.hashAlgorithm` an open vocabulary so that new
16
+ * algorithms can be adopted without a specification change. An identifier the
17
+ * schema accepts is therefore not necessarily one this verifier implements: an
18
+ * event declaring an algorithm outside this list is reported as
19
+ * `unsupported-algorithm` rather than silently treated as verified.
20
+ */
21
+ export const SUPPORTED_HASH_ALGORITHMS = ["SHA-256", "SHA-384", "SHA-512"];
22
+ /** Digest length in bytes for each supported algorithm. */
23
+ export const DIGEST_BYTE_LENGTHS = {
24
+ "SHA-256": 32,
25
+ "SHA-384": 48,
26
+ "SHA-512": 64,
27
+ };
28
+ /**
29
+ * JSON Pointers removed from an event before its digest is calculated.
30
+ *
31
+ * Everything else, including `sequence`, `integrity.previousHash`,
32
+ * `integrity.chainId`, `integrity.batchId`, `integrity.hashAlgorithm` and
33
+ * `integrity.canonicalization`, is part of the digest input.
34
+ */
35
+ export const DIGEST_EXCLUDED_POINTERS = ["/integrity/hash", "/integrity/signature"];
36
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../conformance/src/integrity/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,8EAA8E;AAC9E,MAAM,CAAC,MAAM,wBAAwB,GAAG,SAAS,CAAC;AAElD,0FAA0F;AAC1F,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,wBAAwB,CAAU,CAAC;AAE/E;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,CAAU,CAAC;AAIpF,2DAA2D;AAC3D,MAAM,CAAC,MAAM,mBAAmB,GAAqD;IACnF,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;IACb,SAAS,EAAE,EAAE;CACd,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,iBAAiB,EAAE,sBAAsB,CAAU,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Verification of previous-hash chains.
3
+ *
4
+ * Chain verification proves that the *supplied* set of events is internally
5
+ * consistent. It cannot prove that the supplied set is complete: an attacker
6
+ * who removes the tail of a chain, or who never let an event be produced,
7
+ * leaves nothing for a verifier to find. See specification/integrity.md §8.
8
+ */
9
+ import type { EventValidator } from "../validate-core.js";
10
+ import type { ChainReport } from "./types.js";
11
+ /** One event offered for chain verification. */
12
+ export interface ChainEventInput {
13
+ readonly label: string;
14
+ readonly event: unknown;
15
+ }
16
+ /**
17
+ * Verifies every chain present in a set of events.
18
+ *
19
+ * Events are grouped by `integrity.chainId`; a set containing several chains is
20
+ * verified as several independent chains, which is the intended model — a
21
+ * single global chain is never required.
22
+ */
23
+ export declare function verifyChains(inputs: readonly ChainEventInput[], validator: EventValidator): ChainReport;