@githolon/dsl 0.108.4 → 0.108.7
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/dart/CHANGELOG.md +5 -0
- package/dart/lib/src/application_framework_calls.dart +21 -0
- package/dart/lib/src/dev_cloud.dart +67 -0
- package/dart/lib/src/nms_test_environment.dart +1 -1
- package/dart/lib/src/runner/node-entry.mjs +354 -104
- package/dart/lib/src/runner/offline-install.mjs +64 -8
- package/dart/lib/src/session_bound.dart +58 -30
- package/dart/lib/src/test_harness.dart +60 -98
- package/dart/lib/src/webview_bridge.dart +212 -32
- package/dart/pubspec.lock +1 -1
- package/dart/pubspec.yaml +2 -2
- package/dart/test/node_runner_transport_test.dart +5 -5
- package/dart/test/webview_bridge_test.dart +6 -0
- package/dart_types/CHANGELOG.md +4 -0
- package/dart_types/lib/src/proto/nomos/runtime/v2/runtime.pb.dart +428 -2
- package/dart_types/pubspec.yaml +1 -1
- package/package.json +1 -1
- package/runtime/generated-application-host.js +293 -79
- package/src/application_topology.ts +120 -28
- package/src/births.ts +27 -0
- package/src/codegen_call_usda.ts +9 -4
- package/src/codegen_dart_application.ts +146 -37
- package/src/codegen_dart_client.ts +225 -160
- package/src/codegen_dart_framework_calls.ts +89 -4
- package/src/codegen_ts.ts +135 -60
- package/src/compile_package_main.ts +3598 -1484
- package/src/directive.ts +320 -118
- package/src/fields.ts +2 -3
- package/src/framework/application_home.ts +3 -0
- package/src/framework/auth_provider_law.ts +20 -28
- package/src/framework/genesis.ts +32 -1
- package/src/framework/home.ts +45 -8
- package/src/framework/signing_identity.ts +78 -0
- package/src/framework/workspaces.ts +9 -1
- package/src/framework_call_dart_enums.ts +33 -0
- package/src/framework_call_definitions.ts +11 -2
- package/src/index.ts +12 -0
- package/src/intent.ts +525 -194
- package/src/law_graph.ts +32 -4
- package/src/law_graph_usda.ts +3 -0
- package/src/package_config.ts +16 -1
- package/src/read.ts +33 -11
- package/src/wire.ts +1 -0
- package/src/wire_encode.ts +3 -3
package/src/fields.ts
CHANGED
|
@@ -1079,9 +1079,8 @@ export const t = {
|
|
|
1079
1079
|
{ timestamp: true },
|
|
1080
1080
|
) as TimestampField<number>;
|
|
1081
1081
|
},
|
|
1082
|
-
/** A boolean flag (Lww).
|
|
1083
|
-
*
|
|
1084
|
-
* same string form. (Not encryptable — only Lww-class scalars are, and bool already is.) */
|
|
1082
|
+
/** A first-class USDA boolean flag (Lww). It remains a boolean through authored law, kernel state,
|
|
1083
|
+
* canonical custody and generated reads; it is never lowered through a string or JSON value. */
|
|
1085
1084
|
bool(): Field<boolean, "bool"> {
|
|
1086
1085
|
return makeField("bool", z.boolean(), FirstWriterWins);
|
|
1087
1086
|
},
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import type { AggregateHandle } from "../aggregate.js";
|
|
12
12
|
import type { ApplicationHomeGenesis } from "../application_home_genesis.js";
|
|
13
|
+
import type { WorkspaceRole } from "../births.js";
|
|
13
14
|
import type { Directive } from "../directive.js";
|
|
14
15
|
import type { QueryDecl } from "../query.js";
|
|
15
16
|
import { APPLICATION_HOME_DOMAIN } from "./application_home_domain.js";
|
|
@@ -79,6 +80,7 @@ export function applicationHomePolicyLaw(
|
|
|
79
80
|
maxChildWorkspacesPerUser: number,
|
|
80
81
|
birthPolicyDomains: readonly string[],
|
|
81
82
|
homeGenesis?: ApplicationHomeGenesis,
|
|
83
|
+
parentWorkspaceRoles: readonly WorkspaceRole[] = [],
|
|
82
84
|
) {
|
|
83
85
|
return {
|
|
84
86
|
__nomos_birthReceivingGroup: directive(
|
|
@@ -87,6 +89,7 @@ export function applicationHomePolicyLaw(
|
|
|
87
89
|
maxChildWorkspacesPerUser,
|
|
88
90
|
birthPolicyDomains,
|
|
89
91
|
homeGenesis,
|
|
92
|
+
parentWorkspaceRoles,
|
|
90
93
|
),
|
|
91
94
|
),
|
|
92
95
|
};
|
|
@@ -196,30 +196,7 @@ export type AuthProviderVerifyingConfiguration = Omit<
|
|
|
196
196
|
/** Read the current provider through its three declared O(1) indexes and reconstruct the one nominal
|
|
197
197
|
* configuration value used by child genesis and provider-epoch effects. */
|
|
198
198
|
function readCurrentAuthProviderRows() {
|
|
199
|
-
|
|
200
|
-
return readFrameworkDeclaredRows(authProvider, AuthProvider, { scope: "platform" });
|
|
201
|
-
} catch (error) {
|
|
202
|
-
// Law plans execute in the deterministic VM, not in the compiler's Node
|
|
203
|
-
// realm. Imported class identity therefore cannot be used as an
|
|
204
|
-
// `instanceof` discriminator here: the compiler may carry the property
|
|
205
|
-
// path without carrying a constructible host class. Zod's issue list is
|
|
206
|
-
// already the nominal failure disclosure we need; inspect that bounded
|
|
207
|
-
// shape without depending on host-realm prototype identity.
|
|
208
|
-
const issues = error !== null && typeof error === "object" &&
|
|
209
|
-
"issues" in error && Array.isArray(error.issues)
|
|
210
|
-
? error.issues
|
|
211
|
-
: [];
|
|
212
|
-
if (issues.some((issue: unknown) =>
|
|
213
|
-
issue !== null && typeof issue === "object" &&
|
|
214
|
-
"code" in issue && issue.code === "unrecognized_keys" &&
|
|
215
|
-
"keys" in issue && Array.isArray(issue.keys) && issue.keys.includes("keys")
|
|
216
|
-
)) {
|
|
217
|
-
throw new Error(
|
|
218
|
-
"the AuthProvider still uses the historical serialized key field; migrate it to a typed keySet first",
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
throw error;
|
|
222
|
-
}
|
|
199
|
+
return readFrameworkDeclaredRows(authProvider, AuthProvider, { scope: "platform" });
|
|
223
200
|
}
|
|
224
201
|
|
|
225
202
|
type CurrentAuthProviderRow = ReturnType<typeof readCurrentAuthProviderRows>[number];
|
|
@@ -265,6 +242,9 @@ function readCurrentAuthProviderValue(): {
|
|
|
265
242
|
)
|
|
266
243
|
.map((certificate) => certificate.derBase64),
|
|
267
244
|
}));
|
|
245
|
+
if (keyEpoch === undefined || keys.length === 0) {
|
|
246
|
+
throw new Error("the current AuthProvider has no typed verifying-key epoch");
|
|
247
|
+
}
|
|
268
248
|
return {
|
|
269
249
|
provider,
|
|
270
250
|
verifying: {
|
|
@@ -373,10 +353,13 @@ export function writeAuthProviderKeySet(keySet: z.infer<typeof authProviderKeySe
|
|
|
373
353
|
return ops;
|
|
374
354
|
}
|
|
375
355
|
|
|
376
|
-
|
|
356
|
+
function writeAuthProviderConfigurationWithMarker(
|
|
357
|
+
p: AuthProviderConfiguration,
|
|
358
|
+
marker: "ensures" | "mutates",
|
|
359
|
+
): PlannedOp[] {
|
|
377
360
|
const ap = instance(AuthProvider, AUTH_PROVIDER_ID);
|
|
378
361
|
return [
|
|
379
|
-
withMarker(set(ap, "scope", "platform"),
|
|
362
|
+
withMarker(set(ap, "scope", "platform"), marker),
|
|
380
363
|
set(ap, "issuer", p.issuer),
|
|
381
364
|
set(ap, "jwksUrl", p.jwksUrl),
|
|
382
365
|
...(p.audience ? [set(ap, "audience", p.audience)] : []),
|
|
@@ -400,10 +383,19 @@ export function writeAuthProviderConfiguration(p: AuthProviderConfiguration): Pl
|
|
|
400
383
|
];
|
|
401
384
|
}
|
|
402
385
|
|
|
386
|
+
/** Birth creates the singleton; maintenance requires the existing singleton. */
|
|
387
|
+
export function writeAuthProviderConfiguration(p: AuthProviderConfiguration): PlannedOp[] {
|
|
388
|
+
return writeAuthProviderConfigurationWithMarker(p, "ensures");
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export function updateAuthProviderConfiguration(p: AuthProviderConfiguration): PlannedOp[] {
|
|
392
|
+
return writeAuthProviderConfigurationWithMarker(p, "mutates");
|
|
393
|
+
}
|
|
394
|
+
|
|
403
395
|
export const setAuthProvider = directive("setAuthProvider")
|
|
404
|
-
.
|
|
396
|
+
.mutates(AuthProvider)
|
|
405
397
|
.payload(authProviderConfiguration)
|
|
406
|
-
.plan(
|
|
398
|
+
.plan(updateAuthProviderConfiguration)
|
|
407
399
|
.alsoEnsuresMany(AuthProviderKey)
|
|
408
400
|
.alsoEnsuresMany(AuthProviderCertificate)
|
|
409
401
|
.requires("admin");
|
package/src/framework/genesis.ts
CHANGED
|
@@ -35,6 +35,11 @@ import { directive } from "../directive.js";
|
|
|
35
35
|
import { set, type PlannedOp } from "../ops.js";
|
|
36
36
|
import { RelationTuple, writeTuple } from "./relations.js";
|
|
37
37
|
import { MODEL_LIFECYCLE_AUTHORITY } from "./domain_lifecycle.js";
|
|
38
|
+
import {
|
|
39
|
+
ADMISSION_CHECKPOINT_PRINCIPAL,
|
|
40
|
+
SIGNER_RELATION,
|
|
41
|
+
signerObject,
|
|
42
|
+
} from "./signing_identity.js";
|
|
38
43
|
|
|
39
44
|
/**
|
|
40
45
|
* Deterministic singleton id of the founding warrant — MUST equal
|
|
@@ -60,12 +65,31 @@ export const GenesisWarrant = aggregate("GenesisWarrant", {
|
|
|
60
65
|
export type GenesisWarrantHandle = typeof GenesisWarrant;
|
|
61
66
|
|
|
62
67
|
/** The framework PRIMITIVE plan: record the founding warrant (singleton). */
|
|
63
|
-
export function writeGenesisWarrant(p: {
|
|
68
|
+
export function writeGenesisWarrant(p: {
|
|
69
|
+
principal: string;
|
|
70
|
+
workspaceId: string;
|
|
71
|
+
bornAt: string;
|
|
72
|
+
admissionCheckpointSigners?: readonly {
|
|
73
|
+
keyHash: string;
|
|
74
|
+
validFromEpoch: number;
|
|
75
|
+
}[] | undefined;
|
|
76
|
+
}): PlannedOp[] {
|
|
64
77
|
const w = instance(GenesisWarrant, GENESIS_WARRANT_ID);
|
|
65
78
|
return [
|
|
66
79
|
set(w, "principal", p.principal),
|
|
67
80
|
set(w, "workspaceId", p.workspaceId),
|
|
68
81
|
set(w, "bornAt", p.bornAt),
|
|
82
|
+
...(p.admissionCheckpointSigners ?? []).flatMap((signer) =>
|
|
83
|
+
writeTuple({
|
|
84
|
+
object: signerObject(ADMISSION_CHECKPOINT_PRINCIPAL),
|
|
85
|
+
relation: SIGNER_RELATION,
|
|
86
|
+
subject: `key:${signer.keyHash}`,
|
|
87
|
+
grantedBy: p.principal,
|
|
88
|
+
grantedAt: p.bornAt,
|
|
89
|
+
validFromEpoch: signer.validFromEpoch,
|
|
90
|
+
verifiedVia: "workspace-genesis",
|
|
91
|
+
})
|
|
92
|
+
),
|
|
69
93
|
];
|
|
70
94
|
}
|
|
71
95
|
|
|
@@ -95,6 +119,13 @@ export const seedGenesis = directive("seedGenesis")
|
|
|
95
119
|
// here; this directive just writes the warrant it is given. Era: the regime is per-workspace, at genesis.
|
|
96
120
|
workspaceId: z.string(),
|
|
97
121
|
bornAt: z.string().min(1),
|
|
122
|
+
/** Public workload identities already enrolled by the verified parent. The kernel derives this
|
|
123
|
+
* list from folded parent law-state while assembling a child warrant; neither host nor tenant
|
|
124
|
+
* payload can nominate a key, and the corresponding secret never enters custody. */
|
|
125
|
+
admissionCheckpointSigners: z.array(z.object({
|
|
126
|
+
keyHash: z.string().regex(/^[0-9a-f]{64}$/),
|
|
127
|
+
validFromEpoch: z.number().int().nonnegative(),
|
|
128
|
+
}).strict()).optional(),
|
|
98
129
|
}),
|
|
99
130
|
)
|
|
100
131
|
.plan((p) => [
|
package/src/framework/home.ts
CHANGED
|
@@ -33,7 +33,7 @@ import { directive } from "../directive.js";
|
|
|
33
33
|
import { ensure } from "../authoring.js";
|
|
34
34
|
import { set, withMarker, type PlannedOp } from "../ops.js";
|
|
35
35
|
import { query } from "../query.js";
|
|
36
|
-
import { birth } from "../births.js";
|
|
36
|
+
import { birth, type WorkspaceRole } from "../births.js";
|
|
37
37
|
import {
|
|
38
38
|
authProvider as authProviderQuery,
|
|
39
39
|
authProviderCertificates as authProviderCertificatesQuery,
|
|
@@ -42,8 +42,13 @@ import {
|
|
|
42
42
|
seedAuthProvider,
|
|
43
43
|
} from "./auth_provider_law.js";
|
|
44
44
|
import { readRef, readSet, workspaceInvariant, refAs } from "./workspace_invariant.js";
|
|
45
|
-
import {
|
|
46
|
-
|
|
45
|
+
import {
|
|
46
|
+
identityRelations,
|
|
47
|
+
} from "./signing_identity.js";
|
|
48
|
+
import {
|
|
49
|
+
RelationTuple,
|
|
50
|
+
writeTuple,
|
|
51
|
+
} from "./relations.js";
|
|
47
52
|
import { relationType, self, user, selfObject } from "../relation_schema.js";
|
|
48
53
|
import { requireParentAttestedBirth, type ParentAttestedBirthMarker } from "../births.js";
|
|
49
54
|
import { GenesisWarrant, seedGenesis } from "./genesis.js";
|
|
@@ -123,12 +128,26 @@ export const DEFAULT_RECEIVING_GROUP_POLICY = {
|
|
|
123
128
|
guardianQuorum: 1,
|
|
124
129
|
} as const;
|
|
125
130
|
|
|
126
|
-
|
|
131
|
+
/** The recovery authorities a receiving group may explicitly select. The default remains guardian
|
|
132
|
+
* quorum; an application must deliberately choose its attested parent identity provider. */
|
|
133
|
+
export const RECEIVING_GROUP_RECOVERY_POLICIES = [
|
|
134
|
+
"guardian-quorum",
|
|
135
|
+
"platform-identity-provider",
|
|
136
|
+
] as const;
|
|
137
|
+
export const receivingGroupRecoveryPolicy = z.enum(RECEIVING_GROUP_RECOVERY_POLICIES);
|
|
138
|
+
export type ReceivingGroupRecoveryPolicy = z.infer<typeof receivingGroupRecoveryPolicy>;
|
|
139
|
+
export const PLATFORM_IDENTITY_PROVIDER_RECOVERY: ReceivingGroupRecoveryPolicy =
|
|
140
|
+
"platform-identity-provider";
|
|
141
|
+
|
|
142
|
+
function writeReceivingGroupPolicy(p: {
|
|
143
|
+
setAt: string;
|
|
144
|
+
recovery?: ReceivingGroupRecoveryPolicy | undefined;
|
|
145
|
+
}): PlannedOp[] {
|
|
127
146
|
const policy = instance(ReceivingGroupPolicy, RECEIVING_GROUP_POLICY_ID);
|
|
128
147
|
return [
|
|
129
148
|
set(policy, "additionalDevice", DEFAULT_RECEIVING_GROUP_POLICY.additionalDevice),
|
|
130
149
|
set(policy, "revocation", DEFAULT_RECEIVING_GROUP_POLICY.revocation),
|
|
131
|
-
set(policy, "recovery", DEFAULT_RECEIVING_GROUP_POLICY.recovery),
|
|
150
|
+
set(policy, "recovery", p.recovery ?? DEFAULT_RECEIVING_GROUP_POLICY.recovery),
|
|
132
151
|
set(policy, "guardianQuorum", DEFAULT_RECEIVING_GROUP_POLICY.guardianQuorum),
|
|
133
152
|
set(policy, "setAt", p.setAt),
|
|
134
153
|
];
|
|
@@ -137,7 +156,10 @@ function writeReceivingGroupPolicy(p: { setAt: string }): PlannedOp[] {
|
|
|
137
156
|
/** Genesis-only default policy. Policy changes become a separate, guardian-aware ceremony. */
|
|
138
157
|
export const seedReceivingGroupPolicy = directive("nomosInternalSeedReceivingGroupPolicy7c1f5e")
|
|
139
158
|
.ensures(ReceivingGroupPolicy)
|
|
140
|
-
.payload(z.object({
|
|
159
|
+
.payload(z.object({
|
|
160
|
+
setAt: z.string().min(1),
|
|
161
|
+
recovery: receivingGroupRecoveryPolicy.optional(),
|
|
162
|
+
}))
|
|
141
163
|
.plan((p) => writeReceivingGroupPolicy(p));
|
|
142
164
|
|
|
143
165
|
/**
|
|
@@ -306,6 +328,7 @@ export function birthReceivingGroupForDomain(
|
|
|
306
328
|
maxChildWorkspacesPerUser: number,
|
|
307
329
|
birthPolicyDomains: readonly string[],
|
|
308
330
|
homeGenesis?: ApplicationHomeGenesis,
|
|
331
|
+
parentWorkspaceRoles: readonly WorkspaceRole[] = [],
|
|
309
332
|
) {
|
|
310
333
|
if (groupLawDomain.length === 0) {
|
|
311
334
|
throw new Error("birthReceivingGroupForDomain requires a non-empty receiving-group law domain");
|
|
@@ -438,12 +461,26 @@ export function birthReceivingGroupForDomain(
|
|
|
438
461
|
// THE DECLARED BIRTH EFFECT (the unix model): the recipe rides the committed intent as a declared output
|
|
439
462
|
// (captured_ports.births). The kernel — reading the `.births()` declaration off the law manifest — takes
|
|
440
463
|
// the recipe and spawns + self-validates the child through the child's OWN gate (each step self-verifies).
|
|
441
|
-
birth({
|
|
442
|
-
|
|
464
|
+
birth({
|
|
465
|
+
workspace: groupName,
|
|
466
|
+
genesisChain,
|
|
467
|
+
...(parentWorkspaceRoles.length > 0 ? { parentWorkspaceRoles } : {}),
|
|
468
|
+
});
|
|
469
|
+
// Parent/child lineage is an ordinary global Zanzibar relation in parent custody. The exact child
|
|
470
|
+
// address comes from the same plan which births it, so neither the host nor the caller can redirect
|
|
471
|
+
// this seat. Application law can then authorize upward workspace effects with the ordinary relation.
|
|
472
|
+
return writeTuple({
|
|
473
|
+
object: "workspace:self",
|
|
474
|
+
relation: "child",
|
|
475
|
+
subject: `workspace:${groupName}`,
|
|
476
|
+
grantedBy: p.owner,
|
|
477
|
+
grantedAt: p.bornAt,
|
|
478
|
+
});
|
|
443
479
|
})
|
|
444
480
|
.reads(authProviderQuery) // the parent-side AuthProvider capture the inheritance copies (the #58 lane)
|
|
445
481
|
.reads(authProviderKeysQuery)
|
|
446
482
|
.reads(authProviderCertificatesQuery)
|
|
483
|
+
.alsoEnsures(RelationTuple)
|
|
447
484
|
.births(); // BIRTH IS A DECLARED KERNEL PRIMITIVE — emits the `nomosBirthGate` era key; the kernel folds the recipe
|
|
448
485
|
return {
|
|
449
486
|
...birthDirective,
|
|
@@ -59,6 +59,7 @@ import {
|
|
|
59
59
|
relationTupleInstanceId,
|
|
60
60
|
} from "./relations.js";
|
|
61
61
|
import { MODEL_LIFECYCLE_AUTHORITY } from "./domain_lifecycle.js";
|
|
62
|
+
import { readFrameworkDeclaredRows } from "../read.js";
|
|
62
63
|
|
|
63
64
|
/**
|
|
64
65
|
* The framework `identity` relation schema — the `signer` relation, LEAF-ONLY
|
|
@@ -377,6 +378,19 @@ export const SignerDelegation = aggregate("SignerDelegation", {
|
|
|
377
378
|
}).public();
|
|
378
379
|
export type SignerDelegationHandle = typeof SignerDelegation;
|
|
379
380
|
|
|
381
|
+
/** The bounded, typed disclosure a parent workspace may carry when its law recovers a child device.
|
|
382
|
+
* It deliberately excludes the historical certJson slot: current cross-workspace law consumes only
|
|
383
|
+
* the nominal certificate fields and the exact signer key subject admitted by the parent. */
|
|
384
|
+
export const signerDelegationRecoveryEvidence = z.object({
|
|
385
|
+
user: z.string().min(1),
|
|
386
|
+
deviceKeySubject: z.string().regex(/^key:[0-9a-f]{64}$/),
|
|
387
|
+
enrolledAt: z.string().min(1),
|
|
388
|
+
certificate: birthCertificatePayload,
|
|
389
|
+
}).strict();
|
|
390
|
+
export type SignerDelegationRecoveryEvidence = z.infer<
|
|
391
|
+
typeof signerDelegationRecoveryEvidence
|
|
392
|
+
>;
|
|
393
|
+
|
|
380
394
|
/** The deterministic singleton id of a user's signer delegation (the kernel reads THIS id by-user). */
|
|
381
395
|
export function signerDelegationInstanceId(user: string): string {
|
|
382
396
|
return SIGNER_DELEGATION_PREFIX + user;
|
|
@@ -405,6 +419,25 @@ function writeDelegationCertificate(
|
|
|
405
419
|
];
|
|
406
420
|
}
|
|
407
421
|
|
|
422
|
+
/** Materialise the exact typed delegation disclosed by a parent during device
|
|
423
|
+
* recovery. Keeping this beside the canonical SignerDelegation definition and
|
|
424
|
+
* certificate writer gives application law one compositional write primitive;
|
|
425
|
+
* it does not need to mirror the certificate fields or serialize a document. */
|
|
426
|
+
export function writeSignerDelegationRecoveryEvidence(
|
|
427
|
+
evidence: SignerDelegationRecoveryEvidence,
|
|
428
|
+
): PlannedOp[] {
|
|
429
|
+
const delegation = instance(
|
|
430
|
+
SignerDelegation,
|
|
431
|
+
signerDelegationInstanceId(evidence.user),
|
|
432
|
+
);
|
|
433
|
+
return [
|
|
434
|
+
set(delegation, "user", evidence.user),
|
|
435
|
+
set(delegation, "deviceKey", evidence.deviceKeySubject),
|
|
436
|
+
set(delegation, "enrolledAt", evidence.enrolledAt),
|
|
437
|
+
...writeDelegationCertificate(delegation, evidence.certificate),
|
|
438
|
+
];
|
|
439
|
+
}
|
|
440
|
+
|
|
408
441
|
/**
|
|
409
442
|
* `enrollFirstDevice` (architecture/keyless_verified_onboard.md) — THE KEYLESS VERIFIED FIRST-DEVICE
|
|
410
443
|
* self-onboard. A brand-new principal (an IdP-verified user with NO enrolled signer key) bootstraps its
|
|
@@ -575,6 +608,51 @@ export const enrollDelegation = directive("enrollDelegation")
|
|
|
575
608
|
/** Audit: a user's signer delegation (the enroll-once cert binding their device to the tenant lineage). */
|
|
576
609
|
export const signerDelegationByUser = query("signerDelegationByUser").key("user").returns(SignerDelegation);
|
|
577
610
|
|
|
611
|
+
/** Read exactly one current typed delegation through its declared O(1) index. Missing or incomplete
|
|
612
|
+
* typed certificate members fail closed; no legacy document is parsed or carried. */
|
|
613
|
+
export function readSignerDelegationRecoveryEvidence(
|
|
614
|
+
user: string,
|
|
615
|
+
): SignerDelegationRecoveryEvidence | undefined {
|
|
616
|
+
const rows = readFrameworkDeclaredRows(
|
|
617
|
+
signerDelegationByUser,
|
|
618
|
+
SignerDelegation,
|
|
619
|
+
{ user },
|
|
620
|
+
);
|
|
621
|
+
if (rows.length === 0) return undefined;
|
|
622
|
+
if (rows.length !== 1) {
|
|
623
|
+
throw new Error(
|
|
624
|
+
`signerDelegationByUser('${user}') returned ${rows.length} rows; expected exactly one`,
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
const row = rows[0]!;
|
|
628
|
+
return signerDelegationRecoveryEvidence.parse({
|
|
629
|
+
user: row.user,
|
|
630
|
+
deviceKeySubject: row.deviceKey,
|
|
631
|
+
enrolledAt: row.enrolledAt,
|
|
632
|
+
certificate: {
|
|
633
|
+
child: row.certificateChild,
|
|
634
|
+
founder: row.certificateFounder,
|
|
635
|
+
verified: row.certificateVerified,
|
|
636
|
+
parentKey: row.certificateParentKey,
|
|
637
|
+
parentId: row.certificateParentId,
|
|
638
|
+
epoch: row.certificateEpoch,
|
|
639
|
+
signature: row.certificateSignature,
|
|
640
|
+
verifiedVia: row.certificateVerifiedVia,
|
|
641
|
+
idpToken: row.certificateIdpToken,
|
|
642
|
+
capturedClock: row.certificateCapturedClock,
|
|
643
|
+
...(row.certificateAuthProviderIssuer === undefined
|
|
644
|
+
? {}
|
|
645
|
+
: { authProviderIssuer: row.certificateAuthProviderIssuer }),
|
|
646
|
+
...(row.certificateAuthProviderJwks === undefined
|
|
647
|
+
? {}
|
|
648
|
+
: { authProviderJwks: row.certificateAuthProviderJwks }),
|
|
649
|
+
...(row.certificateAuthProviderAudience === undefined
|
|
650
|
+
? {}
|
|
651
|
+
: { authProviderAudience: row.certificateAuthProviderAudience }),
|
|
652
|
+
},
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
|
|
578
656
|
/** Audit: the signer tuples for an identity (the raw relation aggregate). */
|
|
579
657
|
export const signerTuplesByObject = query("signerTuplesByObject")
|
|
580
658
|
.key("object")
|
|
@@ -76,7 +76,7 @@ import { query } from "../query.js";
|
|
|
76
76
|
import { read } from "../read.js";
|
|
77
77
|
import { readRef, readSet, workspaceInvariant, refAs, type WorkspaceInvariantVerdict } from "./workspace_invariant.js";
|
|
78
78
|
import { writeTuple, removeTuple, RelationTuple, relationTupleInstanceId } from "./relations.js";
|
|
79
|
-
import { relationType, self, user, key } from "../relation_schema.js";
|
|
79
|
+
import { relationType, self, user, key, object } from "../relation_schema.js";
|
|
80
80
|
import { WORKSPACE_ADMIN_RELATION } from "./governance_relations.js";
|
|
81
81
|
import { GENESIS_WARRANT_ID } from "./genesis.js";
|
|
82
82
|
import { idOf } from "../value_object.js";
|
|
@@ -121,6 +121,8 @@ export { SignerDelegation, enrollDelegation, signerDelegationByUser } from "./si
|
|
|
121
121
|
/** Canonical governance-law namespace. Genesis routes refer to this declaration, never a repeated
|
|
122
122
|
* string literal, so renaming the module cannot silently strand part of the founding ceremony. */
|
|
123
123
|
export const WORKSPACES_DOMAIN = "workspaces" as const;
|
|
124
|
+
/** A workspace born directly by this workspace. The canonical birth plan seats this relation atomically. */
|
|
125
|
+
export const WORKSPACE_CHILD_RELATION = "child" as const;
|
|
124
126
|
|
|
125
127
|
// ── WORKSPACE SELF-IDENTITY (the law reads its OWN install-context) ──────────────────────────────────
|
|
126
128
|
// The governance bundle runs on root AND every born platform. A workspace knows its ROLE via this
|
|
@@ -203,6 +205,12 @@ export const workspaceRelations = relationType("workspace")
|
|
|
203
205
|
.relation("creator", { rewrite: self(), allow: [user(), key()] })
|
|
204
206
|
.relation("platformCreator", { rewrite: self(), allow: [user(), key()] });
|
|
205
207
|
|
|
208
|
+
/** Global holarchy edge kept separate so application packages can compose child authority without
|
|
209
|
+
* re-exporting the governance admin/creator surface into a tenant domain. */
|
|
210
|
+
export const workspaceChildRelations = relationType("workspace")
|
|
211
|
+
.asGlobal()
|
|
212
|
+
.relation(WORKSPACE_CHILD_RELATION, { rewrite: self(), allow: [object("workspace")] });
|
|
213
|
+
|
|
206
214
|
// --- vocabulary ----------------------------------------------------------------
|
|
207
215
|
|
|
208
216
|
/** Where a workspace's holon runs: an edge DO or the dedicated 12GiB container. */
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Directive } from "./directive.js";
|
|
2
|
+
import { collectDartEnums } from "./codegen_dart.js";
|
|
3
|
+
import { fixedFrameworkCallDefinitions } from "./framework_call_definitions.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* The Dart types for enums carried by pre-bind framework calls.
|
|
7
|
+
*
|
|
8
|
+
* The authored fixed-call directives remain the one schema authority. This
|
|
9
|
+
* registry only gives their enum vocabularies stable Dart names and emits the
|
|
10
|
+
* corresponding declarations into the stable framework-call contract. The
|
|
11
|
+
* per-application implementation consumes the same registry, so it can never
|
|
12
|
+
* invent an undeclared field-local fallback such as `RecoveryEnum`.
|
|
13
|
+
*/
|
|
14
|
+
export function collectFixedFrameworkDartEnums(): {
|
|
15
|
+
readonly dartTypes: Map<string, string>;
|
|
16
|
+
readonly decls: string[];
|
|
17
|
+
} {
|
|
18
|
+
// Naming enums after the stable framework call kind keeps public Dart names
|
|
19
|
+
// independent of the directive's opaque wire id. Only payload schemas are
|
|
20
|
+
// inspected from these aliases; no executable directive behaviour is copied.
|
|
21
|
+
const directives = fixedFrameworkCallDefinitions
|
|
22
|
+
.filter((definition) => definition.dartBirth === true)
|
|
23
|
+
.map((definition) => ({
|
|
24
|
+
...definition.directive,
|
|
25
|
+
id: definition.kind,
|
|
26
|
+
// collectDartEnums uses aggregateId as the semantic owner when present.
|
|
27
|
+
// This compile-only alias deliberately names that owner after the stable
|
|
28
|
+
// framework call rather than the directive's internal storage aggregate.
|
|
29
|
+
aggregateId: definition.kind,
|
|
30
|
+
})) as Directive<any>[];
|
|
31
|
+
|
|
32
|
+
return collectDartEnums([], directives, "NmsFramework");
|
|
33
|
+
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import type { Directive } from "./directive.js";
|
|
9
9
|
import { APPLICATION_HOME_DOMAIN } from "./framework/application_home_domain.js";
|
|
10
|
-
import { setAuthProvider } from "./framework/auth_provider_law.js";
|
|
10
|
+
import { seedAuthProvider, setAuthProvider } from "./framework/auth_provider_law.js";
|
|
11
11
|
import { seedBirthPolicy } from "./framework/birth_meter.js";
|
|
12
12
|
import { installDomain, promoteDomain, rollbackDomain, stageDomain } from "./framework/domain_lifecycle.js";
|
|
13
13
|
import { seedGenesis } from "./framework/genesis.js";
|
|
@@ -17,13 +17,20 @@ import {
|
|
|
17
17
|
seedReceivingGroup,
|
|
18
18
|
seedReceivingGroupPolicy,
|
|
19
19
|
} from "./framework/home.js";
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
enrollAdmissionCheckpointSigner,
|
|
22
|
+
enrollDelegation,
|
|
23
|
+
enrollFirstDevice,
|
|
24
|
+
enrollSigner,
|
|
25
|
+
} from "./framework/signing_identity.js";
|
|
21
26
|
import { grantAdmin } from "./framework/workspaces.js";
|
|
22
27
|
|
|
23
28
|
export interface FixedFrameworkCallDefinition {
|
|
24
29
|
readonly group: "identity" | "governance" | "lifecycle" | "birth";
|
|
25
30
|
readonly kind: string;
|
|
26
31
|
readonly directive: Directive<any>;
|
|
32
|
+
/** Public command route when a framework effect is wrapped by a stable typed intent. */
|
|
33
|
+
readonly routeId?: string;
|
|
27
34
|
/** Needed by the pre-bind Dart birth ceremony before an application exists. */
|
|
28
35
|
readonly dartBirth?: true;
|
|
29
36
|
/** A composed application-home law must contain this operation. */
|
|
@@ -39,6 +46,7 @@ const receivingGroupBirth = birthReceivingGroupForDomain(
|
|
|
39
46
|
export const fixedFrameworkCallDefinitions: readonly FixedFrameworkCallDefinition[] = [
|
|
40
47
|
{ group: "identity", kind: "enrollFirstDevice", directive: enrollFirstDevice, dartBirth: true, requiredApplicationHome: true },
|
|
41
48
|
{ group: "identity", kind: "enrollSigner", directive: enrollSigner, dartBirth: true, requiredApplicationHome: true },
|
|
49
|
+
{ group: "identity", kind: "enrollAdmissionCheckpointSigner", directive: enrollAdmissionCheckpointSigner, routeId: "enrollAdmissionCheckpointSigner", requiredApplicationHome: true },
|
|
42
50
|
{ group: "identity", kind: "setAuthProvider", directive: setAuthProvider, requiredApplicationHome: true },
|
|
43
51
|
{ group: "identity", kind: "birthReceivingGroup", directive: receivingGroupBirth, dartBirth: true, requiredApplicationHome: true },
|
|
44
52
|
{ group: "governance", kind: "grantAdmin", directive: grantAdmin },
|
|
@@ -47,6 +55,7 @@ export const fixedFrameworkCallDefinitions: readonly FixedFrameworkCallDefinitio
|
|
|
47
55
|
{ group: "lifecycle", kind: "promoteDomain", directive: promoteDomain },
|
|
48
56
|
{ group: "lifecycle", kind: "rollbackDomain", directive: rollbackDomain },
|
|
49
57
|
{ group: "birth", kind: "seedBirthPolicy", directive: seedBirthPolicy, dartBirth: true },
|
|
58
|
+
{ group: "birth", kind: "seedAuthProvider", directive: seedAuthProvider, requiredApplicationHome: true },
|
|
50
59
|
{ group: "birth", kind: "enrollDelegation", directive: enrollDelegation, dartBirth: true },
|
|
51
60
|
{ group: "birth", kind: "seedBirthAttestation", directive: seedBirthAttestation, dartBirth: true },
|
|
52
61
|
{ group: "birth", kind: "seedGenesis", directive: seedGenesis, dartBirth: true },
|
package/src/index.ts
CHANGED
|
@@ -175,6 +175,9 @@ export {
|
|
|
175
175
|
language,
|
|
176
176
|
isBusinessIntent,
|
|
177
177
|
isApplicationLanguage,
|
|
178
|
+
authenticatesWithEnrolledDevice,
|
|
179
|
+
repairsChildAuthenticationFor,
|
|
180
|
+
childAuthenticationRecoveryAggregateId,
|
|
178
181
|
applicationLanguageOf,
|
|
179
182
|
executableDirectivesForLanguage,
|
|
180
183
|
assertApplicationLanguageCoversAuthoredDirectives,
|
|
@@ -320,6 +323,7 @@ export {
|
|
|
320
323
|
export {
|
|
321
324
|
birth,
|
|
322
325
|
workspaceRole,
|
|
326
|
+
parentWorkspaceRoleRelations,
|
|
323
327
|
workspaceNameForKey,
|
|
324
328
|
WORKSPACE_NAME_SEP,
|
|
325
329
|
birthKeyed,
|
|
@@ -526,10 +530,14 @@ export {
|
|
|
526
530
|
// THE ENROLL-ONCE DELEGATION (the peer-sovereign root-of-trust) — the per-user tenant-signed cert the
|
|
527
531
|
// kernel reads to assemble U's home cert chain at birth.
|
|
528
532
|
SignerDelegation,
|
|
533
|
+
signerDelegationRecoveryEvidence,
|
|
529
534
|
SIGNER_DELEGATION_PREFIX,
|
|
530
535
|
signerDelegationInstanceId,
|
|
531
536
|
enrollDelegation,
|
|
532
537
|
signerDelegationByUser,
|
|
538
|
+
readSignerDelegationRecoveryEvidence,
|
|
539
|
+
writeSignerDelegationRecoveryEvidence,
|
|
540
|
+
type SignerDelegationRecoveryEvidence,
|
|
533
541
|
type SignerDelegationHandle,
|
|
534
542
|
type SignerEpochHandle,
|
|
535
543
|
type SignerAuthority,
|
|
@@ -574,6 +582,10 @@ export {
|
|
|
574
582
|
RECEIVING_GROUP_NAME_HASH_LEN,
|
|
575
583
|
RECEIVING_GROUP_POLICY_ID,
|
|
576
584
|
DEFAULT_RECEIVING_GROUP_POLICY,
|
|
585
|
+
RECEIVING_GROUP_RECOVERY_POLICIES,
|
|
586
|
+
receivingGroupRecoveryPolicy,
|
|
587
|
+
PLATFORM_IDENTITY_PROVIDER_RECOVERY,
|
|
588
|
+
type ReceivingGroupRecoveryPolicy,
|
|
577
589
|
seedReceivingGroup,
|
|
578
590
|
seedReceivingGroupPolicy,
|
|
579
591
|
writeReceivingGroup,
|