@uns-kit/core 3.0.26 → 3.0.27
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 +35 -0
- package/dist/runtime/compatibility/energenti-authorization-v1.d.ts +95 -0
- package/dist/runtime/compatibility/energenti-authorization-v1.d.ts.map +1 -0
- package/dist/runtime/compatibility/energenti-authorization-v1.js +315 -0
- package/dist/runtime/compatibility/energenti-authorization-v1.js.map +1 -0
- package/dist/runtime/compatibility/energenti-descriptor-v1.d.ts +10 -0
- package/dist/runtime/compatibility/energenti-descriptor-v1.d.ts.map +1 -0
- package/dist/runtime/compatibility/energenti-descriptor-v1.js +18 -0
- package/dist/runtime/compatibility/energenti-descriptor-v1.js.map +1 -0
- package/dist/runtime/process-group-authorization.d.ts +107 -0
- package/dist/runtime/process-group-authorization.d.ts.map +1 -0
- package/dist/runtime/process-group-authorization.js +352 -0
- package/dist/runtime/process-group-authorization.js.map +1 -0
- package/dist/runtime/process-group-contract.d.ts +65 -0
- package/dist/runtime/process-group-contract.d.ts.map +1 -0
- package/dist/runtime/process-group-contract.js +171 -0
- package/dist/runtime/process-group-contract.js.map +1 -0
- package/dist/runtime/process-group-control-contract.d.ts +56 -0
- package/dist/runtime/process-group-control-contract.d.ts.map +1 -0
- package/dist/runtime/process-group-control-contract.js +37 -0
- package/dist/runtime/process-group-control-contract.js.map +1 -0
- package/dist/runtime/process-group-inspection.d.ts +22 -0
- package/dist/runtime/process-group-inspection.d.ts.map +1 -0
- package/dist/runtime/process-group-inspection.js +185 -0
- package/dist/runtime/process-group-inspection.js.map +1 -0
- package/dist/runtime/process-group-launch-environment.d.ts +3 -0
- package/dist/runtime/process-group-launch-environment.d.ts.map +1 -0
- package/dist/runtime/process-group-launch-environment.js +12 -0
- package/dist/runtime/process-group-launch-environment.js.map +1 -0
- package/dist/runtime/process-group-legacy-start.d.ts +2 -0
- package/dist/runtime/process-group-legacy-start.d.ts.map +1 -0
- package/dist/runtime/process-group-legacy-start.js +16 -0
- package/dist/runtime/process-group-legacy-start.js.map +1 -0
- package/dist/runtime/process-group-resources.d.ts +8 -0
- package/dist/runtime/process-group-resources.d.ts.map +1 -0
- package/dist/runtime/process-group-resources.js +96 -0
- package/dist/runtime/process-group-resources.js.map +1 -0
- package/dist/runtime/process-group-snapshot.mjs +199 -0
- package/dist/runtime/process-group-staging.d.ts +5 -0
- package/dist/runtime/process-group-staging.d.ts.map +1 -0
- package/dist/runtime/process-group-staging.js +63 -0
- package/dist/runtime/process-group-staging.js.map +1 -0
- package/dist/runtime/process-group-supervision.d.ts +13 -0
- package/dist/runtime/process-group-supervision.d.ts.map +1 -0
- package/dist/runtime/process-group-supervision.js +34 -0
- package/dist/runtime/process-group-supervision.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { resolveMqttChannel } from "../uns-config/mqtt-channel.js";
|
|
5
|
+
import { legacyDescriptorForPackage } from "./compatibility/energenti-descriptor-v1.js";
|
|
6
|
+
/** Versioned, data-only contract for same-host MQTT journal process groups.
|
|
7
|
+
* Package declarations describe resources; only private operator policies grant authority.
|
|
8
|
+
*/
|
|
9
|
+
import { readProcessGroupResource, sha256 } from "./process-group-resources.js";
|
|
10
|
+
export { legacyDescriptorForPackage, legacyEnergentiDescriptor } from "./compatibility/energenti-descriptor-v1.js";
|
|
11
|
+
export const processGroupProtocolVersion = 1;
|
|
12
|
+
const identity = z.string().regex(/^[a-z][a-z0-9-]{0,99}$/);
|
|
13
|
+
const selector = z
|
|
14
|
+
.array(z
|
|
15
|
+
.string()
|
|
16
|
+
.regex(/^[a-zA-Z][a-zA-Z0-9_-]{0,99}$/)
|
|
17
|
+
.refine((v) => !["__proto__", "constructor", "prototype"].includes(v)))
|
|
18
|
+
.min(1)
|
|
19
|
+
.max(8);
|
|
20
|
+
const relative = z
|
|
21
|
+
.string()
|
|
22
|
+
.min(1)
|
|
23
|
+
.max(512)
|
|
24
|
+
.refine((v) => !path.isAbsolute(v) && path.normalize(v) === v && !v.split(/[\\/]/).some((x) => x === ".." || x === ".") && !v.includes("\0"));
|
|
25
|
+
export const processGroupRuntimeDescriptorSchema = z
|
|
26
|
+
.strictObject({
|
|
27
|
+
protocolVersion: z.literal(1),
|
|
28
|
+
namespace: identity,
|
|
29
|
+
publisherPath: selector,
|
|
30
|
+
journalPath: selector,
|
|
31
|
+
runtimeRolePath: selector,
|
|
32
|
+
receiverRole: identity,
|
|
33
|
+
defaultDataGroup: identity.optional(),
|
|
34
|
+
match: z.strictObject({ path: selector, value: z.string().min(1).max(100) }).optional(),
|
|
35
|
+
manifests: z
|
|
36
|
+
.array(z.strictObject({ id: identity, file: relative }))
|
|
37
|
+
.min(1)
|
|
38
|
+
.max(64),
|
|
39
|
+
})
|
|
40
|
+
.superRefine((d, c) => {
|
|
41
|
+
if (new Set(d.manifests.map((v) => v.id)).size !== d.manifests.length || new Set(d.manifests.map((v) => v.file)).size !== d.manifests.length)
|
|
42
|
+
c.addIssue({ code: "custom", message: "Distinct group manifests required" });
|
|
43
|
+
const paths = [d.publisherPath, d.journalPath, d.runtimeRolePath].map((v) => v.join("."));
|
|
44
|
+
if (new Set(paths).size !== paths.length || paths.some((p, i) => paths.some((other, j) => i !== j && other.startsWith(p + "."))))
|
|
45
|
+
c.addIssue({ code: "custom", message: "Distinct configuration selectors required" });
|
|
46
|
+
});
|
|
47
|
+
export function readConfigurationSelector(raw, keys) {
|
|
48
|
+
let value = raw;
|
|
49
|
+
for (const key of keys) {
|
|
50
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || !Object.hasOwn(value, key))
|
|
51
|
+
return undefined;
|
|
52
|
+
value = value[key];
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
/** Strictly bounded package metadata, no executable application adapter in the Controller. */
|
|
57
|
+
export function processGroupDescriptor(packageRoot) {
|
|
58
|
+
const file = path.join(packageRoot, "package.json");
|
|
59
|
+
if (!fs.existsSync(file))
|
|
60
|
+
return undefined;
|
|
61
|
+
// Discovery must not impose journal path rules on unrelated Node/Python packages.
|
|
62
|
+
const fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
63
|
+
let bytes;
|
|
64
|
+
try {
|
|
65
|
+
const stat = fs.fstatSync(fd);
|
|
66
|
+
if (!stat.isFile() || stat.size > 1024 * 1024)
|
|
67
|
+
throw Error("Invalid installed runtime metadata");
|
|
68
|
+
bytes = fs.readFileSync(fd);
|
|
69
|
+
if (bytes.length > 1024 * 1024)
|
|
70
|
+
throw Error("Installed runtime metadata is too large");
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
fs.closeSync(fd);
|
|
74
|
+
}
|
|
75
|
+
const pkg = JSON.parse(bytes.toString());
|
|
76
|
+
const declared = pkg.unsDatahub?.processGroupRuntime;
|
|
77
|
+
const descriptor = declared !== undefined
|
|
78
|
+
? processGroupRuntimeDescriptorSchema.parse(declared)
|
|
79
|
+
: [1, 2, 3].includes(pkg.unsDatahub?.processGroupProductionAuthorization)
|
|
80
|
+
? legacyDescriptorForPackage(String(pkg.name))
|
|
81
|
+
: undefined;
|
|
82
|
+
// Opted-in groups still require canonical, unchanged, unlinked installed resources.
|
|
83
|
+
if (descriptor && !readProcessGroupResource(file).equals(bytes))
|
|
84
|
+
throw Error("Installed runtime metadata changed during discovery");
|
|
85
|
+
return descriptor;
|
|
86
|
+
}
|
|
87
|
+
export function normalizeProcessGroupConfiguration(raw, d) {
|
|
88
|
+
const publisher = readConfigurationSelector(raw, d.publisherPath);
|
|
89
|
+
const role = readConfigurationSelector(raw, d.runtimeRolePath);
|
|
90
|
+
return {
|
|
91
|
+
...raw,
|
|
92
|
+
uns: raw["uns"],
|
|
93
|
+
publisher: publisher ?? {},
|
|
94
|
+
journal: readConfigurationSelector(raw, d.journalPath),
|
|
95
|
+
runtimeRole: role === d.receiverRole ? "admission" : role,
|
|
96
|
+
matches: !d.match || readConfigurationSelector(raw, d.match.path) === d.match.value,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
export function projectProcessGroupConfiguration(raw, d, uns, authorizationSha256) {
|
|
100
|
+
const projection = structuredClone(raw);
|
|
101
|
+
projection["uns"] = uns;
|
|
102
|
+
let value = projection;
|
|
103
|
+
for (const key of d.publisherPath.slice(0, -1)) {
|
|
104
|
+
const child = value[key];
|
|
105
|
+
if (!child || typeof child !== "object" || Array.isArray(child))
|
|
106
|
+
throw Error("Invalid publisher projection");
|
|
107
|
+
value = child;
|
|
108
|
+
}
|
|
109
|
+
delete value[d.publisherPath.at(-1)];
|
|
110
|
+
if (authorizationSha256)
|
|
111
|
+
projection["authorizationSha256"] = authorizationSha256;
|
|
112
|
+
return projection;
|
|
113
|
+
}
|
|
114
|
+
export function resolvedProcessGroupChannels(raw, _d) {
|
|
115
|
+
const infra = (raw["infra"] ?? {});
|
|
116
|
+
return [
|
|
117
|
+
resolveMqttChannel(infra),
|
|
118
|
+
resolveMqttChannel(infra, (raw["input"] ?? {})),
|
|
119
|
+
resolveMqttChannel(infra, (raw["output"] ?? {})),
|
|
120
|
+
];
|
|
121
|
+
}
|
|
122
|
+
export function isLocalPilotPath(value, platform = process.platform) {
|
|
123
|
+
return path.resolve(value) === value && (value.startsWith("/private/tmp/") || (platform === "linux" && value.startsWith("/tmp/")));
|
|
124
|
+
}
|
|
125
|
+
export function isProcessGroupJournalPath(root, directory, namespace) {
|
|
126
|
+
return (path.isAbsolute(root) &&
|
|
127
|
+
path.resolve(root) === root &&
|
|
128
|
+
new RegExp(`^${namespace}/admission/[a-z][a-z0-9-]{0,99}$`).test(path.relative(root, directory)));
|
|
129
|
+
}
|
|
130
|
+
export const processGroupJournalSchema = z.strictObject({
|
|
131
|
+
directory: z.string().startsWith("/").max(512),
|
|
132
|
+
journalId: z.string().uuid().optional(),
|
|
133
|
+
minFreeBytes: z
|
|
134
|
+
.number()
|
|
135
|
+
.int()
|
|
136
|
+
.min(1024 * 1024)
|
|
137
|
+
.max(1024 * 1024 * 1024)
|
|
138
|
+
.default(64 * 1024 * 1024),
|
|
139
|
+
groupManifest: z.string().min(1).max(512),
|
|
140
|
+
maxRecords: z.number().int().min(1).max(100000).default(20000),
|
|
141
|
+
maxBytes: z
|
|
142
|
+
.number()
|
|
143
|
+
.int()
|
|
144
|
+
.min(1024)
|
|
145
|
+
.max(256 * 1024 * 1024)
|
|
146
|
+
.default(32 * 1024 * 1024),
|
|
147
|
+
});
|
|
148
|
+
export function resolvedProcessGroupInputChannel(raw) {
|
|
149
|
+
return resolveMqttChannel((raw["infra"] ?? {}), (raw["input"] ?? {}));
|
|
150
|
+
}
|
|
151
|
+
export function processGroupSourceIdentity(input) {
|
|
152
|
+
return sha256(JSON.stringify({
|
|
153
|
+
host: input.host,
|
|
154
|
+
port: input.port ?? 1883,
|
|
155
|
+
protocol: input.protocol ?? "mqtt",
|
|
156
|
+
hosts: input.hosts ?? [],
|
|
157
|
+
servers: input.servers ?? [],
|
|
158
|
+
}));
|
|
159
|
+
}
|
|
160
|
+
export function processGroupJournalContract(sourceIdentity, config, profiles) {
|
|
161
|
+
return JSON.stringify({
|
|
162
|
+
version: 1,
|
|
163
|
+
sourceIdentity,
|
|
164
|
+
maxRecords: config.maxRecords,
|
|
165
|
+
maxBytes: config.maxBytes,
|
|
166
|
+
profiles: profiles
|
|
167
|
+
.map(({ processName, mappingSha256, dataGroup }) => ({ processName, mappingSha256, dataGroup }))
|
|
168
|
+
.sort((a, b) => a.processName.localeCompare(b.processName)),
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=process-group-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-group-contract.js","sourceRoot":"","sources":["../../src/runtime/process-group-contract.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\n\nimport { type MqttChannelConfig, resolveMqttChannel } from \"../uns-config/mqtt-channel.js\";\nimport { legacyDescriptorForPackage, legacyEnergentiDescriptor } from \"./compatibility/energenti-descriptor-v1.js\";\n/** Versioned, data-only contract for same-host MQTT journal process groups.\n * Package declarations describe resources; only private operator policies grant authority.\n */\nimport { readProcessGroupResource, sha256 } from \"./process-group-resources.js\";\n\nexport { legacyDescriptorForPackage, legacyEnergentiDescriptor } from \"./compatibility/energenti-descriptor-v1.js\";\n\nexport const processGroupProtocolVersion = 1 as const;\nconst identity = z.string().regex(/^[a-z][a-z0-9-]{0,99}$/);\nconst selector = z\n .array(\n z\n .string()\n .regex(/^[a-zA-Z][a-zA-Z0-9_-]{0,99}$/)\n .refine((v) => ![\"__proto__\", \"constructor\", \"prototype\"].includes(v)),\n )\n .min(1)\n .max(8);\nconst relative = z\n .string()\n .min(1)\n .max(512)\n .refine((v) => !path.isAbsolute(v) && path.normalize(v) === v && !v.split(/[\\\\/]/).some((x) => x === \"..\" || x === \".\") && !v.includes(\"\\0\"));\nexport const processGroupRuntimeDescriptorSchema = z\n .strictObject({\n protocolVersion: z.literal(1),\n namespace: identity,\n publisherPath: selector,\n journalPath: selector,\n runtimeRolePath: selector,\n receiverRole: identity,\n defaultDataGroup: identity.optional(),\n match: z.strictObject({ path: selector, value: z.string().min(1).max(100) }).optional(),\n manifests: z\n .array(z.strictObject({ id: identity, file: relative }))\n .min(1)\n .max(64),\n })\n .superRefine((d, c) => {\n if (new Set(d.manifests.map((v) => v.id)).size !== d.manifests.length || new Set(d.manifests.map((v) => v.file)).size !== d.manifests.length)\n c.addIssue({ code: \"custom\", message: \"Distinct group manifests required\" });\n const paths = [d.publisherPath, d.journalPath, d.runtimeRolePath].map((v) => v.join(\".\"));\n if (new Set(paths).size !== paths.length || paths.some((p, i) => paths.some((other, j) => i !== j && other.startsWith(p + \".\"))))\n c.addIssue({ code: \"custom\", message: \"Distinct configuration selectors required\" });\n });\nexport type ProcessGroupRuntimeDescriptor = z.infer<typeof processGroupRuntimeDescriptorSchema> & { legacy?: true };\nexport function readConfigurationSelector(raw: unknown, keys: readonly string[]): unknown {\n let value: unknown = raw;\n for (const key of keys) {\n if (!value || typeof value !== \"object\" || Array.isArray(value) || !Object.hasOwn(value, key)) return undefined;\n value = (value as Record<string, unknown>)[key];\n }\n return value;\n}\n/** Strictly bounded package metadata, no executable application adapter in the Controller. */\nexport function processGroupDescriptor(packageRoot: string): ProcessGroupRuntimeDescriptor | undefined {\n const file = path.join(packageRoot, \"package.json\");\n if (!fs.existsSync(file)) return undefined;\n // Discovery must not impose journal path rules on unrelated Node/Python packages.\n const fd = fs.openSync(file, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);\n let bytes: Buffer;\n try {\n const stat = fs.fstatSync(fd);\n if (!stat.isFile() || stat.size > 1024 * 1024) throw Error(\"Invalid installed runtime metadata\");\n bytes = fs.readFileSync(fd);\n if (bytes.length > 1024 * 1024) throw Error(\"Installed runtime metadata is too large\");\n } finally {\n fs.closeSync(fd);\n }\n const pkg = JSON.parse(bytes.toString());\n const declared = pkg.unsDatahub?.processGroupRuntime;\n const descriptor =\n declared !== undefined\n ? processGroupRuntimeDescriptorSchema.parse(declared)\n : [1, 2, 3].includes(pkg.unsDatahub?.processGroupProductionAuthorization)\n ? legacyDescriptorForPackage(String(pkg.name))\n : undefined;\n // Opted-in groups still require canonical, unchanged, unlinked installed resources.\n if (descriptor && !readProcessGroupResource(file).equals(bytes)) throw Error(\"Installed runtime metadata changed during discovery\");\n return descriptor;\n}\nexport function normalizeProcessGroupConfiguration(raw: Record<string, unknown>, d: ProcessGroupRuntimeDescriptor) {\n const publisher = readConfigurationSelector(raw, d.publisherPath) as Record<string, unknown> | undefined;\n const role = readConfigurationSelector(raw, d.runtimeRolePath);\n return {\n ...raw,\n uns: raw[\"uns\"] as Record<string, unknown>,\n publisher: publisher ?? {},\n journal: readConfigurationSelector(raw, d.journalPath),\n runtimeRole: role === d.receiverRole ? \"admission\" : role,\n matches: !d.match || readConfigurationSelector(raw, d.match.path) === d.match.value,\n };\n}\nexport function projectProcessGroupConfiguration(\n raw: Record<string, unknown>,\n d: ProcessGroupRuntimeDescriptor,\n uns: Record<string, unknown>,\n authorizationSha256?: string,\n): Record<string, unknown> {\n const projection = structuredClone(raw);\n projection[\"uns\"] = uns;\n let value = projection;\n for (const key of d.publisherPath.slice(0, -1)) {\n const child = value[key];\n if (!child || typeof child !== \"object\" || Array.isArray(child)) throw Error(\"Invalid publisher projection\");\n value = child as Record<string, unknown>;\n }\n delete value[d.publisherPath.at(-1)!];\n if (authorizationSha256) projection[\"authorizationSha256\"] = authorizationSha256;\n return projection;\n}\nexport function resolvedProcessGroupChannels(raw: Record<string, unknown>, _d?: ProcessGroupRuntimeDescriptor) {\n const infra = (raw[\"infra\"] ?? {}) as MqttChannelConfig;\n return [\n resolveMqttChannel(infra),\n resolveMqttChannel(infra, (raw[\"input\"] ?? {}) as MqttChannelConfig),\n resolveMqttChannel(infra, (raw[\"output\"] ?? {}) as MqttChannelConfig),\n ];\n}\nexport function isLocalPilotPath(value: string, platform = process.platform): boolean {\n return path.resolve(value) === value && (value.startsWith(\"/private/tmp/\") || (platform === \"linux\" && value.startsWith(\"/tmp/\")));\n}\nexport function isProcessGroupJournalPath(root: string, directory: string, namespace: string): boolean {\n return (\n path.isAbsolute(root) &&\n path.resolve(root) === root &&\n new RegExp(`^${namespace}/admission/[a-z][a-z0-9-]{0,99}$`).test(path.relative(root, directory))\n );\n}\nexport const processGroupJournalSchema = z.strictObject({\n directory: z.string().startsWith(\"/\").max(512),\n journalId: z.string().uuid().optional(),\n minFreeBytes: z\n .number()\n .int()\n .min(1024 * 1024)\n .max(1024 * 1024 * 1024)\n .default(64 * 1024 * 1024),\n groupManifest: z.string().min(1).max(512),\n maxRecords: z.number().int().min(1).max(100000).default(20000),\n maxBytes: z\n .number()\n .int()\n .min(1024)\n .max(256 * 1024 * 1024)\n .default(32 * 1024 * 1024),\n});\nexport type ProcessGroupJournalConfiguration = z.infer<typeof processGroupJournalSchema>;\nexport interface ProcessGroupJournalProfile {\n processName: string;\n mappingSha256: string;\n dataGroup: string;\n}\nexport interface ProcessGroupJournalTask {\n profile: string;\n payload: string;\n}\n\nexport function resolvedProcessGroupInputChannel(raw: Record<string, unknown>) {\n return resolveMqttChannel((raw[\"infra\"] ?? {}) as MqttChannelConfig, (raw[\"input\"] ?? {}) as MqttChannelConfig);\n}\n\nexport function processGroupSourceIdentity(input: {\n host: string;\n port?: number | undefined;\n protocol?: string | undefined;\n hosts?: string[] | undefined;\n servers?: unknown[] | undefined;\n}): string {\n return sha256(\n JSON.stringify({\n host: input.host,\n port: input.port ?? 1883,\n protocol: input.protocol ?? \"mqtt\",\n hosts: input.hosts ?? [],\n servers: input.servers ?? [],\n }),\n );\n}\nexport function processGroupJournalContract(\n sourceIdentity: string,\n config: Pick<ProcessGroupJournalConfiguration, \"maxRecords\" | \"maxBytes\">,\n profiles: ProcessGroupJournalProfile[],\n): string {\n return JSON.stringify({\n version: 1,\n sourceIdentity,\n maxRecords: config.maxRecords,\n maxBytes: config.maxBytes,\n profiles: profiles\n .map(({ processName, mappingSha256, dataGroup }) => ({ processName, mappingSha256, dataGroup }))\n .sort((a, b) => a.processName.localeCompare(b.processName)),\n });\n}\n"]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
export declare const groupPlacementSchema: z.ZodObject<{
|
|
3
|
+
controller: z.ZodString;
|
|
4
|
+
rttNode: z.ZodString;
|
|
5
|
+
version: z.ZodString;
|
|
6
|
+
instanceId: z.ZodString;
|
|
7
|
+
}, z.core.$strict>;
|
|
8
|
+
export type GroupPlacement = z.infer<typeof groupPlacementSchema>;
|
|
9
|
+
export declare const groupInputSchema: z.ZodObject<{
|
|
10
|
+
sources: z.ZodArray<z.ZodObject<{
|
|
11
|
+
controller: z.ZodString;
|
|
12
|
+
rttNode: z.ZodString;
|
|
13
|
+
version: z.ZodString;
|
|
14
|
+
instanceId: z.ZodString;
|
|
15
|
+
}, z.core.$strict>>;
|
|
16
|
+
target: z.ZodObject<{
|
|
17
|
+
controller: z.ZodString;
|
|
18
|
+
rttNode: z.ZodString;
|
|
19
|
+
version: z.ZodString;
|
|
20
|
+
instanceId: z.ZodString;
|
|
21
|
+
}, z.core.$strict>;
|
|
22
|
+
}, z.core.$strict>;
|
|
23
|
+
export type GroupInput = z.infer<typeof groupInputSchema>;
|
|
24
|
+
export declare const placementKey: (p: GroupPlacement) => string;
|
|
25
|
+
export { configurationAuthorizationHash as groupHash } from "./process-group-resources.js";
|
|
26
|
+
export type GroupMember = {
|
|
27
|
+
id: string;
|
|
28
|
+
processName: string;
|
|
29
|
+
mappingSha256: string;
|
|
30
|
+
dataGroup: string;
|
|
31
|
+
};
|
|
32
|
+
export declare const groupMemberCommandSchema: z.ZodObject<{
|
|
33
|
+
action: z.ZodEnum<{
|
|
34
|
+
inspect: "inspect";
|
|
35
|
+
reserve: "reserve";
|
|
36
|
+
launch: "launch";
|
|
37
|
+
park: "park";
|
|
38
|
+
restore: "restore";
|
|
39
|
+
release: "release";
|
|
40
|
+
}>;
|
|
41
|
+
placement: z.ZodObject<{
|
|
42
|
+
controller: z.ZodString;
|
|
43
|
+
rttNode: z.ZodString;
|
|
44
|
+
version: z.ZodString;
|
|
45
|
+
instanceId: z.ZodString;
|
|
46
|
+
}, z.core.$strict>;
|
|
47
|
+
operationId: z.ZodString;
|
|
48
|
+
role: z.ZodEnum<{
|
|
49
|
+
source: "source";
|
|
50
|
+
target: "target";
|
|
51
|
+
}>;
|
|
52
|
+
expectedConfigurationChecksum: z.ZodOptional<z.ZodString>;
|
|
53
|
+
requestId: z.ZodOptional<z.ZodString>;
|
|
54
|
+
}, z.core.$strict>;
|
|
55
|
+
export type GroupMemberCommand = z.infer<typeof groupMemberCommandSchema>;
|
|
56
|
+
//# sourceMappingURL=process-group-control-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-group-control-contract.d.ts","sourceRoot":"","sources":["../../src/runtime/process-group-control-contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,eAAO,MAAM,oBAAoB;;;;;kBAK/B,CAAC;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAClE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;kBAazB,CAAC;AACL,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC1D,eAAO,MAAM,YAAY,GAAI,GAAG,cAAc,KAAG,MAAsE,CAAC;AACxH,OAAO,EAAE,8BAA8B,IAAI,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAC3F,MAAM,MAAM,WAAW,GAAG;IACxB,EAAE,EAAE,MAAM,CAAC;IACX,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AACF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;kBAUnC,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const name = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/);
|
|
3
|
+
export const groupPlacementSchema = z.strictObject({
|
|
4
|
+
controller: name,
|
|
5
|
+
rttNode: name,
|
|
6
|
+
version: name,
|
|
7
|
+
instanceId: name,
|
|
8
|
+
});
|
|
9
|
+
export const groupInputSchema = z
|
|
10
|
+
.strictObject({
|
|
11
|
+
sources: z.array(groupPlacementSchema).min(2).max(16),
|
|
12
|
+
target: groupPlacementSchema,
|
|
13
|
+
})
|
|
14
|
+
.superRefine((v, c) => {
|
|
15
|
+
const keys = [...v.sources, v.target].map(placementKey);
|
|
16
|
+
if (new Set(keys).size !== keys.length)
|
|
17
|
+
c.addIssue({ code: "custom", message: "Distinct placements required" });
|
|
18
|
+
if (v.sources.some((s) => s.controller !== v.target.controller || s.rttNode !== v.target.rttNode))
|
|
19
|
+
c.addIssue({
|
|
20
|
+
code: "custom",
|
|
21
|
+
message: "This group contract requires one package on one owning controller",
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
export const placementKey = (p) => [p.controller, p.rttNode, p.version, p.instanceId].join(":");
|
|
25
|
+
export { configurationAuthorizationHash as groupHash } from "./process-group-resources.js";
|
|
26
|
+
export const groupMemberCommandSchema = z.strictObject({
|
|
27
|
+
action: z.enum(["inspect", "reserve", "launch", "park", "restore", "release"]),
|
|
28
|
+
placement: groupPlacementSchema,
|
|
29
|
+
operationId: z.string().uuid(),
|
|
30
|
+
role: z.enum(["source", "target"]),
|
|
31
|
+
expectedConfigurationChecksum: z
|
|
32
|
+
.string()
|
|
33
|
+
.regex(/^[a-f0-9]{64}$/)
|
|
34
|
+
.optional(),
|
|
35
|
+
requestId: z.string().uuid().optional(),
|
|
36
|
+
});
|
|
37
|
+
//# sourceMappingURL=process-group-control-contract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-group-control-contract.js","sourceRoot":"","sources":["../../src/runtime/process-group-control-contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;AACpE,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,YAAY,CAAC;IACjD,UAAU,EAAE,IAAI;IAChB,OAAO,EAAE,IAAI;IACb,OAAO,EAAE,IAAI;IACb,UAAU,EAAE,IAAI;CACjB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC;KAC9B,YAAY,CAAC;IACZ,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IACrD,MAAM,EAAE,oBAAoB;CAC7B,CAAC;KACD,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;IACpB,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IACxD,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM;QAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,8BAA8B,EAAE,CAAC,CAAC;IAChH,IAAI,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;QAC/F,CAAC,CAAC,QAAQ,CAAC;YACT,IAAI,EAAE,QAAQ;YACd,OAAO,EAAE,mEAAmE;SAC7E,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAiB,EAAU,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACxH,OAAO,EAAE,8BAA8B,IAAI,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAO3F,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,YAAY,CAAC;IACrD,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAC9E,SAAS,EAAE,oBAAoB;IAC/B,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE;IAC9B,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAClC,6BAA6B,EAAE,CAAC;SAC7B,MAAM,EAAE;SACR,KAAK,CAAC,gBAAgB,CAAC;SACvB,QAAQ,EAAE;IACb,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,QAAQ,EAAE;CACxC,CAAC,CAAC","sourcesContent":["import { z } from \"zod\";\n\nconst name = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/);\nexport const groupPlacementSchema = z.strictObject({\n controller: name,\n rttNode: name,\n version: name,\n instanceId: name,\n});\nexport type GroupPlacement = z.infer<typeof groupPlacementSchema>;\nexport const groupInputSchema = z\n .strictObject({\n sources: z.array(groupPlacementSchema).min(2).max(16),\n target: groupPlacementSchema,\n })\n .superRefine((v, c) => {\n const keys = [...v.sources, v.target].map(placementKey);\n if (new Set(keys).size !== keys.length) c.addIssue({ code: \"custom\", message: \"Distinct placements required\" });\n if (v.sources.some((s) => s.controller !== v.target.controller || s.rttNode !== v.target.rttNode))\n c.addIssue({\n code: \"custom\",\n message: \"This group contract requires one package on one owning controller\",\n });\n });\nexport type GroupInput = z.infer<typeof groupInputSchema>;\nexport const placementKey = (p: GroupPlacement): string => [p.controller, p.rttNode, p.version, p.instanceId].join(\":\");\nexport { configurationAuthorizationHash as groupHash } from \"./process-group-resources.js\";\nexport type GroupMember = {\n id: string;\n processName: string;\n mappingSha256: string;\n dataGroup: string;\n};\nexport const groupMemberCommandSchema = z.strictObject({\n action: z.enum([\"inspect\", \"reserve\", \"launch\", \"park\", \"restore\", \"release\"]),\n placement: groupPlacementSchema,\n operationId: z.string().uuid(),\n role: z.enum([\"source\", \"target\"]),\n expectedConfigurationChecksum: z\n .string()\n .regex(/^[a-f0-9]{64}$/)\n .optional(),\n requestId: z.string().uuid().optional(),\n});\nexport type GroupMemberCommand = z.infer<typeof groupMemberCommandSchema>;\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface ProcessGroupConfigurationEvidence {
|
|
2
|
+
processName: string;
|
|
3
|
+
configurationChecksum: string;
|
|
4
|
+
projectionChecksum: string;
|
|
5
|
+
mappingSha256: string | null;
|
|
6
|
+
dataGroup: string | null;
|
|
7
|
+
contract: {
|
|
8
|
+
digest: string;
|
|
9
|
+
processName: string;
|
|
10
|
+
profiles: {
|
|
11
|
+
id: string;
|
|
12
|
+
processName: string;
|
|
13
|
+
mappingSha256: string;
|
|
14
|
+
dataGroup: string;
|
|
15
|
+
}[];
|
|
16
|
+
} | null;
|
|
17
|
+
}
|
|
18
|
+
export declare function inspectProcessGroupConfiguration(pkg: string, dir: string, raw: string, controllerName: string, options: {
|
|
19
|
+
configurationChecksum(raw: string): string | null;
|
|
20
|
+
excludedUnsFields: readonly string[];
|
|
21
|
+
}): ProcessGroupConfigurationEvidence;
|
|
22
|
+
//# sourceMappingURL=process-group-inspection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-group-inspection.d.ts","sourceRoot":"","sources":["../../src/runtime/process-group-inspection.ts"],"names":[],"mappings":"AAyBA,MAAM,WAAW,iCAAiC;IAChD,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,CA+InC"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
import { assertProcessGroupStateMount, authorizeConfiguredProcessGroupRuntime, configurationAuthorizationHash, hasProcessGroupAuthorization, processGroupManifestSchema as manifest, } from "./process-group-authorization.js";
|
|
7
|
+
import { isLocalPilotPath, isProcessGroupJournalPath, normalizeProcessGroupConfiguration, processGroupDescriptor, processGroupJournalContract, processGroupJournalSchema, processGroupSourceIdentity, projectProcessGroupConfiguration, resolvedProcessGroupInputChannel, } from "./process-group-contract.js";
|
|
8
|
+
/** Bound reads to installed package/instance resources, never arbitrary paths or symlinks. */
|
|
9
|
+
function resource(pkg, dir, file, relativeTo) {
|
|
10
|
+
if (file.length > 512)
|
|
11
|
+
throw Error("Group resource path too long");
|
|
12
|
+
const roots = [fs.realpathSync(pkg), fs.realpathSync(dir)];
|
|
13
|
+
const candidates = relativeTo
|
|
14
|
+
? [path.resolve(relativeTo, file)]
|
|
15
|
+
: path.isAbsolute(file)
|
|
16
|
+
? [file]
|
|
17
|
+
: [path.resolve(dir, file), path.resolve(pkg, file)];
|
|
18
|
+
for (const candidate of candidates) {
|
|
19
|
+
if (!fs.existsSync(candidate))
|
|
20
|
+
continue;
|
|
21
|
+
const real = fs.realpathSync(candidate);
|
|
22
|
+
if (real !== candidate || !roots.some((root) => real.startsWith(root + path.sep)))
|
|
23
|
+
throw Error("Group resource must stay inside installed package or instance");
|
|
24
|
+
const fd = fs.openSync(real, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);
|
|
25
|
+
try {
|
|
26
|
+
const s = fs.fstatSync(fd);
|
|
27
|
+
if (!s.isFile() || s.size > 1048576)
|
|
28
|
+
throw Error("Invalid group resource");
|
|
29
|
+
const b = fs.readFileSync(fd);
|
|
30
|
+
if (b.length > 1048576)
|
|
31
|
+
throw Error("Group resource too large");
|
|
32
|
+
return b;
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
fs.closeSync(fd);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
throw Error("Installed group resource is missing");
|
|
39
|
+
}
|
|
40
|
+
const sha = (b) => createHash("sha256").update(b).digest("hex");
|
|
41
|
+
export function inspectProcessGroupConfiguration(pkg, dir, raw, controllerName = process.env["UNS_CONTROLLER_NAME"] ?? "", options) {
|
|
42
|
+
const original = JSON.parse(raw);
|
|
43
|
+
const descriptor = processGroupDescriptor(pkg);
|
|
44
|
+
if (!descriptor)
|
|
45
|
+
throw Error("Installed package has no supported process-group contract");
|
|
46
|
+
const c = normalizeProcessGroupConfiguration(original, descriptor), uns = { ...c.uns }, publisher = c.publisher;
|
|
47
|
+
const production = c.journal && (!isLocalPilotPath(pkg) || hasProcessGroupAuthorization())
|
|
48
|
+
? authorizeConfiguredProcessGroupRuntime(pkg, dir, original, controllerName)
|
|
49
|
+
: undefined;
|
|
50
|
+
if (production)
|
|
51
|
+
assertProcessGroupStateMount(production, process.env["UNS_PROCESS_GROUP_STATE_ROOT"] ?? "");
|
|
52
|
+
if (!c.matches || (c.runtimeRole !== undefined && c.runtimeRole !== "publisher") || !publisher || typeof uns.processName !== "string")
|
|
53
|
+
throw Error("This runtime has no supported reviewed group configuration");
|
|
54
|
+
if (c.journal !== undefined) {
|
|
55
|
+
// Readiness requires explicit capacities; their limits come from the shared writer schema.
|
|
56
|
+
const admission = processGroupJournalSchema
|
|
57
|
+
.extend({
|
|
58
|
+
minFreeBytes: processGroupJournalSchema.shape.minFreeBytes.unwrap().optional(),
|
|
59
|
+
maxRecords: processGroupJournalSchema.shape.maxRecords.unwrap(),
|
|
60
|
+
maxBytes: processGroupJournalSchema.shape.maxBytes.unwrap(),
|
|
61
|
+
})
|
|
62
|
+
.parse(c.journal);
|
|
63
|
+
if ((!isLocalPilotPath(pkg) && !production) || path.resolve(admission.directory) !== admission.directory)
|
|
64
|
+
throw Error("Durable process-group admission is a same-host local pilot");
|
|
65
|
+
const persistent = !isLocalPilotPath(admission.directory);
|
|
66
|
+
if (production && !persistent)
|
|
67
|
+
throw Error("Authorized process-group journal requires a permanent mounted state root");
|
|
68
|
+
if (persistent) {
|
|
69
|
+
const stateRoot = process.env["UNS_PROCESS_GROUP_STATE_ROOT"];
|
|
70
|
+
if (!admission.journalId)
|
|
71
|
+
throw Error("Persistent admission needs its initialized journalId binding");
|
|
72
|
+
if (process.platform !== "linux" ||
|
|
73
|
+
!stateRoot ||
|
|
74
|
+
path.resolve(stateRoot) !== stateRoot ||
|
|
75
|
+
!isProcessGroupJournalPath(stateRoot, admission.directory, descriptor.namespace))
|
|
76
|
+
throw Error("Persistent admission needs the reviewed Linux node-local state root");
|
|
77
|
+
if (JSON.parse(resource(pkg, dir, "package.json").toString()).unsDatahub?.processGroupPersistentAdmission !== 1)
|
|
78
|
+
throw Error("Publisher does not support persistent admission ownership");
|
|
79
|
+
}
|
|
80
|
+
const capability = JSON.parse(resource(pkg, dir, "package.json").toString()).unsDatahub?.processGroupAdmission;
|
|
81
|
+
if (capability !== 1)
|
|
82
|
+
throw Error("Publisher does not support durable process-group admission");
|
|
83
|
+
if (path.isAbsolute(admission.groupManifest) || admission.groupManifest.includes(".."))
|
|
84
|
+
throw Error("Admission manifest must be package-relative");
|
|
85
|
+
const admitted = manifest.parse(JSON.parse(resource(pkg, dir, admission.groupManifest).toString()));
|
|
86
|
+
for (let parent = admission.directory; parent !== path.dirname(parent); parent = path.dirname(parent))
|
|
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
|
+
}
|
|
126
|
+
if (publisher.groupManifest && publisher.groupManifest !== admission.groupManifest)
|
|
127
|
+
throw Error("Admission and publisher manifests differ");
|
|
128
|
+
if (!publisher.groupManifest) {
|
|
129
|
+
const member = admitted.profiles.find((p) => p.processName === uns.processName);
|
|
130
|
+
if (!member ||
|
|
131
|
+
member.mappingSha256 !== sha(resource(pkg, dir, String(publisher.mappingFile))) ||
|
|
132
|
+
member.dataGroup !== (publisher.dataGroup ?? descriptor.defaultDataGroup))
|
|
133
|
+
throw Error("Original publisher differs from admission contract");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const checksum = options.configurationChecksum(raw);
|
|
137
|
+
if (!checksum)
|
|
138
|
+
throw Error("Invalid group configuration");
|
|
139
|
+
const processName = uns.processName;
|
|
140
|
+
for (const k of [...options.excludedUnsFields, "processName", "instanceMode", "handover", "handoverProtocol"])
|
|
141
|
+
delete uns[k];
|
|
142
|
+
const projectionChecksum = configurationAuthorizationHash(projectProcessGroupConfiguration(original, descriptor, uns, production?.sha256));
|
|
143
|
+
if (typeof publisher.groupManifest === "string") {
|
|
144
|
+
if (Object.keys(publisher).some((k) => k !== "groupManifest"))
|
|
145
|
+
throw Error("Group selector cannot override member settings");
|
|
146
|
+
// Installed manifests are package-relative; members resolve relative to that exact file.
|
|
147
|
+
if (path.isAbsolute(publisher.groupManifest) || publisher.groupManifest.includes(".."))
|
|
148
|
+
throw Error("Group manifest must be package-relative");
|
|
149
|
+
const bytes = resource(pkg, dir, path.resolve(pkg, publisher.groupManifest)), m = manifest.parse(JSON.parse(bytes.toString()));
|
|
150
|
+
if (m.processName !== processName ||
|
|
151
|
+
new Set(m.profiles.map((p) => p.processName)).size !== m.profiles.length ||
|
|
152
|
+
m.profiles.some((p) => p.processName === processName))
|
|
153
|
+
throw Error("Manifest process identities overlap");
|
|
154
|
+
for (const p of m.profiles)
|
|
155
|
+
if (sha(resource(pkg, dir, p.mappingFile, path.dirname(path.resolve(pkg, publisher.groupManifest)))) !== p.mappingSha256)
|
|
156
|
+
throw Error("Manifest member checksum changed");
|
|
157
|
+
return {
|
|
158
|
+
processName,
|
|
159
|
+
configurationChecksum: checksum,
|
|
160
|
+
projectionChecksum,
|
|
161
|
+
mappingSha256: null,
|
|
162
|
+
dataGroup: null,
|
|
163
|
+
contract: {
|
|
164
|
+
digest: sha(bytes),
|
|
165
|
+
processName,
|
|
166
|
+
profiles: m.profiles.map(({ mappingFile: _, ...p }) => p),
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
if (typeof publisher.mappingFile !== "string" || Object.keys(publisher).some((k) => !["mappingFile", "dataGroup"].includes(k)))
|
|
171
|
+
throw Error("Explicit original mapping file required");
|
|
172
|
+
return {
|
|
173
|
+
processName,
|
|
174
|
+
configurationChecksum: checksum,
|
|
175
|
+
projectionChecksum,
|
|
176
|
+
mappingSha256: sha(resource(pkg, dir, String(publisher.mappingFile))),
|
|
177
|
+
dataGroup: z
|
|
178
|
+
.string()
|
|
179
|
+
.min(1)
|
|
180
|
+
.max(100)
|
|
181
|
+
.parse(publisher.dataGroup ?? descriptor.defaultDataGroup),
|
|
182
|
+
contract: null,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=process-group-inspection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-group-inspection.js","sourceRoot":"","sources":["../../src/runtime/process-group-inspection.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\n\nimport {\n assertProcessGroupStateMount,\n authorizeConfiguredProcessGroupRuntime,\n configurationAuthorizationHash,\n hasProcessGroupAuthorization,\n processGroupManifestSchema as manifest,\n} from \"./process-group-authorization.js\";\nimport {\n isLocalPilotPath,\n isProcessGroupJournalPath,\n normalizeProcessGroupConfiguration,\n processGroupDescriptor,\n processGroupJournalContract,\n processGroupJournalSchema,\n processGroupSourceIdentity,\n projectProcessGroupConfiguration,\n resolvedProcessGroupInputChannel,\n} from \"./process-group-contract.js\";\n\nexport interface ProcessGroupConfigurationEvidence {\n processName: string;\n configurationChecksum: string;\n projectionChecksum: string;\n mappingSha256: string | null;\n dataGroup: string | null;\n contract: { digest: string; processName: string; profiles: { id: string; processName: string; mappingSha256: string; dataGroup: string }[] } | null;\n}\n/** Bound reads to installed package/instance resources, never arbitrary paths or symlinks. */\nfunction resource(pkg: string, dir: string, file: string, relativeTo?: string): Buffer {\n if (file.length > 512) throw Error(\"Group resource path too long\");\n const roots = [fs.realpathSync(pkg), fs.realpathSync(dir)];\n const candidates = relativeTo\n ? [path.resolve(relativeTo, file)]\n : path.isAbsolute(file)\n ? [file]\n : [path.resolve(dir, file), path.resolve(pkg, file)];\n for (const candidate of candidates) {\n if (!fs.existsSync(candidate)) continue;\n const real = fs.realpathSync(candidate);\n if (real !== candidate || !roots.some((root) => real.startsWith(root + path.sep)))\n throw Error(\"Group resource must stay inside installed package or instance\");\n const fd = fs.openSync(real, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW);\n try {\n const s = fs.fstatSync(fd);\n if (!s.isFile() || s.size > 1048576) throw Error(\"Invalid group resource\");\n const b = fs.readFileSync(fd);\n if (b.length > 1048576) throw Error(\"Group resource too large\");\n return b;\n } finally {\n fs.closeSync(fd);\n }\n }\n throw Error(\"Installed group resource is missing\");\n}\nconst sha = (b: Buffer) => createHash(\"sha256\").update(b).digest(\"hex\");\nexport function inspectProcessGroupConfiguration(\n pkg: string,\n dir: string,\n raw: string,\n controllerName = process.env[\"UNS_CONTROLLER_NAME\"] ?? \"\",\n options: { configurationChecksum(raw: string): string | null; excludedUnsFields: readonly string[] },\n): ProcessGroupConfigurationEvidence {\n const original = JSON.parse(raw);\n const descriptor = processGroupDescriptor(pkg);\n if (!descriptor) throw Error(\"Installed package has no supported process-group contract\");\n const c = normalizeProcessGroupConfiguration(original, descriptor),\n uns = { ...c.uns },\n publisher = c.publisher;\n const production =\n c.journal && (!isLocalPilotPath(pkg) || hasProcessGroupAuthorization())\n ? authorizeConfiguredProcessGroupRuntime(pkg, dir, original, controllerName)\n : undefined;\n if (production) assertProcessGroupStateMount(production, process.env[\"UNS_PROCESS_GROUP_STATE_ROOT\"] ?? \"\");\n if (!c.matches || (c.runtimeRole !== undefined && c.runtimeRole !== \"publisher\") || !publisher || typeof uns.processName !== \"string\")\n throw Error(\"This runtime has no supported reviewed group configuration\");\n if (c.journal !== undefined) {\n // Readiness requires explicit capacities; their limits come from the shared writer schema.\n const admission = processGroupJournalSchema\n .extend({\n minFreeBytes: processGroupJournalSchema.shape.minFreeBytes.unwrap().optional(),\n maxRecords: processGroupJournalSchema.shape.maxRecords.unwrap(),\n maxBytes: processGroupJournalSchema.shape.maxBytes.unwrap(),\n })\n .parse(c.journal);\n if ((!isLocalPilotPath(pkg) && !production) || path.resolve(admission.directory) !== admission.directory)\n throw Error(\"Durable process-group admission is a same-host local pilot\");\n const persistent = !isLocalPilotPath(admission.directory);\n if (production && !persistent) throw Error(\"Authorized process-group journal requires a permanent mounted state root\");\n if (persistent) {\n const stateRoot = process.env[\"UNS_PROCESS_GROUP_STATE_ROOT\"];\n if (!admission.journalId) throw Error(\"Persistent admission needs its initialized journalId binding\");\n if (\n process.platform !== \"linux\" ||\n !stateRoot ||\n path.resolve(stateRoot) !== stateRoot ||\n !isProcessGroupJournalPath(stateRoot, admission.directory, descriptor.namespace)\n )\n throw Error(\"Persistent admission needs the reviewed Linux node-local state root\");\n if (JSON.parse(resource(pkg, dir, \"package.json\").toString()).unsDatahub?.processGroupPersistentAdmission !== 1)\n throw Error(\"Publisher does not support persistent admission ownership\");\n }\n const capability = JSON.parse(resource(pkg, dir, \"package.json\").toString()).unsDatahub?.processGroupAdmission;\n if (capability !== 1) throw Error(\"Publisher does not support durable process-group admission\");\n if (path.isAbsolute(admission.groupManifest) || admission.groupManifest.includes(\"..\"))\n throw Error(\"Admission manifest must be package-relative\");\n const admitted = manifest.parse(JSON.parse(resource(pkg, dir, admission.groupManifest).toString()));\n for (let parent = admission.directory; parent !== path.dirname(parent); parent = path.dirname(parent))\n if (fs.lstatSync(parent).isSymbolicLink()) throw Error(\"Admission directory cannot use symbolic links\");\n const databaseFile = path.join(admission.directory, \"admission.sqlite\");\n if (fs.lstatSync(databaseFile).isSymbolicLink()) throw Error(\"Admission journal cannot use symbolic links\");\n const { DatabaseSync } = createRequire(import.meta.url)(\"node:sqlite\") as typeof import(\"node:sqlite\");\n const journal = new DatabaseSync(databaseFile, { readOnly: true });\n try {\n journal.exec(\"PRAGMA busy_timeout=1000\");\n if (persistent && journal.prepare(\"SELECT value FROM metadata WHERE key='id'\").get()?.[\"value\"] !== admission.journalId)\n throw Error(\"Persistent admission journalId binding differs\");\n const input = resolvedProcessGroupInputChannel(original);\n const sourceIdentity = processGroupSourceIdentity(input);\n const expected = processGroupJournalContract(sourceIdentity, admission, admitted.profiles);\n const contract = journal.prepare(\"SELECT value FROM metadata WHERE key='contract'\").get()?.[\"value\"];\n if (contract !== expected) throw Error(\"Durable admission journal contract differs\");\n const capture = JSON.parse(String(journal.prepare(\"SELECT value FROM metadata WHERE key='capture'\").get()?.[\"value\"] ?? \"null\"));\n if (\n !capture ||\n ![\"ready\", \"capacity-blocked\"].includes(capture.state) ||\n !Number.isSafeInteger(capture.pid) ||\n capture.pid <= 0 ||\n !Number.isSafeInteger(capture.heartbeat) ||\n Date.now() - capture.heartbeat > 5000 ||\n capture.heartbeat > Date.now() + 1000\n )\n throw Error(\"Durable admission receiver is not ready\");\n process.kill(capture.pid, 0);\n if (persistent) {\n const namespace = sha(\n Buffer.from(fs.readFileSync(\"/proc/sys/kernel/random/boot_id\", \"utf8\").trim() + \":\" + fs.readlinkSync(\"/proc/self/ns/pid\")),\n );\n const stored = journal.prepare(\"SELECT value FROM metadata WHERE key='runtime_namespace'\").get()?.[\"value\"];\n const stat = fs.readFileSync(`/proc/${capture.pid}/stat`, \"utf8\");\n const start = stat.slice(stat.lastIndexOf(\")\") + 2).split(\" \")[19];\n if (stored !== namespace || !start || capture.runtimeIdentity !== sha(Buffer.from(namespace + \":\" + capture.pid + \":\" + start)))\n throw Error(\"Admission capture namespace or process identity differs\");\n }\n } finally {\n journal.close();\n }\n if (publisher.groupManifest && publisher.groupManifest !== admission.groupManifest) throw Error(\"Admission and publisher manifests differ\");\n if (!publisher.groupManifest) {\n const member = admitted.profiles.find((p) => p.processName === uns.processName);\n if (\n !member ||\n member.mappingSha256 !== sha(resource(pkg, dir, String(publisher.mappingFile))) ||\n member.dataGroup !== (publisher.dataGroup ?? descriptor.defaultDataGroup)\n )\n throw Error(\"Original publisher differs from admission contract\");\n }\n }\n const checksum = options.configurationChecksum(raw);\n if (!checksum) throw Error(\"Invalid group configuration\");\n const processName = uns.processName;\n for (const k of [...options.excludedUnsFields, \"processName\", \"instanceMode\", \"handover\", \"handoverProtocol\"]) delete uns[k];\n const projectionChecksum = configurationAuthorizationHash(projectProcessGroupConfiguration(original, descriptor, uns, production?.sha256));\n if (typeof publisher.groupManifest === \"string\") {\n if (Object.keys(publisher).some((k) => k !== \"groupManifest\")) throw Error(\"Group selector cannot override member settings\");\n // Installed manifests are package-relative; members resolve relative to that exact file.\n if (path.isAbsolute(publisher.groupManifest) || publisher.groupManifest.includes(\"..\")) throw Error(\"Group manifest must be package-relative\");\n const bytes = resource(pkg, dir, path.resolve(pkg, publisher.groupManifest)),\n m = manifest.parse(JSON.parse(bytes.toString()));\n if (\n m.processName !== processName ||\n new Set(m.profiles.map((p) => p.processName)).size !== m.profiles.length ||\n m.profiles.some((p) => p.processName === processName)\n )\n throw Error(\"Manifest process identities overlap\");\n for (const p of m.profiles)\n if (sha(resource(pkg, dir, p.mappingFile, path.dirname(path.resolve(pkg, publisher.groupManifest)))) !== p.mappingSha256)\n throw Error(\"Manifest member checksum changed\");\n return {\n processName,\n configurationChecksum: checksum,\n projectionChecksum,\n mappingSha256: null,\n dataGroup: null,\n contract: {\n digest: sha(bytes),\n processName,\n profiles: m.profiles.map(({ mappingFile: _, ...p }) => p),\n },\n };\n }\n if (typeof publisher.mappingFile !== \"string\" || Object.keys(publisher).some((k) => ![\"mappingFile\", \"dataGroup\"].includes(k)))\n throw Error(\"Explicit original mapping file required\");\n return {\n processName,\n configurationChecksum: checksum,\n projectionChecksum,\n mappingSha256: sha(resource(pkg, dir, String(publisher.mappingFile))),\n dataGroup: z\n .string()\n .min(1)\n .max(100)\n .parse(publisher.dataGroup ?? descriptor.defaultDataGroup),\n contract: null,\n };\n}\n"]}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { ProcessGroupAuthorization } from "./process-group-authorization.js";
|
|
2
|
+
export declare function processGroupLaunchEnvironment(localPilot: boolean, authorization: ProcessGroupAuthorization | undefined, stateRoot: string | undefined, operationId: string | undefined): Record<string, string>;
|
|
3
|
+
//# sourceMappingURL=process-group-launch-environment.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-group-launch-environment.d.ts","sourceRoot":"","sources":["../../src/runtime/process-group-launch-environment.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAC;AAElF,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,OAAO,EACnB,aAAa,EAAE,yBAAyB,GAAG,SAAS,EACpD,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,WAAW,EAAE,MAAM,GAAG,SAAS,GAC9B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASxB"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { legacyPilotEnvironment } from "./compatibility/energenti-descriptor-v1.js";
|
|
2
|
+
export function processGroupLaunchEnvironment(localPilot, authorization, stateRoot, operationId) {
|
|
3
|
+
return {
|
|
4
|
+
UNS_PROCESS_GROUP_LOCAL_PILOT: localPilot ? "1" : "0",
|
|
5
|
+
...legacyPilotEnvironment(localPilot),
|
|
6
|
+
UNS_PROCESS_GROUP_AUTHORIZATION_FILE: authorization?.file ?? "",
|
|
7
|
+
UNS_PROCESS_GROUP_AUTHORIZATION_DIRECTORY: "",
|
|
8
|
+
UNS_PROCESS_GROUP_OPERATION_ID: authorization?.role === "target" ? (operationId ?? "") : "",
|
|
9
|
+
UNS_PROCESS_GROUP_STATE_ROOT: authorization || localPilot ? (stateRoot ?? "") : "",
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=process-group-launch-environment.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-group-launch-environment.js","sourceRoot":"","sources":["../../src/runtime/process-group-launch-environment.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,4CAA4C,CAAC;AAGpF,MAAM,UAAU,6BAA6B,CAC3C,UAAmB,EACnB,aAAoD,EACpD,SAA6B,EAC7B,WAA+B;IAE/B,OAAO;QACL,6BAA6B,EAAE,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;QACrD,GAAG,sBAAsB,CAAC,UAAU,CAAC;QACrC,oCAAoC,EAAE,aAAa,EAAE,IAAI,IAAI,EAAE;QAC/D,yCAAyC,EAAE,EAAE;QAC7C,8BAA8B,EAAE,aAAa,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;QAC3F,4BAA4B,EAAE,aAAa,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;KACnF,CAAC;AACJ,CAAC","sourcesContent":["import { legacyPilotEnvironment } from \"./compatibility/energenti-descriptor-v1.js\";\nimport type { ProcessGroupAuthorization } from \"./process-group-authorization.js\";\n\nexport function processGroupLaunchEnvironment(\n localPilot: boolean,\n authorization: ProcessGroupAuthorization | undefined,\n stateRoot: string | undefined,\n operationId: string | undefined,\n): Record<string, string> {\n return {\n UNS_PROCESS_GROUP_LOCAL_PILOT: localPilot ? \"1\" : \"0\",\n ...legacyPilotEnvironment(localPilot),\n UNS_PROCESS_GROUP_AUTHORIZATION_FILE: authorization?.file ?? \"\",\n UNS_PROCESS_GROUP_AUTHORIZATION_DIRECTORY: \"\",\n UNS_PROCESS_GROUP_OPERATION_ID: authorization?.role === \"target\" ? (operationId ?? \"\") : \"\",\n UNS_PROCESS_GROUP_STATE_ROOT: authorization || localPilot ? (stateRoot ?? \"\") : \"\",\n };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process-group-legacy-start.d.ts","sourceRoot":"","sources":["../../src/runtime/process-group-legacy-start.ts"],"names":[],"mappings":"AAIA,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,UAAU,CAAC,EAAE,OAAO,GAAG,IAAI,CAWvG"}
|