@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.
- package/dist/.tsbuildinfo +1 -0
- package/dist/benchmark.d.ts +14 -0
- package/dist/benchmark.d.ts.map +1 -0
- package/dist/benchmark.js +29 -0
- package/dist/benchmark.js.map +1 -0
- package/dist/canonical.d.ts +10 -0
- package/dist/canonical.d.ts.map +1 -0
- package/dist/canonical.js +52 -0
- package/dist/canonical.js.map +1 -0
- package/dist/content-cache.d.ts +18 -0
- package/dist/content-cache.d.ts.map +1 -0
- package/dist/content-cache.js +94 -0
- package/dist/content-cache.js.map +1 -0
- package/dist/event-journal.d.ts +20 -0
- package/dist/event-journal.d.ts.map +1 -0
- package/dist/event-journal.js +136 -0
- package/dist/event-journal.js.map +1 -0
- package/dist/evidence-store.d.ts +42 -0
- package/dist/evidence-store.d.ts.map +1 -0
- package/dist/evidence-store.js +151 -0
- package/dist/evidence-store.js.map +1 -0
- package/dist/files.d.ts +6 -0
- package/dist/files.d.ts.map +1 -0
- package/dist/files.js +33 -0
- package/dist/files.js.map +1 -0
- package/dist/gates.d.ts +6 -0
- package/dist/gates.d.ts.map +1 -0
- package/dist/gates.js +25 -0
- package/dist/gates.js.map +1 -0
- package/dist/improvement-store.d.ts +48 -0
- package/dist/improvement-store.d.ts.map +1 -0
- package/dist/improvement-store.js +263 -0
- package/dist/improvement-store.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/lease-store.d.ts +23 -0
- package/dist/lease-store.d.ts.map +1 -0
- package/dist/lease-store.js +108 -0
- package/dist/lease-store.js.map +1 -0
- package/dist/object-store.d.ts +10 -0
- package/dist/object-store.d.ts.map +1 -0
- package/dist/object-store.js +86 -0
- package/dist/object-store.js.map +1 -0
- package/dist/project-store.d.ts +30 -0
- package/dist/project-store.d.ts.map +1 -0
- package/dist/project-store.js +72 -0
- package/dist/project-store.js.map +1 -0
- package/dist/run-repository.d.ts +38 -0
- package/dist/run-repository.d.ts.map +1 -0
- package/dist/run-repository.js +151 -0
- package/dist/run-repository.js.map +1 -0
- package/dist/tasks.d.ts +14 -0
- package/dist/tasks.d.ts.map +1 -0
- package/dist/tasks.js +96 -0
- package/dist/tasks.js.map +1 -0
- package/dist/test/canonical.test.d.ts +2 -0
- package/dist/test/canonical.test.d.ts.map +1 -0
- package/dist/test/canonical.test.js +18 -0
- package/dist/test/canonical.test.js.map +1 -0
- package/dist/test/improvement-store.test.d.ts +2 -0
- package/dist/test/improvement-store.test.d.ts.map +1 -0
- package/dist/test/improvement-store.test.js +130 -0
- package/dist/test/improvement-store.test.js.map +1 -0
- package/dist/test/journal-lease.test.d.ts +2 -0
- package/dist/test/journal-lease.test.d.ts.map +1 -0
- package/dist/test/journal-lease.test.js +124 -0
- package/dist/test/journal-lease.test.js.map +1 -0
- package/dist/test/policies.test.d.ts +2 -0
- package/dist/test/policies.test.d.ts.map +1 -0
- package/dist/test/policies.test.js +115 -0
- package/dist/test/policies.test.js.map +1 -0
- package/dist/test/run-repository.test.d.ts +2 -0
- package/dist/test/run-repository.test.d.ts.map +1 -0
- package/dist/test/run-repository.test.js +100 -0
- package/dist/test/run-repository.test.js.map +1 -0
- package/dist/test/storage.test.d.ts +2 -0
- package/dist/test/storage.test.d.ts.map +1 -0
- package/dist/test/storage.test.js +41 -0
- package/dist/test/storage.test.js.map +1 -0
- package/dist/test/workflow-engine.test.d.ts +2 -0
- package/dist/test/workflow-engine.test.d.ts.map +1 -0
- package/dist/test/workflow-engine.test.js +108 -0
- package/dist/test/workflow-engine.test.js.map +1 -0
- package/dist/test/workflow.test.d.ts +2 -0
- package/dist/test/workflow.test.d.ts.map +1 -0
- package/dist/test/workflow.test.js +119 -0
- package/dist/test/workflow.test.js.map +1 -0
- package/dist/test/writer-transfer.test.d.ts +2 -0
- package/dist/test/writer-transfer.test.d.ts.map +1 -0
- package/dist/test/writer-transfer.test.js +355 -0
- package/dist/test/writer-transfer.test.js.map +1 -0
- package/dist/validator-registry.d.ts +22 -0
- package/dist/validator-registry.d.ts.map +1 -0
- package/dist/validator-registry.js +42 -0
- package/dist/validator-registry.js.map +1 -0
- package/dist/workflow-engine.d.ts +72 -0
- package/dist/workflow-engine.d.ts.map +1 -0
- package/dist/workflow-engine.js +269 -0
- package/dist/workflow-engine.js.map +1 -0
- package/dist/workflow-validator-ownership.d.ts +12 -0
- package/dist/workflow-validator-ownership.d.ts.map +1 -0
- package/dist/workflow-validator-ownership.js +163 -0
- package/dist/workflow-validator-ownership.js.map +1 -0
- package/dist/writer-transfer.d.ts +78 -0
- package/dist/writer-transfer.d.ts.map +1 -0
- package/dist/writer-transfer.js +313 -0
- package/dist/writer-transfer.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal-lease.test.d.ts","sourceRoot":"","sources":["../../src/test/journal-lease.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtemp, readFile, symlink, unlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
import { EventJournal, LeaseStore } from "../index.js";
|
|
7
|
+
const projectId = "demo";
|
|
8
|
+
const runId = "run-1";
|
|
9
|
+
test("event journal enforces head CAS, epoch, and verifies replay", async () => {
|
|
10
|
+
const directory = await mkdtemp(join(tmpdir(), "apex-journal-"));
|
|
11
|
+
const journal = new EventJournal(directory);
|
|
12
|
+
const first = await journal.append({
|
|
13
|
+
eventId: "event-1",
|
|
14
|
+
projectId,
|
|
15
|
+
runId,
|
|
16
|
+
type: "started",
|
|
17
|
+
timestamp: "2026-01-01T00:00:00.000Z",
|
|
18
|
+
ownerEpoch: 2,
|
|
19
|
+
expectedHead: null,
|
|
20
|
+
payload: { value: 1 },
|
|
21
|
+
});
|
|
22
|
+
await assert.rejects(journal.append({
|
|
23
|
+
eventId: "event-2",
|
|
24
|
+
projectId,
|
|
25
|
+
runId,
|
|
26
|
+
type: "changed",
|
|
27
|
+
timestamp: "2026-01-01T00:01:00.000Z",
|
|
28
|
+
ownerEpoch: 2,
|
|
29
|
+
expectedHead: null,
|
|
30
|
+
payload: {},
|
|
31
|
+
}), /Stale journal head/);
|
|
32
|
+
await assert.rejects(journal.append({
|
|
33
|
+
eventId: "event-2",
|
|
34
|
+
projectId,
|
|
35
|
+
runId,
|
|
36
|
+
type: "changed",
|
|
37
|
+
timestamp: "2026-01-01T00:01:00.000Z",
|
|
38
|
+
ownerEpoch: 1,
|
|
39
|
+
expectedHead: first.hash,
|
|
40
|
+
payload: {},
|
|
41
|
+
}), /Stale owner epoch/);
|
|
42
|
+
const second = await journal.append({
|
|
43
|
+
eventId: "event-2",
|
|
44
|
+
projectId,
|
|
45
|
+
runId,
|
|
46
|
+
type: "changed",
|
|
47
|
+
timestamp: "2026-01-01T00:01:00.000Z",
|
|
48
|
+
ownerEpoch: 2,
|
|
49
|
+
expectedHead: first.hash,
|
|
50
|
+
payload: { value: 2 },
|
|
51
|
+
});
|
|
52
|
+
assert.equal(second.sequence, 2);
|
|
53
|
+
assert.equal((await journal.replay()).length, 2);
|
|
54
|
+
});
|
|
55
|
+
test("event journal detects corruption", async () => {
|
|
56
|
+
const directory = await mkdtemp(join(tmpdir(), "apex-journal-"));
|
|
57
|
+
const journal = new EventJournal(directory);
|
|
58
|
+
await journal.append({
|
|
59
|
+
eventId: "event-1",
|
|
60
|
+
projectId,
|
|
61
|
+
runId,
|
|
62
|
+
type: "started",
|
|
63
|
+
timestamp: "2026-01-01T00:00:00.000Z",
|
|
64
|
+
ownerEpoch: 1,
|
|
65
|
+
expectedHead: null,
|
|
66
|
+
payload: { value: 1 },
|
|
67
|
+
});
|
|
68
|
+
const path = join(directory, "0000000000000001.json");
|
|
69
|
+
const event = JSON.parse(await readFile(path, "utf8"));
|
|
70
|
+
event.payload = { value: 99 };
|
|
71
|
+
await writeFile(path, JSON.stringify(event));
|
|
72
|
+
await assert.rejects(journal.replay(), /Corrupt journal payload/);
|
|
73
|
+
});
|
|
74
|
+
test("event journal rejects symlinked and oversized event files", async () => {
|
|
75
|
+
const directory = await mkdtemp(join(tmpdir(), "apex-journal-safe-read-"));
|
|
76
|
+
const journal = new EventJournal(directory);
|
|
77
|
+
await journal.append({
|
|
78
|
+
eventId: "event-1",
|
|
79
|
+
projectId,
|
|
80
|
+
runId,
|
|
81
|
+
type: "started",
|
|
82
|
+
timestamp: "2026-01-01T00:00:00.000Z",
|
|
83
|
+
ownerEpoch: 1,
|
|
84
|
+
expectedHead: null,
|
|
85
|
+
payload: { value: 1 },
|
|
86
|
+
});
|
|
87
|
+
const eventPath = join(directory, "0000000000000001.json");
|
|
88
|
+
const outside = join(directory, "outside.json");
|
|
89
|
+
await writeFile(outside, await readFile(eventPath));
|
|
90
|
+
await unlink(eventPath);
|
|
91
|
+
await symlink(outside, eventPath);
|
|
92
|
+
await assert.rejects(journal.replay(), /unsafe file/);
|
|
93
|
+
await unlink(eventPath);
|
|
94
|
+
await writeFile(eventPath, Buffer.alloc(1024 * 1024 + 1, "x"));
|
|
95
|
+
await assert.rejects(journal.replay(), /unsafe file/);
|
|
96
|
+
});
|
|
97
|
+
test("lease expiry permits reacquisition with a new epoch", async () => {
|
|
98
|
+
const root = await mkdtemp(join(tmpdir(), "apex-lease-"));
|
|
99
|
+
let now = new Date("2026-01-01T00:00:00.000Z");
|
|
100
|
+
const leases = new LeaseStore(join(root, "lease.json"), () => now);
|
|
101
|
+
const first = await leases.acquire("owner-a", 1_000);
|
|
102
|
+
await assert.rejects(leases.acquire("owner-b", 1_000), /held by owner-a/);
|
|
103
|
+
now = new Date("2026-01-01T00:00:02.000Z");
|
|
104
|
+
await assert.rejects(leases.heartbeat("owner-a", first.ownerEpoch, 1_000), /expired/);
|
|
105
|
+
const second = await leases.acquire("owner-b", 1_000);
|
|
106
|
+
assert.equal(second.ownerEpoch, first.ownerEpoch + 1);
|
|
107
|
+
await assert.rejects(leases.release("owner-a", first.ownerEpoch), /Stale lease/);
|
|
108
|
+
await leases.release("owner-b", second.ownerEpoch);
|
|
109
|
+
const third = await leases.acquire("owner-c", 1_000);
|
|
110
|
+
assert.equal(third.ownerEpoch, second.ownerEpoch + 1);
|
|
111
|
+
});
|
|
112
|
+
test("lease acquisition can retry a run-authorized epoch without drifting", async () => {
|
|
113
|
+
const root = await mkdtemp(join(tmpdir(), "apex-exact-lease-"));
|
|
114
|
+
let now = new Date("2026-01-01T00:00:00.000Z");
|
|
115
|
+
const leases = new LeaseStore(join(root, "lease.json"), () => now);
|
|
116
|
+
const first = await leases.acquireAtEpoch("owner-a", 2, 1_000);
|
|
117
|
+
assert.equal(first.ownerEpoch, 2);
|
|
118
|
+
await leases.release("owner-a", 2);
|
|
119
|
+
const retried = await leases.acquireAtEpoch("owner-a", 2, 1_000);
|
|
120
|
+
assert.equal(retried.ownerEpoch, 2);
|
|
121
|
+
now = new Date("2026-01-01T00:00:02.000Z");
|
|
122
|
+
await assert.rejects(leases.acquireAtEpoch("owner-b", 1, 1_000), /cannot regress/);
|
|
123
|
+
});
|
|
124
|
+
//# sourceMappingURL=journal-lease.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journal-lease.test.js","sourceRoot":"","sources":["../../src/test/journal-lease.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policies.test.d.ts","sourceRoot":"","sources":["../../src/test/policies.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtemp, mkdir, symlink } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
import { benchmarkKernel, ContentCache, contentCacheKey, EvidencePolicy, EvidenceStore, ObjectStore, } from "../index.js";
|
|
7
|
+
test("evidence redacts structural secrets, deduplicates, enforces budgets, and quarantines uncertain content", async () => {
|
|
8
|
+
const root = await mkdtemp(join(tmpdir(), "apex-evidence-"));
|
|
9
|
+
const policy = new EvidencePolicy({
|
|
10
|
+
kinds: {
|
|
11
|
+
report: { contentTypes: ["application/json"], maxBytes: 200, retention: "immutable" },
|
|
12
|
+
log: { contentTypes: ["text/plain"], maxBytes: 200, retention: "optional" },
|
|
13
|
+
blob: { contentTypes: ["application/octet-stream"], maxBytes: 200, retention: "optional" },
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
const store = new EvidenceStore(root, policy);
|
|
17
|
+
const accepted = await store.accept({
|
|
18
|
+
kind: "report",
|
|
19
|
+
contentType: "application/json",
|
|
20
|
+
value: { nested: { apiKey: "secret-value" }, value: 1 },
|
|
21
|
+
required: true,
|
|
22
|
+
});
|
|
23
|
+
assert.equal(accepted.status, "accepted");
|
|
24
|
+
assert.equal(accepted.redacted, true);
|
|
25
|
+
assert.equal(accepted.retention, "immutable");
|
|
26
|
+
const object = await new ObjectStore(root).getJson(accepted.hash);
|
|
27
|
+
assert.equal(object.nested.apiKey, "[REDACTED]");
|
|
28
|
+
const duplicate = await store.accept({
|
|
29
|
+
kind: "report",
|
|
30
|
+
contentType: "application/json",
|
|
31
|
+
value: { nested: { apiKey: "different" }, value: 1 },
|
|
32
|
+
required: true,
|
|
33
|
+
});
|
|
34
|
+
assert.equal(duplicate.hash, accepted.hash);
|
|
35
|
+
const jsonFile = await store.accept({
|
|
36
|
+
kind: "report",
|
|
37
|
+
contentType: "application/json",
|
|
38
|
+
value: Buffer.from(JSON.stringify({ clientSecret: "file-secret", value: 1 })),
|
|
39
|
+
required: true,
|
|
40
|
+
});
|
|
41
|
+
assert.equal(jsonFile.status, "accepted");
|
|
42
|
+
assert.equal(jsonFile.redacted, true);
|
|
43
|
+
assert.equal((await new ObjectStore(root).getJson(jsonFile.hash)).clientSecret, "[REDACTED]");
|
|
44
|
+
const quarantined = await store.accept({
|
|
45
|
+
kind: "log",
|
|
46
|
+
contentType: "text/plain",
|
|
47
|
+
value: Buffer.from("github_pat_abcdefghijklmnopqrstuvwxyz123456"),
|
|
48
|
+
required: false,
|
|
49
|
+
});
|
|
50
|
+
assert.equal(quarantined.status, "quarantined");
|
|
51
|
+
assert.match(quarantined.quarantinePath, /\.apex\/local\/quarantine/);
|
|
52
|
+
const malformed = await store.accept({
|
|
53
|
+
kind: "log",
|
|
54
|
+
contentType: "text/plain",
|
|
55
|
+
value: Buffer.from("Authorization: Bearer abcdefghijklmnopqrstuvwxyz"),
|
|
56
|
+
required: false,
|
|
57
|
+
});
|
|
58
|
+
assert.equal(malformed.status, "quarantined");
|
|
59
|
+
const binary = await store.accept({
|
|
60
|
+
kind: "blob",
|
|
61
|
+
contentType: "application/octet-stream",
|
|
62
|
+
value: Buffer.from([0, 1, 2, 3]),
|
|
63
|
+
required: false,
|
|
64
|
+
});
|
|
65
|
+
assert.deepEqual(binary.reasons, ["unknown-binary"]);
|
|
66
|
+
await assert.rejects(store.accept({
|
|
67
|
+
kind: "report",
|
|
68
|
+
contentType: "application/json",
|
|
69
|
+
value: Buffer.from("{not-json"),
|
|
70
|
+
required: true,
|
|
71
|
+
}), /high-risk content/);
|
|
72
|
+
await assert.rejects(store.accept({
|
|
73
|
+
kind: "report",
|
|
74
|
+
contentType: "application/json",
|
|
75
|
+
value: { value: "x".repeat(300) },
|
|
76
|
+
required: true,
|
|
77
|
+
}), /byte budget/);
|
|
78
|
+
await assert.rejects(store.accept({ kind: "report", contentType: "text/plain", value: Buffer.from("x"), required: true }), /not allowed/);
|
|
79
|
+
});
|
|
80
|
+
test("telemetry consent is separate, exportable, and deletable", async () => {
|
|
81
|
+
const root = await mkdtemp(join(tmpdir(), "apex-telemetry-"));
|
|
82
|
+
const store = new EvidenceStore(root, new EvidencePolicy({ kinds: {} }));
|
|
83
|
+
await store.setTelemetryConsent(true);
|
|
84
|
+
assert.deepEqual(await store.exportTelemetry(), { consent: true });
|
|
85
|
+
await store.deleteTelemetry();
|
|
86
|
+
assert.equal(await store.exportTelemetry(), null);
|
|
87
|
+
});
|
|
88
|
+
test("content cache keys canonical inputs, invalidates dependencies, and rejects symlink roots", async () => {
|
|
89
|
+
const root = await mkdtemp(join(tmpdir(), "apex-cache-"));
|
|
90
|
+
const cache = new ContentCache(root);
|
|
91
|
+
const first = { dependencies: { source: "a" }, config: { z: 1, a: 2 }, toolchain: { version: "1" } };
|
|
92
|
+
const reordered = { dependencies: { source: "a" }, config: { a: 2, z: 1 }, toolchain: { version: "1" } };
|
|
93
|
+
assert.equal(contentCacheKey(first), contentCacheKey(reordered));
|
|
94
|
+
await cache.set(first, { result: 1 });
|
|
95
|
+
assert.deepEqual(await cache.get(first), { result: 1 });
|
|
96
|
+
assert.equal(await cache.invalidate("other"), 0);
|
|
97
|
+
assert.equal(await cache.invalidate("source"), 1);
|
|
98
|
+
assert.equal(await cache.get(first), null);
|
|
99
|
+
const linkedRoot = await mkdtemp(join(tmpdir(), "apex-cache-link-"));
|
|
100
|
+
const outside = await mkdtemp(join(tmpdir(), "apex-cache-outside-"));
|
|
101
|
+
await mkdir(join(linkedRoot, ".apex", "cache"), { recursive: true });
|
|
102
|
+
await symlink(outside, join(linkedRoot, ".apex", "cache", "content"));
|
|
103
|
+
await assert.rejects(new ContentCache(linkedRoot).set(first, { result: 1 }), /root must not be a symlink/);
|
|
104
|
+
});
|
|
105
|
+
test("benchmark report has deterministic shape and percentile samples", () => {
|
|
106
|
+
const report = benchmarkKernel(20);
|
|
107
|
+
assert.deepEqual(Object.keys(report), ["schemaVersion", "iterations", "append", "replay", "status"]);
|
|
108
|
+
assert.equal(report.iterations, 20);
|
|
109
|
+
for (const metric of [report.append, report.replay, report.status]) {
|
|
110
|
+
assert.equal(metric.samples, 20);
|
|
111
|
+
assert(metric.p50Ms >= 0);
|
|
112
|
+
assert(metric.p95Ms >= metric.p50Ms);
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
//# sourceMappingURL=policies.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"policies.test.js","sourceRoot":"","sources":["../../src/test/policies.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-repository.test.d.ts","sourceRoot":"","sources":["../../src/test/run-repository.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtemp } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
import { ProjectStore, RunRepository } from "../index.js";
|
|
7
|
+
test("run repository CAS permits one mutation and rejects a racing stale hash", async () => {
|
|
8
|
+
const root = await mkdtemp(join(tmpdir(), "apex-run-repository-"));
|
|
9
|
+
const store = new ProjectStore(root, () => new Date("2026-01-01T00:00:00.000Z"), () => "run-1");
|
|
10
|
+
await store.initializeProject({ projectId: "demo", displayName: "Demo", defaultIacTool: "bicep" });
|
|
11
|
+
await store.createRun("demo", { environment: "dev", targetScope: "scope", runtimeLockHash: "a".repeat(64) });
|
|
12
|
+
const repository = new RunRepository(store.runDirectory("demo", "run-1"));
|
|
13
|
+
const expectedRunHash = await repository.hash();
|
|
14
|
+
const mutation = (eventId) => repository.mutate({
|
|
15
|
+
expectedRunHash,
|
|
16
|
+
event: {
|
|
17
|
+
eventId,
|
|
18
|
+
projectId: "demo",
|
|
19
|
+
runId: "run-1",
|
|
20
|
+
type: "owner-changed",
|
|
21
|
+
timestamp: "2026-01-01T00:01:00.000Z",
|
|
22
|
+
ownerEpoch: 2,
|
|
23
|
+
payload: { eventId },
|
|
24
|
+
},
|
|
25
|
+
update: (run) => ({ ...run, ownerEpoch: 2 }),
|
|
26
|
+
});
|
|
27
|
+
const results = await Promise.allSettled([mutation("event-1"), mutation("event-2")]);
|
|
28
|
+
assert.equal(results.filter((result) => result.status === "fulfilled").length, 1);
|
|
29
|
+
assert.equal(results.filter((result) => result.status === "rejected").length, 1);
|
|
30
|
+
assert.equal((await repository.read()).ownerEpoch, 2);
|
|
31
|
+
assert.equal((await repository.journal.replay()).length, 1);
|
|
32
|
+
});
|
|
33
|
+
test("run repository rejects a mutation when the validated journal head changed", async () => {
|
|
34
|
+
const root = await mkdtemp(join(tmpdir(), "apex-run-journal-cas-"));
|
|
35
|
+
const store = new ProjectStore(root, () => new Date("2026-01-01T00:00:00.000Z"), () => "run-1");
|
|
36
|
+
await store.initializeProject({ projectId: "demo", displayName: "Demo", defaultIacTool: "bicep" });
|
|
37
|
+
await store.createRun("demo", { environment: "dev", targetScope: "scope", runtimeLockHash: "a".repeat(64) });
|
|
38
|
+
const repository = new RunRepository(store.runDirectory("demo", "run-1"));
|
|
39
|
+
const validatedHead = await repository.journal.head();
|
|
40
|
+
await repository.journal.append({
|
|
41
|
+
eventId: "transfer-requested",
|
|
42
|
+
projectId: "demo",
|
|
43
|
+
runId: "run-1",
|
|
44
|
+
type: "transfer-requested",
|
|
45
|
+
timestamp: "2026-01-01T00:00:30.000Z",
|
|
46
|
+
ownerEpoch: 1,
|
|
47
|
+
expectedHead: validatedHead,
|
|
48
|
+
payload: { claimHash: "b".repeat(64), recipient: "ci" },
|
|
49
|
+
});
|
|
50
|
+
await assert.rejects(repository.mutate({
|
|
51
|
+
expectedRunHash: await repository.hash(),
|
|
52
|
+
expectedJournalHead: validatedHead,
|
|
53
|
+
event: {
|
|
54
|
+
eventId: "gate-decided",
|
|
55
|
+
projectId: "demo",
|
|
56
|
+
runId: "run-1",
|
|
57
|
+
type: "gate.decided",
|
|
58
|
+
timestamp: "2026-01-01T00:01:00.000Z",
|
|
59
|
+
ownerEpoch: 1,
|
|
60
|
+
payload: { gate: 4 },
|
|
61
|
+
},
|
|
62
|
+
update: (run) => run,
|
|
63
|
+
}), /Stale journal head/);
|
|
64
|
+
assert.equal((await repository.journal.replay()).length, 1);
|
|
65
|
+
});
|
|
66
|
+
for (const stage of ["intent", "journal", "run", "cleanup"]) {
|
|
67
|
+
test(`run repository recovers a crash after ${stage}`, async () => {
|
|
68
|
+
const root = await mkdtemp(join(tmpdir(), "apex-run-recovery-"));
|
|
69
|
+
const store = new ProjectStore(root, () => new Date("2026-01-01T00:00:00.000Z"), () => "run-1");
|
|
70
|
+
await store.initializeProject({ projectId: "demo", displayName: "Demo", defaultIacTool: "bicep" });
|
|
71
|
+
await store.createRun("demo", { environment: "dev", targetScope: "scope", runtimeLockHash: "a".repeat(64) });
|
|
72
|
+
const directory = store.runDirectory("demo", "run-1");
|
|
73
|
+
const repository = new RunRepository(directory, {
|
|
74
|
+
faultInjector: (current) => {
|
|
75
|
+
if (current === stage)
|
|
76
|
+
throw new Error(`crash:${stage}`);
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
await assert.rejects(repository.mutate({
|
|
80
|
+
expectedRunHash: await repository.hash(),
|
|
81
|
+
event: {
|
|
82
|
+
eventId: `event-${stage}`,
|
|
83
|
+
projectId: "demo",
|
|
84
|
+
runId: "run-1",
|
|
85
|
+
type: "owner-changed",
|
|
86
|
+
timestamp: "2026-01-01T00:01:00.000Z",
|
|
87
|
+
ownerEpoch: 2,
|
|
88
|
+
payload: { stage },
|
|
89
|
+
},
|
|
90
|
+
update: (run) => ({ ...run, ownerEpoch: 2 }),
|
|
91
|
+
}), new RegExp(`crash:${stage}`));
|
|
92
|
+
const recovered = new RunRepository(directory);
|
|
93
|
+
const run = await recovered.read();
|
|
94
|
+
const events = await recovered.journal.replay();
|
|
95
|
+
const committed = stage !== "intent";
|
|
96
|
+
assert.equal(run.ownerEpoch, committed ? 2 : 1);
|
|
97
|
+
assert.equal(events.length, committed ? 1 : 0);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=run-repository.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run-repository.test.js","sourceRoot":"","sources":["../../src/test/run-repository.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.test.d.ts","sourceRoot":"","sources":["../../src/test/storage.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { mkdtemp, mkdir, readFile, symlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import test from "node:test";
|
|
6
|
+
import { atomicWriteJson, ObjectStore, sha256Text } from "../index.js";
|
|
7
|
+
test("atomic JSON writes canonical data and can refuse overwrite", async () => {
|
|
8
|
+
const root = await mkdtemp(join(tmpdir(), "apex-kernel-"));
|
|
9
|
+
const path = join(root, "value.json");
|
|
10
|
+
await atomicWriteJson(path, { z: 1, a: true });
|
|
11
|
+
assert.equal(await readFile(path, "utf8"), '{"a":true,"z":1}');
|
|
12
|
+
await assert.rejects(atomicWriteJson(path, { changed: true }, { refuseOverwrite: true }), { code: "EEXIST" });
|
|
13
|
+
});
|
|
14
|
+
test("object store deduplicates immutable content and rejects traversal", async () => {
|
|
15
|
+
const root = await mkdtemp(join(tmpdir(), "apex-kernel-"));
|
|
16
|
+
const store = new ObjectStore(root);
|
|
17
|
+
const hash = await store.putBytes(Buffer.from("immutable"));
|
|
18
|
+
assert.equal(await store.putBytes(Buffer.from("immutable")), hash);
|
|
19
|
+
assert.equal((await store.getBytes(hash)).toString(), "immutable");
|
|
20
|
+
await assert.rejects(store.getBytes("../outside"), /Invalid SHA-256/);
|
|
21
|
+
const objectPath = join(root, ".apex", "objects", "sha256", hash.slice(0, 2), hash.slice(2));
|
|
22
|
+
await writeFile(objectPath, "mutated");
|
|
23
|
+
await assert.rejects(store.getBytes(hash), /verification failed/);
|
|
24
|
+
});
|
|
25
|
+
test("object store rejects a symlinked hash bucket", async () => {
|
|
26
|
+
const root = await mkdtemp(join(tmpdir(), "apex-kernel-"));
|
|
27
|
+
const outside = await mkdtemp(join(tmpdir(), "apex-outside-"));
|
|
28
|
+
const hash = sha256Text("escape");
|
|
29
|
+
const storeRoot = join(root, ".apex", "objects", "sha256");
|
|
30
|
+
await mkdir(storeRoot, { recursive: true });
|
|
31
|
+
await symlink(outside, join(storeRoot, hash.slice(0, 2)));
|
|
32
|
+
await assert.rejects(new ObjectStore(root).putBytes(Buffer.from("escape")), /escapes the store/);
|
|
33
|
+
});
|
|
34
|
+
test("object store rejects a symlinked store root", async () => {
|
|
35
|
+
const root = await mkdtemp(join(tmpdir(), "apex-kernel-"));
|
|
36
|
+
const outside = await mkdtemp(join(tmpdir(), "apex-outside-"));
|
|
37
|
+
await mkdir(join(root, ".apex", "objects"), { recursive: true });
|
|
38
|
+
await symlink(outside, join(root, ".apex", "objects", "sha256"));
|
|
39
|
+
await assert.rejects(new ObjectStore(root).putBytes(Buffer.from("escape")), /root must not be a symlink/);
|
|
40
|
+
});
|
|
41
|
+
//# sourceMappingURL=storage.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.test.js","sourceRoot":"","sources":["../../src/test/storage.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-engine.test.d.ts","sourceRoot":"","sources":["../../src/test/workflow-engine.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import test from "node:test";
|
|
4
|
+
import { composeDependencyHash, WorkflowEngine, workflowValidatorOwnership } from "../index.js";
|
|
5
|
+
const manifest = JSON.parse(await readFile(new URL("../../../../config/workflow.v1.json", import.meta.url), "utf8"));
|
|
6
|
+
test("workflow manifest validates and routes both tracks deterministically", () => {
|
|
7
|
+
const engine = new WorkflowEngine(manifest);
|
|
8
|
+
assert.deepEqual(engine.manifest.nodes[0]?.validators, [
|
|
9
|
+
"schema:requirements-v1",
|
|
10
|
+
"business:requirements-completeness",
|
|
11
|
+
"review:requirements-comprehensive",
|
|
12
|
+
]);
|
|
13
|
+
assert.ok(engine.manifest.nodes.flatMap(({ validators }) => validators).every((id) => workflowValidatorOwnership(id)));
|
|
14
|
+
const initial = engine.route({ run: { iacTool: "bicep" }, artifacts: {} });
|
|
15
|
+
assert.equal(initial.currentNode, "requirements");
|
|
16
|
+
assert.equal(initial.ownerRole, "requirements");
|
|
17
|
+
const bicep = engine.route({
|
|
18
|
+
run: { iacTool: "bicep" },
|
|
19
|
+
artifacts: {
|
|
20
|
+
"implementation-intent-v1": {},
|
|
21
|
+
"iac-binding-v1": {},
|
|
22
|
+
"environment-inputs-v1": {},
|
|
23
|
+
"policy-property-map-v1": {},
|
|
24
|
+
"runtime-bundle": {},
|
|
25
|
+
toolchain: {},
|
|
26
|
+
},
|
|
27
|
+
completedNodes: [
|
|
28
|
+
"requirements",
|
|
29
|
+
"gate-1",
|
|
30
|
+
"architecture",
|
|
31
|
+
"governance-discovery",
|
|
32
|
+
"governance-reconciliation",
|
|
33
|
+
"gate-2",
|
|
34
|
+
"plan",
|
|
35
|
+
"gate-3",
|
|
36
|
+
],
|
|
37
|
+
gateStates: { "gate-1": "approved", "gate-2": "approved", "gate-3": "approved" },
|
|
38
|
+
});
|
|
39
|
+
assert.equal(bicep.nextTask, "codegen-bicep");
|
|
40
|
+
assert.equal(bicep.ownerRole, "bicep-codegen");
|
|
41
|
+
const discovery = engine.route({
|
|
42
|
+
run: { iacTool: "bicep", targetScope: "scope" },
|
|
43
|
+
artifacts: { "governance-capability-lock": {} },
|
|
44
|
+
completedNodes: ["requirements", "gate-1", "architecture"],
|
|
45
|
+
gateStates: { "gate-1": "approved" },
|
|
46
|
+
});
|
|
47
|
+
assert.equal(discovery.nextTask, "governance-discovery");
|
|
48
|
+
const bicepValidators = engine.activeValidatorIds({ run: { iacTool: "bicep" }, artifacts: {} });
|
|
49
|
+
assert.ok(bicepValidators.includes("bicep:build"));
|
|
50
|
+
assert.equal(bicepValidators.includes("terraform:validate"), false);
|
|
51
|
+
});
|
|
52
|
+
test("workflow rejects unknown operators, cycles, duplicate gates, and missing tracks", () => {
|
|
53
|
+
const base = structuredClone(manifest);
|
|
54
|
+
base.nodes[0].condition = { script: "true" };
|
|
55
|
+
assert.throws(() => new WorkflowEngine(base), /Unsupported/);
|
|
56
|
+
const cyclic = structuredClone(manifest);
|
|
57
|
+
cyclic.edges.push({ from: "gate-1", to: "requirements" });
|
|
58
|
+
assert.throws(() => new WorkflowEngine(cyclic), /cycle/);
|
|
59
|
+
const duplicate = structuredClone(manifest);
|
|
60
|
+
duplicate.nodes.find((node) => node.id === "gate-2").gateNumber = 1;
|
|
61
|
+
assert.throws(() => new WorkflowEngine(duplicate), /duplicate gate/);
|
|
62
|
+
const badInvalidation = structuredClone(manifest);
|
|
63
|
+
badInvalidation.nodes[0].invalidates.push("missing-node");
|
|
64
|
+
assert.throws(() => new WorkflowEngine(badInvalidation), /invalidates unknown node/);
|
|
65
|
+
const oneTrack = structuredClone(manifest);
|
|
66
|
+
oneTrack.nodes = oneTrack.nodes.filter((node) => !JSON.stringify(node.condition ?? {}).includes("terraform"));
|
|
67
|
+
const oneTrackIds = new Set(oneTrack.nodes.map((node) => node.id));
|
|
68
|
+
oneTrack.nodes.forEach((node) => {
|
|
69
|
+
node.invalidates = (node.invalidates ?? []).filter((target) => oneTrackIds.has(target));
|
|
70
|
+
});
|
|
71
|
+
oneTrack.edges = oneTrack.edges.filter((edge) => oneTrack.nodes.some((node) => node.id === edge.from) &&
|
|
72
|
+
oneTrack.nodes.some((node) => node.id === edge.to));
|
|
73
|
+
oneTrack.returnRoutes = oneTrack.returnRoutes.filter((edge) => oneTrack.nodes.some((node) => node.id === edge.from) &&
|
|
74
|
+
oneTrack.nodes.some((node) => node.id === edge.to));
|
|
75
|
+
assert.throws(() => new WorkflowEngine(oneTrack), /bicep and terraform/);
|
|
76
|
+
});
|
|
77
|
+
test("workflow rejects unowned and duplicate validator IDs", () => {
|
|
78
|
+
const unknown = structuredClone(manifest);
|
|
79
|
+
unknown.nodes[0].validators[0] = "schema:unknown-v1";
|
|
80
|
+
assert.throws(() => new WorkflowEngine(unknown), /Unknown workflow validator schema:unknown-v1/);
|
|
81
|
+
const duplicate = structuredClone(manifest);
|
|
82
|
+
duplicate.nodes[0].validators.push(duplicate.nodes[0].validators[0]);
|
|
83
|
+
assert.throws(() => new WorkflowEngine(duplicate), /Duplicate workflow validator/);
|
|
84
|
+
});
|
|
85
|
+
test("dependency hashes are canonical and invalidation cascades with semantic reasons", () => {
|
|
86
|
+
assert.equal(composeDependencyHash({ b: 2, a: 1 }), composeDependencyHash({ a: 1, b: 2 }));
|
|
87
|
+
const plan = new WorkflowEngine(manifest).invalidationPlan("requirements", "requirements changed");
|
|
88
|
+
assert(plan.some((entry) => entry.nodeId === "deploy-bicep"));
|
|
89
|
+
assert(plan.every((entry) => entry.reason === "requirements: requirements changed"));
|
|
90
|
+
assert.equal(new Set(plan.map((entry) => entry.nodeId)).size, plan.length);
|
|
91
|
+
});
|
|
92
|
+
test("manifest order and dependencies are runtime routing authority", () => {
|
|
93
|
+
const changed = structuredClone(manifest);
|
|
94
|
+
const architecture = changed.nodes.find((node) => node.id === "architecture");
|
|
95
|
+
const governance = changed.nodes.find((node) => node.id === "governance-discovery");
|
|
96
|
+
architecture.sourceDependencies.push("new-runtime-evidence");
|
|
97
|
+
changed.nodes.splice(changed.nodes.indexOf(governance), 1);
|
|
98
|
+
changed.nodes.splice(changed.nodes.indexOf(architecture), 0, governance);
|
|
99
|
+
const route = new WorkflowEngine(changed).route({
|
|
100
|
+
run: { iacTool: "bicep", targetScope: "scope" },
|
|
101
|
+
artifacts: { "governance-capability-lock": {} },
|
|
102
|
+
completedNodes: ["requirements", "gate-1"],
|
|
103
|
+
gateStates: { "gate-1": "approved" },
|
|
104
|
+
});
|
|
105
|
+
assert.equal(route.nextTask, "governance-discovery");
|
|
106
|
+
assert.notEqual(route.currentNode, "architecture");
|
|
107
|
+
});
|
|
108
|
+
//# sourceMappingURL=workflow-engine.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow-engine.test.js","sourceRoot":"","sources":["../../src/test/workflow-engine.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflow.test.d.ts","sourceRoot":"","sources":["../../src/test/workflow.test.ts"],"names":[],"mappings":""}
|