@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,62 @@
1
+ /**
2
+ * Schema validation with no filesystem dependency.
3
+ *
4
+ * This module is the boundary that lets the conformance engines run unchanged
5
+ * in environments that do not read the schema from disk — the MCP server in
6
+ * particular, where the schema is compiled in at build time.
7
+ *
8
+ * Everything here operates on a schema **object**. Locating and reading schema
9
+ * files lives in `validate.ts`, which imports this module.
10
+ */
11
+ import { Ajv2020 } from "ajv/dist/2020.js";
12
+ import formatsModule from "ajv-formats";
13
+ import { toIssues } from "./format-errors.js";
14
+ import { createValidatorFromCompiled, SCHEMA_ID, SPEC_VERSION, } from "./validator-interface.js";
15
+ // Re-exported so that existing import sites keep working. Code that only needs
16
+ // a precompiled validator should import ./validator-interface.js directly, which
17
+ // keeps Ajv out of its bundle entirely.
18
+ export { createValidatorFromCompiled, SCHEMA_ID, SPEC_VERSION };
19
+ /** `ajv-formats` is published as CommonJS; this is its ESM-interop entry point. */
20
+ const addFormats = formatsModule.default;
21
+ /** Creates an Ajv instance configured the way OpenAuditModel conformance requires. */
22
+ export function createAjv() {
23
+ const ajv = new Ajv2020({
24
+ // Reject schema authoring mistakes rather than silently ignoring them.
25
+ strict: true,
26
+ // Union types are used deliberately by the free-form JSON value definition.
27
+ allowUnionTypes: true,
28
+ // `strictRequired` is an Ajv-specific authoring lint that rejects the
29
+ // standard `if`/`then` + `required` idiom, which OpenAuditModel relies on
30
+ // for its conditional rules. The idiom is valid Draft 2020-12 and portable
31
+ // across validators, so this single check is disabled.
32
+ strictRequired: false,
33
+ // Report every problem in one pass so that a report is actionable.
34
+ allErrors: true,
35
+ });
36
+ addFormats(ajv);
37
+ return ajv;
38
+ }
39
+ /** Validates a schema document itself against the Draft 2020-12 meta-schema. */
40
+ export function validateSchemaDocument(schema) {
41
+ const ajv = createAjv();
42
+ const valid = ajv.validateSchema(schema);
43
+ return valid ? [] : toIssues(ajv.errors);
44
+ }
45
+ /**
46
+ * Compiles a schema object into a reusable validator.
47
+ *
48
+ * Used directly where the schema is already in memory. Environments that forbid
49
+ * dynamic code generation cannot call this — Ajv compiles with `new Function` —
50
+ * and supply a precompiled validation function instead; see
51
+ * {@link createValidatorFromCompiled}.
52
+ */
53
+ export function createValidatorFromSchema(schema) {
54
+ const ajv = createAjv();
55
+ const compiled = ajv.compile(schema);
56
+ const schemaId = typeof schema["$id"] === "string" ? schema["$id"] : SCHEMA_ID;
57
+ return {
58
+ schemaId,
59
+ validateEvent: (event) => (compiled(event) ? [] : toIssues(compiled.errors)),
60
+ };
61
+ }
62
+ //# sourceMappingURL=validate-core.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-core.js","sourceRoot":"","sources":["../../../conformance/src/validate-core.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAE3C,OAAO,aAAa,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAwB,MAAM,oBAAoB,CAAC;AACpE,OAAO,EACL,2BAA2B,EAC3B,SAAS,EACT,YAAY,GAEb,MAAM,0BAA0B,CAAC;AAElC,+EAA+E;AAC/E,iFAAiF;AACjF,wCAAwC;AACxC,OAAO,EAAE,2BAA2B,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;AAGhE,mFAAmF;AACnF,MAAM,UAAU,GAAG,aAAa,CAAC,OAAO,CAAC;AAEzC,sFAAsF;AACtF,MAAM,UAAU,SAAS;IACvB,MAAM,GAAG,GAAG,IAAI,OAAO,CAAC;QACtB,uEAAuE;QACvE,MAAM,EAAE,IAAI;QACZ,4EAA4E;QAC5E,eAAe,EAAE,IAAI;QACrB,sEAAsE;QACtE,0EAA0E;QAC1E,2EAA2E;QAC3E,uDAAuD;QACvD,cAAc,EAAE,KAAK;QACrB,mEAAmE;QACnE,SAAS,EAAE,IAAI;KAChB,CAAC,CAAC;IACH,UAAU,CAAC,GAAG,CAAC,CAAC;IAChB,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,sBAAsB,CAAC,MAAuB;IAC5D,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,KAAK,GAAG,GAAG,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,MAA8B,CAAC,CAAC;AACnE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAuB;IAC/D,MAAM,GAAG,GAAG,SAAS,EAAE,CAAC;IACxB,MAAM,QAAQ,GAAqB,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE/E,OAAO;QACL,QAAQ;QACR,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;KAC7E,CAAC;AACJ,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type { AnySchemaObject } from "ajv";
2
+ import type { ValidationIssue } from "./format-errors.js";
3
+ import { expandInputPaths } from "./sources.js";
4
+ import { createAjv, SCHEMA_ID, SPEC_VERSION, validateSchemaDocument, type EventValidator } from "./validate-core.js";
5
+ export { createAjv, SCHEMA_ID, SPEC_VERSION, validateSchemaDocument };
6
+ export type { EventValidator };
7
+ export declare const SCHEMA_RELATIVE_PATH: string;
8
+ /** Outcome of validating a single file. */
9
+ export type FileStatus = "valid" | "invalid" | "unreadable";
10
+ export interface FileValidationResult {
11
+ readonly file: string;
12
+ readonly status: FileStatus;
13
+ readonly issues: readonly ValidationIssue[];
14
+ /** Set when the file could not be read or parsed as JSON. */
15
+ readonly error?: string;
16
+ }
17
+ export interface Validator extends EventValidator {
18
+ readonly schemaPath: string;
19
+ /** Reads, parses and validates a single JSON file. */
20
+ validateFile(file: string): FileValidationResult;
21
+ }
22
+ /**
23
+ * Walks upwards from a starting directory until the canonical schema is found.
24
+ * This keeps the CLI working when run from `dist/`, from the repository root,
25
+ * or from an installed package directory.
26
+ */
27
+ export declare function resolveSchemaPath(startDir?: string): string;
28
+ /** Reads the canonical schema document from disk. */
29
+ export declare function loadSchema(schemaPath?: string): AnySchemaObject;
30
+ /** Compiles the canonical schema and returns a reusable validator. */
31
+ export declare function createValidator(schemaPath?: string): Validator;
32
+ /** Re-exported so that consumers of the validator keep a single import site. */
33
+ export { expandInputPaths };
34
+ export type { ValidationIssue };
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Validation of audit events against the canonical OpenAuditModel schema, read
3
+ * from this repository.
4
+ *
5
+ * The filesystem-free half lives in `validate-core.ts`, which this module
6
+ * re-exports so that existing import sites keep working. Environments without a
7
+ * filesystem import that module directly.
8
+ */
9
+ import { existsSync, readFileSync } from "node:fs";
10
+ import path from "node:path";
11
+ import { fileURLToPath } from "node:url";
12
+ import { expandInputPaths, readJsonFile } from "./sources.js";
13
+ import { createAjv, createValidatorFromSchema, SCHEMA_ID, SPEC_VERSION, validateSchemaDocument, } from "./validate-core.js";
14
+ export { createAjv, SCHEMA_ID, SPEC_VERSION, validateSchemaDocument };
15
+ export const SCHEMA_RELATIVE_PATH = path.join("schemas", `v${SPEC_VERSION}`, "audit-event.schema.json");
16
+ /**
17
+ * Walks upwards from a starting directory until the canonical schema is found.
18
+ * This keeps the CLI working when run from `dist/`, from the repository root,
19
+ * or from an installed package directory.
20
+ */
21
+ export function resolveSchemaPath(startDir) {
22
+ const from = startDir ?? path.dirname(fileURLToPath(import.meta.url));
23
+ let dir = path.resolve(from);
24
+ for (let depth = 0; depth < 10; depth += 1) {
25
+ const candidate = path.join(dir, SCHEMA_RELATIVE_PATH);
26
+ if (existsSync(candidate)) {
27
+ return candidate;
28
+ }
29
+ const parent = path.dirname(dir);
30
+ if (parent === dir) {
31
+ break;
32
+ }
33
+ dir = parent;
34
+ }
35
+ throw new Error(`Unable to locate ${SCHEMA_RELATIVE_PATH}. Searched upwards from ${path.resolve(from)}.`);
36
+ }
37
+ /** Reads the canonical schema document from disk. */
38
+ export function loadSchema(schemaPath) {
39
+ const resolved = schemaPath ?? resolveSchemaPath();
40
+ const raw = readFileSync(resolved, "utf8");
41
+ return JSON.parse(raw);
42
+ }
43
+ /** Compiles the canonical schema and returns a reusable validator. */
44
+ export function createValidator(schemaPath) {
45
+ const resolvedPath = schemaPath ?? resolveSchemaPath();
46
+ const schema = loadSchema(resolvedPath);
47
+ const core = createValidatorFromSchema(schema);
48
+ const { schemaId } = core;
49
+ const validateEvent = (event) => core.validateEvent(event);
50
+ const validateFile = (file) => {
51
+ const parsed = readJsonFile(file);
52
+ if (!parsed.ok) {
53
+ return { file, status: "unreadable", issues: [], error: parsed.error };
54
+ }
55
+ const issues = validateEvent(parsed.value);
56
+ return { file, status: issues.length === 0 ? "valid" : "invalid", issues };
57
+ };
58
+ return { schemaId, schemaPath: resolvedPath, validateEvent, validateFile };
59
+ }
60
+ /** Re-exported so that consumers of the validator keep a single import site. */
61
+ export { expandInputPaths };
62
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../conformance/src/validate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The validator interface, with no dependency on Ajv's runtime.
3
+ *
4
+ * This module exists so that an environment which validates with an
5
+ * ahead-of-time compiled function never pulls Ajv's compiler into its bundle.
6
+ * The MCP server validates with Ajv's standalone output, so importing the
7
+ * compiler there would ship a large module of dead code and put runtime code
8
+ * generation on a path that has no use for it.
9
+ *
10
+ * `ValidateFunction` is imported as a type only, so it is erased at build time.
11
+ */
12
+ import type { ValidateFunction } from "ajv";
13
+ import { type ValidationIssue } from "./format-errors.js";
14
+ export declare const SPEC_VERSION = "0.1";
15
+ /** Canonical identifier of the OpenAuditModel Audit Event Schema. */
16
+ export declare const SCHEMA_ID = "https://openauditmodel.org/schemas/audit-event/0.1/schema.json";
17
+ /**
18
+ * Validates parsed events. The smallest interface the conformance engines need,
19
+ * so that they work with a schema read from disk or compiled in at build time.
20
+ */
21
+ export interface EventValidator {
22
+ readonly schemaId: string;
23
+ /** Validates an already parsed event and returns the issues found. */
24
+ validateEvent(event: unknown): ValidationIssue[];
25
+ }
26
+ /**
27
+ * Wraps an already compiled Ajv validation function.
28
+ *
29
+ * This is how the MCP server validates: Ajv's standalone code generator emits
30
+ * the same validation logic ahead of time, so the server's verdict is identical
31
+ * to the command line tool's by construction rather than by coincidence — and
32
+ * Ajv's compiler is not reachable from its module graph.
33
+ */
34
+ export declare function createValidatorFromCompiled(compiled: ValidateFunction, schemaId?: string): EventValidator;
35
+ export type { ValidationIssue };
@@ -0,0 +1,19 @@
1
+ import { toIssues } from "./format-errors.js";
2
+ export const SPEC_VERSION = "0.1";
3
+ /** Canonical identifier of the OpenAuditModel Audit Event Schema. */
4
+ export const SCHEMA_ID = "https://openauditmodel.org/schemas/audit-event/0.1/schema.json";
5
+ /**
6
+ * Wraps an already compiled Ajv validation function.
7
+ *
8
+ * This is how the MCP server validates: Ajv's standalone code generator emits
9
+ * the same validation logic ahead of time, so the server's verdict is identical
10
+ * to the command line tool's by construction rather than by coincidence — and
11
+ * Ajv's compiler is not reachable from its module graph.
12
+ */
13
+ export function createValidatorFromCompiled(compiled, schemaId = SCHEMA_ID) {
14
+ return {
15
+ schemaId,
16
+ validateEvent: (event) => (compiled(event) ? [] : toIssues(compiled.errors)),
17
+ };
18
+ }
19
+ //# sourceMappingURL=validator-interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator-interface.js","sourceRoot":"","sources":["../../../conformance/src/validator-interface.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,QAAQ,EAAwB,MAAM,oBAAoB,CAAC;AAEpE,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,CAAC;AAElC,qEAAqE;AACrE,MAAM,CAAC,MAAM,SAAS,GAAG,gEAAgE,CAAC;AAY1F;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B,CACzC,QAA0B,EAC1B,WAAmB,SAAS;IAE5B,OAAO;QACL,QAAQ;QACR,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;KAC7E,CAAC;AACJ,CAAC"}
package/package.json ADDED
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "@openauditmodel/cli",
3
+ "version": "0.1.0",
4
+ "description": "Conformance toolchain for OpenAuditModel: validate audit events against the canonical JSON Schema, verify tamper-evidence, lint for leaked secrets and check domain profiles. Offline and deterministic.",
5
+ "keywords": [
6
+ "audit",
7
+ "audit-event",
8
+ "audit-log",
9
+ "specification",
10
+ "json-schema",
11
+ "conformance",
12
+ "openauditmodel"
13
+ ],
14
+ "license": "Apache-2.0",
15
+ "type": "module",
16
+ "engines": {
17
+ "node": ">=22.0.0"
18
+ },
19
+ "bin": {
20
+ "auditmodel": "dist/conformance/src/cli.js",
21
+ "openauditmodel": "dist/conformance/src/cli.js"
22
+ },
23
+ "files": [
24
+ "dist/conformance/src",
25
+ "schemas",
26
+ "profiles",
27
+ "semantic-conventions",
28
+ "specification",
29
+ "LICENSE",
30
+ "README.md"
31
+ ],
32
+ "scripts": {
33
+ "build": "tsc -p tsconfig.json",
34
+ "clean": "node --eval \"import('node:fs').then((fs) => fs.rmSync('dist', { recursive: true, force: true }))\"",
35
+ "auditmodel": "node dist/conformance/src/cli.js",
36
+ "format": "prettier --write .",
37
+ "format:check": "prettier --check .",
38
+ "lint": "eslint .",
39
+ "schema:validate": "npm run build && node --test dist/conformance/tests/schema-validation.test.js",
40
+ "test": "npm run build && node --test \"dist/conformance/tests/*.test.js\" \"dist/mcp/tests/*.test.js\"",
41
+ "validate:valid": "npm run build && node dist/conformance/src/cli.js validate examples/valid",
42
+ "verify:integrity": "npm run build && node dist/conformance/src/cli.js verify-integrity examples/integrity/valid && node dist/conformance/src/cli.js verify-chain examples/integrity/valid/three-event-chain",
43
+ "lint:privacy": "npm run build && node dist/conformance/src/cli.js lint-privacy examples/valid examples/integrity/valid examples/privacy/clean examples/profiles/identity-and-access-management/valid examples/profiles/document-management/valid examples/profiles/incident-management/valid examples/profiles/message-broker-management/valid examples/profiles/deployment-and-change-management/valid examples/profiles/financial-transaction-management/valid examples/profiles/secrets-and-key-management/valid examples/profiles/customer-and-account-management/valid examples/profiles/backup-and-recovery/valid examples/profiles/api-and-integration-management/valid",
44
+ "check:profile": "npm run build && node dist/conformance/src/cli.js check-profile examples/profiles/identity-and-access-management/valid --profile identity-and-access-management && node dist/conformance/src/cli.js check-profile examples/profiles/document-management/valid --profile document-management && node dist/conformance/src/cli.js check-profile examples/profiles/incident-management/valid --profile incident-management && node dist/conformance/src/cli.js check-profile examples/profiles/message-broker-management/valid --profile message-broker-management && node dist/conformance/src/cli.js check-profile examples/profiles/deployment-and-change-management/valid --profile deployment-and-change-management && node dist/conformance/src/cli.js check-profile examples/profiles/financial-transaction-management/valid --profile financial-transaction-management && node dist/conformance/src/cli.js check-profile examples/profiles/secrets-and-key-management/valid --profile secrets-and-key-management && node dist/conformance/src/cli.js check-profile examples/profiles/customer-and-account-management/valid --profile customer-and-account-management && node dist/conformance/src/cli.js check-profile examples/profiles/backup-and-recovery/valid --profile backup-and-recovery && node dist/conformance/src/cli.js check-profile examples/profiles/api-and-integration-management/valid --profile api-and-integration-management",
45
+ "fixtures:integrity": "npm run build && node dist/conformance/tools/generate-integrity-fixtures.js && prettier --write examples/integrity",
46
+ "fixtures:check": "npm run build && node dist/conformance/tools/generate-integrity-fixtures.js --check",
47
+ "verify": "npm run format:check && npm run lint && npm run test && npm run validate:valid && npm run verify:integrity && npm run lint:privacy && npm run check:profile",
48
+ "mcp:generate": "npm run generate --workspace mcp",
49
+ "mcp:check-generated": "npm run generate:check --workspace mcp",
50
+ "mcp:start": "npm run build && node dist/mcp/src/index.js",
51
+ "prepare": "npm run build",
52
+ "prepack": "npm run build && node scripts/verify-package.mjs",
53
+ "package:verify": "node scripts/verify-package.mjs",
54
+ "package:smoke": "npm run build && node scripts/package-smoke-test.mjs",
55
+ "site:build": "node scripts/build-site.mjs",
56
+ "site:check": "node scripts/build-site.mjs --check"
57
+ },
58
+ "dependencies": {
59
+ "ajv": "^8.17.1",
60
+ "ajv-formats": "^3.0.1",
61
+ "canonicalize": "^3.0.0"
62
+ },
63
+ "devDependencies": {
64
+ "@eslint/js": "^10.0.1",
65
+ "@types/node": "^22.10.2",
66
+ "eslint": "^10.8.0",
67
+ "prettier": "^3.4.2",
68
+ "typescript": "^5.7.2",
69
+ "typescript-eslint": "^8.18.1"
70
+ },
71
+ "homepage": "https://openauditmodel.org",
72
+ "repository": {
73
+ "type": "git",
74
+ "url": "git+https://github.com/OpenAuditModel/OpenAuditModel.git"
75
+ },
76
+ "bugs": {
77
+ "url": "https://github.com/OpenAuditModel/OpenAuditModel/issues"
78
+ },
79
+ "workspaces": [
80
+ "mcp"
81
+ ],
82
+ "publishConfig": {
83
+ "access": "public"
84
+ }
85
+ }
@@ -0,0 +1,201 @@
1
+ # Profiles
2
+
3
+ **Specification version: 0.1 · Status: Experimental**
4
+
5
+ A **profile** is an optional, stricter set of requirements for a specific domain, layered on top of
6
+ the core model.
7
+
8
+ ```bash
9
+ auditmodel check-profile <path...> --profile identity-and-access-management
10
+ ```
11
+
12
+ ## The invariant
13
+
14
+ **A profile only ever adds constraints.**
15
+
16
+ A profile MAY:
17
+
18
+ - Require fields the core model leaves OPTIONAL, for a specific class of events.
19
+ - Require a field to have a particular JSON type.
20
+ - Require a field to equal a particular scalar.
21
+ - Recommend fields, producing warnings that never fail conformance.
22
+
23
+ A profile MUST NOT:
24
+
25
+ - Relax, replace or reinterpret any core requirement.
26
+ - Add a top-level property to an audit event.
27
+ - Redefine the meaning of a core field.
28
+ - Introduce product-specific, company-specific, country-specific or regulation-specific fields.
29
+
30
+ **Every profile-conforming event is a core-conforming event.** The reverse does not hold.
31
+
32
+ This is enforced structurally rather than by review. The rule vocabulary has no keyword that could
33
+ remove a requirement — there is no `optionalPaths`, no `exemptPaths`, no `overrides` — and core
34
+ validation runs first, so an event that fails the core schema is reported as core-invalid with its
35
+ profile rules **not evaluated**. Both properties are covered by tests. See
36
+ [ADR 0008](../decisions/0008-declarative-profile-conformance.md).
37
+
38
+ ## Status in v0.1
39
+
40
+ | Profile | Status |
41
+ | --------------------------------------------------------------------- | ------------------------- |
42
+ | [identity-and-access-management](identity-and-access-management/) | **Implemented**, 11 rules |
43
+ | [document-management](document-management/) | **Implemented**, 11 rules |
44
+ | [incident-management](incident-management/) | **Implemented**, 15 rules |
45
+ | [message-broker-management](message-broker-management/) | **Implemented**, 12 rules |
46
+ | [deployment-and-change-management](deployment-and-change-management/) | **Implemented**, 13 rules |
47
+ | [financial-transaction-management](financial-transaction-management/) | **Implemented**, 12 rules |
48
+ | [secrets-and-key-management](secrets-and-key-management/) | **Implemented**, 14 rules |
49
+ | [customer-and-account-management](customer-and-account-management/) | **Implemented**, 13 rules |
50
+ | [backup-and-recovery](backup-and-recovery/) | **Implemented**, 13 rules |
51
+ | [api-and-integration-management](api-and-integration-management/) | **Implemented**, 13 rules |
52
+
53
+ All ten profiles are enforceable and carry fixtures. There are no placeholder profiles left in v0.1.
54
+
55
+ ## Profile definition format
56
+
57
+ A profile is a JSON document at `profiles/<name>/profile.json`, validated against
58
+ [profile-definition.schema.json](profile-definition.schema.json). That schema validates **profile
59
+ documents**; it is not part of the canonical audit event schema and never constrains an audit event.
60
+
61
+ ```json
62
+ {
63
+ "profileVersion": "0.1",
64
+ "name": "identity-and-access-management",
65
+ "version": "0.1",
66
+ "status": "experimental",
67
+ "coreVersions": ["0.1"],
68
+ "title": "Identity and Access Management Profile",
69
+ "description": "Additional conformance requirements for identity and access management audit events.",
70
+ "rules": []
71
+ }
72
+ ```
73
+
74
+ `version` is the profile's own version and moves independently of the core specification.
75
+ `coreVersions` lists the core versions the profile applies to; an event declaring any other
76
+ `specVersion` is **not applicable** rather than in violation.
77
+
78
+ ### Rules
79
+
80
+ Each rule has an `id` and a `description`, and MAY have a `rationale` and a `severity`.
81
+
82
+ ```json
83
+ {
84
+ "id": "IAM-ROLE-002",
85
+ "description": "A privileged role change is approved and performed from a multi-factor authenticated session.",
86
+ "rationale": "Privileged access is the control that protects every other control.",
87
+ "severity": "error",
88
+ "events": ["identity.role.assign", "identity.role.revoke"],
89
+ "when": { "path": "/metadata/role/privileged", "equals": true },
90
+ "requiredPaths": ["/approval", "/authentication"],
91
+ "requiredValues": [{ "path": "/authentication/mfa", "equals": true }]
92
+ }
93
+ ```
94
+
95
+ Rule severities are `info`, `warning` and `error`. Only `error` fails conformance. These are the
96
+ profile vocabulary and are **unrelated** to the privacy linter's severities, which describe a
97
+ different kind of risk.
98
+
99
+ ### Selectors
100
+
101
+ A rule MUST have at least one selector.
102
+
103
+ | Selector | Matches |
104
+ | --------------- | --------------------------------------------------------------------------------------------------------------------------------- |
105
+ | `events` | Exact event names |
106
+ | `eventPrefixes` | Event names starting with the prefix. A prefix MUST end with a dot, so that `identity.role.` cannot match `identity.roles-export` |
107
+
108
+ There is no regular expression selector. A profile is a published statement about which events it
109
+ governs, and a pattern language turns "does this rule apply to my event?" into a question only a tool
110
+ can answer.
111
+
112
+ ### Requirements
113
+
114
+ | Keyword | Path syntax | Meaning |
115
+ | ------------------ | ---------------------------------------- | -------------------------------------------------------- |
116
+ | `requiredPaths` | Absolute JSON Pointer | The value must be **present** |
117
+ | `requiredMetadata` | JSON Pointer **relative to `/metadata`** | The value must be present and of a JSON type |
118
+ | `requiredValues` | Absolute JSON Pointer | The value must be present and strictly equal to a scalar |
119
+ | `recommendedPaths` | Absolute JSON Pointer | Absence produces a warning, never a failure |
120
+
121
+ `requiredMetadata` paths are relative because every one of them starts `/metadata`; `/role/id` means
122
+ `/metadata/role/id`. All other paths are absolute pointers into the event. Findings always report the
123
+ **full** pointer, so a report never needs the reader to know which convention a keyword used.
124
+
125
+ Supported metadata types: `string`, `number`, `integer`, `boolean`, `object`, `array`. `integer` is a
126
+ subset of `number`. Profiles do not embed schema fragments in v0.1.
127
+
128
+ ### Presence
129
+
130
+ A required path is satisfied only when the value:
131
+
132
+ - exists, **and**
133
+ - is not `null`, **and**
134
+ - is not an empty string, **and**
135
+ - is not an empty array, **and**
136
+ - is not an empty object.
137
+
138
+ `false` and `0` **are** present. They are answers, not absences: a profile that could not require
139
+ `mfa: false` to be recorded would be unable to distinguish "not recorded" from "recorded as false".
140
+
141
+ This differs deliberately from the privacy linter's notion of a populated value, which excludes
142
+ booleans because a credential cannot be `true`.
143
+
144
+ ### Conditional requirements
145
+
146
+ A rule MAY carry one `when` condition: one path compared for equality against one scalar.
147
+
148
+ ```json
149
+ { "when": { "path": "/metadata/role/privileged", "equals": true } }
150
+ ```
151
+
152
+ That is the entire conditional mechanism. There are no boolean combinations, no nesting, no
153
+ comparison operators other than equality, and no expression language.
154
+
155
+ Comparison is strict: `1` does not equal `true`, and `"true"` does not equal `true`. **When the
156
+ condition's path is absent, the condition does not hold** and the rule contributes nothing. The
157
+ alternative — treating an absent flag as possibly true — would fail every event that omitted a field
158
+ the rule was never meant to govern. Profiles requiring such a flag require it separately, through
159
+ `requiredMetadata`.
160
+
161
+ ## Results
162
+
163
+ | Status | Meaning | Exit |
164
+ | ---------------- | ----------------------------------------------------------------- | ---- |
165
+ | `conforming` | At least one rule matched and every requirement was satisfied | 0 |
166
+ | `violations` | A rule matched and a requirement was not satisfied | 1 |
167
+ | `core-invalid` | The event fails the core schema; profile rules were not evaluated | 1 |
168
+ | `not-applicable` | No rule in the profile governs this event | 3 |
169
+
170
+ **`not-applicable` is not conformance.** An event no rule governs is reported as out of scope, never
171
+ as conforming, so that a pipeline cannot read "the profile said nothing" as "the profile was
172
+ satisfied". Exit code `3` exists for the same reason.
173
+
174
+ When a run mixes conforming and not-applicable events, the exit code is `0`. Exit `3` means nothing
175
+ checked was governed at all.
176
+
177
+ ## What profiles are not
178
+
179
+ **Profiles are not regulatory mappings.** A profile requires audit fields. It cites no regulation,
180
+ article, control identifier or jurisdiction, and the profile definition schema gives it nowhere to put
181
+ one. Regulations are revised on their own schedules and interpreted differently by different auditors;
182
+ a profile that encoded one would be wrong when the regulation changed and useless everywhere it did
183
+ not apply.
184
+
185
+ **Profile conformance is not legal or regulatory compliance**, and MUST NOT be presented as evidence
186
+ of it. It is a statement that an event carries the fields a domain agreed it should carry.
187
+
188
+ **Profiles do not replace privacy linting.** A profile says which fields must be present; the privacy
189
+ linter says which values must not. They are complementary and independent: a profile-conforming event
190
+ can still carry a secret, and `auditmodel lint-privacy` is what looks for one. Every published
191
+ profile fixture is required by test to pass both.
192
+
193
+ **Profiles are not a policy engine.** OpenAuditModel records decisions; it does not evaluate them.
194
+
195
+ ## Proposing a profile
196
+
197
+ Use the profile proposal issue template. A proposal must show that the domain has requirements the
198
+ core cannot express and that those requirements are shared across independent products — not one
199
+ product's field list wearing a domain's name. See [CONTRIBUTING.md](../CONTRIBUTING.md).
200
+
201
+ Adding a profile requires **no code**: a profile is a JSON document plus fixtures.