@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,136 @@
1
+ # Delivery
2
+
3
+ **Specification version: 0.1 · Status: Experimental · This document: Normative**
4
+
5
+ ## 1. OpenAuditModel defines no transport
6
+
7
+ The model defines the **event**, not how it moves. There is no OpenAuditModel protocol, wire format,
8
+ endpoint, envelope or delivery guarantee, and none will be introduced.
9
+
10
+ An event is equally valid when it is:
11
+
12
+ - Written to a local file or standard output.
13
+ - Inserted into a table.
14
+ - Published to a topic or queue.
15
+ - Sent as an HTTP request body.
16
+ - Emitted as an OpenTelemetry log record.
17
+ - Wrapped in a CloudEvents envelope.
18
+ - Held in memory in a test.
19
+
20
+ Producers MUST NOT be required to adopt any pipeline in order to conform. See
21
+ [ADR 0003](../decisions/0003-backend-and-transport-independence.md).
22
+
23
+ ## 2. Producing
24
+
25
+ A producer:
26
+
27
+ 1. MUST emit events that validate against the canonical schema.
28
+ 2. SHOULD emit an event for an auditable operation regardless of its outcome. Recording only
29
+ successes produces an audit trail that cannot answer the questions failures raise.
30
+ 3. SHOULD emit the event as close to the operation as possible, so that `time` reflects the operation
31
+ rather than a later batch.
32
+ 4. SHOULD NOT make the success of the audited operation depend on the success of audit emission,
33
+ unless the operator has explicitly chosen that trade-off. This is a genuine design decision:
34
+ dropping audit records under load and refusing business operations when the audit path is down are
35
+ both defensible, and the specification does not choose for the operator.
36
+ 5. MUST record the decision it made, in its own documentation. A consumer cannot tell from the data
37
+ whether missing events mean "nothing happened" or "the buffer overflowed".
38
+
39
+ ## 3. Identity and idempotency
40
+
41
+ `id` is the basis of safe delivery.
42
+
43
+ - A producer that retries emission of the same audited operation MUST reuse the same `id`.
44
+ - A producer MUST NOT reuse an `id` for a different operation.
45
+ - A consumer SHOULD deduplicate by `id`.
46
+ - A consumer MUST NOT assume that receiving an event twice means the operation happened twice.
47
+
48
+ This is what makes at-least-once transports safe to use for audit data, and it is why `id` is
49
+ required rather than optional.
50
+
51
+ ## 4. Time and observation
52
+
53
+ `time` is when the operation occurred. `observedTime` is when a component in the path observed the
54
+ event.
55
+
56
+ - A producer SHOULD set `time` and SHOULD NOT set `observedTime`.
57
+ - The first component that receives an event MAY set `observedTime`. Later components SHOULD NOT
58
+ overwrite it.
59
+ - A consumer MUST NOT assume the two are equal, and MUST NOT compute pipeline latency from `time`
60
+ alone. Backfilled, queued and replayed events legitimately arrive long after they occurred.
61
+ - Clocks differ. A consumer MUST NOT assume that `time` values from different producers are directly
62
+ comparable at fine resolution, and SHOULD NOT reconstruct causality from timestamps alone.
63
+ `request.traceId` and `request.correlationId` group events that belong to the same execution or
64
+ logical operation; neither establishes which event caused another. See
65
+ [event-model.md §10.3](event-model.md).
66
+
67
+ ## 5. Ordering
68
+
69
+ The model provides no global ordering and no total order.
70
+
71
+ - `sequence` orders events **within** one producer, partition or chain. It is meaningless across
72
+ producers.
73
+ - A consumer MUST NOT assume events arrive in `time` order, in `sequence` order, or in the order the
74
+ operations occurred.
75
+ - A consumer that needs ordering MUST establish it from `sequence` within a chain, and MUST tolerate
76
+ gaps. Trace context groups related events but does not order them.
77
+
78
+ ## 6. Loss, duplication and gaps
79
+
80
+ Any realistic pipeline will duplicate or drop events. The model responds to this by being explicit
81
+ rather than by promising a guarantee it cannot enforce:
82
+
83
+ | Situation | What the model provides |
84
+ | ------------------ | ----------------------------------------------------- |
85
+ | Duplicate delivery | `id` for deduplication |
86
+ | Reordering | `sequence` within a chain; trace context for grouping |
87
+ | Silent loss | `integrity.previousHash` chains make gaps detectable |
88
+ | Delay | `observedTime` separate from `time` |
89
+
90
+ Detecting a gap requires that something was chained or counted. A pipeline with no chain and no
91
+ counter cannot distinguish a quiet period from a broken exporter, and operators SHOULD monitor
92
+ production rates independently of the audit data itself.
93
+
94
+ ## 7. Enrichment
95
+
96
+ Components between producer and consumer MAY enrich events. When they do:
97
+
98
+ 1. They MUST NOT alter `event`, `actor`, `subject`, `resource`, `application`, `change`,
99
+ `authorization`, `approval` or `id`. Those describe what the producer observed, and a collector
100
+ was not there.
101
+ 2. They MUST NOT set `application` to describe themselves. `application` is the producer. A pipeline
102
+ that rewrites it destroys the provenance of the entire trail.
103
+ 3. They MAY set `observedTime` if it is not already present.
104
+ 4. They MAY add `extensions` under their own reverse-domain namespace.
105
+ 5. They MUST NOT invalidate an event. Any enriched event MUST still validate against the canonical
106
+ schema.
107
+ 6. They MUST NOT modify an event that carries `integrity.hash` or `integrity.signature`, because any
108
+ modification invalidates it. Enrichment of a sealed event MUST be carried alongside it, not inside
109
+ it. This includes `observedTime`: every field except the two excluded pointers is part of the
110
+ digest, so adding an observation timestamp to a sealed event breaks its verification. See
111
+ [integrity.md](integrity.md) §4.2.
112
+
113
+ ## 8. Batching
114
+
115
+ Batching is a transport concern, and the model defines no batch envelope. Producers that batch:
116
+
117
+ - MUST keep each event individually valid. A batch is a list of complete events, not a shared header
118
+ plus fragments.
119
+ - MAY record `integrity.batchId` to identify the batch an event was sealed with.
120
+ - SHOULD NOT let batching distort `time`.
121
+
122
+ ## 9. Optional envelopes
123
+
124
+ Where an envelope is used, the complete audit event SHOULD be carried as the envelope's payload
125
+ without being flattened or restructured, so that it can be validated on arrival exactly as it was
126
+ produced. Conceptual mappings for CloudEvents and OpenTelemetry are described in
127
+ [mappings/](../mappings/), which is informative.
128
+
129
+ Using an envelope MUST NOT change the event. An event that is only valid after being unwrapped and
130
+ transformed is not a conforming event.
131
+
132
+ ## 10. Storage
133
+
134
+ Out of scope, deliberately and permanently. The specification says nothing about schemas for storage,
135
+ indexes, partitioning, retention enforcement, compaction or query. It says only that whatever the
136
+ store does, it MUST be able to return the event as it was produced if the trail is to mean anything.
@@ -0,0 +1,137 @@
1
+ # Design Principles
2
+
3
+ **Specification version: 0.1 · Status: Experimental · This document: Normative**
4
+
5
+ These principles are the reason the model looks the way it does. They are normative in the sense that
6
+ a proposed change to the core model MUST be evaluated against them, and a change that violates one
7
+ MUST be rejected or must first change the principle.
8
+
9
+ ## 1. The core stays small
10
+
11
+ The core model contains only concepts that are meaningful in **every** business application,
12
+ regardless of industry, jurisdiction or architecture.
13
+
14
+ A field belongs in the core only if all of the following hold:
15
+
16
+ 1. It is meaningful to a document system, a payment system, a hospital system, a message broker
17
+ console and an internal admin tool alike.
18
+ 2. Omitting it would make an audit event ambiguous in a way no other field resolves.
19
+ 3. It cannot be expressed as `metadata`, an extension, or a profile requirement without losing
20
+ cross-application comparability.
21
+
22
+ Everything else belongs in `metadata`, `extensions` or a profile. A core model that grows to cover
23
+ every domain stops being a common model.
24
+
25
+ ## 2. The core is explainable
26
+
27
+ An engineer MUST be able to read [event-model.md](event-model.md) and instrument an application
28
+ correctly without reading the rest of the specification. Concepts that require a diagram of five
29
+ interacting objects to explain are a sign that the model is wrong, not that the reader is slow.
30
+
31
+ ## 3. Composition, not inheritance
32
+
33
+ The model has no type hierarchy, no discriminated event subclasses and no abstract base event.
34
+ An event is a flat set of optional context objects attached to a small required core. A privileged
35
+ configuration change is not a subclass of a change: it is an event with `change`, `approval`,
36
+ `authorization` and `controlCategories` populated.
37
+
38
+ This keeps the schema flat, keeps validation cheap, and keeps profiles additive.
39
+
40
+ ## 4. Backend independence
41
+
42
+ The model MUST NOT require, assume or favour any storage system, message broker, telemetry pipeline,
43
+ SIEM, cloud provider or vendor product. An event MUST be equally valid when it is written to a file,
44
+ inserted into a table, published to a topic or held in memory.
45
+
46
+ Consequences that are enforced today:
47
+
48
+ - No field describes a storage location, index, partition key or retention backend.
49
+ - `application` describes the **producer**, never a collector or a store.
50
+ - Schema identifiers never have to be dereferenced: no `$ref` resolves remotely, so validation never requires a network call.
51
+ - Validation is fully offline.
52
+
53
+ See [ADR 0003](../decisions/0003-backend-and-transport-independence.md).
54
+
55
+ ## 5. Transport independence
56
+
57
+ The model defines no transport, envelope or delivery guarantee. It MAY be carried by CloudEvents,
58
+ OpenTelemetry, HTTP, a broker, a file or a database write. Delivery concerns — retries, duplicates,
59
+ ordering, batching — are addressed by making the event **idempotent and self-describing**, not by
60
+ defining a protocol. See [delivery.md](delivery.md).
61
+
62
+ ## 6. Machine-verifiable by default
63
+
64
+ Every rule that **can** be expressed in JSON Schema Draft 2020-12 **is** expressed there, so that
65
+ conformance is testable rather than aspirational. This includes conditional rules such as "a failure
66
+ carries an error" and "acting for a principal identifies that principal".
67
+
68
+ Where a rule cannot be machine-checked — such as "do not log secrets" — the specification says so
69
+ explicitly rather than pretending validation covers it. See [privacy.md](privacy.md).
70
+
71
+ Schema patterns MUST remain portable across regular expression engines: no look-around and no
72
+ back-references, so that the same schema behaves identically in JavaScript, Python, Go, Java and .NET
73
+ validators.
74
+
75
+ ## 7. Strict where it matters, open where it must be
76
+
77
+ Core objects reject unknown properties. This is deliberate: silently accepting an unknown field means
78
+ a producer can believe it is recording something that no consumer will ever read.
79
+
80
+ Vocabularies are treated differently depending on whether the value space is universal:
81
+
82
+ | Kind | Enforcement | Examples |
83
+ | --------------------- | ----------------------------------- | ------------------------------------------------------------------------- |
84
+ | **Closed vocabulary** | `enum` in the schema | `event.outcome`, `event.severity`, `actor.type`, `authorization.decision` |
85
+ | **Open vocabulary** | Form constrained, membership is not | `resource.type`, `resource.classification`, `application.environment` |
86
+
87
+ A vocabulary is closed only when the value set is small, universal, and load-bearing for
88
+ interpretation. A vocabulary is open when organizations legitimately differ — classification schemes
89
+ and environment names differ between companies, and forcing them into a fixed list would produce
90
+ false data rather than comparable data.
91
+
92
+ Both are constrained in **form**: open vocabulary values are lower-case, hyphen-separated tokens, so
93
+ that they remain comparable even when they are not identical.
94
+
95
+ ## 8. Privacy is a first-class constraint
96
+
97
+ Audit data is high-risk data: it concentrates who did what to whom. The model therefore:
98
+
99
+ - Prohibits specific values outright, in normative language.
100
+ - Prefers stable identifiers over personal identifiers.
101
+ - Prefers route templates over resolved URLs.
102
+ - Prefers changed field names over changed field values.
103
+ - Prefers references over embedded payloads.
104
+ - Treats capture as an **allowlist**: a producer records the fields it decided to record, never
105
+ "whatever the request contained".
106
+
107
+ See [privacy.md](privacy.md).
108
+
109
+ ## 9. Regulation-neutral, industry-neutral, jurisdiction-neutral
110
+
111
+ The core model MUST NOT contain a regulation identifier, an article number, a control identifier, a
112
+ country-specific field or an industry-specific field. Not because compliance does not matter, but
113
+ because a model that encodes one framework becomes unusable everywhere that framework does not apply,
114
+ and becomes wrong when the framework is revised.
115
+
116
+ Regulatory interpretation is a **mapping over** audit data, produced and maintained separately from
117
+ the data model. `controlCategories` exists to carry the neutral half of that relationship.
118
+
119
+ ## 10. Stability of meaning
120
+
121
+ An event name, once published, keeps its meaning. A field, once defined, keeps its meaning. If the
122
+ meaning must change, the name changes.
123
+
124
+ Silent redefinition is worse than a breaking change: a breaking change is detected by a validator,
125
+ while a silent redefinition corrupts historical analysis without anyone noticing.
126
+
127
+ ## 11. Specification before implementation
128
+
129
+ The normative model, the canonical schema and the conformance tooling come before production SDKs.
130
+ An SDK written first would freeze accidental implementation details into the standard. See
131
+ [ADR 0001](../decisions/0001-specification-first.md).
132
+
133
+ ## 12. Do not confuse completeness with quality
134
+
135
+ An event that populates every optional object is not a better audit event than one that populates
136
+ five fields correctly. Optional fields exist so that applications with a real need can express it —
137
+ not as a checklist. Producers SHOULD populate what their audit purpose requires and omit the rest.
@@ -0,0 +1,387 @@
1
+ # Event Model
2
+
3
+ **Specification version: 0.1 · Status: Experimental · This document: Normative**
4
+
5
+ ## 1. Structure
6
+
7
+ An audit event is a JSON object with a small required core and a set of optional context objects.
8
+
9
+ ### 1.1 Required fields
10
+
11
+ A conforming event MUST contain exactly these seven fields:
12
+
13
+ | Field | Type | Meaning |
14
+ | ------------- | ------ | ----------------------------------------- |
15
+ | `specVersion` | string | Specification version. MUST be `"0.1"`. |
16
+ | `id` | string | Globally unique identifier of this event. |
17
+ | `time` | string | When the audited operation occurred. |
18
+ | `event` | object | What happened and how it ended. |
19
+ | `actor` | object | Who technically performed the operation. |
20
+ | `resource` | object | What the operation acted upon. |
21
+ | `application` | object | Which application produced the event. |
22
+
23
+ ### 1.2 Optional fields
24
+
25
+ | Field | Type | Defined in |
26
+ | ------------------- | ------- | -------------------------------------------------------- |
27
+ | `observedTime` | string | This document, §4 |
28
+ | `sequence` | integer | This document, §5 |
29
+ | `subject` | object | [actor-model.md](actor-model.md) |
30
+ | `delegation` | object | [approval-and-delegation.md](approval-and-delegation.md) |
31
+ | `relatedResources` | array | [resource-model.md](resource-model.md) |
32
+ | `organization` | object | This document, §9 |
33
+ | `authentication` | object | [authentication.md](authentication.md) |
34
+ | `authorization` | object | [authorization.md](authorization.md) |
35
+ | `approval` | object | [approval-and-delegation.md](approval-and-delegation.md) |
36
+ | `request` | object | This document, §10 |
37
+ | `change` | object | [change-model.md](change-model.md) |
38
+ | `reason` | object | This document, §11 |
39
+ | `evidence` | array | [evidence-model.md](evidence-model.md) |
40
+ | `integrity` | object | [integrity.md](integrity.md) |
41
+ | `privacy` | object | [privacy.md](privacy.md) |
42
+ | `controlCategories` | array | This document, §12 |
43
+ | `tags` | array | This document, §13 |
44
+ | `metadata` | object | [extension-model.md](extension-model.md) |
45
+ | `extensions` | object | [extension-model.md](extension-model.md) |
46
+
47
+ ### 1.3 Strictness
48
+
49
+ The event object and every core object within it MUST reject unknown properties.
50
+
51
+ Domain-specific data MUST NOT be added as a new top-level property. It belongs in `metadata`,
52
+ `extensions`, an object's `attributes`, or a profile.
53
+
54
+ An OPTIONAL object, when present, MUST contain at least one property. An empty object carries no
55
+ information and is rejected, so that "the producer had nothing to say" and "the producer said
56
+ nothing" are not confused.
57
+
58
+ ## 2. Event identity
59
+
60
+ `id` MUST be a globally unique, idempotent identifier for the event.
61
+
62
+ - The specification does NOT mandate an identifier technology.
63
+ - UUIDv4, UUIDv7 and ULID are RECOMMENDED. Any collision-resistant identifier is acceptable.
64
+ - A database-generated sequential integer MUST NOT be required by an implementation of this
65
+ specification, because it is not unique across producers and is not available before the event is
66
+ stored.
67
+ - A producer that retries emission of the same audited operation MUST reuse the same `id`, so that
68
+ consumers can deduplicate. See [delivery.md](delivery.md).
69
+ - `id` SHOULD be opaque. It MUST NOT encode personal data.
70
+
71
+ ## 3. Event time
72
+
73
+ `time` is when the audited operation **occurred**, as observed by the producer.
74
+
75
+ - MUST be an RFC 3339 compatible date-time string.
76
+ - UTC is RECOMMENDED. A producer that records a local offset MUST include the offset.
77
+ - `time` MUST reflect the operation, not the moment the event object was serialized, when those
78
+ differ meaningfully.
79
+
80
+ ## 4. Observed time
81
+
82
+ `observedTime` is when a collector, exporter, gateway or receiving system **observed** the event.
83
+
84
+ - MUST be an RFC 3339 compatible date-time string.
85
+ - MUST NOT be assumed equal to `time`. Queued, batched, retried and backfilled events legitimately
86
+ have an observed time much later than their event time.
87
+ - A producer SHOULD NOT set `observedTime`; it is normally set by the first component that receives
88
+ the event.
89
+ - A consumer that needs to reason about pipeline latency MUST use `observedTime`, and MUST NOT infer
90
+ latency from `time` alone.
91
+
92
+ ## 5. Sequence
93
+
94
+ `sequence` is a producer-assigned, monotonically increasing, non-negative integer used to order
95
+ events that share a timestamp.
96
+
97
+ - Ordering is meaningful only **within** a single producer, partition or integrity chain.
98
+ - A consumer MUST NOT assume that sequence numbers are comparable across producers, or that they are
99
+ contiguous.
100
+
101
+ ## 6. Event descriptor
102
+
103
+ The `event` object describes what happened.
104
+
105
+ ### 6.1 Required
106
+
107
+ | Field | Meaning |
108
+ | ---------- | ---------------------------------- |
109
+ | `name` | Hierarchical event name. See §7. |
110
+ | `category` | Coarse grouping of the event name. |
111
+ | `outcome` | Result of the audited operation. |
112
+
113
+ ### 6.2 Optional
114
+
115
+ | Field | Meaning |
116
+ | ---------- | ---------------------------------------------------------------------------- |
117
+ | `type` | Domain-independent activity classifier, such as `create`, `read`, `approve`. |
118
+ | `severity` | Audit significance of the event. |
119
+ | `summary` | Short human-readable description. |
120
+ | `error` | Sanitized failure descriptor. See §6.5. |
121
+
122
+ ### 6.3 Outcome
123
+
124
+ `outcome` MUST be one of:
125
+
126
+ | Value | Meaning |
127
+ | --------- | ----------------------------------------------------------------------------------------- |
128
+ | `success` | The operation completed as requested. |
129
+ | `failure` | The operation did not complete. |
130
+ | `partial` | The operation completed for some targets and failed for others. |
131
+ | `unknown` | The producer cannot determine the result, for example after a timeout on a remote system. |
132
+
133
+ A denied authorization is a `failure` outcome with an `authorization.decision` of `deny`. It is not a
134
+ separate outcome value.
135
+
136
+ ### 6.4 Severity
137
+
138
+ `severity`, when present, MUST be one of `debug`, `info`, `low`, `medium`, `high`, `critical`.
139
+
140
+ Severity describes the **audit significance** of the operation, not the severity of a software fault.
141
+ A successful privileged configuration change in production is `critical` even though nothing went
142
+ wrong. A failed read of a public resource is `info` even though it failed.
143
+
144
+ The scale is closed in v0.1 because an ordinal scale with producer-defined members cannot be
145
+ compared. Reopening it is an open question for v0.2.
146
+
147
+ ### 6.5 Error
148
+
149
+ When `event.outcome` is `failure`, the event MUST contain `event.error`.
150
+
151
+ `event.error` MUST contain `code`, a stable machine-readable failure code defined by the producer.
152
+ It MAY contain `type`, `message` and `retryable`.
153
+
154
+ When `outcome` is `partial`, the event SHOULD contain `event.error` describing the failing portion.
155
+
156
+ `event.error` MUST NOT contain:
157
+
158
+ - Secrets, tokens, credentials or connection strings.
159
+ - Personal data beyond what the audit purpose requires.
160
+ - Full request or response payloads.
161
+ - Internal stack traces, unless explicitly permitted by the operator's policy.
162
+
163
+ Error text is for humans. A consumer MUST NOT parse `message` to make decisions; that is what `code`
164
+ is for.
165
+
166
+ ### 6.6 Summary
167
+
168
+ `summary` is optional human-readable text. A consumer MUST NOT parse it. It MUST NOT contain values
169
+ prohibited by [privacy.md](privacy.md).
170
+
171
+ ## 7. Event naming
172
+
173
+ ### 7.1 Form
174
+
175
+ Event names are hierarchical, lower-case, dot-separated names of the general form:
176
+
177
+ ```text
178
+ domain.resource.action
179
+ ```
180
+
181
+ At least two segments are REQUIRED. Segments are lower-case and may contain digits and hyphenated
182
+ words, for example `offset-reset`.
183
+
184
+ ```text
185
+ authentication.login
186
+ identity.role.assign
187
+ document.share.create
188
+ incident.case.close
189
+ configuration.setting.update
190
+ deployment.release.approve
191
+ queue.consumer.offset-reset
192
+ ```
193
+
194
+ The core schema MUST NOT enumerate event names. Recommended names are published as
195
+ [semantic conventions](../semantic-conventions/event-naming.md), which producers SHOULD follow.
196
+
197
+ ### 7.2 Rules
198
+
199
+ 1. Event names MUST be stable across releases.
200
+ 2. Event names MUST NOT contain product names.
201
+ 3. Event names MUST NOT contain company names.
202
+ 4. Event names MUST NOT contain jurisdiction names.
203
+ 5. Event names MUST describe the audited operation, not the implementation method. `identity.role.assign`,
204
+ not `identity.role.update-via-graph-api`.
205
+ 6. Success and failure of the same operation SHOULD use the **same** event name with different
206
+ `outcome` values. `authentication.login` with `outcome: failure`, not `authentication.login-failed`.
207
+ 7. The meaning of an event name MUST NOT change silently between versions. If the meaning changes,
208
+ the name changes.
209
+
210
+ ## 8. Application context
211
+
212
+ `application` describes the **producer** of the event.
213
+
214
+ ### 8.1 Required
215
+
216
+ | Field | Meaning |
217
+ | ------------- | --------------------------------------------------- |
218
+ | `name` | Stable name of the producing application. |
219
+ | `environment` | Deployment environment the producer was running in. |
220
+
221
+ ### 8.2 Optional
222
+
223
+ `version`, `instance`, `service`, `component`, `region`, `zone`, `deploymentId`.
224
+
225
+ ### 8.3 Rules
226
+
227
+ 1. `application` MUST describe the application that **produced** the event. It MUST NOT describe a
228
+ collector, forwarder, gateway, storage backend or SIEM that later received it. An audit trail in
229
+ which every event claims to come from the log pipeline is not an audit trail.
230
+ 2. `application.name` SHOULD be stable across releases and SHOULD be lower-case and hyphenated.
231
+ 3. `environment` is an open vocabulary. The RECOMMENDED values are `local`, `development`, `test`,
232
+ `staging`, `production`, `disaster-recovery` and `unknown`. Organizations that use additional
233
+ environment names, such as a user acceptance environment, MAY use their own token rather than
234
+ forcing it into one of the recommended values.
235
+ 4. `region` and `zone` are operator-defined identifiers. They MUST NOT be assumed to follow any
236
+ particular provider's naming.
237
+
238
+ ## 9. Organization context
239
+
240
+ `organization` is OPTIONAL and MAY contain `tenantId`, `organizationId`, `departmentId`,
241
+ `workspaceId` and `businessUnitId`.
242
+
243
+ Not every application is multi-tenant. The core specification MUST NOT require organization context,
244
+ and a consumer MUST NOT treat its absence as an error.
245
+
246
+ Where a tenant applies to a specific principal or resource rather than to the operation as a whole,
247
+ `actor.tenantId` and `resource.tenantId` are the more precise place to record it.
248
+
249
+ ## 10. Request and correlation context
250
+
251
+ `request` is OPTIONAL and describes how the operation was requested.
252
+
253
+ | Field | Notes |
254
+ | --------------------------------- | ----------------------------------------------------------- |
255
+ | `requestId` | The inbound request currently being served. |
256
+ | `correlationId` | The logical operation the event belongs to. See §10.1. |
257
+ | `traceId`, `spanId` | W3C Trace Context compatible. See §10.2. |
258
+ | `ipAddress`, `forwardedFor` | IPv4 or IPv6 literals. Personal data in many jurisdictions. |
259
+ | `userAgent`, `protocol`, `method` | Client and protocol context. |
260
+ | `route` | Route template. See §10.4. |
261
+
262
+ Guidance on choosing between these identifiers is in
263
+ [semantic-conventions/correlation-and-tracing.md](../semantic-conventions/correlation-and-tracing.md),
264
+ which is informative.
265
+
266
+ ### 10.1 Correlation identifiers
267
+
268
+ `requestId` identifies the inbound request currently being served. It is scoped to one service
269
+ handling one call, and SHOULD NOT be propagated into asynchronous messages: a message consumer is not
270
+ serving the request that produced the message.
271
+
272
+ `correlationId` identifies the logical operation, workflow, job, conversation or business process the
273
+ event belongs to. It MAY span services, messages, trace boundaries and time, and it is the identifier
274
+ that remains stable when a `traceId` does not.
275
+
276
+ ### 10.2 Trace identifiers
277
+
278
+ `traceId` MUST be 32 lower-case hexadecimal characters and `spanId` MUST be 16 lower-case
279
+ hexadecimal characters, matching W3C Trace Context. The all-zero value is invalid for both.
280
+
281
+ This makes audit events correlatable with distributed traces without requiring any particular
282
+ telemetry stack. See [mappings/opentelemetry.md](../mappings/opentelemetry.md), which is informative.
283
+
284
+ Producers SHOULD obtain `traceId` and `spanId` from the active trace context rather than generating
285
+ identifiers specifically for the audit event. An identifier minted for the audit record is
286
+ well-formed and correlates with nothing.
287
+
288
+ `spanId` SHOULD be recorded only together with `traceId`. A span identifier alone cannot be resolved,
289
+ because there is nothing to resolve it against.
290
+
291
+ Raw `traceparent` and `tracestate` values SHOULD NOT be stored. Producers SHOULD extract the trace and
292
+ span identifiers and discard the remainder: the version and flag fields describe the tracing system's
293
+ own decisions, and `tracestate` is vendor-specific and may carry tenant or account information.
294
+
295
+ ### 10.3 Trust and independence
296
+
297
+ Correlation identifiers — `requestId`, `correlationId`, `traceId` and `spanId` — are **observational
298
+ metadata**. They MUST NOT be used as proof of identity, authorization, authenticity, integrity or
299
+ tenant isolation. Each can be supplied by a caller, guessed, replayed or copied between tenants.
300
+ `authentication`, `authorization` and `integrity` are the fields that carry those guarantees.
301
+
302
+ A shared `traceId` indicates that two events belong to the same execution. It does NOT establish
303
+ which event caused another, nor the order in which they occurred. Ordering within a producer is
304
+ established by `sequence`; see [delivery.md](delivery.md).
305
+
306
+ Audit event generation MUST NOT depend on trace sampling. An audit event MUST be produced whether or
307
+ not a trace is sampled, recorded or retained, and a `traceId` that resolves to no stored trace is a
308
+ normal outcome rather than an error.
309
+
310
+ Personal data, credentials, account numbers and sensitive business values SHOULD NOT be used as
311
+ correlation identifiers. A non-reversible surrogate SHOULD be used instead; see
312
+ [privacy.md](privacy.md).
313
+
314
+ ### 10.4 Route templates
315
+
316
+ `route` SHOULD be the **route template**, not the resolved URL:
317
+
318
+ ```text
319
+ /users/{userId}/roles ← RECOMMENDED
320
+ /users/472918/roles ← NOT RECOMMENDED
321
+ ```
322
+
323
+ The resolved identifier belongs in `resource.id`, where it is structured and can be redacted
324
+ independently.
325
+
326
+ Query strings and fragments are rejected by the schema. Producers MUST NOT capture query strings
327
+ automatically: they routinely carry search terms, filters, tokens and personal identifiers that no
328
+ one decided to audit.
329
+
330
+ ## 11. Reason
331
+
332
+ `reason` is OPTIONAL and records **why** the operation was performed: a business justification,
333
+ support request, change ticket, incident response or emergency access explanation.
334
+
335
+ | Field | Meaning |
336
+ | ----------- | ------------------------------------------------------ |
337
+ | `code` | Machine-readable justification code. |
338
+ | `text` | Human-readable justification. |
339
+ | `reference` | Identifier of the record that justifies the operation. |
340
+
341
+ `reason` MUST NOT be used for technical error information. A justification explains intent; an error
342
+ explains failure. An event may legitimately carry both.
343
+
344
+ ## 12. Control categories
345
+
346
+ `controlCategories` is an OPTIONAL array of regulation-neutral labels describing the kind of control
347
+ this event provides evidence for:
348
+
349
+ ```text
350
+ authentication-logging
351
+ privileged-access
352
+ data-access-logging
353
+ external-data-sharing
354
+ change-approval
355
+ separation-of-duties
356
+ configuration-integrity
357
+ incident-traceability
358
+ ```
359
+
360
+ Control categories MUST NOT contain regulation names, article numbers, control framework identifiers
361
+ or jurisdiction names. Mapping a control category to a specific framework is the job of a separate,
362
+ optional mapping artifact maintained outside the core specification.
363
+
364
+ ## 13. Tags
365
+
366
+ `tags` is an OPTIONAL array of producer-defined labels for filtering and routing. Tags carry no
367
+ normative meaning, and a consumer MUST NOT derive audit semantics from them.
368
+
369
+ ## 14. Complete minimal event
370
+
371
+ ```json
372
+ {
373
+ "specVersion": "0.1",
374
+ "id": "018f1b5c-6d2a-7c3e-9a1b-4f5e6d7c8b9a",
375
+ "time": "2026-03-14T09:24:31.412Z",
376
+ "event": {
377
+ "name": "data.record.update",
378
+ "category": "data-modification",
379
+ "outcome": "success"
380
+ },
381
+ "actor": { "type": "user", "id": "user-123" },
382
+ "resource": { "type": "record", "id": "resource-123" },
383
+ "application": { "name": "application-service", "environment": "production" }
384
+ }
385
+ ```
386
+
387
+ This is a complete, conforming audit event. Nothing else is required.