@apexops/kernel 0.10.0-next.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 (110) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/benchmark.d.ts +14 -0
  3. package/dist/benchmark.d.ts.map +1 -0
  4. package/dist/benchmark.js +29 -0
  5. package/dist/benchmark.js.map +1 -0
  6. package/dist/canonical.d.ts +10 -0
  7. package/dist/canonical.d.ts.map +1 -0
  8. package/dist/canonical.js +52 -0
  9. package/dist/canonical.js.map +1 -0
  10. package/dist/content-cache.d.ts +18 -0
  11. package/dist/content-cache.d.ts.map +1 -0
  12. package/dist/content-cache.js +94 -0
  13. package/dist/content-cache.js.map +1 -0
  14. package/dist/event-journal.d.ts +20 -0
  15. package/dist/event-journal.d.ts.map +1 -0
  16. package/dist/event-journal.js +136 -0
  17. package/dist/event-journal.js.map +1 -0
  18. package/dist/evidence-store.d.ts +42 -0
  19. package/dist/evidence-store.d.ts.map +1 -0
  20. package/dist/evidence-store.js +151 -0
  21. package/dist/evidence-store.js.map +1 -0
  22. package/dist/files.d.ts +6 -0
  23. package/dist/files.d.ts.map +1 -0
  24. package/dist/files.js +33 -0
  25. package/dist/files.js.map +1 -0
  26. package/dist/gates.d.ts +6 -0
  27. package/dist/gates.d.ts.map +1 -0
  28. package/dist/gates.js +25 -0
  29. package/dist/gates.js.map +1 -0
  30. package/dist/improvement-store.d.ts +48 -0
  31. package/dist/improvement-store.d.ts.map +1 -0
  32. package/dist/improvement-store.js +263 -0
  33. package/dist/improvement-store.js.map +1 -0
  34. package/dist/index.d.ts +18 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +18 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/lease-store.d.ts +23 -0
  39. package/dist/lease-store.d.ts.map +1 -0
  40. package/dist/lease-store.js +108 -0
  41. package/dist/lease-store.js.map +1 -0
  42. package/dist/object-store.d.ts +10 -0
  43. package/dist/object-store.d.ts.map +1 -0
  44. package/dist/object-store.js +86 -0
  45. package/dist/object-store.js.map +1 -0
  46. package/dist/project-store.d.ts +30 -0
  47. package/dist/project-store.d.ts.map +1 -0
  48. package/dist/project-store.js +72 -0
  49. package/dist/project-store.js.map +1 -0
  50. package/dist/run-repository.d.ts +38 -0
  51. package/dist/run-repository.d.ts.map +1 -0
  52. package/dist/run-repository.js +151 -0
  53. package/dist/run-repository.js.map +1 -0
  54. package/dist/tasks.d.ts +14 -0
  55. package/dist/tasks.d.ts.map +1 -0
  56. package/dist/tasks.js +96 -0
  57. package/dist/tasks.js.map +1 -0
  58. package/dist/test/canonical.test.d.ts +2 -0
  59. package/dist/test/canonical.test.d.ts.map +1 -0
  60. package/dist/test/canonical.test.js +18 -0
  61. package/dist/test/canonical.test.js.map +1 -0
  62. package/dist/test/improvement-store.test.d.ts +2 -0
  63. package/dist/test/improvement-store.test.d.ts.map +1 -0
  64. package/dist/test/improvement-store.test.js +130 -0
  65. package/dist/test/improvement-store.test.js.map +1 -0
  66. package/dist/test/journal-lease.test.d.ts +2 -0
  67. package/dist/test/journal-lease.test.d.ts.map +1 -0
  68. package/dist/test/journal-lease.test.js +124 -0
  69. package/dist/test/journal-lease.test.js.map +1 -0
  70. package/dist/test/policies.test.d.ts +2 -0
  71. package/dist/test/policies.test.d.ts.map +1 -0
  72. package/dist/test/policies.test.js +115 -0
  73. package/dist/test/policies.test.js.map +1 -0
  74. package/dist/test/run-repository.test.d.ts +2 -0
  75. package/dist/test/run-repository.test.d.ts.map +1 -0
  76. package/dist/test/run-repository.test.js +100 -0
  77. package/dist/test/run-repository.test.js.map +1 -0
  78. package/dist/test/storage.test.d.ts +2 -0
  79. package/dist/test/storage.test.d.ts.map +1 -0
  80. package/dist/test/storage.test.js +41 -0
  81. package/dist/test/storage.test.js.map +1 -0
  82. package/dist/test/workflow-engine.test.d.ts +2 -0
  83. package/dist/test/workflow-engine.test.d.ts.map +1 -0
  84. package/dist/test/workflow-engine.test.js +108 -0
  85. package/dist/test/workflow-engine.test.js.map +1 -0
  86. package/dist/test/workflow.test.d.ts +2 -0
  87. package/dist/test/workflow.test.d.ts.map +1 -0
  88. package/dist/test/workflow.test.js +119 -0
  89. package/dist/test/workflow.test.js.map +1 -0
  90. package/dist/test/writer-transfer.test.d.ts +2 -0
  91. package/dist/test/writer-transfer.test.d.ts.map +1 -0
  92. package/dist/test/writer-transfer.test.js +355 -0
  93. package/dist/test/writer-transfer.test.js.map +1 -0
  94. package/dist/validator-registry.d.ts +22 -0
  95. package/dist/validator-registry.d.ts.map +1 -0
  96. package/dist/validator-registry.js +42 -0
  97. package/dist/validator-registry.js.map +1 -0
  98. package/dist/workflow-engine.d.ts +72 -0
  99. package/dist/workflow-engine.d.ts.map +1 -0
  100. package/dist/workflow-engine.js +269 -0
  101. package/dist/workflow-engine.js.map +1 -0
  102. package/dist/workflow-validator-ownership.d.ts +12 -0
  103. package/dist/workflow-validator-ownership.d.ts.map +1 -0
  104. package/dist/workflow-validator-ownership.js +163 -0
  105. package/dist/workflow-validator-ownership.js.map +1 -0
  106. package/dist/writer-transfer.d.ts +78 -0
  107. package/dist/writer-transfer.d.ts.map +1 -0
  108. package/dist/writer-transfer.js +313 -0
  109. package/dist/writer-transfer.js.map +1 -0
  110. package/package.json +39 -0
