@githolon/dsl 0.98.1 → 0.98.3
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
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
## 0.61.3
|
|
2
|
+
|
|
3
|
+
- cloudBound seeds the KEYLESS enroll-once delegation (mintKeylessDelegation) so a keyless private home
|
|
4
|
+
is born with a well-formed cert chain (was: platform_cert in the delegation slot → self-refusal).
|
|
5
|
+
|
|
1
6
|
## 0.61.2
|
|
2
7
|
|
|
3
8
|
- cloudBound works against PRIVATE platforms/homes (declared read caps — the co2 shape): the device
|
|
@@ -835,6 +835,22 @@ class NomosTestHarness {
|
|
|
835
835
|
if (idpToken.isEmpty || issuer.isEmpty) {
|
|
836
836
|
throw NomosTestHarnessException('cloudBound: /dev/mint-token returned no token — is the test cloud started with platform:/deployJsonPath: and a law composing setAuthProvider?');
|
|
837
837
|
}
|
|
838
|
+
// THE KEYLESS ENROLL-ONCE DELEGATION (links[1] of the home cert chain) — device-self-signed,
|
|
839
|
+
// its authority the dev-IdP token. enrollFirstDevice SEEDS it as the user's SignerDelegation, so
|
|
840
|
+
// birthHome's offer-effect assembles a WELL-FORMED chain [home_cert, u_delegation, …platform…].
|
|
841
|
+
// WITHOUT it the platform holds no delegation for the owner, the assembly falls to the
|
|
842
|
+
// no-delegation branch, the platform_cert lands in the delegation slot, and the home refuses at
|
|
843
|
+
// its OWN verify door ("home cert founder != delegation cert founder").
|
|
844
|
+
final delegationCert = await plane.mintKeylessDelegation({
|
|
845
|
+
'user': subject,
|
|
846
|
+
'deviceKey': publicB64,
|
|
847
|
+
'childName': _homeNameOf(subject),
|
|
848
|
+
'parentId': platformWorkspace,
|
|
849
|
+
'verifiedVia': issuer,
|
|
850
|
+
'idpToken': idpToken,
|
|
851
|
+
'capturedClock': DateTime.now().toUtc().millisecondsSinceEpoch,
|
|
852
|
+
'epoch': 0,
|
|
853
|
+
}, secret);
|
|
838
854
|
await post('/v2/workspaces/$platformWorkspace/enrollFirstDevice', {
|
|
839
855
|
'keyHash': keyHash,
|
|
840
856
|
'verifiedVia': issuer,
|
|
@@ -843,6 +859,7 @@ class NomosTestHarness {
|
|
|
843
859
|
'idpToken': idpToken,
|
|
844
860
|
'actor': subject,
|
|
845
861
|
'authorSecret': secret,
|
|
862
|
+
'delegationCert': jsonEncode(delegationCert),
|
|
846
863
|
}, headers: {'x-nomos-auth': idpToken});
|
|
847
864
|
return (publicB64: publicB64, secret: secret, keyHash: keyHash, idpToken: idpToken);
|
|
848
865
|
});
|
|
@@ -1829,6 +1829,20 @@ class NomosBridge {
|
|
|
1829
1829
|
}))['cert'] as Map<String, Object?>? ??
|
|
1830
1830
|
const {};
|
|
1831
1831
|
|
|
1832
|
+
/// MINT THE KEYLESS ENROLL-ONCE DELEGATION (`enrollFirstDevice.delegationCert`, the verified-first-device
|
|
1833
|
+
/// lane). The device SELF-signs it; its authority is the carried `idpToken` (the kernel re-verifies that to
|
|
1834
|
+
/// the platform's AuthProvider at every lane), so no S_P/admin signature is needed. [spec] carries
|
|
1835
|
+
/// `{user, deviceKey, childName, parentId, verifiedVia, idpToken, capturedClock, epoch}`. WITHOUT this the
|
|
1836
|
+
/// keyless home is born with a malformed cert chain (the platform_cert falls into the delegation slot →
|
|
1837
|
+
/// `home cert founder != delegation cert founder` at the home's own verify door).
|
|
1838
|
+
Future<Map<String, Object?>> mintKeylessDelegation(
|
|
1839
|
+
Map<String, Object?> spec, String deviceSecret) async =>
|
|
1840
|
+
_asMap(await _call('mintKeylessDelegation', {
|
|
1841
|
+
'spec': spec,
|
|
1842
|
+
'deviceSecret': deviceSecret,
|
|
1843
|
+
}))['cert'] as Map<String, Object?>? ??
|
|
1844
|
+
const {};
|
|
1845
|
+
|
|
1832
1846
|
/// ENROLL THIS DEVICE — the LIVE gate: bind a device key's PUBLIC half to `principal` on-chain as a
|
|
1833
1847
|
/// `signer` so the holon's gate can PROVE this device's authorship on replay (and the VA chain attest it).
|
|
1834
1848
|
/// `publicKey` is the base64 PUBLIC half (from [mintDeviceKey]); `authToken` (defaults to the connect-time
|
package/dart/pubspec.yaml
CHANGED
|
@@ -11,7 +11,7 @@ description: >-
|
|
|
11
11
|
Nomos 2 Dart frontend types — the hand-written kernel wire types plus the
|
|
12
12
|
code-generated per-domain aggregate + directive-payload types. (De)serializes
|
|
13
13
|
the EXACT serde JSON the Rust kernel + projection produce/consume.
|
|
14
|
-
version: 0.61.
|
|
14
|
+
version: 0.61.3
|
|
15
15
|
|
|
16
16
|
environment:
|
|
17
17
|
sdk: ^3.5.0
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@githolon/dsl",
|
|
3
|
-
"version": "0.98.
|
|
3
|
+
"version": "0.98.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Nomos 2 domain-authoring DSL: aggregates + directives in TS, executed and encoded to the Rust kernel's wire shapes.",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE.md",
|
package/src/framework/home.ts
CHANGED
|
@@ -231,6 +231,30 @@ export const birthHome = directive("birthHome")
|
|
|
231
231
|
.plan((p) => {
|
|
232
232
|
const founder = p.owner; // the actor for the child's own genesis steps (its self-bound owner subject)
|
|
233
233
|
const homeName = homeNameOf(p.owner); // workspace name == seeded homeName — derived from the SAME owner
|
|
234
|
+
// THE PARENT'S DECLARED VERIFIER (one captured read serves BOTH consumers below): the inherited
|
|
235
|
+
// `setAuthProvider` genesis step AND the enroll step's `verifiedVia` provenance stamp. Read it up
|
|
236
|
+
// front so the enroll step (which precedes the inheritance step in the chain) can see the issuer.
|
|
237
|
+
const apRows = p.inheritAuthProvider !== false
|
|
238
|
+
? readFrameworkDeclared<Array<Record<string, unknown>>>("authProvider", { scope: "platform" })
|
|
239
|
+
: undefined;
|
|
240
|
+
const apRaw = Array.isArray(apRows) && apRows.length > 0 ? apRows[0] : undefined;
|
|
241
|
+
// Projected rows are `{type,id,data:{…fields}}`; folded shapes may be flat — accept both.
|
|
242
|
+
const ap = (apRaw && typeof apRaw === "object" && typeof (apRaw as { data?: unknown }).data === "object"
|
|
243
|
+
? (apRaw as { data: Record<string, unknown> }).data
|
|
244
|
+
: apRaw) as Record<string, unknown> | undefined;
|
|
245
|
+
const apStr = (k: string): string | undefined => {
|
|
246
|
+
const v = ap?.[k];
|
|
247
|
+
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
248
|
+
};
|
|
249
|
+
// PROVENANCE (the verified-lineage thread, 2026-07-16): the kernel derives every later write's
|
|
250
|
+
// `principal_verified` from the ENROLL LEAF's `verifiedVia` — so a verified birth must stamp it or the
|
|
251
|
+
// born home's owner writes UNVERIFIED forever (and its own children are then born `verified:false`,
|
|
252
|
+
// whose chains refuse `verify_to_root`). The cert's `verified` IS the gate verdict post-admission
|
|
253
|
+
// (assemble_birth_attestation CAS-refuses a mismatch), so reading it in-plan is trustworthy — a lying
|
|
254
|
+
// cert never reaches this fold. An unverified birth stamps nothing (the unverified lane stays honest).
|
|
255
|
+
let certVerified = false;
|
|
256
|
+
try { certVerified = p.homeCert !== undefined && JSON.parse(p.homeCert).verified === true; } catch { /* malformed cert ⇒ unverified (the gate will refuse the birth anyway) */ }
|
|
257
|
+
const verifiedVia = certVerified ? apStr("issuer") : undefined;
|
|
234
258
|
const genesisChain: Array<{ domain: string; directiveId: string; actor: string; payload: Record<string, unknown>; domainHash?: string; domainPackageB64?: string }> = [
|
|
235
259
|
// THE ORDER-DECLARED LAW INSTALL: two layers, bytes-by-hash (empty package — the kernel resolves them
|
|
236
260
|
// from the parent's custody when it folds the birth; never the host). Matches buildGenesisChain's shape.
|
|
@@ -248,22 +272,13 @@ export const birthHome = directive("birthHome")
|
|
|
248
272
|
// ladder: every seed runs UNSIGNED on the still-warrant-free prefix; the warrant closes it). ERA-SAFE: a
|
|
249
273
|
// home born earlier (pre-feature law, no such step in its recipe) replays byte-identical — the era rule
|
|
250
274
|
// rides the LAW hash, not this branch.
|
|
251
|
-
{ domain: HOME_LAW_DOMAIN, directiveId: "enrollSigner", actor: founder, payload: { keyHash: p.ownerKeyHash, grantedBy: p.owner, grantedAt: 1 } },
|
|
275
|
+
{ domain: HOME_LAW_DOMAIN, directiveId: "enrollSigner", actor: founder, payload: { keyHash: p.ownerKeyHash, grantedBy: p.owner, grantedAt: 1, ...(verifiedVia !== undefined ? { verifiedVia } : {}) } },
|
|
252
276
|
];
|
|
253
|
-
// AUTHPROVIDER INHERITANCE (default ON — see the payload doc):
|
|
254
|
-
// (
|
|
255
|
-
//
|
|
277
|
+
// AUTHPROVIDER INHERITANCE (default ON — see the payload doc): copy the parent's declared provider
|
|
278
|
+
// (the up-front captured read above) AS DATA into the child genesis. The child owns the copy as its
|
|
279
|
+
// own law-state; nothing is inherited-by-reference. Opt out: `inheritAuthProvider: false`.
|
|
256
280
|
if (p.inheritAuthProvider !== false) {
|
|
257
|
-
const
|
|
258
|
-
const raw = Array.isArray(rows) && rows.length > 0 ? rows[0] : undefined;
|
|
259
|
-
// Projected rows are `{type,id,data:{…fields}}`; folded shapes may be flat — accept both.
|
|
260
|
-
const ap = (raw && typeof raw === "object" && typeof (raw as { data?: unknown }).data === "object"
|
|
261
|
-
? (raw as { data: Record<string, unknown> }).data
|
|
262
|
-
: raw) as Record<string, unknown> | undefined;
|
|
263
|
-
const str = (k: string): string | undefined => {
|
|
264
|
-
const v = ap?.[k];
|
|
265
|
-
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
266
|
-
};
|
|
281
|
+
const str = apStr;
|
|
267
282
|
const issuer = str("issuer");
|
|
268
283
|
if (issuer !== undefined) {
|
|
269
284
|
genesisChain.push({
|
|
@@ -212,6 +212,14 @@ export const enrollSigner = directive("enrollSigner")
|
|
|
212
212
|
keyHash: sha256Hex, // sha256hex of the ed25519 device PUBLIC key
|
|
213
213
|
grantedBy: z.string().min(1),
|
|
214
214
|
grantedAt: z.number().int().nonnegative(), // epoch ms, caller-stamped (determinism)
|
|
215
|
+
/** OPTIONAL PROVENANCE — the IdP/issuer that VOUCHED for this principal at the enrolling birth.
|
|
216
|
+
* The kernel's `verify_captured_principal` derives `principal_verified` from THIS leaf field on
|
|
217
|
+
* every later write, so a genesis enroll that omits it leaves the workspace's owner permanently
|
|
218
|
+
* UNVERIFIED (their children are then born `verified:false` and their chains refuse
|
|
219
|
+
* `verify_to_root` — the 2026-07-16 estate holarchy RED). Birth recipes stamp it from the
|
|
220
|
+
* CAS-verified birth cert (`cert.verified` IS the gate verdict post-admission) + the inherited
|
|
221
|
+
* AuthProvider issuer; an unverified birth omits it (the unverified lane stays honest). */
|
|
222
|
+
verifiedVia: z.string().min(1).optional(),
|
|
215
223
|
}),
|
|
216
224
|
)
|
|
217
225
|
.plan((p, ctx) => {
|
|
@@ -227,6 +235,7 @@ export const enrollSigner = directive("enrollSigner")
|
|
|
227
235
|
subject: "key:" + p.keyHash,
|
|
228
236
|
grantedBy: p.grantedBy,
|
|
229
237
|
grantedAt: String(p.grantedAt),
|
|
238
|
+
...(p.verifiedVia !== undefined ? { verifiedVia: p.verifiedVia } : {}),
|
|
230
239
|
});
|
|
231
240
|
});
|
|
232
241
|
|
package/src/index.ts
CHANGED
|
@@ -416,6 +416,15 @@ export {
|
|
|
416
416
|
type SignerEpochHandle,
|
|
417
417
|
type SignerAuthority,
|
|
418
418
|
} from "./framework/signing_identity.js";
|
|
419
|
+
// THE WORKSPACE VERIFIER is framework-owned law-state. Ordinary birth/onboarding flows compose and
|
|
420
|
+
// inherit it automatically; these exports exist for governance and acceptance laws that need to author
|
|
421
|
+
// the provider explicitly, without re-declaring the kernel's security schema in tenant code.
|
|
422
|
+
export {
|
|
423
|
+
AUTH_PROVIDER_ID,
|
|
424
|
+
AuthProvider,
|
|
425
|
+
setAuthProvider,
|
|
426
|
+
authProvider,
|
|
427
|
+
} from "./framework/auth_provider_law.js";
|
|
419
428
|
// THE HOME HOLON (home_holons_and_cross_custody.md §4) — the identity-role law: the shared-with-me access
|
|
420
429
|
// index + the owner lane to maintain it (the key directory is the `signer` relation above).
|
|
421
430
|
export {
|