@uns-kit/core 3.0.28 → 3.0.31
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/MIGRATIONS.md +118 -0
- package/README.md +10 -0
- package/dist/config/app-config.d.ts +15 -0
- package/dist/config/app-config.d.ts.map +1 -1
- package/dist/config/app-config.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/runtime/configuration-group-authorization.d.ts +50 -0
- package/dist/runtime/configuration-group-authorization.d.ts.map +1 -0
- package/dist/runtime/configuration-group-authorization.js +113 -0
- package/dist/runtime/configuration-group-authorization.js.map +1 -0
- package/dist/runtime/configuration-group-contract.d.ts +75 -0
- package/dist/runtime/configuration-group-contract.d.ts.map +1 -0
- package/dist/runtime/configuration-group-contract.js +233 -0
- package/dist/runtime/configuration-group-contract.js.map +1 -0
- package/dist/runtime/mqtt-output-state-contract.d.ts +27 -0
- package/dist/runtime/mqtt-output-state-contract.d.ts.map +1 -0
- package/dist/runtime/mqtt-output-state-contract.js +32 -0
- package/dist/runtime/mqtt-output-state-contract.js.map +1 -0
- package/dist/runtime/mqtt-output-state-contract.json +8 -0
- package/dist/runtime/mqtt-output-state-program.d.mts +28 -0
- package/dist/runtime/mqtt-output-state-program.mjs +511 -0
- package/dist/runtime/process-group-authorization.d.ts +2 -0
- package/dist/runtime/process-group-authorization.d.ts.map +1 -1
- package/dist/runtime/process-group-authorization.js +34 -12
- package/dist/runtime/process-group-authorization.js.map +1 -1
- package/dist/runtime/process-group-backup-contract.d.ts +22 -0
- package/dist/runtime/process-group-backup-contract.d.ts.map +1 -0
- package/dist/runtime/process-group-backup-contract.js +20 -0
- package/dist/runtime/process-group-backup-contract.js.map +1 -0
- package/dist/runtime/process-group-backup-contract.json +7 -0
- package/dist/runtime/process-group-configured-upgrade.d.ts +4 -0
- package/dist/runtime/process-group-configured-upgrade.d.ts.map +1 -0
- package/dist/runtime/process-group-configured-upgrade.js +107 -0
- package/dist/runtime/process-group-configured-upgrade.js.map +1 -0
- package/dist/runtime/process-group-generation.d.ts +166 -0
- package/dist/runtime/process-group-generation.d.ts.map +1 -0
- package/dist/runtime/process-group-generation.js +278 -0
- package/dist/runtime/process-group-generation.js.map +1 -0
- package/dist/runtime/process-group-inspection.d.ts +2 -0
- package/dist/runtime/process-group-inspection.d.ts.map +1 -1
- package/dist/runtime/process-group-inspection.js +120 -40
- package/dist/runtime/process-group-inspection.js.map +1 -1
- package/dist/runtime/process-group-resources.d.ts +1 -0
- package/dist/runtime/process-group-resources.d.ts.map +1 -1
- package/dist/runtime/process-group-resources.js +8 -0
- package/dist/runtime/process-group-resources.js.map +1 -1
- package/dist/runtime/process-group-runtime-selection.d.ts +14 -0
- package/dist/runtime/process-group-runtime-selection.d.ts.map +1 -0
- package/dist/runtime/process-group-runtime-selection.js +29 -0
- package/dist/runtime/process-group-runtime-selection.js.map +1 -0
- package/dist/runtime/process-group-snapshot.mjs +60 -8
- package/dist/runtime/process-group-staging.d.ts +2 -2
- package/dist/runtime/process-group-staging.d.ts.map +1 -1
- package/dist/runtime/process-group-staging.js +6 -4
- package/dist/runtime/process-group-staging.js.map +1 -1
- package/dist/runtime/process-group-supervision.d.ts +2 -2
- package/dist/runtime/process-group-supervision.d.ts.map +1 -1
- package/dist/runtime/process-group-supervision.js +3 -2
- package/dist/runtime/process-group-supervision.js.map +1 -1
- package/dist/runtime/process-group-upgrade.d.ts +76 -6
- package/dist/runtime/process-group-upgrade.d.ts.map +1 -1
- package/dist/runtime/process-group-upgrade.js +7 -1
- package/dist/runtime/process-group-upgrade.js.map +1 -1
- package/dist/uns/uns-interfaces.d.ts +3 -0
- package/dist/uns/uns-interfaces.d.ts.map +1 -1
- package/dist/uns/uns-interfaces.js.map +1 -1
- package/dist/uns/uns-proxy-process.d.ts.map +1 -1
- package/dist/uns/uns-proxy-process.js +3 -0
- package/dist/uns/uns-proxy-process.js.map +1 -1
- package/dist/uns-config/config-schema.d.ts +20 -0
- package/dist/uns-config/config-schema.d.ts.map +1 -1
- package/dist/uns-config/mqtt-channel.d.ts +1 -1
- package/dist/uns-config/mqtt-channel.d.ts.map +1 -1
- package/dist/uns-config/mqtt-channel.js +3 -0
- package/dist/uns-config/mqtt-channel.js.map +1 -1
- package/dist/uns-config/uns-core-schema.d.ts +145 -0
- package/dist/uns-config/uns-core-schema.d.ts.map +1 -1
- package/dist/uns-config/uns-core-schema.js +6 -1
- package/dist/uns-config/uns-core-schema.js.map +1 -1
- package/dist/uns-mqtt/mqtt-interfaces.d.ts +5 -0
- package/dist/uns-mqtt/mqtt-interfaces.d.ts.map +1 -1
- package/dist/uns-mqtt/mqtt-interfaces.js.map +1 -1
- package/dist/uns-mqtt/mqtt-proxy.d.ts +3 -0
- package/dist/uns-mqtt/mqtt-proxy.d.ts.map +1 -1
- package/dist/uns-mqtt/mqtt-proxy.js +26 -1
- package/dist/uns-mqtt/mqtt-proxy.js.map +1 -1
- package/dist/uns-mqtt/mqtt-worker.d.ts +3 -1
- package/dist/uns-mqtt/mqtt-worker.d.ts.map +1 -1
- package/dist/uns-mqtt/mqtt-worker.js +45 -8
- package/dist/uns-mqtt/mqtt-worker.js.map +1 -1
- package/dist/uns-mqtt/publish-queue-contract.d.ts +37 -0
- package/dist/uns-mqtt/publish-queue-contract.d.ts.map +1 -0
- package/dist/uns-mqtt/publish-queue-contract.js +19 -0
- package/dist/uns-mqtt/publish-queue-contract.js.map +1 -0
- package/dist/uns-mqtt/publish-queue-store.d.ts +34 -0
- package/dist/uns-mqtt/publish-queue-store.d.ts.map +1 -0
- package/dist/uns-mqtt/publish-queue-store.js +176 -0
- package/dist/uns-mqtt/publish-queue-store.js.map +1 -0
- package/dist/uns-mqtt/publish-queue.d.ts +43 -0
- package/dist/uns-mqtt/publish-queue.d.ts.map +1 -0
- package/dist/uns-mqtt/publish-queue.js +235 -0
- package/dist/uns-mqtt/publish-queue.js.map +1 -0
- package/dist/uns-mqtt/uns-mqtt-proxy.d.ts +7 -0
- package/dist/uns-mqtt/uns-mqtt-proxy.d.ts.map +1 -1
- package/dist/uns-mqtt/uns-mqtt-proxy.js +98 -5
- package/dist/uns-mqtt/uns-mqtt-proxy.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { configurationGroupJournalContract, configurationGroupJournalSchema } from "./configuration-group-contract.js";
|
|
6
|
+
import { authorizeProcessGroupRuntime } from "./process-group-authorization.js";
|
|
7
|
+
import { processGroupManifestSchema } from "./process-group-authorization.js";
|
|
8
|
+
import { processGroupJournalContract, processGroupJournalSchema, processGroupSourceIdentity, resolvedProcessGroupChannels, } from "./process-group-contract.js";
|
|
9
|
+
import { groupPlacementSchema, placementKey } from "./process-group-control-contract.js";
|
|
10
|
+
import { groupArtifactHash, groupChannelsHash, configurationAuthorizationHash as hash, readProcessGroupResource as read, sha256, } from "./process-group-resources.js";
|
|
11
|
+
import { normalizeRuntimeProcessGroup, selectedProcessGroupDescriptor } from "./process-group-runtime-selection.js";
|
|
12
|
+
const pair = z.strictObject({ publisher: groupPlacementSchema, receiver: groupPlacementSchema });
|
|
13
|
+
export const processGroupGenerationInputSchema = z
|
|
14
|
+
.strictObject({
|
|
15
|
+
protocolVersion: z.literal(2),
|
|
16
|
+
source: pair,
|
|
17
|
+
target: pair,
|
|
18
|
+
acknowledgeInputPause: z.literal(true),
|
|
19
|
+
acknowledgeResourceReview: z.literal(true),
|
|
20
|
+
acknowledgePossibleReplay: z.literal(true),
|
|
21
|
+
})
|
|
22
|
+
.superRefine((v, c) => {
|
|
23
|
+
const all = [v.source.publisher, v.source.receiver, v.target.publisher, v.target.receiver];
|
|
24
|
+
if (new Set(all.map(placementKey)).size !== 4 ||
|
|
25
|
+
all.some((p) => p.controller !== all[0].controller || p.rttNode !== all[0].rttNode) ||
|
|
26
|
+
v.source.publisher.version !== v.source.receiver.version ||
|
|
27
|
+
v.target.publisher.version !== v.target.receiver.version)
|
|
28
|
+
c.addIssue({ code: "custom", message: "Four distinct paired placements on one package/controller required" });
|
|
29
|
+
});
|
|
30
|
+
/** Bounded read-only storage evidence; no initializer, rewriting or replay. */
|
|
31
|
+
export function inspectGenerationJournal(reference) {
|
|
32
|
+
const file = path.join(reference.directory, "admission.sqlite"), stat = fs.lstatSync(file);
|
|
33
|
+
if (fs.realpathSync(file) !== file ||
|
|
34
|
+
!stat.isFile() ||
|
|
35
|
+
stat.nlink !== 1 ||
|
|
36
|
+
stat.uid !== process.getuid?.() ||
|
|
37
|
+
(stat.mode & 0o077) !== 0 ||
|
|
38
|
+
stat.size > 512 * 1024 * 1024)
|
|
39
|
+
throw Error("Private retained generation journal required");
|
|
40
|
+
const { DatabaseSync } = createRequire(import.meta.url)("node:sqlite");
|
|
41
|
+
const db = new DatabaseSync(file, { readOnly: true });
|
|
42
|
+
try {
|
|
43
|
+
db.exec("PRAGMA query_only=ON; PRAGMA busy_timeout=1000; BEGIN");
|
|
44
|
+
const meta = Object.fromEntries(db
|
|
45
|
+
.prepare("SELECT key,value FROM metadata WHERE key IN ('id','contract')")
|
|
46
|
+
.all()
|
|
47
|
+
.map((r) => [r["key"], r["value"]]));
|
|
48
|
+
if (meta["id"] !== reference.journalId ||
|
|
49
|
+
typeof meta["contract"] !== "string" ||
|
|
50
|
+
meta["contract"].length > 1048576 ||
|
|
51
|
+
sha256(meta["contract"]) !== reference.journalContractSha256)
|
|
52
|
+
throw Error("Reviewed journal generation changed");
|
|
53
|
+
const rows = db.prepare("SELECT name,contract,completed,last_seq FROM profiles ORDER BY name").all();
|
|
54
|
+
if (rows.length !== reference.profiles.length)
|
|
55
|
+
throw Error("Journal profile set differs");
|
|
56
|
+
for (const profile of reference.profiles) {
|
|
57
|
+
const row = rows.find((r) => r["name"] === profile.processName), binding = row ? JSON.parse(String(row["contract"])) : null;
|
|
58
|
+
if (!binding ||
|
|
59
|
+
binding.processName !== profile.processName ||
|
|
60
|
+
binding.dataGroup !== profile.dataGroup ||
|
|
61
|
+
binding[reference.contractVersion === 1 ? "mappingSha256" : "resourceSha256"] !== profile.mappingSha256)
|
|
62
|
+
throw Error("Journal resource binding differs");
|
|
63
|
+
}
|
|
64
|
+
const usage = db.prepare("SELECT records,bytes,admitted FROM usage WHERE id=1").get();
|
|
65
|
+
const actual = db.prepare("SELECT count(*) records,coalesce(sum(bytes),0) bytes FROM tasks").get();
|
|
66
|
+
const numbers = [usage?.["records"], usage?.["bytes"], usage?.["admitted"], ...rows.flatMap((r) => [r["completed"], r["last_seq"]])];
|
|
67
|
+
const completed = rows.reduce((n, r) => n + Number(r["completed"]), 0);
|
|
68
|
+
if (!usage ||
|
|
69
|
+
!actual ||
|
|
70
|
+
numbers.some((n) => typeof n !== "number" || !Number.isSafeInteger(n) || n < 0) ||
|
|
71
|
+
usage["records"] !== actual["records"] ||
|
|
72
|
+
usage["bytes"] !== actual["bytes"] ||
|
|
73
|
+
!Number.isSafeInteger(completed) ||
|
|
74
|
+
Number(usage["admitted"]) !== completed + Number(usage["records"]) ||
|
|
75
|
+
rows.some((r) => (r["completed"] === 0) !== (r["last_seq"] === 0)) ||
|
|
76
|
+
Number(usage["records"]) > reference.maxRecords ||
|
|
77
|
+
Number(usage["bytes"]) > reference.maxBytes)
|
|
78
|
+
throw Error("Journal usage is unconfirmed");
|
|
79
|
+
return {
|
|
80
|
+
records: Number(usage["records"]),
|
|
81
|
+
bytes: Number(usage["bytes"]),
|
|
82
|
+
admitted: Number(usage["admitted"]),
|
|
83
|
+
completed,
|
|
84
|
+
lastSequence: rows.reduce((n, r) => Math.max(n, Number(r["last_seq"])), 0),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
try {
|
|
89
|
+
db.exec("ROLLBACK");
|
|
90
|
+
}
|
|
91
|
+
finally {
|
|
92
|
+
db.close();
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/** Recheck immediately before the first launch; initialization is never silently reused. */
|
|
97
|
+
export function inspectPristineGenerationJournal(reference) {
|
|
98
|
+
const status = inspectGenerationJournal(reference);
|
|
99
|
+
if (status.records || status.bytes || status.admitted || status.completed || status.lastSequence)
|
|
100
|
+
throw Error("Target generation is not pristine; inspect the existing initialization outcome");
|
|
101
|
+
return status;
|
|
102
|
+
}
|
|
103
|
+
/** Data-only normalized revision and immutable journal contract shared by reviewed transitions. */
|
|
104
|
+
export function describeInstalledProcessGroupGeneration(c) {
|
|
105
|
+
const d = selectedProcessGroupDescriptor(c.packageRoot, c.raw);
|
|
106
|
+
if (!d)
|
|
107
|
+
throw Error("Declared process group required");
|
|
108
|
+
const normalized = normalizeRuntimeProcessGroup(c.raw, d);
|
|
109
|
+
if (!normalized.matches)
|
|
110
|
+
throw Error("Runtime selector differs");
|
|
111
|
+
const channels = resolvedProcessGroupChannels(c.resolved), sourceIdentity = processGroupSourceIdentity(channels[1]);
|
|
112
|
+
if (d.protocolVersion === 2) {
|
|
113
|
+
const snapshot = normalized.configurationSnapshot;
|
|
114
|
+
const journal = configurationGroupJournalSchema.parse(normalized.journal);
|
|
115
|
+
const contract = configurationGroupJournalContract(snapshot, sourceIdentity, journal, snapshot.profiles.map(({ processName, resourceSha256, dataGroup }) => ({ processName, resourceSha256, dataGroup })));
|
|
116
|
+
return {
|
|
117
|
+
d,
|
|
118
|
+
normalized,
|
|
119
|
+
channels,
|
|
120
|
+
id: snapshot.group.id,
|
|
121
|
+
processName: snapshot.group.processName,
|
|
122
|
+
receiverProcessName: snapshot.group.receiverProcessName,
|
|
123
|
+
inputTopic: snapshot.group.inputTopic,
|
|
124
|
+
reference: {
|
|
125
|
+
directory: journal.directory,
|
|
126
|
+
journalId: journal.journalId,
|
|
127
|
+
generationId: journal.generationId,
|
|
128
|
+
groupSha256: snapshot.sha256,
|
|
129
|
+
contractVersion: 2,
|
|
130
|
+
journalContractSha256: sha256(contract),
|
|
131
|
+
maxRecords: journal.maxRecords,
|
|
132
|
+
maxBytes: journal.maxBytes,
|
|
133
|
+
minFreeBytes: journal.minFreeBytes,
|
|
134
|
+
profiles: snapshot.profiles.map(({ processName, resourceSha256, dataGroup }) => ({ processName, mappingSha256: resourceSha256, dataGroup })),
|
|
135
|
+
},
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
const journal = processGroupJournalSchema.parse(normalized.journal);
|
|
139
|
+
if (!d.manifests.some((m) => m.file === journal.groupManifest))
|
|
140
|
+
throw Error("Registered file group required");
|
|
141
|
+
const group = processGroupManifestSchema.parse(JSON.parse(read(path.resolve(c.packageRoot, journal.groupManifest)).toString()));
|
|
142
|
+
const contract = processGroupJournalContract(sourceIdentity, journal, group.profiles);
|
|
143
|
+
return {
|
|
144
|
+
d,
|
|
145
|
+
normalized,
|
|
146
|
+
channels,
|
|
147
|
+
id: group.id,
|
|
148
|
+
processName: group.processName,
|
|
149
|
+
receiverProcessName: group.processName + "-admission",
|
|
150
|
+
inputTopic: group.inputTopic,
|
|
151
|
+
reference: {
|
|
152
|
+
directory: journal.directory,
|
|
153
|
+
journalId: journal.journalId,
|
|
154
|
+
generationId: group.id,
|
|
155
|
+
contractVersion: 1,
|
|
156
|
+
journalContractSha256: sha256(contract),
|
|
157
|
+
maxRecords: journal.maxRecords,
|
|
158
|
+
maxBytes: journal.maxBytes,
|
|
159
|
+
minFreeBytes: journal.minFreeBytes,
|
|
160
|
+
profiles: group.profiles.map(({ processName, mappingSha256, dataGroup }) => ({ processName, mappingSha256, dataGroup })),
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/** Operator reviews opaque before/after digests; business equivalence is application-owned. */
|
|
165
|
+
export function reviewInstalledProcessGroupGeneration(configs, controllerName, stateRoot, excludedUnsFields = []) {
|
|
166
|
+
const context = (c) => ({
|
|
167
|
+
packageRoot: c.packageRoot,
|
|
168
|
+
instanceDirectory: c.instanceDirectory,
|
|
169
|
+
rawConfiguration: c.raw,
|
|
170
|
+
channels: resolvedProcessGroupChannels(c.resolved),
|
|
171
|
+
controllerName,
|
|
172
|
+
stateRoot,
|
|
173
|
+
});
|
|
174
|
+
const a = describeInstalledProcessGroupGeneration(configs.source.publisher), b = describeInstalledProcessGroupGeneration(configs.target.publisher);
|
|
175
|
+
if (b.d.protocolVersion !== 2 ||
|
|
176
|
+
a.d.namespace !== b.d.namespace ||
|
|
177
|
+
a.id !== b.id ||
|
|
178
|
+
a.processName !== b.processName ||
|
|
179
|
+
a.receiverProcessName !== b.receiverProcessName ||
|
|
180
|
+
a.inputTopic !== b.inputTopic ||
|
|
181
|
+
a.reference.directory === b.reference.directory ||
|
|
182
|
+
!a.reference.journalId ||
|
|
183
|
+
!b.reference.journalId ||
|
|
184
|
+
a.reference.journalId === b.reference.journalId ||
|
|
185
|
+
a.reference.maxRecords !== b.reference.maxRecords ||
|
|
186
|
+
a.reference.maxBytes !== b.reference.maxBytes ||
|
|
187
|
+
a.reference.minFreeBytes !== b.reference.minFreeBytes)
|
|
188
|
+
throw Error("Distinct bounded generations with the same process/input identity required");
|
|
189
|
+
const policyFiles = {}, policies = {};
|
|
190
|
+
const members = [];
|
|
191
|
+
const portable = (raw, d) => {
|
|
192
|
+
const copy = structuredClone(raw), uns = { ...copy["uns"] };
|
|
193
|
+
for (const key of excludedUnsFields)
|
|
194
|
+
delete uns[key];
|
|
195
|
+
copy["uns"] = uns;
|
|
196
|
+
for (const keys of [d.publisherPath, d.journalPath, d.runtimeRolePath]) {
|
|
197
|
+
let node = copy;
|
|
198
|
+
let present = true;
|
|
199
|
+
for (const key of keys.slice(0, -1)) {
|
|
200
|
+
const child = node[key];
|
|
201
|
+
if (child === undefined) {
|
|
202
|
+
present = false;
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
205
|
+
if (!child || typeof child !== "object" || Array.isArray(child))
|
|
206
|
+
throw Error("Invalid resource selector parent");
|
|
207
|
+
node = child;
|
|
208
|
+
}
|
|
209
|
+
if (present)
|
|
210
|
+
delete node[keys.at(-1)];
|
|
211
|
+
}
|
|
212
|
+
return hash(copy);
|
|
213
|
+
};
|
|
214
|
+
for (const side of ["source", "target"])
|
|
215
|
+
for (const role of ["publisher", "receiver"]) {
|
|
216
|
+
const c = configs[side][role], g = describeInstalledProcessGroupGeneration(c), expected = side === "source" ? a : b, proof = authorizeProcessGroupRuntime(context(c));
|
|
217
|
+
if (proof.role !== (role === "publisher" ? "target" : "receiver") ||
|
|
218
|
+
proof.directory !== expected.reference.directory ||
|
|
219
|
+
proof.journalId !== expected.reference.journalId ||
|
|
220
|
+
hash(g.reference) !== hash(expected.reference) ||
|
|
221
|
+
g.normalized.uns["processName"] !== (role === "publisher" ? g.processName : g.receiverProcessName) ||
|
|
222
|
+
(role === "receiver"
|
|
223
|
+
? g.normalized.runtimeRole !== "admission"
|
|
224
|
+
: g.normalized.runtimeRole !== undefined && g.normalized.runtimeRole !== "publisher"))
|
|
225
|
+
throw Error("Exact reviewed generation pair required");
|
|
226
|
+
const pkg = JSON.parse(read(path.join(c.packageRoot, "package.json")).toString());
|
|
227
|
+
if (pkg.name !== JSON.parse(read(path.join(configs.source.publisher.packageRoot, "package.json")).toString()).name ||
|
|
228
|
+
portable(c.raw, g.d) !== portable(configs.source[role].raw, a.d) ||
|
|
229
|
+
groupChannelsHash(g.channels) !== groupChannelsHash(a.channels))
|
|
230
|
+
throw Error("Configuration or broker identity changed outside the reviewed resources");
|
|
231
|
+
if (policyFiles[side] && policyFiles[side] !== proof.file)
|
|
232
|
+
throw Error("Pair policies differ");
|
|
233
|
+
policyFiles[side] = proof.file;
|
|
234
|
+
policies[side] = read(proof.file, true);
|
|
235
|
+
members.push({
|
|
236
|
+
side,
|
|
237
|
+
role,
|
|
238
|
+
processName: String(g.normalized.uns["processName"]),
|
|
239
|
+
configurationSha256: hash(c.raw),
|
|
240
|
+
artifactSha256: groupArtifactHash(c.packageRoot),
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
if (policyFiles.source === policyFiles.target)
|
|
244
|
+
throw Error("Each generation requires its own retained policy");
|
|
245
|
+
const profiles = a.reference.profiles;
|
|
246
|
+
if (profiles.length !== b.reference.profiles.length ||
|
|
247
|
+
profiles.some((p) => !b.reference.profiles.some((q) => q.processName === p.processName && q.dataGroup === p.dataGroup)))
|
|
248
|
+
throw Error("Logical profile identities or data groups changed");
|
|
249
|
+
inspectGenerationJournal(a.reference);
|
|
250
|
+
inspectPristineGenerationJournal(b.reference);
|
|
251
|
+
if (sha256(read(policyFiles.source, true)) !== sha256(policies.source) || sha256(read(policyFiles.target, true)) !== sha256(policies.target))
|
|
252
|
+
throw Error("Reviewed policies changed");
|
|
253
|
+
const review = {
|
|
254
|
+
protocolVersion: 2,
|
|
255
|
+
namespace: b.d.namespace,
|
|
256
|
+
groupId: b.id,
|
|
257
|
+
policyFile: policyFiles.target,
|
|
258
|
+
sourcePolicyFile: policyFiles.source,
|
|
259
|
+
sourcePolicySha256: sha256(policies.source),
|
|
260
|
+
targetPolicySha256: sha256(policies.target),
|
|
261
|
+
journalId: b.reference.journalId,
|
|
262
|
+
directory: b.reference.directory,
|
|
263
|
+
journalContractSha256: b.reference.journalContractSha256,
|
|
264
|
+
profiles: b.reference.profiles,
|
|
265
|
+
members,
|
|
266
|
+
sourceJournal: a.reference,
|
|
267
|
+
targetJournal: b.reference,
|
|
268
|
+
delivery: { inputPausePossible: true, retainedBrokerSessionMayReplay: true, exactlyOnceOutput: false },
|
|
269
|
+
resourceChanges: profiles.map((p) => ({
|
|
270
|
+
processName: p.processName,
|
|
271
|
+
beforeSha256: p.mappingSha256,
|
|
272
|
+
afterSha256: b.reference.profiles.find((q) => q.processName === p.processName).mappingSha256,
|
|
273
|
+
dataGroup: p.dataGroup,
|
|
274
|
+
})),
|
|
275
|
+
};
|
|
276
|
+
return { review, sourcePolicy: policies.source, targetPolicy: policies.target };
|
|
277
|
+
}
|
|
278
|
+
//# sourceMappingURL=process-group-generation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-group-generation.js","sourceRoot":"","sources":["../../src/runtime/process-group-generation.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\n\nimport { configurationGroupJournalContract, configurationGroupJournalSchema } from \"./configuration-group-contract.js\";\nimport { authorizeProcessGroupRuntime } from \"./process-group-authorization.js\";\nimport { processGroupManifestSchema } from \"./process-group-authorization.js\";\nimport {\n processGroupJournalContract,\n processGroupJournalSchema,\n processGroupSourceIdentity,\n resolvedProcessGroupChannels,\n} from \"./process-group-contract.js\";\nimport { groupPlacementSchema, placementKey } from \"./process-group-control-contract.js\";\nimport {\n groupArtifactHash,\n groupChannelsHash,\n configurationAuthorizationHash as hash,\n readProcessGroupResource as read,\n sha256,\n} from \"./process-group-resources.js\";\nimport { normalizeRuntimeProcessGroup, selectedProcessGroupDescriptor } from \"./process-group-runtime-selection.js\";\nimport type { GroupVersionUpgradeReview, PreparedGroupUpgrade, UpgradeConfiguration, UpgradeConfigurations } from \"./process-group-upgrade.js\";\n\nconst pair = z.strictObject({ publisher: groupPlacementSchema, receiver: groupPlacementSchema });\nexport const processGroupGenerationInputSchema = z\n .strictObject({\n protocolVersion: z.literal(2),\n source: pair,\n target: pair,\n acknowledgeInputPause: z.literal(true),\n acknowledgeResourceReview: z.literal(true),\n acknowledgePossibleReplay: z.literal(true),\n })\n .superRefine((v, c) => {\n const all = [v.source.publisher, v.source.receiver, v.target.publisher, v.target.receiver];\n if (\n new Set(all.map(placementKey)).size !== 4 ||\n all.some((p) => p.controller !== all[0]!.controller || p.rttNode !== all[0]!.rttNode) ||\n v.source.publisher.version !== v.source.receiver.version ||\n v.target.publisher.version !== v.target.receiver.version\n )\n c.addIssue({ code: \"custom\", message: \"Four distinct paired placements on one package/controller required\" });\n });\nexport type ProcessGroupGenerationInput = z.infer<typeof processGroupGenerationInputSchema>;\nexport type GenerationJournalReference = {\n directory: string;\n journalId: string;\n journalContractSha256: string;\n generationId: string;\n groupSha256?: string;\n contractVersion: 1 | 2;\n maxRecords: number;\n maxBytes: number;\n minFreeBytes: number;\n profiles: Array<{ processName: string; mappingSha256: string; dataGroup: string }>;\n};\nexport type GroupGenerationReview = Omit<GroupVersionUpgradeReview, \"protocolVersion\"> & {\n protocolVersion: 2;\n sourcePolicyFile: string;\n sourceJournal: GenerationJournalReference;\n targetJournal: GenerationJournalReference;\n delivery: { inputPausePossible: true; retainedBrokerSessionMayReplay: true; exactlyOnceOutput: false };\n resourceChanges: Array<{ processName: string; beforeSha256: string; afterSha256: string; dataGroup: string }>;\n};\n\n/** Bounded read-only storage evidence; no initializer, rewriting or replay. */\nexport function inspectGenerationJournal(reference: GenerationJournalReference) {\n const file = path.join(reference.directory, \"admission.sqlite\"),\n stat = fs.lstatSync(file);\n if (\n fs.realpathSync(file) !== file ||\n !stat.isFile() ||\n stat.nlink !== 1 ||\n stat.uid !== process.getuid?.() ||\n (stat.mode & 0o077) !== 0 ||\n stat.size > 512 * 1024 * 1024\n )\n throw Error(\"Private retained generation journal required\");\n const { DatabaseSync } = createRequire(import.meta.url)(\"node:sqlite\") as typeof import(\"node:sqlite\");\n const db = new DatabaseSync(file, { readOnly: true });\n try {\n db.exec(\"PRAGMA query_only=ON; PRAGMA busy_timeout=1000; BEGIN\");\n const meta = Object.fromEntries(\n db\n .prepare(\"SELECT key,value FROM metadata WHERE key IN ('id','contract')\")\n .all()\n .map((r) => [r[\"key\"], r[\"value\"]]),\n );\n if (\n meta[\"id\"] !== reference.journalId ||\n typeof meta[\"contract\"] !== \"string\" ||\n meta[\"contract\"].length > 1048576 ||\n sha256(meta[\"contract\"]) !== reference.journalContractSha256\n )\n throw Error(\"Reviewed journal generation changed\");\n const rows = db.prepare(\"SELECT name,contract,completed,last_seq FROM profiles ORDER BY name\").all();\n if (rows.length !== reference.profiles.length) throw Error(\"Journal profile set differs\");\n for (const profile of reference.profiles) {\n const row = rows.find((r) => r[\"name\"] === profile.processName),\n binding = row ? JSON.parse(String(row[\"contract\"])) : null;\n if (\n !binding ||\n binding.processName !== profile.processName ||\n binding.dataGroup !== profile.dataGroup ||\n binding[reference.contractVersion === 1 ? \"mappingSha256\" : \"resourceSha256\"] !== profile.mappingSha256\n )\n throw Error(\"Journal resource binding differs\");\n }\n const usage = db.prepare(\"SELECT records,bytes,admitted FROM usage WHERE id=1\").get();\n const actual = db.prepare(\"SELECT count(*) records,coalesce(sum(bytes),0) bytes FROM tasks\").get();\n const numbers = [usage?.[\"records\"], usage?.[\"bytes\"], usage?.[\"admitted\"], ...rows.flatMap((r) => [r[\"completed\"], r[\"last_seq\"]])];\n const completed = rows.reduce((n, r) => n + Number(r[\"completed\"]), 0);\n if (\n !usage ||\n !actual ||\n numbers.some((n) => typeof n !== \"number\" || !Number.isSafeInteger(n) || n < 0) ||\n usage[\"records\"] !== actual[\"records\"] ||\n usage[\"bytes\"] !== actual[\"bytes\"] ||\n !Number.isSafeInteger(completed) ||\n Number(usage[\"admitted\"]) !== completed + Number(usage[\"records\"]) ||\n rows.some((r) => (r[\"completed\"] === 0) !== (r[\"last_seq\"] === 0)) ||\n Number(usage[\"records\"]) > reference.maxRecords ||\n Number(usage[\"bytes\"]) > reference.maxBytes\n )\n throw Error(\"Journal usage is unconfirmed\");\n return {\n records: Number(usage[\"records\"]),\n bytes: Number(usage[\"bytes\"]),\n admitted: Number(usage[\"admitted\"]),\n completed,\n lastSequence: rows.reduce((n, r) => Math.max(n, Number(r[\"last_seq\"])), 0),\n };\n } finally {\n try {\n db.exec(\"ROLLBACK\");\n } finally {\n db.close();\n }\n }\n}\n\n/** Recheck immediately before the first launch; initialization is never silently reused. */\nexport function inspectPristineGenerationJournal(reference: GenerationJournalReference) {\n const status = inspectGenerationJournal(reference);\n if (status.records || status.bytes || status.admitted || status.completed || status.lastSequence)\n throw Error(\"Target generation is not pristine; inspect the existing initialization outcome\");\n return status;\n}\n\n/** Data-only normalized revision and immutable journal contract shared by reviewed transitions. */\nexport function describeInstalledProcessGroupGeneration(c: UpgradeConfiguration) {\n const d = selectedProcessGroupDescriptor(c.packageRoot, c.raw);\n if (!d) throw Error(\"Declared process group required\");\n const normalized = normalizeRuntimeProcessGroup(c.raw, d);\n if (!normalized.matches) throw Error(\"Runtime selector differs\");\n const channels = resolvedProcessGroupChannels(c.resolved),\n sourceIdentity = processGroupSourceIdentity(channels[1]!);\n if (d.protocolVersion === 2) {\n const snapshot = normalized.configurationSnapshot!;\n const journal = configurationGroupJournalSchema.parse(normalized.journal);\n const contract = configurationGroupJournalContract(\n snapshot,\n sourceIdentity,\n journal,\n snapshot.profiles.map(({ processName, resourceSha256, dataGroup }) => ({ processName, resourceSha256, dataGroup })),\n );\n return {\n d,\n normalized,\n channels,\n id: snapshot.group.id,\n processName: snapshot.group.processName,\n receiverProcessName: snapshot.group.receiverProcessName,\n inputTopic: snapshot.group.inputTopic,\n reference: {\n directory: journal.directory,\n journalId: journal.journalId!,\n generationId: journal.generationId,\n groupSha256: snapshot.sha256,\n contractVersion: 2 as const,\n journalContractSha256: sha256(contract),\n maxRecords: journal.maxRecords,\n maxBytes: journal.maxBytes,\n minFreeBytes: journal.minFreeBytes,\n profiles: snapshot.profiles.map(({ processName, resourceSha256, dataGroup }) => ({ processName, mappingSha256: resourceSha256, dataGroup })),\n },\n };\n }\n const journal = processGroupJournalSchema.parse(normalized.journal);\n if (!d.manifests.some((m) => m.file === journal.groupManifest)) throw Error(\"Registered file group required\");\n const group = processGroupManifestSchema.parse(JSON.parse(read(path.resolve(c.packageRoot, journal.groupManifest)).toString()));\n const contract = processGroupJournalContract(sourceIdentity, journal, group.profiles);\n return {\n d,\n normalized,\n channels,\n id: group.id,\n processName: group.processName,\n receiverProcessName: group.processName + \"-admission\",\n inputTopic: group.inputTopic,\n reference: {\n directory: journal.directory,\n journalId: journal.journalId!,\n generationId: group.id,\n contractVersion: 1 as const,\n journalContractSha256: sha256(contract),\n maxRecords: journal.maxRecords,\n maxBytes: journal.maxBytes,\n minFreeBytes: journal.minFreeBytes,\n profiles: group.profiles.map(({ processName, mappingSha256, dataGroup }) => ({ processName, mappingSha256, dataGroup })),\n },\n };\n}\n\n/** Operator reviews opaque before/after digests; business equivalence is application-owned. */\nexport function reviewInstalledProcessGroupGeneration(\n configs: UpgradeConfigurations,\n controllerName: string,\n stateRoot: string,\n excludedUnsFields: readonly string[] = [],\n): PreparedGroupUpgrade {\n const context = (c: UpgradeConfiguration) => ({\n packageRoot: c.packageRoot,\n instanceDirectory: c.instanceDirectory,\n rawConfiguration: c.raw,\n channels: resolvedProcessGroupChannels(c.resolved),\n controllerName,\n stateRoot,\n });\n const a = describeInstalledProcessGroupGeneration(configs.source.publisher),\n b = describeInstalledProcessGroupGeneration(configs.target.publisher);\n if (\n b.d.protocolVersion !== 2 ||\n a.d.namespace !== b.d.namespace ||\n a.id !== b.id ||\n a.processName !== b.processName ||\n a.receiverProcessName !== b.receiverProcessName ||\n a.inputTopic !== b.inputTopic ||\n a.reference.directory === b.reference.directory ||\n !a.reference.journalId ||\n !b.reference.journalId ||\n a.reference.journalId === b.reference.journalId ||\n a.reference.maxRecords !== b.reference.maxRecords ||\n a.reference.maxBytes !== b.reference.maxBytes ||\n a.reference.minFreeBytes !== b.reference.minFreeBytes\n )\n throw Error(\"Distinct bounded generations with the same process/input identity required\");\n const policyFiles = {} as Record<\"source\" | \"target\", string>,\n policies = {} as Record<\"source\" | \"target\", Buffer>;\n const members: GroupVersionUpgradeReview[\"members\"] = [];\n const portable = (raw: Record<string, unknown>, d: typeof a.d) => {\n const copy = structuredClone(raw),\n uns = { ...(copy[\"uns\"] as Record<string, unknown>) };\n for (const key of excludedUnsFields) delete uns[key];\n copy[\"uns\"] = uns;\n for (const keys of [d.publisherPath, d.journalPath, d.runtimeRolePath]) {\n let node = copy;\n let present = true;\n for (const key of keys.slice(0, -1)) {\n const child = node[key];\n if (child === undefined) {\n present = false;\n break;\n }\n if (!child || typeof child !== \"object\" || Array.isArray(child)) throw Error(\"Invalid resource selector parent\");\n node = child as Record<string, unknown>;\n }\n if (present) delete node[keys.at(-1)!];\n }\n return hash(copy);\n };\n for (const side of [\"source\", \"target\"] as const)\n for (const role of [\"publisher\", \"receiver\"] as const) {\n const c = configs[side][role],\n g = describeInstalledProcessGroupGeneration(c),\n expected = side === \"source\" ? a : b,\n proof = authorizeProcessGroupRuntime(context(c));\n if (\n proof.role !== (role === \"publisher\" ? \"target\" : \"receiver\") ||\n proof.directory !== expected.reference.directory ||\n proof.journalId !== expected.reference.journalId ||\n hash(g.reference) !== hash(expected.reference) ||\n g.normalized.uns[\"processName\"] !== (role === \"publisher\" ? g.processName : g.receiverProcessName) ||\n (role === \"receiver\"\n ? g.normalized.runtimeRole !== \"admission\"\n : g.normalized.runtimeRole !== undefined && g.normalized.runtimeRole !== \"publisher\")\n )\n throw Error(\"Exact reviewed generation pair required\");\n const pkg = JSON.parse(read(path.join(c.packageRoot, \"package.json\")).toString());\n if (\n pkg.name !== JSON.parse(read(path.join(configs.source.publisher.packageRoot, \"package.json\")).toString()).name ||\n portable(c.raw, g.d) !== portable(configs.source[role].raw, a.d) ||\n groupChannelsHash(g.channels) !== groupChannelsHash(a.channels)\n )\n throw Error(\"Configuration or broker identity changed outside the reviewed resources\");\n if (policyFiles[side] && policyFiles[side] !== proof.file) throw Error(\"Pair policies differ\");\n policyFiles[side] = proof.file;\n policies[side] = read(proof.file, true);\n members.push({\n side,\n role,\n processName: String(g.normalized.uns[\"processName\"]),\n configurationSha256: hash(c.raw),\n artifactSha256: groupArtifactHash(c.packageRoot),\n });\n }\n if (policyFiles.source === policyFiles.target) throw Error(\"Each generation requires its own retained policy\");\n const profiles = a.reference.profiles;\n if (\n profiles.length !== b.reference.profiles.length ||\n profiles.some((p) => !b.reference.profiles.some((q) => q.processName === p.processName && q.dataGroup === p.dataGroup))\n )\n throw Error(\"Logical profile identities or data groups changed\");\n inspectGenerationJournal(a.reference);\n inspectPristineGenerationJournal(b.reference);\n if (sha256(read(policyFiles.source, true)) !== sha256(policies.source) || sha256(read(policyFiles.target, true)) !== sha256(policies.target))\n throw Error(\"Reviewed policies changed\");\n const review: GroupGenerationReview = {\n protocolVersion: 2,\n namespace: b.d.namespace,\n groupId: b.id,\n policyFile: policyFiles.target,\n sourcePolicyFile: policyFiles.source,\n sourcePolicySha256: sha256(policies.source),\n targetPolicySha256: sha256(policies.target),\n journalId: b.reference.journalId,\n directory: b.reference.directory,\n journalContractSha256: b.reference.journalContractSha256,\n profiles: b.reference.profiles,\n members,\n sourceJournal: a.reference,\n targetJournal: b.reference,\n delivery: { inputPausePossible: true, retainedBrokerSessionMayReplay: true, exactlyOnceOutput: false },\n resourceChanges: profiles.map((p) => ({\n processName: p.processName,\n beforeSha256: p.mappingSha256,\n afterSha256: b.reference.profiles.find((q) => q.processName === p.processName)!.mappingSha256,\n dataGroup: p.dataGroup,\n })),\n };\n return { review, sourcePolicy: policies.source, targetPolicy: policies.target };\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-group-inspection.d.ts","sourceRoot":"","sources":["../../src/runtime/process-group-inspection.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"process-group-inspection.d.ts","sourceRoot":"","sources":["../../src/runtime/process-group-inspection.ts"],"names":[],"mappings":"AAgCA,MAAM,WAAW,iCAAiC;IAChD,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,QAAQ,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,WAAW,EAAE,MAAM,CAAC;YAAC,aAAa,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,EAAE,CAAA;KAAE,GAAG,IAAI,CAAC;CACrJ;AA6BD,wBAAgB,gCAAgC,CAC9C,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,cAAc,QAA2C,EACzD,OAAO,EAAE;IAAE,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GACnG,iCAAiC,CA8GnC"}
|
|
@@ -3,7 +3,9 @@ import fs from "node:fs";
|
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
+
import { configurationGroupJournalContract, configurationGroupJournalSchema, configurationResourceHash, selectedConfigurationGroup, } from "./configuration-group-contract.js";
|
|
6
7
|
import { assertProcessGroupStateMount, authorizeConfiguredProcessGroupRuntime, configurationAuthorizationHash, hasProcessGroupAuthorization, processGroupManifestSchema as manifest, } from "./process-group-authorization.js";
|
|
8
|
+
import { readConfigurationSelector } from "./process-group-contract.js";
|
|
7
9
|
import { isLocalPilotPath, isProcessGroupJournalPath, normalizeProcessGroupConfiguration, processGroupDescriptor, processGroupJournalContract, processGroupJournalSchema, processGroupSourceIdentity, projectProcessGroupConfiguration, resolvedProcessGroupInputChannel, } from "./process-group-contract.js";
|
|
8
10
|
/** Bound reads to installed package/instance resources, never arbitrary paths or symlinks. */
|
|
9
11
|
function resource(pkg, dir, file, relativeTo) {
|
|
@@ -40,6 +42,9 @@ function resource(pkg, dir, file, relativeTo) {
|
|
|
40
42
|
const sha = (b) => createHash("sha256").update(b).digest("hex");
|
|
41
43
|
export function inspectProcessGroupConfiguration(pkg, dir, raw, controllerName = process.env["UNS_CONTROLLER_NAME"] ?? "", options) {
|
|
42
44
|
const original = JSON.parse(raw);
|
|
45
|
+
const configured = selectedConfigurationGroup(pkg, original);
|
|
46
|
+
if (configured)
|
|
47
|
+
return inspectConfigurationGroup(pkg, dir, raw, original, configured, controllerName, options);
|
|
43
48
|
const descriptor = processGroupDescriptor(pkg);
|
|
44
49
|
if (!descriptor)
|
|
45
50
|
throw Error("Installed package has no supported process-group contract");
|
|
@@ -83,46 +88,7 @@ export function inspectProcessGroupConfiguration(pkg, dir, raw, controllerName =
|
|
|
83
88
|
if (path.isAbsolute(admission.groupManifest) || admission.groupManifest.includes(".."))
|
|
84
89
|
throw Error("Admission manifest must be package-relative");
|
|
85
90
|
const admitted = manifest.parse(JSON.parse(resource(pkg, dir, admission.groupManifest).toString()));
|
|
86
|
-
|
|
87
|
-
if (fs.lstatSync(parent).isSymbolicLink())
|
|
88
|
-
throw Error("Admission directory cannot use symbolic links");
|
|
89
|
-
const databaseFile = path.join(admission.directory, "admission.sqlite");
|
|
90
|
-
if (fs.lstatSync(databaseFile).isSymbolicLink())
|
|
91
|
-
throw Error("Admission journal cannot use symbolic links");
|
|
92
|
-
const { DatabaseSync } = createRequire(import.meta.url)("node:sqlite");
|
|
93
|
-
const journal = new DatabaseSync(databaseFile, { readOnly: true });
|
|
94
|
-
try {
|
|
95
|
-
journal.exec("PRAGMA busy_timeout=1000");
|
|
96
|
-
if (persistent && journal.prepare("SELECT value FROM metadata WHERE key='id'").get()?.["value"] !== admission.journalId)
|
|
97
|
-
throw Error("Persistent admission journalId binding differs");
|
|
98
|
-
const input = resolvedProcessGroupInputChannel(original);
|
|
99
|
-
const sourceIdentity = processGroupSourceIdentity(input);
|
|
100
|
-
const expected = processGroupJournalContract(sourceIdentity, admission, admitted.profiles);
|
|
101
|
-
const contract = journal.prepare("SELECT value FROM metadata WHERE key='contract'").get()?.["value"];
|
|
102
|
-
if (contract !== expected)
|
|
103
|
-
throw Error("Durable admission journal contract differs");
|
|
104
|
-
const capture = JSON.parse(String(journal.prepare("SELECT value FROM metadata WHERE key='capture'").get()?.["value"] ?? "null"));
|
|
105
|
-
if (!capture ||
|
|
106
|
-
!["ready", "capacity-blocked"].includes(capture.state) ||
|
|
107
|
-
!Number.isSafeInteger(capture.pid) ||
|
|
108
|
-
capture.pid <= 0 ||
|
|
109
|
-
!Number.isSafeInteger(capture.heartbeat) ||
|
|
110
|
-
Date.now() - capture.heartbeat > 5000 ||
|
|
111
|
-
capture.heartbeat > Date.now() + 1000)
|
|
112
|
-
throw Error("Durable admission receiver is not ready");
|
|
113
|
-
process.kill(capture.pid, 0);
|
|
114
|
-
if (persistent) {
|
|
115
|
-
const namespace = sha(Buffer.from(fs.readFileSync("/proc/sys/kernel/random/boot_id", "utf8").trim() + ":" + fs.readlinkSync("/proc/self/ns/pid")));
|
|
116
|
-
const stored = journal.prepare("SELECT value FROM metadata WHERE key='runtime_namespace'").get()?.["value"];
|
|
117
|
-
const stat = fs.readFileSync(`/proc/${capture.pid}/stat`, "utf8");
|
|
118
|
-
const start = stat.slice(stat.lastIndexOf(")") + 2).split(" ")[19];
|
|
119
|
-
if (stored !== namespace || !start || capture.runtimeIdentity !== sha(Buffer.from(namespace + ":" + capture.pid + ":" + start)))
|
|
120
|
-
throw Error("Admission capture namespace or process identity differs");
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
finally {
|
|
124
|
-
journal.close();
|
|
125
|
-
}
|
|
91
|
+
inspectJournal(admission, persistent, processGroupJournalContract(processGroupSourceIdentity(resolvedProcessGroupInputChannel(original)), admission, admitted.profiles));
|
|
126
92
|
if (publisher.groupManifest && publisher.groupManifest !== admission.groupManifest)
|
|
127
93
|
throw Error("Admission and publisher manifests differ");
|
|
128
94
|
if (!publisher.groupManifest) {
|
|
@@ -182,4 +148,118 @@ export function inspectProcessGroupConfiguration(pkg, dir, raw, controllerName =
|
|
|
182
148
|
contract: null,
|
|
183
149
|
};
|
|
184
150
|
}
|
|
151
|
+
/** Shared read-only receiver/journal evidence for both resource protocols. */
|
|
152
|
+
function inspectJournal(admission, persistent, expected) {
|
|
153
|
+
for (let parent = admission.directory; parent !== path.dirname(parent); parent = path.dirname(parent))
|
|
154
|
+
if (fs.lstatSync(parent).isSymbolicLink())
|
|
155
|
+
throw Error("Admission directory cannot use symbolic links");
|
|
156
|
+
const databaseFile = path.join(admission.directory, "admission.sqlite");
|
|
157
|
+
if (fs.lstatSync(databaseFile).isSymbolicLink())
|
|
158
|
+
throw Error("Admission journal cannot use symbolic links");
|
|
159
|
+
const { DatabaseSync } = createRequire(import.meta.url)("node:sqlite");
|
|
160
|
+
const journal = new DatabaseSync(databaseFile, { readOnly: true });
|
|
161
|
+
try {
|
|
162
|
+
journal.exec("PRAGMA busy_timeout=1000");
|
|
163
|
+
if (persistent && journal.prepare("SELECT value FROM metadata WHERE key='id'").get()?.["value"] !== admission.journalId)
|
|
164
|
+
throw Error("Persistent admission journalId binding differs");
|
|
165
|
+
const contract = journal.prepare("SELECT value FROM metadata WHERE key='contract'").get()?.["value"];
|
|
166
|
+
if (contract !== expected)
|
|
167
|
+
throw Error("Durable admission journal contract differs");
|
|
168
|
+
const capture = JSON.parse(String(journal.prepare("SELECT value FROM metadata WHERE key='capture'").get()?.["value"] ?? "null"));
|
|
169
|
+
if (!capture ||
|
|
170
|
+
!["ready", "capacity-blocked"].includes(capture.state) ||
|
|
171
|
+
!Number.isSafeInteger(capture.pid) ||
|
|
172
|
+
capture.pid <= 0 ||
|
|
173
|
+
!Number.isSafeInteger(capture.heartbeat) ||
|
|
174
|
+
Date.now() - capture.heartbeat > 5000 ||
|
|
175
|
+
capture.heartbeat > Date.now() + 1000)
|
|
176
|
+
throw Error("Durable admission receiver is not ready");
|
|
177
|
+
process.kill(capture.pid, 0);
|
|
178
|
+
if (persistent) {
|
|
179
|
+
const namespace = sha(Buffer.from(fs.readFileSync("/proc/sys/kernel/random/boot_id", "utf8").trim() + ":" + fs.readlinkSync("/proc/self/ns/pid")));
|
|
180
|
+
const stored = journal.prepare("SELECT value FROM metadata WHERE key='runtime_namespace'").get()?.["value"];
|
|
181
|
+
const stat = fs.readFileSync(`/proc/${capture.pid}/stat`, "utf8");
|
|
182
|
+
const start = stat.slice(stat.lastIndexOf(")") + 2).split(" ")[19];
|
|
183
|
+
if (stored !== namespace || !start || capture.runtimeIdentity !== sha(Buffer.from(namespace + ":" + capture.pid + ":" + start)))
|
|
184
|
+
throw Error("Admission capture namespace or process identity differs");
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
finally {
|
|
188
|
+
journal.close();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function inspectConfigurationGroup(pkg, dir, raw, original, selected, controllerName, options) {
|
|
192
|
+
const { descriptor: d, snapshot } = selected;
|
|
193
|
+
const uns = { ...original["uns"] };
|
|
194
|
+
const memberId = readConfigurationSelector(original, d.memberPath), role = readConfigurationSelector(original, d.runtimeRolePath);
|
|
195
|
+
const member = memberId === undefined ? undefined : snapshot.profiles.find((p) => p.id === memberId);
|
|
196
|
+
if ((memberId !== undefined && !member) ||
|
|
197
|
+
uns["processName"] !== (member?.processName ?? snapshot.group.processName) ||
|
|
198
|
+
(role !== undefined && role !== "publisher"))
|
|
199
|
+
throw Error("Configured publisher role or identity differs");
|
|
200
|
+
const journal = configurationGroupJournalSchema
|
|
201
|
+
.extend({
|
|
202
|
+
minFreeBytes: configurationGroupJournalSchema.shape.minFreeBytes.unwrap().optional(),
|
|
203
|
+
maxRecords: configurationGroupJournalSchema.shape.maxRecords.unwrap(),
|
|
204
|
+
maxBytes: configurationGroupJournalSchema.shape.maxBytes.unwrap(),
|
|
205
|
+
})
|
|
206
|
+
.parse(readConfigurationSelector(original, d.journalPath));
|
|
207
|
+
const production = !isLocalPilotPath(pkg) || hasProcessGroupAuthorization() ? authorizeConfiguredProcessGroupRuntime(pkg, dir, original, controllerName) : undefined;
|
|
208
|
+
const persistent = !isLocalPilotPath(journal.directory);
|
|
209
|
+
if (production)
|
|
210
|
+
assertProcessGroupStateMount(production, process.env["UNS_PROCESS_GROUP_STATE_ROOT"] ?? "");
|
|
211
|
+
if (path.resolve(journal.directory) !== journal.directory || (production && !persistent))
|
|
212
|
+
throw Error("Configured journal storage differs");
|
|
213
|
+
if (persistent && (!production || !journal.journalId))
|
|
214
|
+
throw Error("Persistent configured journal requires exact reviewed authority and UUID");
|
|
215
|
+
const metadata = JSON.parse(resource(pkg, dir, "package.json").toString()).unsDatahub;
|
|
216
|
+
if (metadata?.processGroupAdmission !== 1 || (persistent && metadata?.processGroupPersistentAdmission !== 1))
|
|
217
|
+
throw Error("Required journal capabilities missing");
|
|
218
|
+
const expected = configurationGroupJournalContract(snapshot, processGroupSourceIdentity(resolvedProcessGroupInputChannel(original)), configurationGroupJournalSchema.parse(journal), snapshot.profiles.map(({ processName, resourceSha256, dataGroup }) => ({ processName, resourceSha256, dataGroup })));
|
|
219
|
+
inspectJournal(journal, persistent, expected);
|
|
220
|
+
const checksum = options.configurationChecksum(raw);
|
|
221
|
+
if (!checksum)
|
|
222
|
+
throw Error("Invalid configured group configuration");
|
|
223
|
+
for (const key of [...options.excludedUnsFields, "processName", "instanceMode", "handover", "handoverProtocol"])
|
|
224
|
+
delete uns[key];
|
|
225
|
+
const projection = structuredClone(original);
|
|
226
|
+
projection["uns"] = uns;
|
|
227
|
+
const remove = (keys) => {
|
|
228
|
+
let node = projection;
|
|
229
|
+
for (const key of keys.slice(0, -1)) {
|
|
230
|
+
const child = node[key];
|
|
231
|
+
if (child === undefined)
|
|
232
|
+
return;
|
|
233
|
+
if (!child || typeof child !== "object" || Array.isArray(child))
|
|
234
|
+
throw Error("Invalid selector projection");
|
|
235
|
+
node = child;
|
|
236
|
+
}
|
|
237
|
+
delete node[keys.at(-1)];
|
|
238
|
+
};
|
|
239
|
+
remove(d.memberPath);
|
|
240
|
+
remove(d.runtimeRolePath);
|
|
241
|
+
if (production)
|
|
242
|
+
projection["authorizationSha256"] = production.sha256;
|
|
243
|
+
return {
|
|
244
|
+
processName: String(original["uns"]["processName"]),
|
|
245
|
+
configurationChecksum: checksum,
|
|
246
|
+
projectionChecksum: configurationResourceHash(projection),
|
|
247
|
+
configurationGroupSha256: snapshot.sha256,
|
|
248
|
+
generationId: journal.generationId,
|
|
249
|
+
mappingSha256: member?.resourceSha256 ?? null,
|
|
250
|
+
dataGroup: member?.dataGroup ?? null,
|
|
251
|
+
contract: member
|
|
252
|
+
? null
|
|
253
|
+
: {
|
|
254
|
+
digest: snapshot.sha256,
|
|
255
|
+
processName: snapshot.group.processName,
|
|
256
|
+
profiles: snapshot.profiles.map(({ id, processName, resourceSha256, dataGroup }) => ({
|
|
257
|
+
id,
|
|
258
|
+
processName,
|
|
259
|
+
mappingSha256: resourceSha256,
|
|
260
|
+
dataGroup,
|
|
261
|
+
})),
|
|
262
|
+
},
|
|
263
|
+
};
|
|
264
|
+
}
|
|
185
265
|
//# sourceMappingURL=process-group-inspection.js.map
|