@@ -0,0 +1,18 @@
1
+ import { type JsonValue } from "./canonical.js";
2
+ export interface ContentCacheInput {
3
+ dependencies: Record<string, JsonValue>;
4
+ config: JsonValue;
5
+ toolchain: JsonValue;
6
+ }
7
+ export declare function contentCacheKey(input: ContentCacheInput): string;
8
+ export declare class ContentCache {
9
+ private readonly root;
10
+ private readonly objects;
11
+ constructor(projectRoot: string);
12
+ get<T extends JsonValue>(input: ContentCacheInput): Promise<T | null>;
13
+ set(input: ContentCacheInput, value: JsonValue): Promise<string>;
14
+ invalidate(dependency?: string): Promise<number>;
15
+ private assertRoot;
16
+ private entryPath;
17
+ }
18
+ //# sourceMappingURL=content-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-cache.d.ts","sourceRoot":"","sources":["../src/content-cache.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAI5D,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACxC,MAAM,EAAE,SAAS,CAAC;IAClB,SAAS,EAAE,SAAS,CAAC;CACtB;AAOD,wBAAgB,eAAe,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAEhE;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IAEtC,YAAY,WAAW,EAAE,MAAM,EAI9B;IAEK,GAAG,CAAC,CAAC,SAAS,SAAS,EAAE,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAS1E;IAEK,GAAG,CAAC,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAQrE;IAEK,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAmBrD;YAEa,UAAU;YASV,SAAS;CAexB"}
@@ -0,0 +1,94 @@
1
+ import { constants } from "node:fs";
2
+ import { lstat, mkdir, open, readFile, readdir, rm } from "node:fs/promises";
3
+ import { join, relative, resolve } from "node:path";
4
+ import { sha256Json } from "./canonical.js";
5
+ import { atomicWriteJson } from "./files.js";
6
+ import { ObjectStore } from "./object-store.js";
7
+ export function contentCacheKey(input) {
8
+ return sha256Json(input);
9
+ }
10
+ export class ContentCache {
11
+ root;
12
+ objects;
13
+ constructor(projectRoot) {
14
+ const root = resolve(projectRoot);
15
+ this.root = join(root, ".apex", "cache", "content");
16
+ this.objects = new ObjectStore(projectRoot);
17
+ }
18
+ async get(input) {
19
+ const path = await this.entryPath(contentCacheKey(input));
20
+ try {
21
+ const entry = JSON.parse(await readFile(path, "utf8"));
22
+ return this.objects.getJson(entry.objectHash);
23
+ }
24
+ catch (error) {
25
+ if (error.code === "ENOENT")
26
+ return null;
27
+ throw error;
28
+ }
29
+ }
30
+ async set(input, value) {
31
+ const key = contentCacheKey(input);
32
+ const objectHash = await this.objects.putJson(value);
33
+ await atomicWriteJson(await this.entryPath(key, true), {
34
+ objectHash,
35
+ dependencies: Object.keys(input.dependencies).sort(),
36
+ });
37
+ return key;
38
+ }
39
+ async invalidate(dependency) {
40
+ await this.assertRoot();
41
+ let names;
42
+ try {
43
+ names = await readdir(this.root);
44
+ }
45
+ catch (error) {
46
+ if (error.code === "ENOENT")
47
+ return 0;
48
+ throw error;
49
+ }
50
+ let count = 0;
51
+ for (const name of names.filter((item) => /^[0-9a-f]{64}\.json$/.test(item))) {
52
+ const path = await this.entryPath(name.slice(0, -5));
53
+ const entry = JSON.parse(await readFile(path, "utf8"));
54
+ if (dependency === undefined || entry.dependencies.includes(dependency)) {
55
+ await rm(path);
56
+ count += 1;
57
+ }
58
+ }
59
+ return count;
60
+ }
61
+ async assertRoot(create = false) {
62
+ if (create)
63
+ await mkdir(this.root, { recursive: true });
64
+ try {
65
+ if ((await lstat(this.root)).isSymbolicLink())
66
+ throw new Error("Content cache root must not be a symlink");
67
+ }
68
+ catch (error) {
69
+ if (error.code !== "ENOENT")
70
+ throw error;
71
+ }
72
+ }
73
+ async entryPath(key, create = false) {
74
+ if (!/^[0-9a-f]{64}$/.test(key))
75
+ throw new Error("Invalid content cache key");
76
+ await this.assertRoot(create);
77
+ const path = join(this.root, `${key}.json`);
78
+ if (relative(this.root, path).startsWith(".."))
79
+ throw new Error("Content cache path escapes root");
80
+ try {
81
+ const stat = await lstat(path);
82
+ if (stat.isSymbolicLink() || !stat.isFile())
83
+ throw new Error("Content cache entry must be a regular file");
84
+ const handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
85
+ await handle.close();
86
+ }
87
+ catch (error) {
88
+ if (error.code !== "ENOENT")
89
+ throw error;
90
+ }
91
+ return path;
92
+ }
93
+ }
94
+ //# sourceMappingURL=content-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-cache.js","sourceRoot":"","sources":["../src/content-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import type { EventV1, ProjectId, RunId } from "@apexops/contracts";
2
+ import { type JsonValue } from "./canonical.js";
3
+ export interface AppendEventInput {
4
+ eventId: string;
5
+ projectId: ProjectId;
6
+ runId: RunId;
7
+ type: string;
8
+ timestamp: string;
9
+ ownerEpoch: number;
10
+ expectedHead: string | null;
11
+ payload: JsonValue;
12
+ }
13
+ export declare class EventJournal {
14
+ readonly directory: string;
15
+ constructor(directory: string);
16
+ head(): Promise<string | null>;
17
+ append(input: AppendEventInput): Promise<EventV1>;
18
+ replay(): Promise<EventV1[]>;
19
+ }
20
+ //# sourceMappingURL=event-journal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-journal.d.ts","sourceRoot":"","sources":["../src/event-journal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAKpE,OAAO,EAAkC,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhF,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,SAAS,CAAC;CACpB;AAiCD,qBAAa,YAAY;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,YAAY,SAAS,EAAE,MAAM,EAE5B;IAEK,IAAI,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGnC;IAEK,MAAM,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAsCtD;IAEK,MAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC,CAiDjC;CACF"}
@@ -0,0 +1,136 @@
1
+ import { CONTRACT_VERSION } from "@apexops/contracts";
2
+ import { constants } from "node:fs";
3
+ import { lstat, open, readdir } from "node:fs/promises";
4
+ import { join, resolve } from "node:path";
5
+ import { canonicalJsonBytes, sha256Json } from "./canonical.js";
6
+ import { atomicWriteBytes } from "./files.js";
7
+ const MAX_EVENT_BYTES = 1024 * 1024;
8
+ async function readEventFile(path) {
9
+ const before = await lstat(path, { bigint: true });
10
+ if (!before.isFile() || before.isSymbolicLink() || before.size > BigInt(MAX_EVENT_BYTES)) {
11
+ throw new Error("Journal event must be a bounded regular file");
12
+ }
13
+ const handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
14
+ try {
15
+ const opened = await handle.stat({ bigint: true });
16
+ if (!opened.isFile() ||
17
+ opened.dev !== before.dev ||
18
+ opened.ino !== before.ino ||
19
+ opened.size > BigInt(MAX_EVENT_BYTES)) {
20
+ throw new Error("Journal event changed before read");
21
+ }
22
+ const bytes = await handle.readFile();
23
+ if (bytes.byteLength > MAX_EVENT_BYTES)
24
+ throw new Error("Journal event exceeds its byte budget");
25
+ const after = await lstat(path, { bigint: true });
26
+ if (after.isSymbolicLink() || after.dev !== opened.dev || after.ino !== opened.ino) {
27
+ throw new Error("Journal event changed during read");
28
+ }
29
+ return bytes.toString("utf8");
30
+ }
31
+ finally {
32
+ await handle.close();
33
+ }
34
+ }
35
+ export class EventJournal {
36
+ directory;
37
+ constructor(directory) {
38
+ this.directory = resolve(directory);
39
+ }
40
+ async head() {
41
+ const events = await this.replay();
42
+ return events.at(-1)?.hash ?? null;
43
+ }
44
+ async append(input) {
45
+ const events = await this.replay();
46
+ const previous = events.at(-1);
47
+ const actualHead = previous?.hash ?? null;
48
+ if (input.expectedHead !== actualHead) {
49
+ throw new Error(`Stale journal head: expected ${String(input.expectedHead)}, found ${String(actualHead)}`);
50
+ }
51
+ if (previous !== undefined && input.ownerEpoch < previous.ownerEpoch) {
52
+ throw new Error(`Stale owner epoch: minimum ${previous.ownerEpoch}, received ${input.ownerEpoch}`);
53
+ }
54
+ if (!Number.isInteger(input.ownerEpoch) || input.ownerEpoch < 1) {
55
+ throw new Error("Owner epoch must be a positive integer");
56
+ }
57
+ const eventWithoutHash = {
58
+ schemaVersion: CONTRACT_VERSION,
59
+ eventId: input.eventId,
60
+ projectId: input.projectId,
61
+ runId: input.runId,
62
+ sequence: events.length + 1,
63
+ type: input.type,
64
+ timestamp: input.timestamp,
65
+ ownerEpoch: input.ownerEpoch,
66
+ previousHash: actualHead,
67
+ payloadHash: sha256Json(input.payload),
68
+ payload: input.payload,
69
+ };
70
+ const event = { ...eventWithoutHash, hash: sha256Json(eventWithoutHash) };
71
+ const path = join(this.directory, `${String(event.sequence).padStart(16, "0")}.json`);
72
+ try {
73
+ await atomicWriteBytes(path, canonicalJsonBytes(event), { refuseOverwrite: true });
74
+ }
75
+ catch (error) {
76
+ if (error.code === "EEXIST") {
77
+ throw new Error("Stale journal head: another writer appended first", { cause: error });
78
+ }
79
+ throw error;
80
+ }
81
+ return event;
82
+ }
83
+ async replay() {
84
+ let names;
85
+ try {
86
+ names = (await readdir(this.directory)).filter((name) => /^\d{16}\.json$/.test(name)).sort();
87
+ }
88
+ catch (error) {
89
+ if (error.code === "ENOENT") {
90
+ return [];
91
+ }
92
+ throw error;
93
+ }
94
+ const events = [];
95
+ let previousHash = null;
96
+ let identity;
97
+ for (const [index, name] of names.entries()) {
98
+ let contents;
99
+ try {
100
+ contents = await readEventFile(join(this.directory, name));
101
+ }
102
+ catch (error) {
103
+ throw new Error(`Corrupt journal event ${name}: unsafe file`, { cause: error });
104
+ }
105
+ let event;
106
+ try {
107
+ event = JSON.parse(contents);
108
+ }
109
+ catch (error) {
110
+ throw new Error(`Corrupt journal event ${name}: invalid JSON`, { cause: error });
111
+ }
112
+ const { hash, ...withoutHash } = event;
113
+ const expectedSequence = index + 1;
114
+ if (event.sequence !== expectedSequence || name !== `${String(expectedSequence).padStart(16, "0")}.json`) {
115
+ throw new Error(`Corrupt journal sequence at ${name}`);
116
+ }
117
+ if (event.previousHash !== previousHash) {
118
+ throw new Error(`Corrupt journal chain at sequence ${event.sequence}`);
119
+ }
120
+ if (sha256Json(event.payload) !== event.payloadHash) {
121
+ throw new Error(`Corrupt journal payload at sequence ${event.sequence}`);
122
+ }
123
+ if (sha256Json(withoutHash) !== hash) {
124
+ throw new Error(`Corrupt journal hash at sequence ${event.sequence}`);
125
+ }
126
+ identity ??= event;
127
+ if (event.projectId !== identity.projectId || event.runId !== identity.runId) {
128
+ throw new Error(`Corrupt journal identity at sequence ${event.sequence}`);
129
+ }
130
+ events.push(event);
131
+ previousHash = hash;
132
+ }
133
+ return events;
134
+ }
135
+ }
136
+ //# sourceMappingURL=event-journal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-journal.js","sourceRoot":"","sources":["../src/event-journal.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ import { type JsonValue } from "./canonical.js";
2
+ export type EvidenceRetention = "immutable" | "project" | "optional";
3
+ export interface EvidenceKindPolicy {
4
+ contentTypes: string[];
5
+ maxBytes: number;
6
+ retention: EvidenceRetention;
7
+ }
8
+ export interface EvidencePolicyConfig {
9
+ kinds: Record<string, EvidenceKindPolicy>;
10
+ }
11
+ export interface EvidenceAcceptance {
12
+ status: "accepted" | "quarantined";
13
+ kind: string;
14
+ bytes: number;
15
+ retention: EvidenceRetention;
16
+ hash?: string;
17
+ quarantinePath?: string;
18
+ redacted: boolean;
19
+ reasons: string[];
20
+ }
21
+ export declare class EvidencePolicy {
22
+ readonly config: EvidencePolicyConfig;
23
+ constructor(config: EvidencePolicyConfig);
24
+ rule(kind: string, contentType: string): EvidenceKindPolicy;
25
+ }
26
+ export declare class EvidenceStore {
27
+ private readonly policy;
28
+ private readonly objects;
29
+ private readonly localRoot;
30
+ private readonly telemetryPath;
31
+ constructor(projectRoot: string, policy: EvidencePolicy);
32
+ accept(input: {
33
+ kind: string;
34
+ contentType: string;
35
+ value: JsonValue | Uint8Array;
36
+ required: boolean;
37
+ }): Promise<EvidenceAcceptance>;
38
+ setTelemetryConsent(consent: boolean): Promise<void>;
39
+ exportTelemetry(): Promise<JsonValue | null>;
40
+ deleteTelemetry(): Promise<void>;
41
+ }
42
+ //# sourceMappingURL=evidence-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence-store.d.ts","sourceRoot":"","sources":["../src/evidence-store.ts"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAIpE,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,SAAS,GAAG,UAAU,CAAC;AAErE,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,iBAAiB,CAAC;CAC9B;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC;CAC3C;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,UAAU,GAAG,aAAa,CAAC;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,iBAAiB,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAeD,qBAAa,cAAc;IACb,QAAQ,CAAC,MAAM,EAAE,oBAAoB;IAAjD,YAAqB,MAAM,EAAE,oBAAoB,EAAI;IAErD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,kBAAkB,CAQ1D;CACF;AAED,qBAAa,aAAa;IAOtB,OAAO,CAAC,QAAQ,CAAC,MAAM;IANzB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAEvC,YACE,WAAW,EAAE,MAAM,EACF,MAAM,EAAE,cAAc,EAMxC;IAEK,MAAM,CAAC,KAAK,EAAE;QAClB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,SAAS,GAAG,UAAU,CAAC;QAC9B,QAAQ,EAAE,OAAO,CAAC;KACnB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA0D9B;IAEK,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAEzD;IAEK,eAAe,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAOjD;IAEK,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAErC;CACF"}
@@ -0,0 +1,151 @@
1
+ import { readFile, rm } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ import { canonicalJsonBytes } from "./canonical.js";
4
+ import { atomicWriteBytes, atomicWriteJson } from "./files.js";
5
+ import { ObjectStore } from "./object-store.js";
6
+ const SECRET_KEY = /(?:secret|password|passphrase|token|authorization|api[-_]?key|private[-_]?key|access[-_]?key|clientSecret|connectionString|sasToken)/i;
7
+ const HIGH_RISK = [
8
+ /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/,
9
+ /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----[\s\S]*?-----END (?:RSA |EC |OPENSSH )?PRIVATE KEY-----/,
10
+ /\b(?:ghp|github_pat)_[A-Za-z0-9_]{20,}\b/,
11
+ /\b(?:AccountKey|SharedAccessSignature)=[^\s;]+/i,
12
+ /\bAuthorization\s*[:=]\s*Bearer\s+[A-Za-z0-9._~+\/-]{16,}/i,
13
+ /\bBearer\s+[A-Za-z0-9._~+\/-]{20,}/i,
14
+ /\b(?:Server|Data Source)=[^;\r\n]+;[\s\S]{0,512}\b(?:Password|Pwd|AccountKey)=[^;\r\n]+/i,
15
+ /\b(?:clientSecret|accessToken|refreshToken|sasToken)\s*[:=]\s*["']?[^\s,"'}]{8,}/i,
16
+ ];
17
+ export class EvidencePolicy {
18
+ config;
19
+ constructor(config) {
20
+ this.config = config;
21
+ }
22
+ rule(kind, contentType) {
23
+ const rule = this.config.kinds[kind];
24
+ if (rule === undefined)
25
+ throw new Error(`Evidence kind ${kind} is not allowed`);
26
+ if (!rule.contentTypes.includes(contentType))
27
+ throw new Error(`Content type ${contentType} is not allowed for ${kind}`);
28
+ if (!Number.isInteger(rule.maxBytes) || rule.maxBytes < 1)
29
+ throw new Error(`Invalid evidence byte budget for ${kind}`);
30
+ return rule;
31
+ }
32
+ }
33
+ export class EvidenceStore {
34
+ policy;
35
+ objects;
36
+ localRoot;
37
+ telemetryPath;
38
+ constructor(projectRoot, policy) {
39
+ this.policy = policy;
40
+ const root = resolve(projectRoot);
41
+ this.objects = new ObjectStore(root);
42
+ this.localRoot = join(root, ".apex", "local");
43
+ this.telemetryPath = join(this.localRoot, "telemetry.json");
44
+ }
45
+ async accept(input) {
46
+ const rule = this.policy.rule(input.kind, input.contentType);
47
+ const originalBytes = input.value instanceof Uint8Array ? Buffer.from(input.value) : canonicalJsonBytes(input.value);
48
+ let bytes;
49
+ let wasRedacted = false;
50
+ const uncertainReasons = [];
51
+ if (input.value instanceof Uint8Array) {
52
+ bytes = Buffer.from(input.value);
53
+ if (input.contentType === "application/json") {
54
+ try {
55
+ const parsed = JSON.parse(bytes.toString("utf8"));
56
+ const redactedValue = redact(parsed);
57
+ bytes = canonicalJsonBytes(redactedValue.value);
58
+ wasRedacted = redactedValue.redacted;
59
+ }
60
+ catch {
61
+ uncertainReasons.push("malformed-json");
62
+ }
63
+ }
64
+ else if (!isSafeText(bytes)) {
65
+ uncertainReasons.push("unknown-binary");
66
+ }
67
+ }
68
+ else {
69
+ const redactedValue = redact(input.value);
70
+ bytes = canonicalJsonBytes(redactedValue.value);
71
+ wasRedacted = redactedValue.redacted;
72
+ }
73
+ if (bytes.byteLength > rule.maxBytes)
74
+ throw new Error(`Evidence exceeds ${input.kind} byte budget`);
75
+ const reasons = [
76
+ ...uncertainReasons,
77
+ ...HIGH_RISK.filter((pattern) => pattern.test(originalBytes.toString("utf8")) || pattern.test(bytes.toString("utf8"))).map((pattern) => `high-risk-pattern:${pattern.source}`),
78
+ ];
79
+ if (reasons.length > 0) {
80
+ if (input.required || rule.retention === "immutable")
81
+ throw new Error("Required immutable evidence contains high-risk content");
82
+ const quarantinePath = join(this.localRoot, "quarantine", `${crypto.randomUUID()}.bin`);
83
+ await atomicWriteBytes(quarantinePath, bytes, { refuseOverwrite: true });
84
+ return {
85
+ status: "quarantined",
86
+ kind: input.kind,
87
+ bytes: bytes.byteLength,
88
+ retention: rule.retention,
89
+ quarantinePath,
90
+ redacted: wasRedacted,
91
+ reasons,
92
+ };
93
+ }
94
+ const hash = await this.objects.putBytes(bytes);
95
+ return {
96
+ status: "accepted",
97
+ kind: input.kind,
98
+ bytes: bytes.byteLength,
99
+ retention: input.required ? "immutable" : rule.retention,
100
+ hash,
101
+ redacted: wasRedacted,
102
+ reasons: [],
103
+ };
104
+ }
105
+ async setTelemetryConsent(consent) {
106
+ await atomicWriteJson(this.telemetryPath, { consent });
107
+ }
108
+ async exportTelemetry() {
109
+ try {
110
+ return JSON.parse(await readFile(this.telemetryPath, "utf8"));
111
+ }
112
+ catch (error) {
113
+ if (error.code === "ENOENT")
114
+ return null;
115
+ throw error;
116
+ }
117
+ }
118
+ async deleteTelemetry() {
119
+ await rm(this.telemetryPath, { force: true });
120
+ }
121
+ }
122
+ function isSafeText(bytes) {
123
+ if (bytes.includes(0))
124
+ return false;
125
+ const text = bytes.toString("utf8");
126
+ return Buffer.from(text, "utf8").equals(bytes) && !/[\u0001-\u0008\u000B\u000C\u000E-\u001F]/.test(text);
127
+ }
128
+ function redact(value) {
129
+ if (Array.isArray(value)) {
130
+ const items = value.map(redact);
131
+ return { value: items.map((item) => item.value), redacted: items.some((item) => item.redacted) };
132
+ }
133
+ if (value !== null && typeof value === "object") {
134
+ let changed = false;
135
+ const result = {};
136
+ for (const [key, item] of Object.entries(value)) {
137
+ if (SECRET_KEY.test(key)) {
138
+ result[key] = "[REDACTED]";
139
+ changed = true;
140
+ }
141
+ else {
142
+ const nested = redact(item);
143
+ result[key] = nested.value;
144
+ changed ||= nested.redacted;
145
+ }
146
+ }
147
+ return { value: result, redacted: changed };
148
+ }
149
+ return { value, redacted: false };
150
+ }
151
+ //# sourceMappingURL=evidence-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence-store.js","sourceRoot":"","sources":["../src/evidence-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export interface AtomicWriteOptions {
2
+ refuseOverwrite?: boolean;
3
+ }
4
+ export declare function atomicWriteBytes(path: string, bytes: Uint8Array, options?: AtomicWriteOptions): Promise<void>;
5
+ export declare function atomicWriteJson(path: string, value: unknown, options?: AtomicWriteOptions): Promise<void>;
6
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,kBAAkB;IACjC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,UAAU,EACjB,OAAO,GAAE,kBAAuB,GAC/B,OAAO,CAAC,IAAI,CAAC,CAsBf;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,kBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAEnH"}
package/dist/files.js ADDED
@@ -0,0 +1,33 @@
1
+ import { constants } from "node:fs";
2
+ import { link, mkdir, open, rename, rm } from "node:fs/promises";
3
+ import { basename, dirname, join } from "node:path";
4
+ import { canonicalJsonBytes } from "./canonical.js";
5
+ export async function atomicWriteBytes(path, bytes, options = {}) {
6
+ const directory = dirname(path);
7
+ await mkdir(directory, { recursive: true });
8
+ const temporary = join(directory, `.${basename(path)}.${process.pid}.${crypto.randomUUID()}.tmp`);
9
+ const handle = await open(temporary, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o600);
10
+ try {
11
+ await handle.writeFile(bytes);
12
+ await handle.sync();
13
+ }
14
+ finally {
15
+ await handle.close();
16
+ }
17
+ try {
18
+ if (options.refuseOverwrite) {
19
+ await link(temporary, path);
20
+ await rm(temporary);
21
+ return;
22
+ }
23
+ await rename(temporary, path);
24
+ }
25
+ catch (error) {
26
+ await rm(temporary, { force: true });
27
+ throw error;
28
+ }
29
+ }
30
+ export async function atomicWriteJson(path, value, options = {}) {
31
+ await atomicWriteBytes(path, canonicalJsonBytes(value), options);
32
+ }
33
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../src/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAMpD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,IAAY,EACZ,KAAiB,EACjB,OAAO,GAAuB,EAAE;IAEhC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,GAAG,IAAI,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAClG,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACvG,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IACD,IAAI,CAAC;QACH,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC;YAC5B,MAAM,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC5B,MAAM,EAAE,CAAC,SAAS,CAAC,CAAC;YACpB,OAAO;QACT,CAAC;QACD,MAAM,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAChC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,EAAE,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACrC,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY,EAAE,KAAc,EAAE,OAAO,GAAuB,EAAE;IAClG,MAAM,gBAAgB,CAAC,IAAI,EAAE,kBAAkB,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,CAAC;AACnE,CAAC"}
@@ -0,0 +1,6 @@
1
+ import type { GateRecordV1, RunId } from "@apexops/contracts";
2
+ export declare function openGate(gate: GateRecordV1, dependencyHash: string): GateRecordV1;
3
+ export declare function decideGate(gate: GateRecordV1, decision: "approved" | "rejected", decidedAt: string, reason?: string): GateRecordV1;
4
+ export declare function invalidateGate(gate: GateRecordV1, dependencyHash: string, reason: string): GateRecordV1;
5
+ export declare function inheritGate(gate: GateRecordV1, fromRunId: RunId, dependencyHash: string, decidedAt: string): GateRecordV1;
6
+ //# sourceMappingURL=gates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gates.d.ts","sourceRoot":"","sources":["../src/gates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE9D,wBAAgB,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,GAAG,YAAY,CAKjF;AAED,wBAAgB,UAAU,CACxB,IAAI,EAAE,YAAY,EAClB,QAAQ,EAAE,UAAU,GAAG,UAAU,EACjC,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,GACd,YAAY,CAKd;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,CAEvG;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,YAAY,EAClB,SAAS,EAAE,KAAK,EAChB,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,GAChB,YAAY,CAQd"}
package/dist/gates.js ADDED
@@ -0,0 +1,25 @@
1
+ export function openGate(gate, dependencyHash) {
2
+ if (gate.state !== "closed" && gate.state !== "invalidated") {
3
+ throw new Error(`Gate ${gate.gate} cannot open from ${gate.state}`);
4
+ }
5
+ return { gate: gate.gate, state: "open", dependencyHash };
6
+ }
7
+ export function decideGate(gate, decision, decidedAt, reason) {
8
+ if (gate.state !== "open") {
9
+ throw new Error(`Gate ${gate.gate} is not open`);
10
+ }
11
+ return { ...gate, state: decision, decidedAt, ...(reason === undefined ? {} : { reason }) };
12
+ }
13
+ export function invalidateGate(gate, dependencyHash, reason) {
14
+ return { gate: gate.gate, state: "invalidated", dependencyHash, reason };
15
+ }
16
+ export function inheritGate(gate, fromRunId, dependencyHash, decidedAt) {
17
+ if (gate.gate === 4) {
18
+ throw new Error("Gate 4 cannot be inherited");
19
+ }
20
+ if (gate.dependencyHash !== dependencyHash || (gate.state !== "approved" && gate.state !== "inherited")) {
21
+ throw new Error(`Gate ${gate.gate} dependencies are not approved for inheritance`);
22
+ }
23
+ return { gate: gate.gate, state: "inherited", dependencyHash, inheritedFromRunId: fromRunId, decidedAt };
24
+ }
25
+ //# sourceMappingURL=gates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gates.js","sourceRoot":"","sources":["../src/gates.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,QAAQ,CAAC,IAAkB,EAAE,cAAsB;IACjE,IAAI,IAAI,CAAC,KAAK,KAAK,QAAQ,IAAI,IAAI,CAAC,KAAK,KAAK,aAAa,EAAE,CAAC;QAC5D,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,IAAI,qBAAqB,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IACtE,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,CAAC;AAC5D,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,IAAkB,EAClB,QAAiC,EACjC,SAAiB,EACjB,MAAe;IAEf,IAAI,IAAI,CAAC,KAAK,KAAK,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,IAAI,cAAc,CAAC,CAAC;IACnD,CAAC;IACD,OAAO,EAAE,GAAG,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;AAC9F,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,IAAkB,EAAE,cAAsB,EAAE,MAAc;IACvF,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,EAAE,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,WAAW,CACzB,IAAkB,EAClB,SAAgB,EAChB,cAAsB,EACtB,SAAiB;IAEjB,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IAChD,CAAC;IACD,IAAI,IAAI,CAAC,cAAc,KAAK,cAAc,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,UAAU,IAAI,IAAI,CAAC,KAAK,KAAK,WAAW,CAAC,EAAE,CAAC;QACxG,MAAM,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,IAAI,gDAAgD,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,cAAc,EAAE,kBAAkB,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAC3G,CAAC"}