@serve.zone/interfaces 30.6.0 → 30.8.1

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.
@@ -0,0 +1,448 @@
1
+ import type { TSha256Digest } from './immutableimage.js';
2
+ import type { IRuntimeAssignmentReferenceV1, IRuntimeAuthorityReferenceV1, IRuntimeControllerV1 } from './runtimeassignment.js';
3
+ import { snapshotRuntimeAssignmentV1, validateRuntimeAssignmentV1 } from './runtimeassignment.js';
4
+ import type { IRuntimeNetworkHandoffLeaseV1, IRuntimeNetworkProtectedAuthorityV1 } from './networkauthority.js';
5
+ import { bindRuntimeNetworkHandoffLeaseV1, computeRuntimeNetworkProtectedAuthorityV1Digest,
6
+ snapshotRuntimeNetworkHandoffLeaseV1, snapshotRuntimeNetworkProtectedAuthorityV1 } from './networkauthority.js';
7
+ import type { IPrivateNetworkV1, IServicePrivateNetworksV1, IServicePrivateNetworkDnsPolicyV1 } from './privatenetwork.js';
8
+ import { buildPrivateNetworkFqdnV1, composeServicePrivateNetworkDnsPolicyV1,
9
+ snapshotPrivateNetworkV1, snapshotServicePrivateNetworksV1 } from './privatenetwork.js';
10
+ import { captureNetwork, failNetwork, networkCanonical, networkContains, networkController, networkCounter,
11
+ networkDigest, networkEqual, networkHash, networkId, networkIpv4, networkIpv4Number, networkList,
12
+ networkOverlaps, networkPrefixBounds, networkRecord, networkReference, networkReferenceOf, networkRevision,
13
+ networkSafe, networkSorted, requireNetwork } from '../private/networkcontract.js';
14
+
15
+ export interface IRuntimeNetworkNodeScopeV1 {
16
+ controller: IRuntimeControllerV1;
17
+ nodeId: string;
18
+ runtimeNamespace: string;
19
+ }
20
+
21
+ /** Immutable per-attempt address material. Membership and projection revisions are independent. */
22
+ export interface IRuntimeNetworkWorkloadLeaseV1 extends IRuntimeNetworkNodeScopeV1 {
23
+ schemaVersion: 1;
24
+ id: string;
25
+ /** Allocation incarnation, not a mutable desired-state revision. */
26
+ generation: number;
27
+ organizationId: string;
28
+ assignmentId: string;
29
+ serviceId: string;
30
+ replicaId: string;
31
+ attemptId: string;
32
+ protectedAuthority: IRuntimeAuthorityReferenceV1;
33
+ routerIncarnationId: string;
34
+ ipv4: {
35
+ poolId: string;
36
+ /** Dedicated, unbridged point-to-point subnet; never the host transit pool. */
37
+ linkSubnet: string;
38
+ address: string;
39
+ /** Exactly address/32, distinct from the link subnet and node-control prefix. */
40
+ sourcePrefix: string;
41
+ gateway: string;
42
+ };
43
+ /** Router-side reachable address on port 53, injected through CRI dns_config. */
44
+ dnsServer: string;
45
+ digest: TSha256Digest;
46
+ }
47
+
48
+ /** Controller-owned readiness evidence. A signature does not prove this evidence's provenance. */
49
+ export interface IRuntimeNetworkEndpointV1 {
50
+ lease: IRuntimeNetworkWorkloadLeaseV1;
51
+ ready: boolean;
52
+ observation: {
53
+ assignment: IRuntimeAssignmentReferenceV1;
54
+ reporterSessionId: string;
55
+ sequence: number;
56
+ digest: TSha256Digest;
57
+ } | null;
58
+ /** TCP/UDP only; the complete protected union remains denied. */
59
+ publicEgress: boolean;
60
+ platformEndpointIds: string[];
61
+ }
62
+
63
+ /** Exact directed grant identity; receiver-owned realization resolves the lease to kernel facts. */
64
+ export interface IRuntimeNetworkPacketGrantV1 {
65
+ source: IRuntimeAuthorityReferenceV1;
66
+ destination:
67
+ | { kind: 'workload'; lease: IRuntimeAuthorityReferenceV1 }
68
+ | { kind: 'public' }
69
+ | { kind: 'platform'; id: string; address: string; protocol: 'tcp' | 'udp'; port: number };
70
+ }
71
+
72
+ export interface IRuntimeNetworkProjectionV1 extends IRuntimeNetworkNodeScopeV1 {
73
+ schemaVersion: 1;
74
+ id: string;
75
+ generation: number;
76
+ previous: IRuntimeAuthorityReferenceV1 | null;
77
+ protectedAuthority: IRuntimeNetworkProtectedAuthorityV1;
78
+ /** Exact historical authorities needed to authenticate retained allocation material. */
79
+ allocationAuthorities: IRuntimeNetworkProtectedAuthorityV1[];
80
+ handoff: IRuntimeNetworkHandoffLeaseV1 | null;
81
+ /** COMPLETE relevant definitions, including declared names with no ready replicas. */
82
+ networks: IPrivateNetworkV1[];
83
+ memberships: IServicePrivateNetworksV1[];
84
+ endpoints: IRuntimeNetworkEndpointV1[];
85
+ dns: { issuedAt: number; notBefore: number; expiresAt: number };
86
+ /** Explicit denial intent. Carry until the exact predecessor's application is proven. */
87
+ withdrawals: IRuntimeNetworkPacketGrantV1[];
88
+ retiredLeases: IRuntimeAuthorityReferenceV1[];
89
+ retiredHandoffs: IRuntimeAuthorityReferenceV1[];
90
+ digest: TSha256Digest;
91
+ }
92
+
93
+ export interface IRuntimeNetworkDnsViewV1 {
94
+ source: IRuntimeAuthorityReferenceV1;
95
+ sourceAddress: string;
96
+ dnsServer: string;
97
+ policy: IServicePrivateNetworkDnsPolicyV1;
98
+ /** Sorted complete A sets; [] is declared NODATA, never an omitted name. AAAA is NODATA. */
99
+ records: Array<{ name: string; addresses: string[] }>;
100
+ }
101
+
102
+ export const runtimeNetworkProjectionV1Contract = Object.freeze({
103
+ workloadDigestDomain: 'serve.zone/runtime-network-workload-lease-v1',
104
+ projectionDigestDomain: 'serve.zone/runtime-network-projection-v1',
105
+ maximumCanonicalBytes: 917_504,
106
+ maximumAllocationAuthorities: 16,
107
+ maximumNetworks: 128,
108
+ maximumMemberships: 256,
109
+ maximumEndpoints: 256,
110
+ maximumGrants: 4096,
111
+ maximumDnsLeaseMs: 900_000,
112
+ positiveTtlSeconds: 5,
113
+ negativeTtlSeconds: 1,
114
+ omission: 'no-effect-without-explicit-withdrawal',
115
+ packetLifetime: 'until-applied-denial-or-independent-fence',
116
+ acknowledgement: 'admission-is-not-application-or-readiness',
117
+ allocationReuse: 'requires-controller-quarantine-and-all-affected-authority-fences',
118
+ } as const);
119
+
120
+ const scope = (item: Record<string, unknown>): IRuntimeNetworkNodeScopeV1 => ({
121
+ controller: networkController(item.controller), nodeId: networkId(item.nodeId), runtimeNamespace: networkId(item.runtimeNamespace),
122
+ });
123
+ const sameScope = (left: IRuntimeNetworkNodeScopeV1, right: IRuntimeNetworkNodeScopeV1): boolean =>
124
+ networkEqual(left.controller, right.controller) && left.nodeId === right.nodeId && left.runtimeNamespace === right.runtimeNamespace;
125
+ const ownerKey = (value: { organizationId: string; serviceId: string }): string => networkCanonical([value.organizationId, value.serviceId]);
126
+ const attemptKey = (value: IRuntimeNetworkWorkloadLeaseV1): string =>
127
+ networkCanonical([value.organizationId, value.serviceId, value.replicaId, value.attemptId]);
128
+ const refKey = (value: IRuntimeAuthorityReferenceV1): string => networkCanonical(networkReferenceOf(value));
129
+ const sortedReferences = (value: unknown): IRuntimeAuthorityReferenceV1[] =>
130
+ networkSorted(networkList(value, 256, networkReference), refKey);
131
+
132
+ export const snapshotRuntimeNetworkNodeScopeV1 = (value: unknown): IRuntimeNetworkNodeScopeV1 => networkSafe(() =>
133
+ scope(networkRecord(captureNetwork(value), ['controller', 'nodeId', 'runtimeNamespace'])));
134
+
135
+ export const snapshotRuntimeNetworkWorkloadLeaseV1 = (value: unknown): IRuntimeNetworkWorkloadLeaseV1 => networkSafe(() => {
136
+ const item = networkRecord(captureNetwork(value), ['schemaVersion', 'id', 'generation', 'controller', 'nodeId', 'runtimeNamespace',
137
+ 'organizationId', 'assignmentId', 'serviceId', 'replicaId', 'attemptId', 'protectedAuthority', 'routerIncarnationId', 'ipv4', 'dnsServer', 'digest']);
138
+ requireNetwork(item.schemaVersion === 1);
139
+ const ip = networkRecord(item.ipv4, ['poolId', 'linkSubnet', 'address', 'sourcePrefix', 'gateway']);
140
+ requireNetwork(typeof ip.linkSubnet === 'string' && ip.linkSubnet.length <= 18);
141
+ const pieces = ip.linkSubnet.split('/');
142
+ requireNetwork(pieces.length === 2 && /^(?:[89]|[12][0-9]|3[01])$/.test(pieces[1]));
143
+ const first = networkIpv4Number(networkIpv4(pieces[0]));
144
+ requireNetwork(first % 2 ** (32 - Number(pieces[1])) === 0
145
+ && ['10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16'].some(prefix => networkContains(prefix, ip.linkSubnet as string)));
146
+ const address = networkIpv4(ip.address), gateway = networkIpv4(ip.gateway), [low, high] = networkPrefixBounds(ip.linkSubnet);
147
+ requireNetwork(address !== gateway && ip.sourcePrefix === `${address}/32`);
148
+ for (const current of [address, gateway]) {
149
+ const number = networkIpv4Number(current);
150
+ requireNetwork(number >= low && number <= high && (high - low === 1 || (number !== low && number !== high)));
151
+ }
152
+ requireNetwork(item.dnsServer === gateway);
153
+ return { schemaVersion: 1, id: networkId(item.id), generation: networkCounter(item.generation), ...scope(item),
154
+ organizationId: networkId(item.organizationId), assignmentId: networkId(item.assignmentId), serviceId: networkId(item.serviceId),
155
+ replicaId: networkId(item.replicaId), attemptId: networkId(item.attemptId), protectedAuthority: networkReference(item.protectedAuthority),
156
+ routerIncarnationId: networkId(item.routerIncarnationId), ipv4: { poolId: networkId(ip.poolId), linkSubnet: ip.linkSubnet,
157
+ address, sourcePrefix: ip.sourcePrefix, gateway }, dnsServer: gateway, digest: networkDigest(item.digest) };
158
+ });
159
+
160
+ export const computeRuntimeNetworkWorkloadLeaseV1Digest = (value: IRuntimeNetworkWorkloadLeaseV1): Promise<TSha256Digest> =>
161
+ networkHash(runtimeNetworkProjectionV1Contract.workloadDigestDomain, snapshotRuntimeNetworkWorkloadLeaseV1(value));
162
+
163
+ const packetGrant = (value: unknown): IRuntimeNetworkPacketGrantV1 => {
164
+ const item = networkRecord(value, ['source', 'destination']);
165
+ requireNetwork(item.destination !== null && typeof item.destination === 'object');
166
+ const kind = (item.destination as Record<string, unknown>).kind;
167
+ if (kind === 'workload') {
168
+ const destination = networkRecord(item.destination, ['kind', 'lease']);
169
+ const source = networkReference(item.source), lease = networkReference(destination.lease);
170
+ requireNetwork(!networkEqual(source, lease));
171
+ return { source, destination: { kind, lease } };
172
+ }
173
+ if (kind === 'public') {
174
+ networkRecord(item.destination, ['kind']); return { source: networkReference(item.source), destination: { kind } };
175
+ }
176
+ requireNetwork(kind === 'platform');
177
+ const destination = networkRecord(item.destination, ['kind', 'id', 'address', 'protocol', 'port']);
178
+ requireNetwork(destination.protocol === 'tcp' || destination.protocol === 'udp');
179
+ return { source: networkReference(item.source), destination: { kind, id: networkId(destination.id), address: networkIpv4(destination.address),
180
+ protocol: destination.protocol, port: networkCounter(destination.port, 65535) } };
181
+ };
182
+ const endpoint = (value: unknown): IRuntimeNetworkEndpointV1 => {
183
+ const item = networkRecord(value, ['lease', 'ready', 'observation', 'publicEgress', 'platformEndpointIds']);
184
+ requireNetwork(typeof item.ready === 'boolean' && typeof item.publicEgress === 'boolean');
185
+ const lease = snapshotRuntimeNetworkWorkloadLeaseV1(item.lease);
186
+ let observation: IRuntimeNetworkEndpointV1['observation'] = null;
187
+ if (item.observation !== null) {
188
+ const observed = networkRecord(item.observation, ['assignment', 'reporterSessionId', 'sequence', 'digest']);
189
+ const assignment = networkRecord(observed.assignment, ['assignmentId', 'generation', 'digest']);
190
+ requireNetwork(assignment.assignmentId === lease.assignmentId);
191
+ observation = { assignment: { assignmentId: lease.assignmentId, generation: networkCounter(assignment.generation), digest: networkDigest(assignment.digest) },
192
+ reporterSessionId: networkId(observed.reporterSessionId), sequence: networkCounter(observed.sequence), digest: networkDigest(observed.digest) };
193
+ }
194
+ requireNetwork(!item.ready || (observation !== null && observation.assignment.generation === 1));
195
+ return { lease, ready: item.ready, observation, publicEgress: item.publicEgress,
196
+ platformEndpointIds: networkSorted(networkList(item.platformEndpointIds, 64, networkId), value => value) };
197
+ };
198
+
199
+ /** Structural snapshot only; use validate/signature/admission helpers before accepting authority. */
200
+ export const snapshotRuntimeNetworkProjectionV1 = (value: unknown): IRuntimeNetworkProjectionV1 => networkSafe(() => {
201
+ const captured = captureNetwork(value);
202
+ requireNetwork(new TextEncoder().encode(networkCanonical(captured)).length <= runtimeNetworkProjectionV1Contract.maximumCanonicalBytes);
203
+ const item = networkRecord(captured, ['schemaVersion', 'id', 'generation', 'previous', 'controller', 'nodeId', 'runtimeNamespace',
204
+ 'protectedAuthority', 'allocationAuthorities', 'handoff', 'networks', 'memberships', 'endpoints', 'dns', 'withdrawals', 'retiredLeases', 'retiredHandoffs', 'digest']);
205
+ requireNetwork(item.schemaVersion === 1);
206
+ const dns = networkRecord(item.dns, ['issuedAt', 'notBefore', 'expiresAt']);
207
+ const window = { issuedAt: networkCounter(dns.issuedAt), notBefore: networkCounter(dns.notBefore), expiresAt: networkCounter(dns.expiresAt) };
208
+ requireNetwork(window.notBefore >= window.issuedAt && window.expiresAt > window.notBefore && window.expiresAt - window.issuedAt <= 900_000);
209
+ return { schemaVersion: 1, ...networkRevision(item), ...scope(item),
210
+ protectedAuthority: snapshotRuntimeNetworkProtectedAuthorityV1(item.protectedAuthority),
211
+ allocationAuthorities: networkSorted(networkList(item.allocationAuthorities, 16, snapshotRuntimeNetworkProtectedAuthorityV1), refKey),
212
+ handoff: item.handoff === null ? null : snapshotRuntimeNetworkHandoffLeaseV1(item.handoff),
213
+ networks: networkSorted(networkList(item.networks, 128, snapshotPrivateNetworkV1), value => value.id),
214
+ memberships: networkSorted(networkList(item.memberships, 256, snapshotServicePrivateNetworksV1), ownerKey),
215
+ endpoints: networkSorted(networkList(item.endpoints, 256, endpoint), value => value.lease.id), dns: window,
216
+ withdrawals: networkSorted(networkList(item.withdrawals, 4096, packetGrant), networkCanonical),
217
+ retiredLeases: sortedReferences(item.retiredLeases), retiredHandoffs: sortedReferences(item.retiredHandoffs), digest: networkDigest(item.digest) };
218
+ });
219
+
220
+ const grantsOf = (projection: IRuntimeNetworkProjectionV1): IRuntimeNetworkPacketGrantV1[] => {
221
+ const result: IRuntimeNetworkPacketGrantV1[] = [];
222
+ const memberships = new Map(projection.memberships.map(member => [ownerKey(member), member]));
223
+ const append = (grant: IRuntimeNetworkPacketGrantV1) => {
224
+ requireNetwork(result.length < 4096); result.push(grant);
225
+ };
226
+ for (const source of projection.endpoints) {
227
+ const member = memberships.get(ownerKey(source.lease)); requireNetwork(member);
228
+ for (const destination of projection.endpoints) {
229
+ if (source === destination || (!sameScope(source.lease, projection) && !sameScope(destination.lease, projection))) continue;
230
+ const target = memberships.get(ownerKey(destination.lease)); requireNetwork(target);
231
+ if (member.organizationId === target.organizationId && member.attachments.some(attachment =>
232
+ target.attachments.some(other => other.networkId === attachment.networkId))) {
233
+ append({ source: networkReferenceOf(source.lease), destination: { kind: 'workload', lease: networkReferenceOf(destination.lease) } });
234
+ }
235
+ }
236
+ if (!sameScope(source.lease, projection)) continue;
237
+ if (source.publicEgress) append({ source: networkReferenceOf(source.lease), destination: { kind: 'public' } });
238
+ for (const id of source.platformEndpointIds) {
239
+ const platform = projection.protectedAuthority.platformEndpoints.find(item => item.id === id); requireNetwork(platform);
240
+ append({ source: networkReferenceOf(source.lease), destination: { kind: 'platform', ...platform } });
241
+ }
242
+ }
243
+ return result.sort((left, right) => networkCanonical(left) < networkCanonical(right) ? -1 : 1);
244
+ };
245
+
246
+ export const computeRuntimeNetworkProjectionV1Digest = (value: IRuntimeNetworkProjectionV1): Promise<TSha256Digest> =>
247
+ networkHash(runtimeNetworkProjectionV1Contract.projectionDigestDomain, snapshotRuntimeNetworkProjectionV1(value));
248
+
249
+ /** Complete structural, digest, allocation and policy binding. Not an allocation/barrier/readiness proof. */
250
+ export const validateRuntimeNetworkProjectionV1 = async (value: unknown): Promise<IRuntimeNetworkProjectionV1> => {
251
+ try {
252
+ const projection = snapshotRuntimeNetworkProjectionV1(value), current = projection.protectedAuthority;
253
+ requireNetwork(networkEqual(current.controller, projection.controller) && current.egressAuthorities.some(owner =>
254
+ owner.nodeId === projection.nodeId && owner.runtimeNamespace === projection.runtimeNamespace));
255
+ const authorities = [current, ...projection.allocationAuthorities];
256
+ requireNetwork(new Set(authorities.map(refKey)).size === authorities.length);
257
+ for (const authority of authorities) {
258
+ requireNetwork(networkEqual(authority.controller, projection.controller)
259
+ && authority.digest === await computeRuntimeNetworkProtectedAuthorityV1Digest(authority));
260
+ }
261
+ const allocationAuthority = (reference: IRuntimeAuthorityReferenceV1) => {
262
+ const result = authorities.find(authority => networkEqual(networkReferenceOf(authority), reference)); requireNetwork(result); return result;
263
+ };
264
+ if (projection.handoff !== null) {
265
+ await bindRuntimeNetworkHandoffLeaseV1(projection.handoff, allocationAuthority(projection.handoff.protectedAuthority));
266
+ requireNetwork(sameScope(projection.handoff, projection));
267
+ requireNetwork(current.pools.some(pool => pool.id === projection.handoff!.transit.poolId && pool.purpose === 'transit'
268
+ && networkContains(pool.prefix, projection.handoff!.transit.prefix)));
269
+ }
270
+ const networks = new Map(projection.networks.map(network => [network.id, network]));
271
+ const organizationKeys = new Map<string, string>(), keysToOrganizations = new Map<string, string>();
272
+ const names = new Set<string>();
273
+ for (const network of projection.networks) {
274
+ requireNetwork(network.state === 'active');
275
+ const key = `${network.organizationDnsKey}.${network.networkDnsKey}`;
276
+ requireNetwork(!names.has(key)); names.add(key);
277
+ requireNetwork(!organizationKeys.has(network.organizationId) || organizationKeys.get(network.organizationId) === network.organizationDnsKey);
278
+ requireNetwork(!keysToOrganizations.has(network.organizationDnsKey) || keysToOrganizations.get(network.organizationDnsKey) === network.organizationId);
279
+ organizationKeys.set(network.organizationId, network.organizationDnsKey); keysToOrganizations.set(network.organizationDnsKey, network.organizationId);
280
+ for (const upstream of network.policy.externalDns?.upstreams ?? []) requireNetwork(current.resolvers.some(resolver =>
281
+ resolver.address === upstream.address && resolver.port === upstream.port));
282
+ }
283
+ const members = new Map(projection.memberships.map(member => [ownerKey(member), member])), aliases = new Set<string>();
284
+ for (const member of projection.memberships) {
285
+ composeServicePrivateNetworkDnsPolicyV1(member, member.attachments.map(attachment => networks.get(attachment.networkId)));
286
+ for (const attachment of member.attachments) for (const alias of attachment.aliases) {
287
+ const name = buildPrivateNetworkFqdnV1(networks.get(attachment.networkId), alias);
288
+ requireNetwork(!aliases.has(name)); aliases.add(name);
289
+ }
290
+ }
291
+ const assignments = new Set<string>(), attempts = new Set<string>(), readyReplicas = new Set<string>();
292
+ for (const endpoint of projection.endpoints) {
293
+ const lease = endpoint.lease, authority = allocationAuthority(lease.protectedAuthority);
294
+ requireNetwork(networkEqual(lease.controller, projection.controller) && members.has(ownerKey(lease))
295
+ && !assignments.has(lease.assignmentId) && !attempts.has(attemptKey(lease)));
296
+ assignments.add(lease.assignmentId); attempts.add(attemptKey(lease));
297
+ if (endpoint.ready) {
298
+ const replica = networkCanonical([lease.organizationId, lease.serviceId, lease.replicaId]);
299
+ requireNetwork(!readyReplicas.has(replica)); readyReplicas.add(replica);
300
+ }
301
+ requireNetwork(lease.digest === await computeRuntimeNetworkWorkloadLeaseV1Digest(lease));
302
+ requireNetwork(authority.egressAuthorities.some(owner => owner.nodeId === lease.nodeId && owner.runtimeNamespace === lease.runtimeNamespace)
303
+ && current.egressAuthorities.some(owner => owner.nodeId === lease.nodeId && owner.runtimeNamespace === lease.runtimeNamespace));
304
+ for (const protection of [authority, current]) requireNetwork(protection.pools.some(pool =>
305
+ pool.id === lease.ipv4.poolId && pool.purpose === 'workload' && networkContains(pool.prefix, lease.ipv4.linkSubnet)));
306
+ if (sameScope(lease, projection)) requireNetwork(projection.handoff !== null && lease.routerIncarnationId === projection.handoff.routerIncarnationId);
307
+ for (const id of endpoint.platformEndpointIds) requireNetwork(current.platformEndpoints.some(platform => platform.id === id));
308
+ requireNetwork(!projection.retiredLeases.some(retired => networkEqual(retired, networkReferenceOf(lease))));
309
+ }
310
+ for (let index = 0; index < projection.endpoints.length; index++) for (let previous = 0; previous < index; previous++) {
311
+ requireNetwork(!networkOverlaps(projection.endpoints[index].lease.ipv4.linkSubnet, projection.endpoints[previous].lease.ipv4.linkSubnet));
312
+ }
313
+ if (projection.handoff) requireNetwork(!projection.retiredHandoffs.some(retired => networkEqual(retired, networkReferenceOf(projection.handoff!))));
314
+ const grants = new Set(grantsOf(projection).map(networkCanonical));
315
+ requireNetwork(projection.withdrawals.every(grant => !grants.has(networkCanonical(grant))));
316
+ requireNetwork(projection.digest === await computeRuntimeNetworkProjectionV1Digest(projection));
317
+ return projection;
318
+ } catch { return failNetwork(); }
319
+ };
320
+
321
+ /** Complete directed full-mesh and explicitly authorized egress; no DNS readiness dependency. */
322
+ export const getRuntimeNetworkProjectionPacketGrantsV1 = async (value: unknown): Promise<IRuntimeNetworkPacketGrantV1[]> =>
323
+ grantsOf(await validateRuntimeNetworkProjectionV1(value));
324
+
325
+ /** Complete offline DNS material, including authorized names never previously queried. */
326
+ export const composeRuntimeNetworkProjectionDnsViewsV1 = async (value: unknown): Promise<IRuntimeNetworkDnsViewV1[]> => {
327
+ const projection = await validateRuntimeNetworkProjectionV1(value);
328
+ const networks = new Map(projection.networks.map(network => [network.id, network]));
329
+ const members = new Map(projection.memberships.map(member => [ownerKey(member), member]));
330
+ return projection.endpoints.filter(endpoint => sameScope(endpoint.lease, projection)).map(endpoint => {
331
+ const member = members.get(ownerKey(endpoint.lease))!;
332
+ const policy = composeServicePrivateNetworkDnsPolicyV1(member, member.attachments.map(attachment => networks.get(attachment.networkId)));
333
+ const records: IRuntimeNetworkDnsViewV1['records'] = [];
334
+ for (const target of projection.memberships) {
335
+ if (target.organizationId !== member.organizationId) continue;
336
+ const addresses = projection.endpoints.filter(candidate => candidate.ready && ownerKey(candidate.lease) === ownerKey(target))
337
+ .map(candidate => candidate.lease.ipv4.address).sort();
338
+ for (const attachment of target.attachments) {
339
+ if (!member.attachments.some(own => own.networkId === attachment.networkId)) continue;
340
+ for (const alias of attachment.aliases) records.push({ name: buildPrivateNetworkFqdnV1(networks.get(attachment.networkId), alias), addresses: [...addresses] });
341
+ }
342
+ }
343
+ records.sort((left, right) => left.name < right.name ? -1 : 1);
344
+ return { source: networkReferenceOf(endpoint.lease), sourceAddress: endpoint.lease.ipv4.address, dnsServer: endpoint.lease.dnsServer, policy, records };
345
+ });
346
+ };
347
+
348
+ /** Bind immutable address material without a circular assignment-digest dependency. */
349
+ export const bindRuntimeNetworkWorkloadLeaseToAssignmentV1 = async (leaseValue: unknown, assignmentValue: unknown): Promise<IRuntimeNetworkWorkloadLeaseV1> => {
350
+ try {
351
+ const lease = snapshotRuntimeNetworkWorkloadLeaseV1(leaseValue), assignment = snapshotRuntimeAssignmentV1(assignmentValue);
352
+ requireNetwork((await validateRuntimeAssignmentV1(assignment)).length === 0 && sameScope(lease, assignment)
353
+ && lease.organizationId === assignment.organizationId && lease.assignmentId === assignment.assignmentId
354
+ && lease.serviceId === assignment.serviceId && lease.replicaId === assignment.replicaId && lease.attemptId === assignment.attemptId
355
+ && networkEqual(networkReferenceOf(lease), assignment.workload.network)
356
+ && lease.digest === await computeRuntimeNetworkWorkloadLeaseV1Digest(lease));
357
+ return lease;
358
+ } catch { return failNetwork(); }
359
+ };
360
+
361
+ /**
362
+ * Pure revision decision. appliedPrevious must be the receiver's exact durable,
363
+ * joined application receipt, never an incoming ACK field. All prior accepted
364
+ * material/apply journals survive until effects and DNS/allocation quarantine end.
365
+ */
366
+ export const admitRuntimeNetworkProjectionV1 = async (
367
+ value: unknown, previousValue: unknown | null, trustedScopeValue: unknown, appliedPreviousValue: unknown | null,
368
+ ): Promise<{ status: 'accepted' | 'replay'; projection: IRuntimeNetworkProjectionV1 }> => {
369
+ try {
370
+ // Snapshot ALL caller-owned inputs before the first asynchronous operation.
371
+ const incoming = snapshotRuntimeNetworkProjectionV1(value);
372
+ const previousInput = previousValue === null ? null : snapshotRuntimeNetworkProjectionV1(previousValue);
373
+ const trusted = snapshotRuntimeNetworkNodeScopeV1(trustedScopeValue);
374
+ const applied = appliedPreviousValue === null ? null : networkReference(captureNetwork(appliedPreviousValue));
375
+ const projection = await validateRuntimeNetworkProjectionV1(incoming);
376
+ requireNetwork(sameScope(projection, trusted));
377
+ if (previousInput === null) {
378
+ requireNetwork(projection.generation === 1 && applied === null && projection.withdrawals.length === 0
379
+ && projection.retiredLeases.length === 0 && projection.retiredHandoffs.length === 0);
380
+ return { status: 'accepted', projection };
381
+ }
382
+ const previous = await validateRuntimeNetworkProjectionV1(previousInput);
383
+ requireNetwork(sameScope(previous, trusted) && previous.id === projection.id);
384
+ requireNetwork(applied === null || networkEqual(applied, networkReferenceOf(previous)));
385
+ if (projection.generation === previous.generation) {
386
+ requireNetwork(networkEqual(previous, projection)); return { status: 'replay', projection };
387
+ }
388
+ requireNetwork(networkEqual(projection.previous, networkReferenceOf(previous)));
389
+ requireNetwork(projection.dns.issuedAt >= previous.dns.issuedAt);
390
+ for (const old of previous.networks) {
391
+ const current = projection.networks.find(network => network.id === old.id);
392
+ if (!current) continue;
393
+ requireNetwork(current.organizationId === old.organizationId && current.organizationDnsKey === old.organizationDnsKey
394
+ && current.networkDnsKey === old.networkDnsKey && current.createdAt === old.createdAt && current.revision >= old.revision);
395
+ if (current.revision === old.revision) requireNetwork(networkEqual(current, old));
396
+ }
397
+ for (const old of previous.memberships) {
398
+ const current = projection.memberships.find(member => ownerKey(member) === ownerKey(old));
399
+ if (!current) continue;
400
+ requireNetwork(current.revision >= old.revision);
401
+ if (current.revision === old.revision) requireNetwork(networkEqual(current, old));
402
+ }
403
+ const grants = new Set(grantsOf(projection).map(networkCanonical)), withdrawn = new Set(projection.withdrawals.map(networkCanonical));
404
+ const previousGrants = grantsOf(previous);
405
+ for (const grant of previousGrants) requireNetwork(grants.has(networkCanonical(grant)) || withdrawn.has(networkCanonical(grant)));
406
+ const knownWithdrawals = new Set([...previousGrants, ...previous.withdrawals].map(networkCanonical));
407
+ requireNetwork(projection.withdrawals.every(grant => knownWithdrawals.has(networkCanonical(grant))));
408
+ const knownLeases = [...previous.endpoints.map(endpoint => networkReferenceOf(endpoint.lease)), ...previous.retiredLeases];
409
+ const knownHandoffs = [...(previous.handoff ? [networkReferenceOf(previous.handoff)] : []), ...previous.retiredHandoffs];
410
+ requireNetwork(projection.retiredLeases.every(retired => knownLeases.some(known => networkEqual(known, retired)))
411
+ && projection.retiredHandoffs.every(retired => knownHandoffs.some(known => networkEqual(known, retired))));
412
+ const requireCarried = (old: IRuntimeAuthorityReferenceV1[], next: IRuntimeAuthorityReferenceV1[]) => {
413
+ for (const reference of old) requireNetwork(next.some(item => networkEqual(item, reference)));
414
+ };
415
+ if (applied === null) {
416
+ for (const grant of previous.withdrawals) requireNetwork(withdrawn.has(networkCanonical(grant)));
417
+ requireCarried(previous.retiredLeases, projection.retiredLeases); requireCarried(previous.retiredHandoffs, projection.retiredHandoffs);
418
+ }
419
+ for (const old of previous.endpoints) {
420
+ // A different allocation ID cannot rename the same immutable execution attempt.
421
+ for (const candidate of projection.endpoints) {
422
+ if (candidate.lease.assignmentId === old.lease.assignmentId || attemptKey(candidate.lease) === attemptKey(old.lease)) {
423
+ requireNetwork(networkEqual(candidate.lease, old.lease));
424
+ }
425
+ }
426
+ const current = projection.endpoints.find(item => item.lease.id === old.lease.id);
427
+ if (current) {
428
+ requireNetwork(networkEqual(current.lease, old.lease));
429
+ if (old.observation) {
430
+ requireNetwork(current.observation !== null && current.observation.sequence >= old.observation.sequence);
431
+ requireNetwork(current.observation.assignment.generation >= old.observation.assignment.generation);
432
+ if (current.observation.assignment.generation === old.observation.assignment.generation) {
433
+ requireNetwork(networkEqual(current.observation.assignment, old.observation.assignment));
434
+ }
435
+ if (current.observation.sequence === old.observation.sequence) requireNetwork(networkEqual(current.observation, old.observation)
436
+ && (!current.ready || old.ready));
437
+ }
438
+ }
439
+ else requireNetwork(projection.retiredLeases.some(item => networkEqual(item, networkReferenceOf(old.lease))));
440
+ }
441
+ if (previous.handoff && !networkEqual(previous.handoff, projection.handoff)) requireNetwork(projection.retiredHandoffs.some(item =>
442
+ networkEqual(item, networkReferenceOf(previous.handoff!))));
443
+ const protection = projection.protectedAuthority, oldProtection = previous.protectedAuthority;
444
+ requireNetwork(networkEqual(protection, oldProtection) || (protection.id === oldProtection.id
445
+ && networkEqual(protection.previous, networkReferenceOf(oldProtection))));
446
+ return { status: 'accepted', projection };
447
+ } catch { return failNetwork(); }
448
+ };
@@ -0,0 +1,84 @@
1
+ import type { TSha256Digest } from './immutableimage.js';
2
+ import type { IRuntimeAuthorityReferenceV1, IRuntimeControllerV1 } from './runtimeassignment.js';
3
+ import type { IRuntimeNetworkProjectionV1 } from './networkprojection.js';
4
+ import { snapshotRuntimeNetworkProjectionV1 } from './networkprojection.js';
5
+ import { snapshotRuntimeSessionBindingV1 } from './runtimesession.js';
6
+ import { captureNetwork, failNetwork, networkController, networkDigest, networkEqual, networkHash,
7
+ networkRecord, networkReference, networkReferenceOf, networkRevision, networkSafe, requireNetwork } from '../private/networkcontract.js';
8
+
9
+ export interface ISignedRuntimeNetworkProjectionV1 {
10
+ schemaVersion: 1;
11
+ authority: IRuntimeAuthorityReferenceV1;
12
+ projection: IRuntimeNetworkProjectionV1;
13
+ /** Ed25519 signature of the complete domain-separated envelope, lowercase hex. */
14
+ signature: string;
15
+ }
16
+
17
+ export const snapshotSignedRuntimeNetworkProjectionV1 = (value: unknown): ISignedRuntimeNetworkProjectionV1 => networkSafe(() => {
18
+ const item = networkRecord(captureNetwork(value), ['schemaVersion', 'authority', 'projection', 'signature']);
19
+ requireNetwork(item.schemaVersion === 1 && typeof item.signature === 'string' && /^[a-f0-9]{128}$/.test(item.signature));
20
+ return { schemaVersion: 1, authority: networkReference(item.authority), projection: snapshotRuntimeNetworkProjectionV1(item.projection), signature: item.signature };
21
+ });
22
+
23
+ /**
24
+ * Dedicated controller signing authority, installed through the CURRENT authenticated
25
+ * physical session. Never obtain trusted authority from an envelope being verified.
26
+ * null revokes signing; rotation requires a new complete signed projection for DNS.
27
+ * Existing packet grants still require applied denial or independent fencing.
28
+ */
29
+ export interface IRuntimeNetworkSigningAuthorityV1 {
30
+ schemaVersion: 1;
31
+ id: string;
32
+ generation: number;
33
+ previous: IRuntimeAuthorityReferenceV1 | null;
34
+ controller: IRuntimeControllerV1;
35
+ algorithm: 'Ed25519';
36
+ /** Canonical 32-byte raw public key, lowercase hex. No private material. */
37
+ publicKey: string | null;
38
+ digest: TSha256Digest;
39
+ }
40
+
41
+ export const runtimeNetworkSigningV1Contract = Object.freeze({
42
+ authorityDigestDomain: 'serve.zone/runtime-network-signing-authority-v1',
43
+ signatureDomain: 'serve.zone/runtime-network-projection-signature-v1',
44
+ trust: 'current-authenticated-physical-session-and-durable-revision-fence',
45
+ rotation: 'replace-dns-authority-with-new-signed-projection',
46
+ revocation: 'no-implicit-packet-denial-or-allocation-reuse',
47
+ } as const);
48
+
49
+ export const snapshotRuntimeNetworkSigningAuthorityV1 = (value: unknown): IRuntimeNetworkSigningAuthorityV1 => networkSafe(() => {
50
+ const item = networkRecord(captureNetwork(value), ['schemaVersion', 'id', 'generation', 'previous', 'controller', 'algorithm', 'publicKey', 'digest']);
51
+ requireNetwork(item.schemaVersion === 1 && item.algorithm === 'Ed25519');
52
+ requireNetwork(item.publicKey === null || (typeof item.publicKey === 'string'
53
+ && /^[a-f0-9]{64}$/.test(item.publicKey) && item.publicKey !== '0'.repeat(64)));
54
+ return { schemaVersion: 1, ...networkRevision(item), controller: networkController(item.controller),
55
+ algorithm: 'Ed25519', publicKey: item.publicKey, digest: networkDigest(item.digest) };
56
+ });
57
+
58
+ export const computeRuntimeNetworkSigningAuthorityV1Digest = (value: IRuntimeNetworkSigningAuthorityV1): Promise<TSha256Digest> =>
59
+ networkHash(runtimeNetworkSigningV1Contract.authorityDigestDomain, snapshotRuntimeNetworkSigningAuthorityV1(value));
60
+
61
+ /**
62
+ * Detached content/CAS check. Caller must fence the live peer and commit atomically.
63
+ * A newly enrolled node bootstraps the controller's CURRENT authority at any generation;
64
+ * it must not fabricate local history or use this bootstrap path to erase existing trust.
65
+ */
66
+ export const admitRuntimeNetworkSigningAuthorityV1 = async (
67
+ value: unknown, previousValue: unknown | null, trustedSessionValue: unknown,
68
+ ): Promise<{ status: 'accepted' | 'replay'; authority: IRuntimeNetworkSigningAuthorityV1 }> => {
69
+ try {
70
+ const authority = snapshotRuntimeNetworkSigningAuthorityV1(value);
71
+ const previous = previousValue === null ? null : snapshotRuntimeNetworkSigningAuthorityV1(previousValue);
72
+ const session = snapshotRuntimeSessionBindingV1(trustedSessionValue);
73
+ requireNetwork(networkEqual(authority.controller, session.controller));
74
+ requireNetwork(authority.digest === await computeRuntimeNetworkSigningAuthorityV1Digest(authority));
75
+ if (previous === null) return { status: 'accepted', authority };
76
+ requireNetwork(previous.digest === await computeRuntimeNetworkSigningAuthorityV1Digest(previous)
77
+ && authority.id === previous.id && networkEqual(previous.controller, authority.controller));
78
+ if (authority.generation === previous.generation) {
79
+ requireNetwork(networkEqual(authority, previous)); return { status: 'replay', authority };
80
+ }
81
+ requireNetwork(networkEqual(authority.previous, networkReferenceOf(previous)));
82
+ return { status: 'accepted', authority };
83
+ } catch { return failNetwork(); }
84
+ };
@@ -0,0 +1,117 @@
1
+ import type { TSha256Digest } from '../data/immutableimage.js';
2
+ import type { IRuntimeAuthorityReferenceV1, IRuntimeControllerV1 } from '../data/runtimeassignment.js';
3
+ import { canonicalizeStrictJson, createCanonicalJsonSha256Hex } from './canonicaljson.js';
4
+
5
+ export const failNetwork = (): never => { throw new Error('Runtime network projection contract rejected.'); };
6
+ export function requireNetwork(value: unknown): asserts value { if (!value) failNetwork(); }
7
+ export const networkCanonical = (value: unknown): string => canonicalizeStrictJson(value, failNetwork);
8
+ export const networkEqual = (left: unknown, right: unknown): boolean => networkCanonical(left) === networkCanonical(right);
9
+ export const networkSafe = <T>(operation: () => T): T => { try { return operation(); } catch { return failNetwork(); } };
10
+
11
+ /** Bound decoded transport input before canonicalization; never execute getters/toJSON. */
12
+ export const captureNetwork = (value: unknown): unknown => networkSafe(() => {
13
+ const encoder = new TextEncoder(), ancestors = new Set<object>();
14
+ let nodes = 0, bytes = 0;
15
+ const account = (text: string) => {
16
+ requireNetwork(text.length <= 1_048_576);
17
+ bytes += encoder.encode(text).length;
18
+ requireNetwork(bytes <= 1_048_576);
19
+ };
20
+ const copy = (item: unknown, depth: number): unknown => {
21
+ requireNetwork(++nodes <= 65_536 && depth <= 24);
22
+ if (typeof item === 'string') { account(item); return item; }
23
+ if (item === null || typeof item === 'boolean') return item;
24
+ if (typeof item === 'number') {
25
+ requireNetwork(Number.isSafeInteger(item) && !Object.is(item, -0)); return item;
26
+ }
27
+ requireNetwork(item !== null && typeof item === 'object' && !ancestors.has(item));
28
+ const array = Array.isArray(item), prototype = Object.getPrototypeOf(item), keys = Reflect.ownKeys(item);
29
+ requireNetwork(array ? prototype === Array.prototype : prototype === Object.prototype || prototype === null);
30
+ requireNetwork(keys.length <= 4097);
31
+ ancestors.add(item);
32
+ try {
33
+ if (array) {
34
+ const length = Object.getOwnPropertyDescriptor(item, 'length')?.value;
35
+ requireNetwork(Number.isSafeInteger(length) && length >= 0 && length <= 4096 && keys.length === length + 1);
36
+ const result: unknown[] = [];
37
+ for (let index = 0; index < length; index++) {
38
+ const descriptor = Object.getOwnPropertyDescriptor(item, String(index));
39
+ requireNetwork(descriptor?.enumerable && Object.hasOwn(descriptor, 'value'));
40
+ result.push(copy(descriptor.value, depth + 1));
41
+ }
42
+ return result;
43
+ }
44
+ const result: Record<string, unknown> = Object.create(null);
45
+ for (const key of keys) {
46
+ requireNetwork(typeof key === 'string'); account(key);
47
+ const descriptor = Object.getOwnPropertyDescriptor(item, key);
48
+ requireNetwork(descriptor?.enumerable && Object.hasOwn(descriptor, 'value'));
49
+ result[key] = copy(descriptor.value, depth + 1);
50
+ }
51
+ return result;
52
+ } finally { ancestors.delete(item); }
53
+ };
54
+ const result = copy(value, 0);
55
+ requireNetwork(encoder.encode(networkCanonical(result)).length <= 1_048_576);
56
+ return result;
57
+ });
58
+
59
+ export const networkRecord = (value: unknown, keys: string[]): Record<string, unknown> => {
60
+ requireNetwork(value !== null && typeof value === 'object' && !Array.isArray(value));
61
+ const actual = Object.keys(value);
62
+ requireNetwork(actual.length === keys.length && keys.every(key => Object.hasOwn(value, key)));
63
+ return value as Record<string, unknown>;
64
+ };
65
+ export const networkList = <T>(value: unknown, maximum: number, read: (item: unknown) => T): T[] => {
66
+ requireNetwork(Array.isArray(value) && value.length <= maximum); return value.map(read);
67
+ };
68
+ export const networkSorted = <T>(values: T[], key: (item: T) => string): T[] => {
69
+ requireNetwork(values.every((value, index) => index === 0 || key(values[index - 1]) < key(value))); return values;
70
+ };
71
+ export const networkId = (value: unknown): string => {
72
+ requireNetwork(typeof value === 'string' && /^[A-Za-z0-9][A-Za-z0-9:._-]{0,199}$/.test(value)); return value;
73
+ };
74
+ export const networkCounter = (value: unknown, maximum = Number.MAX_SAFE_INTEGER - 1): number => {
75
+ requireNetwork(typeof value === 'number' && Number.isSafeInteger(value) && value > 0 && value <= maximum); return value;
76
+ };
77
+ export const networkDigest = (value: unknown): TSha256Digest => {
78
+ requireNetwork(typeof value === 'string' && /^sha256:[a-f0-9]{64}$/.test(value)); return value as TSha256Digest;
79
+ };
80
+ export const networkController = (value: unknown): IRuntimeControllerV1 => {
81
+ const item = networkRecord(value, ['kind', 'id', 'epoch']);
82
+ requireNetwork(item.kind === 'cloudly' || item.kind === 'onebox');
83
+ return { kind: item.kind, id: networkId(item.id), epoch: networkId(item.epoch) };
84
+ };
85
+ export const networkReference = (value: unknown): IRuntimeAuthorityReferenceV1 => {
86
+ const item = networkRecord(value, ['id', 'generation', 'digest']);
87
+ return { id: networkId(item.id), generation: networkCounter(item.generation), digest: networkDigest(item.digest) };
88
+ };
89
+ export const networkReferenceOf = (value: IRuntimeAuthorityReferenceV1): IRuntimeAuthorityReferenceV1 =>
90
+ ({ id: value.id, generation: value.generation, digest: value.digest });
91
+ export const networkRevision = (item: Record<string, unknown>) => {
92
+ const id = networkId(item.id), generation = networkCounter(item.generation);
93
+ const previous = item.previous === null ? null : networkReference(item.previous);
94
+ requireNetwork(generation === 1 ? previous === null : previous?.id === id && previous.generation === generation - 1);
95
+ return { id, generation, previous };
96
+ };
97
+ export const networkHash = async (domain: string, value: { digest: TSha256Digest }): Promise<TSha256Digest> => {
98
+ const { digest: omitted, ...payload } = value;
99
+ return `sha256:${await createCanonicalJsonSha256Hex(networkCanonical({ domain, payload }), failNetwork)}`;
100
+ };
101
+ export const networkIpv4 = (value: unknown): string => {
102
+ requireNetwork(typeof value === 'string' && value.length <= 15);
103
+ const parts = value.split('.');
104
+ requireNetwork(parts.length === 4 && parts.every(part => /^(?:0|[1-9][0-9]{0,2})$/.test(part) && Number(part) <= 255));
105
+ return value;
106
+ };
107
+ export const networkIpv4Number = (value: string): number => value.split('.').reduce((sum, part) => sum * 256 + Number(part), 0);
108
+ export const networkPrefixBounds = (value: string): [number, number] => {
109
+ const [address, bits] = value.split('/'), first = networkIpv4Number(address);
110
+ return [first, first + 2 ** (32 - Number(bits)) - 1];
111
+ };
112
+ export const networkContains = (outer: string, inner: string): boolean => {
113
+ const [a, b] = networkPrefixBounds(outer), [c, d] = networkPrefixBounds(inner); return a <= c && b >= d;
114
+ };
115
+ export const networkOverlaps = (left: string, right: string): boolean => {
116
+ const [a, b] = networkPrefixBounds(left), [c, d] = networkPrefixBounds(right); return a <= d && c <= b;
117
+ };