@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,172 @@
1
+ # OpenAuditModel Core Specification — Overview
2
+
3
+ **Specification version: 0.1 · Status: Experimental · This document: Normative**
4
+
5
+ > OpenAuditModel defines a common, verifiable and backend-independent audit event model for business
6
+ > applications.
7
+
8
+ ## 1. Purpose
9
+
10
+ Business applications record auditable operations. Almost every application invents its own shape for
11
+ those records, so audit data cannot be validated, correlated, reviewed or exported without bespoke
12
+ work in every system. OpenAuditModel defines one shape for that data.
13
+
14
+ The specification describes **what an audit event is**, not where it is stored, how it is
15
+ transported, or which regulation it satisfies.
16
+
17
+ ## 2. Scope
18
+
19
+ This specification defines:
20
+
21
+ 1. The structure of an audit event.
22
+ 2. The meaning of each field in that structure.
23
+ 3. The rules a conforming event MUST satisfy.
24
+ 4. The rules a conforming producer and consumer MUST satisfy.
25
+ 5. The extension mechanism by which vendors and domains add their own data.
26
+
27
+ This specification does not define:
28
+
29
+ - A storage format, database, index or retention system.
30
+ - A transport protocol, wire encoding or delivery guarantee.
31
+ - A query language or reporting model.
32
+ - An authorization or policy evaluation engine.
33
+ - A mapping to any regulation, standard or control framework.
34
+
35
+ See [design-principles.md](design-principles.md) for why these exclusions exist, and the repository
36
+ [README](../README.md) for the full list of non-goals.
37
+
38
+ ## 3. Conformance
39
+
40
+ ### 3.1 Conforming event
41
+
42
+ A JSON document is a **conforming OpenAuditModel v0.1 event** if and only if it validates against the
43
+ [OpenAuditModel Audit Event Schema](../schemas/v0.1/audit-event.schema.json), identified by:
44
+
45
+ ```text
46
+ https://openauditmodel.org/schemas/audit-event/0.1/schema.json
47
+ ```
48
+
49
+ Schema validation is necessary but **not sufficient** for a good audit event. Rules that a schema
50
+ cannot express — a `subject` used as a target resource, a secret placed in `metadata`, an event name
51
+ that changed meaning between releases — are stated normatively in this specification and MUST be
52
+ satisfied by conforming producers even though a validator cannot detect their violation.
53
+
54
+ ### 3.2 Conforming producer
55
+
56
+ A conforming producer:
57
+
58
+ - MUST emit events that validate against the canonical schema.
59
+ - MUST set `specVersion` to the version of the specification the event conforms to.
60
+ - MUST NOT record the values listed as prohibited in [privacy.md](privacy.md).
61
+ - MUST keep the meaning of an event name stable across releases, as required by
62
+ [event-model.md](event-model.md).
63
+ - SHOULD populate only the optional fields its audit purpose requires.
64
+
65
+ ### 3.3 Conforming consumer
66
+
67
+ A conforming consumer:
68
+
69
+ - MUST accept any event that validates against the canonical schema, including events that use only
70
+ the required fields.
71
+ - MUST NOT reject an event because it carries `metadata` or `extensions` the consumer does not
72
+ recognise.
73
+ - MUST treat `event.summary` as human-readable text and MUST NOT parse it for machine decisions.
74
+ - SHOULD deduplicate events by `id`, as described in [delivery.md](delivery.md).
75
+
76
+ ### 3.4 Conformance is not compliance
77
+
78
+ Conformance to this specification is a statement about the **shape and semantics of data**. It is not
79
+ a statement about regulatory, legal or contractual compliance, and it MUST NOT be presented as one.
80
+
81
+ ## 4. Document status labels
82
+
83
+ Every document in this repository is labelled with one of:
84
+
85
+ | Label | Meaning |
86
+ | ---------------- | ----------------------------------------------------------------------------------------------------------- |
87
+ | **Normative** | Defines requirements. Conforming implementations MUST satisfy them. |
88
+ | **Informative** | Explains, illustrates or maps. Carries no requirements, even where it uses examples that look prescriptive. |
89
+ | **Experimental** | Expected to change, possibly incompatibly, before version 1.0. All of version 0.1 is experimental. |
90
+
91
+ Where a document is normative, only the capitalized keywords defined in
92
+ [terminology.md](terminology.md) express requirements.
93
+
94
+ Everything under [examples/](../examples/), [mappings/](../mappings/) and [profiles/](../profiles/)
95
+ is informative in v0.1. [semantic-conventions/](../semantic-conventions/) is normative only where it
96
+ says so explicitly; its recommended vocabularies are otherwise SHOULD-level guidance.
97
+
98
+ ## 5. Specification documents
99
+
100
+ | Document | Covers |
101
+ | -------------------------------------------------------- | --------------------------------------------------------------- |
102
+ | [terminology.md](terminology.md) | Normative keywords and the vocabulary used throughout |
103
+ | [design-principles.md](design-principles.md) | The constraints that shape every decision in the model |
104
+ | [event-model.md](event-model.md) | Top-level structure, identity, time, event descriptor, outcomes |
105
+ | [actor-model.md](actor-model.md) | Who acted, and on whose behalf |
106
+ | [resource-model.md](resource-model.md) | What was acted upon |
107
+ | [authentication.md](authentication.md) | How the actor was authenticated |
108
+ | [authorization.md](authorization.md) | Which decision permitted or denied the operation |
109
+ | [approval-and-delegation.md](approval-and-delegation.md) | Human approval and transferred authority |
110
+ | [change-model.md](change-model.md) | What changed, without leaking the data that changed |
111
+ | [evidence-model.md](evidence-model.md) | Referencing supporting material |
112
+ | [privacy.md](privacy.md) | What MUST NOT be recorded, and how personal data is described |
113
+ | [integrity.md](integrity.md) | Tamper-evidence, and what it does and does not guarantee |
114
+ | [delivery.md](delivery.md) | Producing, transporting and receiving events |
115
+ | [extension-model.md](extension-model.md) | `metadata`, `extensions` and profile boundaries |
116
+
117
+ ## 6. Versioning and compatibility
118
+
119
+ ### 6.1 Version 0.1
120
+
121
+ `specVersion` is a constant in v0.1:
122
+
123
+ ```json
124
+ { "specVersion": "0.1" }
125
+ ```
126
+
127
+ The canonical schema enforces this with `const`. An event that declares any other value is not a
128
+ conforming v0.1 event.
129
+
130
+ Fixing the value keeps the experimental phase unambiguous: there is exactly one version of the model
131
+ in existence, and no producer can claim conformance to a version that has not been published.
132
+
133
+ ### 6.2 Future versions
134
+
135
+ The compatibility strategy **is expected to change** after v0.1. Later versions may:
136
+
137
+ - Replace the `const` constraint with a range or a set of accepted versions.
138
+ - Define which changes are compatible and which require a version increment.
139
+ - Define how a consumer should behave when it receives a newer minor version.
140
+
141
+ None of that is decided in v0.1, and implementations MUST NOT assume any particular future strategy.
142
+ The decision will be recorded as an architecture decision record in [decisions/](../decisions/).
143
+
144
+ ### 6.3 What is already committed to
145
+
146
+ Even in the experimental phase, two rules hold:
147
+
148
+ 1. **Event names do not silently change meaning.** If the meaning of an event name changes, the name
149
+ changes. See [event-model.md](event-model.md).
150
+ 2. **Extensions never weaken the core.** An extension MUST NOT remove a required field, relax a
151
+ constraint, or redefine the meaning of a core field. See
152
+ [extension-model.md](extension-model.md).
153
+
154
+ ## 7. Relationship to other standards
155
+
156
+ OpenAuditModel is an **event model**, not a transport, a telemetry pipeline or a security taxonomy.
157
+ It is designed to be carried by, and mapped to, the standards that already exist:
158
+
159
+ - **CloudEvents** MAY carry an OpenAuditModel event as its `data` payload.
160
+ - **OpenTelemetry** MAY transport, collect and correlate audit events, and `request.traceId` /
161
+ `request.spanId` are defined to be compatible with W3C Trace Context.
162
+ - **ECS** and **OCSF** MAY be produced from OpenAuditModel events by export mappings.
163
+ - **CADF** is a conceptual reference for audit semantics.
164
+ - **OSCAL** may later be used for control and assessment mappings.
165
+
166
+ None of these are required. An OpenAuditModel event is valid on its own, with no envelope and no
167
+ pipeline. See [mappings/](../mappings/), which is informative.
168
+
169
+ ## 8. Stability warning
170
+
171
+ Version 0.1 is **experimental and not production-ready**. Field names, constraints, vocabularies and
172
+ the compatibility strategy may all change. It carries **no compliance guarantee** of any kind.
@@ -0,0 +1,386 @@
1
+ # Privacy
2
+
3
+ **Specification version: 0.1 · Status: Experimental · This document: Normative**
4
+
5
+ Audit data concentrates the most sensitive relationship in a system: who did what to whom, and when.
6
+ It is frequently retained longer than production data, replicated to more systems, and read by more
7
+ people. This document defines what MUST NOT be recorded, and how the personal-data character of an
8
+ event is described.
9
+
10
+ None of this constitutes legal advice or a compliance guarantee. See §9.
11
+
12
+ ## 1. Values that MUST NEVER be recorded
13
+
14
+ The following MUST NOT appear in any field of an OpenAuditModel event — not in `metadata`, not in
15
+ `extensions`, not in `attributes`, not in `before` or `after`, not in an error message, not in a
16
+ summary, and not inside a reference:
17
+
18
+ 1. Passwords, in any form, including password hashes and password history.
19
+ 2. Access tokens.
20
+ 3. Refresh tokens.
21
+ 4. API keys.
22
+ 5. Connection strings.
23
+ 6. Private keys and other secret key material.
24
+ 7. Authorization headers.
25
+ 8. Session cookies and any other value that grants a session by possession.
26
+
27
+ This list is absolute. There is no audit purpose that requires the value of a credential; the audit
28
+ purpose is served by recording the **fact** of its creation, use, rotation or revocation.
29
+
30
+ Where a system's session identifier is itself a bearer credential, producers MUST record a derived,
31
+ non-reversible correlation value or omit the field. See
32
+ [authentication.md](authentication.md).
33
+
34
+ ## 2. Data that MUST NOT be captured automatically
35
+
36
+ The following MUST NOT be captured automatically — that is, without an explicit, per-field decision
37
+ by the producer:
38
+
39
+ 1. Full request bodies.
40
+ 2. Full response bodies.
41
+ 3. Message broker payloads.
42
+ 4. Database query parameters.
43
+ 5. Query strings. The canonical schema enforces this for `request.route`.
44
+ 6. Complete database records in `change.before` or `change.after`.
45
+ 7. Raw forwarding and client headers copied verbatim.
46
+
47
+ A producer MAY record a **selected, named subset** of any of these where the audit purpose requires
48
+ it and the values have been reviewed. The prohibition is on capturing them wholesale because they
49
+ happened to be available.
50
+
51
+ ## 3. The allowlist model
52
+
53
+ Audit event fields MUST follow an **allowlist** model.
54
+
55
+ A producer decides, per field, what it records. It MUST NOT populate audit fields by serializing
56
+ whatever object was at hand and removing known-bad keys afterwards. Denylists fail silently: the
57
+ first time a new field appears in an upstream model, it is captured, and nobody finds out until it is
58
+ in seven years of retained records.
59
+
60
+ Practically:
61
+
62
+ - Map application data to audit fields explicitly, field by field.
63
+ - Prefer `changedFields` over `before`/`after` when the field names alone answer the question.
64
+ - Prefer identifiers over values, and stable identifiers over personal identifiers.
65
+ - Prefer references over content.
66
+ - Prefer route templates over resolved paths.
67
+ - Treat every new audit field as a change that needs review, in the same way a new database column
68
+ containing personal data would.
69
+
70
+ ## 4. Data minimization
71
+
72
+ Audit data MUST be minimized to what the audit purpose requires.
73
+
74
+ - A field that no reviewer, control or investigation would use SHOULD NOT be recorded.
75
+ - An optional object SHOULD be omitted when the producer has no specific need for it. Completeness is
76
+ not a goal; see [design-principles.md](design-principles.md).
77
+ - `actor.displayName`, `resource.name` and `request.ipAddress` are the fields most often recorded out
78
+ of habit. Each is personal data in common circumstances, and each SHOULD be justified rather than
79
+ defaulted.
80
+ - Minimization applies to retention as well as capture. The model provides `privacy.retentionClass`
81
+ so that events can be governed differently; enforcing it is the operator's responsibility.
82
+
83
+ ## 5. The privacy object
84
+
85
+ `privacy` is OPTIONAL and describes how this event relates to personal data.
86
+
87
+ | Field | Meaning |
88
+ | ---------------------- | ------------------------------------------------------------- |
89
+ | `containsPersonalData` | Whether the event as serialized contains personal data. |
90
+ | `dataCategories` | Categories of personal data present. Open vocabulary. |
91
+ | `processing` | How personal data was handled when the event was produced. |
92
+ | `minimized` | Whether the producer applied data minimization to this event. |
93
+ | `retentionClass` | Producer-defined retention class governing this event. |
94
+ | `purpose` | Purpose for which the event is recorded. |
95
+
96
+ ### 5.1 Data categories
97
+
98
+ RECOMMENDED values:
99
+
100
+ ```text
101
+ identifier contact network financial health
102
+ biometric location employment behavioral special-category
103
+ other
104
+ ```
105
+
106
+ `special-category` marks data that the operator's own policy treats as requiring heightened
107
+ protection. The specification deliberately does not define which categories are special, because that
108
+ determination is jurisdictional.
109
+
110
+ Producers SHOULD populate `dataCategories` whenever `containsPersonalData` is `true`. The schema does
111
+ not enforce this, because a producer may know that personal data is present before it has classified
112
+ it.
113
+
114
+ ### 5.2 Processing
115
+
116
+ `processing` MUST be one of:
117
+
118
+ | Value | Meaning |
119
+ | ----------- | -------------------------------------------------------------- |
120
+ | `include` | Personal data is present in the event as recorded. |
121
+ | `mask` | Personal data was partially obscured before recording. |
122
+ | `hash` | Personal data was replaced with a digest. |
123
+ | `drop` | Personal data was removed entirely. |
124
+ | `encrypt` | Personal data was encrypted before recording. |
125
+ | `reference` | Personal data was replaced with a reference to another system. |
126
+
127
+ A single value describes the treatment applied to the event as a whole. Per-field processing
128
+ descriptions are an open question for v0.2.
129
+
130
+ Note that `hash` is not anonymization. Hashing a low-entropy identifier such as an email address or a
131
+ national identification number is reversible by enumeration and MUST NOT be presented as removing the
132
+ personal-data character of the field.
133
+
134
+ ### 5.3 Regulation neutrality
135
+
136
+ The privacy object MUST NOT be extended with regulation-specific fields: no lawful basis
137
+ enumerations, no article references, no jurisdiction-specific consent flags, no framework identifiers.
138
+
139
+ Those are interpretations of audit data, produced by mapping artifacts maintained outside this
140
+ specification. Encoding one framework's vocabulary into the core model would make the model wrong
141
+ everywhere else, and stale as soon as the framework is revised.
142
+
143
+ ## 6. Validation cannot detect secrets
144
+
145
+ Schema validation alone **cannot** detect a leaked secret.
146
+
147
+ A password placed in `metadata.oldValue` is a valid string in a valid free-form object. The event will
148
+ pass every conformance test in this repository. This is a limitation of machine validation, not a gap
149
+ that a future schema version will close.
150
+
151
+ Implementations SHOULD therefore:
152
+
153
+ - Run secret scanning over audit events before they leave the producer, and again in the pipeline.
154
+ - Review audit instrumentation in code review with the same seriousness as data model changes.
155
+ - Fail closed: when a producer cannot determine whether a value is safe, it SHOULD omit the value.
156
+ - Treat the audit store as a system holding personal data, with corresponding access control,
157
+ retention and disclosure controls.
158
+
159
+ `auditmodel lint-privacy` makes **part** of this checkable. The rest of this section describes what
160
+ that part is, and — more importantly — what it is not.
161
+
162
+ ### 6.1 Four kinds of rule
163
+
164
+ The requirements in this document fall into four groups. Conflating them is how a linter comes to be
165
+ trusted for things it cannot do.
166
+
167
+ | Kind | Enforced by | Examples |
168
+ | --------------------------- | ---------------------------- | --------------------------------------------------------- |
169
+ | **Normative requirement** | This specification. Binding. | §1 "passwords MUST NEVER be recorded" |
170
+ | **Deterministic lint rule** | Exact matching. No guessing. | A property named `password`; a PEM private key marker |
171
+ | **Heuristic lint rule** | Measurement. Guesses. | High character entropy; an oversized object |
172
+ | **Not automatable** | Review. Nothing else. | Whether a value is personal data; whether §3 was followed |
173
+
174
+ A deterministic rule can still be wrong about **meaning**: a property named `password` might hold a
175
+ policy description. It is deterministic because the same input always produces the same finding, not
176
+ because the finding is always correct.
177
+
178
+ ### 6.2 What the linter checks
179
+
180
+ `auditmodel lint-privacy` is deterministic local static analysis. It reads events, reports
181
+ suspicions, and does nothing else. It MUST NOT send event content anywhere, resolve or fetch any
182
+ reference, open any file an event names, modify or redact an event, or consult any remote service or
183
+ model.
184
+
185
+ Deterministic rules:
186
+
187
+ | Rule | Detects |
188
+ | -------------------------------- | ------------------------------------------------------------------------------------- |
189
+ | `OAM-PRIV-001` | A populated property whose name is a credential name after normalization |
190
+ | `OAM-PRIV-002` | A value shaped as `Bearer`, `Basic`, `Digest`, `ApiKey` or `Token` plus a credential |
191
+ | `OAM-PRIV-003` | A PEM marker introducing private key material |
192
+ | `OAM-PRIV-010` | A structurally valid JSON Web Token |
193
+ | `OAM-PRIV-011` | A published access key identifier shape |
194
+ | `OAM-PRIV-012` to `OAM-PRIV-016` | Published credential prefixes for source forge, messaging, payment and cloud API keys |
195
+ | `OAM-PRIV-030` | A URL with embedded user information |
196
+ | `OAM-PRIV-031` | An evidence reference carrying a query string or fragment |
197
+ | `OAM-PRIV-040` | A connection string carrying a password |
198
+ | `OAM-PRIV-041` | A connection string without a credential, which still discloses infrastructure |
199
+ | `OAM-PRIV-061` | A populated property whose name denotes a raw request, response or message body |
200
+
201
+ Heuristic rules:
202
+
203
+ | Rule | Measures |
204
+ | -------------- | --------------------------------------- |
205
+ | `OAM-PRIV-050` | Character entropy, as a token candidate |
206
+ | `OAM-PRIV-060` | Value size, as a minimization signal |
207
+
208
+ Recognising a published credential prefix is a property of the **tooling**, not of the model. The
209
+ specification, the canonical schema and the semantic conventions name no vendor, and no lint rule
210
+ introduces a field, vocabulary or concept into the model.
211
+
212
+ ### 6.3 What the linter does not check
213
+
214
+ It does not, and largely cannot, determine:
215
+
216
+ - Whether a value **is** personal data. `privacy.dataCategories` is a producer declaration; nothing
217
+ verifies it.
218
+ - Whether `privacy.minimized` is truthful.
219
+ - Whether the audit purpose required a field to be recorded at all.
220
+ - Whether a hash of a low-entropy identifier is reversible by enumeration.
221
+ - Whether `actor.displayName`, `resource.name` or `request.ipAddress` were justified.
222
+ - Whether §3's allowlist model was followed. That is a property of the producer's **code**; an event
223
+ built by copying a request object and one built field by field can be byte-identical.
224
+ - Whether the audit store has access control or retention (§7).
225
+ - Anything about regulatory classification (§9).
226
+ - Whether a detected credential is real, current, revoked or usable. No rule validates a signature,
227
+ decodes a token for its claims, or contacts an issuer.
228
+
229
+ ### 6.4 A finding is a suspicion; a clean result is not a clearance
230
+
231
+ A finding means a value **matched a rule**. It does not establish a data breach, a regulatory
232
+ violation, a confirmed credential or confirmed personal data. Tooling and documentation MUST NOT
233
+ present findings in those terms.
234
+
235
+ **A clean result does not mean an event is safe or compliant.** A password that happens to be a
236
+ dictionary word, stored under a field named `note`, matches nothing here. Neither does a national
237
+ identification number, a home address or a medical detail: the linter looks for values shaped like
238
+ secrets, and most personal data is not shaped like anything.
239
+
240
+ ### 6.5 Findings never contain the offending value
241
+
242
+ No finding — in any output format — contains the value that produced it, any part of it, a preview, a
243
+ prefix, a suffix, or a decoded claim. A finding carries a rule identifier, a severity, a confidence,
244
+ a JSON Pointer, a message and a recommendation.
245
+
246
+ The reason is direct: linter output goes into CI logs, pull request comments and issue trackers,
247
+ which are usually less protected than the audit store. A tool that echoed what it found would move
248
+ secrets from a controlled system into an uncontrolled one, and would do it precisely when a secret
249
+ was present.
250
+
251
+ ### 6.6 Inspected locations
252
+
253
+ Values are inspected under:
254
+
255
+ ```text
256
+ /metadata /change/before
257
+ /extensions /change/after
258
+ /actor/attributes /event/error/message
259
+ /subject/attributes /event/summary
260
+ /resource/attributes /reason/text
261
+ /relatedResources/*/attributes /reason/reference
262
+ /evidence/*/reference /request/route
263
+ /authorization/reason /delegation/reason
264
+ ```
265
+
266
+ Property **names** are inspected recursively within `metadata`, `extensions`, every `attributes`
267
+ object, `change.before` and `change.after`. Extension keys are also tested on their final
268
+ dot-separated segment, because a reverse-domain key names its field there.
269
+
270
+ Everything else is excluded, including `integrity` digests and signatures, `request.traceId` and
271
+ `request.spanId`, and the event `id`. Those fields hold high-entropy values by design; scanning them
272
+ would produce a finding on every well-formed event.
273
+
274
+ ### 6.7 Known-safe exclusions from the entropy heuristic
275
+
276
+ The entropy rule — and **only** the entropy rule — ignores values recognised as: UUIDs, ULIDs, W3C
277
+ Trace Context trace and span identifiers, lower-case hexadecimal digests of SHA-256, SHA-384 and
278
+ SHA-512 length, RFC 3339 timestamps, purely numeric identifiers, lower-case separated identifiers and
279
+ reference paths, anything containing `://`, and redaction placeholders.
280
+
281
+ A value under a property named `password` is reported whatever it looks like. A value matching a
282
+ published credential format is reported even if it also looks like an identifier.
283
+
284
+ ### 6.8 Fixed thresholds
285
+
286
+ Version 0.1 hard-codes these. They are not configurable; see
287
+ [ADR 0007](../decisions/0007-deterministic-privacy-linting.md).
288
+
289
+ | Threshold | Value |
290
+ | ------------------------------- | ------------------------------------ |
291
+ | Minimum length for entropy | 24 characters |
292
+ | Maximum length for entropy | 4096 characters |
293
+ | Entropy threshold | 4.0 bits per character |
294
+ | Minimum character classes | 3 of 4 (lower, upper, digit, symbol) |
295
+ | Oversized: serialized size | 4096 bytes |
296
+ | Oversized: property count | 50 |
297
+ | Oversized: nesting depth | 6 |
298
+ | Oversized: array length | 100 |
299
+ | Oversized: single string length | 2048 characters |
300
+ | Maximum traversal depth | 64 |
301
+
302
+ ### 6.9 False positives and false negatives
303
+
304
+ Both are expected, and the design prefers false negatives in the heuristic rules and false positives
305
+ in nothing.
306
+
307
+ **False positives** are most likely from `OAM-PRIV-050` on legitimate opaque identifiers, from
308
+ `OAM-PRIV-060` on genuinely detailed metadata, and from `OAM-PRIV-001` where a credential-named field
309
+ holds something else. `OAM-PRIV-050` reports at low confidence for exactly this reason.
310
+
311
+ **False negatives** are certain. A secret in an unpublished format, under a harmless name, below the
312
+ entropy threshold, or in all lower case with a separator, is invisible. So is any personal data that
313
+ is not shaped like a secret. A recognised redaction placeholder under a credential name is
314
+ deliberately not reported, because a tool that flags `"password": "[REDACTED]"` teaches people to
315
+ ignore it.
316
+
317
+ `OAM-PRIV-001` reports a credential-named property when it holds a **scalar**. A **container** under
318
+ such a name is treated as a descriptor and is not itself reported; its members are inspected
319
+ individually. `credential: { "type": "api-key" }` describes a credential without carrying one, and is
320
+ the shape the identity-and-access-management profile requires for credential rotation events —
321
+ flagging it would fire on every conforming rotation event, which is how a linter earns the reputation
322
+ that gets it switched off. The accepted cost is a secret stored under a harmless member name inside
323
+ such a container.
324
+
325
+ ### 6.10 Schema validation is not secret scanning
326
+
327
+ These are different questions and neither substitutes for the other.
328
+
329
+ Schema validation asks whether an event is **well formed**. It passes an event containing a password
330
+ in `metadata`, because a password is a valid string. Privacy linting asks whether an event **looks
331
+ like it contains something it should not**. It passes an event that is structurally broken, which is
332
+ why the linter validates first and refuses to deep-lint an invalid event: traversing an arbitrary
333
+ structure yields findings whose paths mean nothing.
334
+
335
+ ### 6.11 Exit codes
336
+
337
+ ```text
338
+ 0 no findings
339
+ 1 one or more privacy findings, or a schema-invalid event
340
+ 2 usage error, or a file could not be read or parsed
341
+ ```
342
+
343
+ A schema-invalid event is reported and **not** deep linted, and exits non-zero: a clean privacy
344
+ result for an event that was never linted would be misleading.
345
+
346
+ ### 6.12 Using it
347
+
348
+ ```bash
349
+ auditmodel lint-privacy examples/privacy/clean/minimal-clean-event.json
350
+ auditmodel lint-privacy examples/privacy/findings/access-token-field.json
351
+ auditmodel lint-privacy examples/privacy --format json
352
+ ```
353
+
354
+ Producers SHOULD run it in CI over fixture events and over samples of real output, and SHOULD treat
355
+ it as one control among several. It is not a substitute for reviewing audit instrumentation, and
356
+ running it does not make an event safe.
357
+
358
+ ## 7. Access to audit data
359
+
360
+ Audit data MUST be access-controlled. It describes individuals' behaviour, and in many systems it is
361
+ readable by more people than the data it describes.
362
+
363
+ The specification defines no access control model. It notes only that an audit trail readable by
364
+ everyone in an organization is a privacy exposure that no amount of field-level minimization
365
+ compensates for.
366
+
367
+ ## 8. Example
368
+
369
+ ```json
370
+ {
371
+ "privacy": {
372
+ "containsPersonalData": true,
373
+ "dataCategories": ["identifier", "contact", "behavioral"],
374
+ "processing": "reference",
375
+ "minimized": true,
376
+ "retentionClass": "standard",
377
+ "purpose": "operational-audit"
378
+ }
379
+ }
380
+ ```
381
+
382
+ ## 9. No legal or compliance guarantee
383
+
384
+ This document describes engineering practice for reducing the risk that audit data creates. It is not
385
+ legal advice, it does not establish a lawful basis for processing, and conformance to it does not
386
+ constitute compliance with any law, regulation, standard or contract.
@@ -0,0 +1,116 @@
1
+ # Resource Model
2
+
3
+ **Specification version: 0.1 · Status: Experimental · This document: Normative**
4
+
5
+ ## 1. Purpose
6
+
7
+ `resource` answers "what was acted upon". It is REQUIRED, because an audit event that records an
8
+ action without a target cannot be reviewed, correlated or scoped to a data subject.
9
+
10
+ ## 2. Structure
11
+
12
+ ### 2.1 Required
13
+
14
+ | Field | Meaning |
15
+ | ------ | -------------------------------------------------------------- |
16
+ | `type` | Kind of resource. Open vocabulary. |
17
+ | `id` | Stable identifier of the resource within the producing system. |
18
+
19
+ ### 2.2 Optional
20
+
21
+ | Field | Meaning |
22
+ | ---------------- | ------------------------------------------------------------------ |
23
+ | `name` | Human-readable resource name. |
24
+ | `parentId` | Containing resource: folder, workspace, project, cluster, account. |
25
+ | `classification` | Data classification of the resource. Open vocabulary. |
26
+ | `ownerId` | Owning principal or team. |
27
+ | `tenantId` | Tenant the resource belongs to. |
28
+ | `attributes` | Producer-defined additional attributes. |
29
+
30
+ ## 3. Resource types are open-ended
31
+
32
+ `resource.type` is an **open vocabulary**. The core schema MUST NOT enumerate resource types, and a
33
+ consumer MUST NOT reject a resource type it does not recognise.
34
+
35
+ Types observed across the domains this model targets include:
36
+
37
+ ```text
38
+ user role document incident
39
+ configuration deployment database-record api-key
40
+ consumer-group topic queue workflow
41
+ tenant report session share-link
42
+ policy secret cluster service
43
+ ```
44
+
45
+ This list is illustrative, not exhaustive and not normative. A hard-coded list of resource types is
46
+ the fastest way to make a general model unusable in a domain nobody thought of.
47
+
48
+ Resource types MUST be lower-case, hyphen-separated tokens, so that independently produced events
49
+ remain comparable in form even when the vocabularies differ.
50
+
51
+ ## 4. Identifiers and names
52
+
53
+ - `id` MUST be stable for the lifetime of the resource. A path or display name that changes when the
54
+ resource is moved or renamed is not an identifier.
55
+ - `id` MUST be recorded even when the operation failed, when the producer knows what was attempted.
56
+ - `name` is OPTIONAL, and MAY itself be sensitive. Document titles, incident summaries and file names
57
+ routinely contain personal data, customer names and unreleased business information. Producers
58
+ SHOULD consider whether recording `name` is necessary for the audit purpose. See
59
+ [privacy.md](privacy.md).
60
+ - `resource.attributes` MUST NOT contain the **contents** of the resource. An audit event records
61
+ that a document was downloaded; it does not carry the document.
62
+
63
+ ## 5. Classification
64
+
65
+ `classification` describes the sensitivity of the resource. It is an **open vocabulary**, because
66
+ classification schemes are defined by organizations and differ legitimately in the number of levels
67
+ and their names.
68
+
69
+ RECOMMENDED values:
70
+
71
+ ```text
72
+ public internal confidential restricted secret unknown
73
+ ```
74
+
75
+ Organizations that use a different scheme MAY use their own tokens. Where a mapping to the
76
+ recommended values is possible, producers SHOULD publish it so that cross-system reporting remains
77
+ meaningful.
78
+
79
+ `classification` describes the **resource**, not the event. The sensitivity of the audit event itself
80
+ is described by [privacy.md](privacy.md).
81
+
82
+ ## 6. Related resources
83
+
84
+ `relatedResources` is an OPTIONAL array of additional resources affected by, or required to
85
+ interpret, the same operation. Each entry has the same shape as `resource`.
86
+
87
+ Rules:
88
+
89
+ 1. `resource` MUST hold the **primary** target. `relatedResources` MUST NOT be used as an alternative
90
+ to choosing one.
91
+ 2. `relatedResources`, when present, MUST contain at least one entry.
92
+ 3. `relatedResources` SHOULD be used for genuinely affected resources, not for arbitrary context. A
93
+ consumer group reset affects the consumer group primarily and the topic secondarily; both belong.
94
+ The cluster's monitoring dashboard does not.
95
+ 4. A bulk operation over many resources SHOULD be recorded as one event per resource where the
96
+ resources are individually significant, and as a single event with a representative primary
97
+ resource and a count in `metadata` where they are not. Producers SHOULD document which approach
98
+ they use, because the two are not interchangeable for review purposes.
99
+
100
+ Example:
101
+
102
+ ```json
103
+ {
104
+ "resource": { "type": "consumer-group", "id": "payments-settlement-consumer" },
105
+ "relatedResources": [
106
+ { "type": "topic", "id": "payments.settlement.completed" },
107
+ { "type": "cluster", "id": "cluster-streaming-production" }
108
+ ]
109
+ }
110
+ ```
111
+
112
+ ## 7. Resource is not subject
113
+
114
+ `resource` is what the operation acted **on**. `subject` is the principal the operation was performed
115
+ **for**. When an administrator disables a user account, the user is a `resource` — nobody delegated
116
+ authority to the administrator. See [actor-model.md](actor-model.md).