githolon 0.100.6 → 0.101.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.
- package/dist/cli.mjs +589 -79
- package/dist/dev-server.mjs +198 -54
- package/dist/framework/domain_nomos.package.usda +2 -2
- package/package.json +3 -3
package/dist/dev-server.mjs
CHANGED
|
@@ -328,6 +328,13 @@ var init_custody_transport = __esm({
|
|
|
328
328
|
}
|
|
329
329
|
});
|
|
330
330
|
|
|
331
|
+
// ../adapter/managed-promotion.ts
|
|
332
|
+
var init_managed_promotion = __esm({
|
|
333
|
+
"../adapter/managed-promotion.ts"() {
|
|
334
|
+
"use strict";
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
|
|
331
338
|
// ../adapter/engine.ts
|
|
332
339
|
import { WASI, File, Directory, OpenFile, ConsoleStdout, PreopenDirectory } from "@bjorn3/browser_wasi_shim";
|
|
333
340
|
function b64Bytes(bytes) {
|
|
@@ -598,7 +605,7 @@ function summaryOfCapture(ctx, fromOid, toOid) {
|
|
|
598
605
|
rowsByHome: Object.fromEntries([...ctx.rowsByHome.entries()].sort((a, b) => a[0] < b[0] ? -1 : 1))
|
|
599
606
|
};
|
|
600
607
|
}
|
|
601
|
-
async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null, shardRouting = null, clientBase = null
|
|
608
|
+
async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null, shardRouting = null, clientBase = null } = {}) {
|
|
602
609
|
const main = await mainIntentIds(eng, ws);
|
|
603
610
|
const sessions = /* @__PURE__ */ new Map();
|
|
604
611
|
const deadLetters = [];
|
|
@@ -665,8 +672,8 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
665
672
|
}
|
|
666
673
|
const cap = summaryCtx ? beginSummaryCapture(eng, ws, summaryCtx, blob) : null;
|
|
667
674
|
const _tOffer = Date.now();
|
|
668
|
-
const res = offerAdmit(eng, ws, blob, { defer:
|
|
669
|
-
log("offer-admit-ms", { ws, ms: Date.now() - _tOffer, deferred:
|
|
675
|
+
const res = offerAdmit(eng, ws, blob, { defer: false });
|
|
676
|
+
log("offer-admit-ms", { ws, ms: Date.now() - _tOffer, deferred: false, ok: res.ok });
|
|
670
677
|
if (res.ok) {
|
|
671
678
|
if (intentId) main.ids.add(intentId);
|
|
672
679
|
main.oids.add(res.head);
|
|
@@ -689,7 +696,6 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
689
696
|
}
|
|
690
697
|
timings.sessions = sessions.size;
|
|
691
698
|
timings.intents = admittedTotal;
|
|
692
|
-
if (admittedTotal && !summaryCtx) (eng.pendingProjection ??= /* @__PURE__ */ new Set()).add(ws);
|
|
693
699
|
if (deadLetters.length) {
|
|
694
700
|
try {
|
|
695
701
|
await materializeRefused(eng, ws, ledger, deadLetters);
|
|
@@ -697,8 +703,7 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
697
703
|
log("refused-materialize-failed", { ws, error: String(e).slice(0, 200) });
|
|
698
704
|
}
|
|
699
705
|
}
|
|
700
|
-
|
|
701
|
-
if (admittedTotal && !deferDurability) {
|
|
706
|
+
if (admittedTotal) {
|
|
702
707
|
const sealDone = span("seal offered intents", "cseal", 1, { admitted: admittedTotal });
|
|
703
708
|
await commitAndPush(eng, ws, ledger);
|
|
704
709
|
sealDone();
|
|
@@ -716,7 +721,7 @@ async function admitIntentOffers(eng, ws, ledger, offers, { receiptFence = null,
|
|
|
716
721
|
}
|
|
717
722
|
log("admit-intent-offers", { ws, sessions: sessions.size, admitted: admittedTotal, rejected: [...sessions.values()].reduce((n, s) => n + s.rejected.length, 0), resultPack: resultPackB64 ? "inline" : "none" });
|
|
718
723
|
const bornPacked = born.length ? packBornChildren(eng, born) : born;
|
|
719
|
-
return { sessions: [...sessions.values()].map((s) => ({ ...s, ...s.skipped.length ? {} : { skipped: void 0 } })), main: head, deadLetters, timings, summary: summary ?? null, born: bornPacked, birthOutcomes, ...resultPackB64 ? { resultPackB64, resultBase: clientBase } : {}
|
|
724
|
+
return { sessions: [...sessions.values()].map((s) => ({ ...s, ...s.skipped.length ? {} : { skipped: void 0 } })), main: head, deadLetters, timings, summary: summary ?? null, born: bornPacked, birthOutcomes, ...resultPackB64 ? { resultPackB64, resultBase: clientBase } : {} };
|
|
720
725
|
}
|
|
721
726
|
async function authorOn(eng, ws, ledger, domain, directiveId, payload, lawHash, opts = {}) {
|
|
722
727
|
await mountWorkspace(eng, ws, ledger);
|
|
@@ -780,6 +785,9 @@ function evolveDryRun(eng, ws, usda, domainHash, dispositions = null) {
|
|
|
780
785
|
function author(eng, ws, domain, directiveId, payload, controllerHash, opts = {}) {
|
|
781
786
|
const seq = eng.seq++;
|
|
782
787
|
const capPorts = { clock: { physical: Date.now(), logical: 0, replica: eng.replica }, rng: osEntropyBuffer(opts.rngDraws ?? 64) };
|
|
788
|
+
if (opts.__nomosConflictSnapshots !== void 0 && opts.__nomosConflictSnapshots.length > 0) {
|
|
789
|
+
capPorts.conflict_snapshots = opts.__nomosConflictSnapshots;
|
|
790
|
+
}
|
|
783
791
|
if (opts.validFromEpoch !== void 0) capPorts.valid_from_epoch = opts.validFromEpoch;
|
|
784
792
|
if (opts.principalVerified !== void 0) {
|
|
785
793
|
capPorts.principal = opts.actor ?? "";
|
|
@@ -1376,26 +1384,89 @@ async function boot(eng, ws, ledger) {
|
|
|
1376
1384
|
);
|
|
1377
1385
|
}
|
|
1378
1386
|
async function deploy(eng, ws, ledger, usda, domainHash, dispositions, opts = {}) {
|
|
1379
|
-
const
|
|
1380
|
-
if (
|
|
1387
|
+
const existing = qById(eng, ws, `domain-installation:${domainHash}`);
|
|
1388
|
+
if (existing.length > 0) {
|
|
1389
|
+
const phase = String(existing[0]?.data?.["status.phase"] ?? "");
|
|
1390
|
+
return {
|
|
1391
|
+
head: kgit.resolveRef(eng, gitdirOf(ws), BRANCH),
|
|
1392
|
+
installation: existing,
|
|
1393
|
+
staged: phase === "Pending",
|
|
1394
|
+
alreadyInstalled: true
|
|
1395
|
+
};
|
|
1396
|
+
}
|
|
1397
|
+
const before = currentLaw(eng, ws);
|
|
1398
|
+
const tenantHashes = [...new Set(Object.values(before).filter(
|
|
1399
|
+
(hash) => typeof hash === "string" && hash !== eng.hashes.bootstrap && hash !== eng.hashes.nomos
|
|
1400
|
+
))];
|
|
1401
|
+
const upgrade = tenantHashes.length > 0;
|
|
1402
|
+
let supersedes = opts.supersedes?.trim() || void 0;
|
|
1403
|
+
if (supersedes !== void 0 && !tenantHashes.includes(supersedes)) {
|
|
1381
1404
|
throw new Error(
|
|
1382
|
-
`deploy-
|
|
1405
|
+
`deploy-predecessor-changed: the client named ${supersedes.slice(0, 12)}\u2026 as the current model, but this workspace no longer serves it. Refresh and deploy again; nothing was committed.`
|
|
1383
1406
|
);
|
|
1384
1407
|
}
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
const law = installedLaw(eng, ws);
|
|
1389
|
-
const currentLaw2 = law?.currentLaw ?? {};
|
|
1390
|
-
const stale = keys.filter((k) => currentLaw2[k] !== void 0 && currentLaw2[k] !== domainHash);
|
|
1391
|
-
if (stale.length > 0) {
|
|
1408
|
+
if (upgrade && supersedes === void 0) {
|
|
1409
|
+
if (tenantHashes.length === 1) supersedes = tenantHashes[0];
|
|
1410
|
+
else {
|
|
1392
1411
|
throw new Error(
|
|
1393
|
-
`deploy-
|
|
1412
|
+
`deploy-predecessor-ambiguous: this workspace currently serves ${tenantHashes.length} business-model packages. Nomos will not guess which one this candidate follows; use the generated deploy client, which binds the candidate to the current model before staging. Nothing was committed.`
|
|
1394
1413
|
);
|
|
1395
1414
|
}
|
|
1396
1415
|
}
|
|
1397
|
-
|
|
1398
|
-
|
|
1416
|
+
if (upgrade && dispositions && Object.keys(dispositions).length > 0) {
|
|
1417
|
+
throw new Error(
|
|
1418
|
+
"deploy-manual-evolution-refused: successor deployment no longer accepts caller-chosen schema dispositions. Schema evolution belongs to the candidate model's adoption proof; nothing was committed."
|
|
1419
|
+
);
|
|
1420
|
+
}
|
|
1421
|
+
const directiveId = upgrade ? "stageDomain" : "installDomain";
|
|
1422
|
+
const payload = upgrade ? stagePayload(domainHash, usda, eng.installedBy, supersedes) : installPayload(domainHash, usda, eng.installedBy, dispositions);
|
|
1423
|
+
const result = author(eng, ws, "nomos", directiveId, payload, eng.hashes.nomos, {
|
|
1424
|
+
actor: opts.actor ?? "",
|
|
1425
|
+
...opts.authToken ? { authToken: opts.authToken } : {}
|
|
1426
|
+
});
|
|
1427
|
+
if (result.ok === false) {
|
|
1428
|
+
unmount(eng, ws);
|
|
1429
|
+
throw new Error(
|
|
1430
|
+
`deploy-refused: ${upgrade ? "staging" : "installing"} ${domainHash.slice(0, 12)}\u2026 was REFUSED by the one gate (custody unchanged): ${result.error ?? "unknown refusal"}`
|
|
1431
|
+
);
|
|
1432
|
+
}
|
|
1433
|
+
try {
|
|
1434
|
+
const installation = qById(eng, ws, `domain-installation:${domainHash}`);
|
|
1435
|
+
if (upgrade) {
|
|
1436
|
+
const phase = String(installation[0]?.data?.["status.phase"] ?? "");
|
|
1437
|
+
if (phase !== "Pending") {
|
|
1438
|
+
throw new Error(
|
|
1439
|
+
`deploy-did-not-stage: candidate ${domainHash.slice(0, 12)}\u2026 admitted but its lifecycle phase is '${phase || "missing"}', not Pending. Custody was not pushed.`
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1442
|
+
const after = currentLaw(eng, ws);
|
|
1443
|
+
const moved = Object.entries(before).filter(([key, hash]) => after[key] !== hash);
|
|
1444
|
+
if (moved.length > 0 || Object.values(after).includes(domainHash)) {
|
|
1445
|
+
throw new Error(
|
|
1446
|
+
`deploy-activated-candidate: staging ${domainHash.slice(0, 12)}\u2026 changed served law (${moved.map(([key]) => key).join(", ") || "candidate became current"}). Nomos refuses to persist an upgrade that bypassed model.adopt().`
|
|
1447
|
+
);
|
|
1448
|
+
}
|
|
1449
|
+
await commitAndPush(eng, ws, ledger);
|
|
1450
|
+
return { head: result.head, installation, staged: true, supersedes };
|
|
1451
|
+
}
|
|
1452
|
+
const law = installedLaw(eng, ws);
|
|
1453
|
+
const installed = (law?.domains ?? []).find((row) => row?.domainHash === domainHash);
|
|
1454
|
+
const keys = installed?.domainKeys ?? installation[0]?.data?.domainKeys ?? installation[0]?.domainKeys ?? [];
|
|
1455
|
+
if (keys.length > 0) {
|
|
1456
|
+
const currentLaw2 = law?.currentLaw ?? {};
|
|
1457
|
+
const stale = keys.filter((k) => currentLaw2[k] !== domainHash);
|
|
1458
|
+
if (stale.length > 0) {
|
|
1459
|
+
throw new Error(
|
|
1460
|
+
`deploy-did-not-advance: the install of ${domainHash.slice(0, 12)}\u2026 ADMITTED but the workspace's current law still serves ${stale.map((k) => `'${k}' from ${String(currentLaw2[k]).slice(0, 12)}\u2026`).join(", ")} \u2014 refusing (custody unchanged) instead of a silent no-op. This usually means the existing installation's era/lineage prevents supersession: run \`githolon deploy --dry-run=evolve\` for the gate's verdict, supply #58 dispositions for a true removal/retype, or re-forge the workspace onto the current lineage.`
|
|
1461
|
+
);
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
await commitAndPush(eng, ws, ledger);
|
|
1465
|
+
return { head: result.head, installation, staged: false };
|
|
1466
|
+
} catch (error) {
|
|
1467
|
+
unmount(eng, ws);
|
|
1468
|
+
throw error;
|
|
1469
|
+
}
|
|
1399
1470
|
}
|
|
1400
1471
|
function snapshot(eng, ws) {
|
|
1401
1472
|
const wsDir = dirOf(eng.preopen.dir.contents.get("ws")).contents.get(ws);
|
|
@@ -1428,13 +1499,14 @@ async function ledgerStats(eng, ws, ledger = null) {
|
|
|
1428
1499
|
if (mounted) mounted.ledgerStats = out;
|
|
1429
1500
|
return out;
|
|
1430
1501
|
}
|
|
1431
|
-
var enc3, dec3, BRANCH, RESULT_PACK_INLINE_MAX, dirOf, repoArgOf, gitdirOf, unpack, log, repoArgOfGitdir, bytesFromB64, kgit, installPayload, routeTagHexOfHomeKey, SUMMARY_SEP, summaryKey, splitSummaryKey, NOMOS_SHARD_ROWS_READ, groupOf, tallyOf, isExtremumRead, extremumMonotone, pushVia, fullRef, applyPackInto, custodyLsRefs, qById, query, authorKeygen, attestedRead, certSign, readPosture, count, sum, pendingConflicts, spatialBboxParams, spatialWithin, extremum, nomosActive, refusedRefName, GENESIS_WARRANT_ID, isWarranted;
|
|
1502
|
+
var enc3, dec3, BRANCH, RESULT_PACK_INLINE_MAX, dirOf, repoArgOf, gitdirOf, unpack, log, repoArgOfGitdir, bytesFromB64, kgit, installPayload, stagePayload, routeTagHexOfHomeKey, SUMMARY_SEP, summaryKey, splitSummaryKey, NOMOS_SHARD_ROWS_READ, groupOf, tallyOf, isExtremumRead, extremumMonotone, pushVia, fullRef, applyPackInto, custodyLsRefs, qById, query, authorKeygen, attestedRead, certSign, readPosture, count, sum, pendingConflicts, pendingConflictSummary, spatialBboxParams, spatialWithin, extremum, nomosActive, refusedRefName, GENESIS_WARRANT_ID, isWarranted;
|
|
1432
1503
|
var init_engine = __esm({
|
|
1433
1504
|
"../adapter/engine.ts"() {
|
|
1434
1505
|
"use strict";
|
|
1435
1506
|
init_git_fs();
|
|
1436
1507
|
init_tree();
|
|
1437
1508
|
init_custody_transport();
|
|
1509
|
+
init_managed_promotion();
|
|
1438
1510
|
enc3 = new TextEncoder();
|
|
1439
1511
|
dec3 = new TextDecoder();
|
|
1440
1512
|
BRANCH = "main";
|
|
@@ -1480,6 +1552,14 @@ var init_engine = __esm({
|
|
|
1480
1552
|
}, eng.STDERR)).oid
|
|
1481
1553
|
};
|
|
1482
1554
|
installPayload = (hash, usda, installedBy, dispositions) => ({ domainHash: hash, packageUsda: usda, installedBy, dependencies: [], finalizers: [], ...dispositions ? { dispositions } : {} });
|
|
1555
|
+
stagePayload = (hash, usda, installedBy, supersedes) => ({
|
|
1556
|
+
domainHash: hash,
|
|
1557
|
+
packageUsda: usda,
|
|
1558
|
+
installedBy,
|
|
1559
|
+
dependencies: [],
|
|
1560
|
+
...supersedes ? { supersedes } : {},
|
|
1561
|
+
finalizers: []
|
|
1562
|
+
});
|
|
1483
1563
|
routeTagHexOfHomeKey = async (homeKey) => (await sha256hex(`nomos-route:${homeKey}`)).slice(0, 12);
|
|
1484
1564
|
SUMMARY_SEP = "";
|
|
1485
1565
|
summaryKey = (readId, group) => `${readId}${SUMMARY_SEP}${group}`;
|
|
@@ -1547,7 +1627,8 @@ var init_engine = __esm({
|
|
|
1547
1627
|
readPosture = (eng, ws, principal = "", authToken = "", nowUnix = 0) => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "readPosture", authToken, nowUnix }), principal, branch: BRANCH }, eng.STDERR));
|
|
1548
1628
|
count = (eng, ws, countId, groupKey, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "count", countId, groupKey }), principal, branch: BRANCH }, eng.STDERR));
|
|
1549
1629
|
sum = (eng, ws, sumId, groupKey, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "sum", sumId, groupKey }), principal, branch: BRANCH }, eng.STDERR));
|
|
1550
|
-
pendingConflicts = (eng, ws, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "pendingConflicts" }), principal, branch: BRANCH }, eng.STDERR));
|
|
1630
|
+
pendingConflicts = (eng, ws, principal = "", aggregateType = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "pendingConflicts", aggregateType }), principal, branch: BRANCH }, eng.STDERR));
|
|
1631
|
+
pendingConflictSummary = (eng, ws, principal = "") => JSON.parse(call(eng.ex, "query", { repoArg: repoArgOf(ws), workspace: ws, queryBytes: b64Json({ op: "pendingConflictSummary" }), principal, branch: BRANCH }, eng.STDERR));
|
|
1551
1632
|
spatialBboxParams = (bbox) => {
|
|
1552
1633
|
const minX = bbox.minX ?? bbox.minLng, minY = bbox.minY ?? bbox.minLat, maxX = bbox.maxX ?? bbox.maxLng, maxY = bbox.maxY ?? bbox.maxLat;
|
|
1553
1634
|
return { minX, minY, maxX, maxY, minLng: minX, minLat: minY, maxLng: maxX, maxLat: maxY };
|
|
@@ -1579,6 +1660,7 @@ var init_types = __esm({
|
|
|
1579
1660
|
var bootstrap_exports = {};
|
|
1580
1661
|
__export(bootstrap_exports, {
|
|
1581
1662
|
bootstrapPlatform: () => bootstrapPlatform,
|
|
1663
|
+
completeDevAuthProviderPayload: () => completeDevAuthProviderPayload,
|
|
1582
1664
|
homeDomainOf: () => homeDomainOf,
|
|
1583
1665
|
isTestMint: () => isTestMint
|
|
1584
1666
|
});
|
|
@@ -1592,10 +1674,42 @@ function isTestMint(eng) {
|
|
|
1592
1674
|
return !/poisoned|unknown|adapter-visible API/.test(errMsg(e));
|
|
1593
1675
|
}
|
|
1594
1676
|
}
|
|
1677
|
+
function completeDevAuthProviderPayload(deployBody, homeDomain, initial, nowMillis = Date.now(), operator = "user:dev-operator") {
|
|
1678
|
+
const payload = { ...initial };
|
|
1679
|
+
const iface = deployBody?.interface ?? {};
|
|
1680
|
+
const legacy = iface.domains?.[homeDomain]?.directives?.setAuthProvider?.fields ?? iface[homeDomain]?.directives?.setAuthProvider?.fields ?? {};
|
|
1681
|
+
const openapi = deployBody?.openapi;
|
|
1682
|
+
const frameworkPaths = openapi?.["x-nomos-framework-routes"]?.paths ?? {};
|
|
1683
|
+
const setAuthOperation = Object.values(frameworkPaths).map((pathItem) => pathItem.post).filter((operation) => operation?.["x-nomos"]?.directiveId === "setAuthProvider").sort((a, b) => Number(b?.["x-nomos"]?.domain === homeDomain) - Number(a?.["x-nomos"]?.domain === homeDomain))[0] ?? frameworkPaths["/setAuthProvider"]?.post;
|
|
1684
|
+
const schema = setAuthOperation?.requestBody?.content?.["application/json"]?.schema;
|
|
1685
|
+
const required = new Set(schema?.required ?? []);
|
|
1686
|
+
const fields = { ...legacy };
|
|
1687
|
+
for (const [name, spec] of Object.entries(schema?.properties ?? {})) {
|
|
1688
|
+
fields[name] = {
|
|
1689
|
+
kind: spec.type === "integer" ? "int" : spec.type,
|
|
1690
|
+
optional: !required.has(name)
|
|
1691
|
+
};
|
|
1692
|
+
}
|
|
1693
|
+
for (const [name, spec] of Object.entries(fields)) {
|
|
1694
|
+
if (spec.optional === true || payload[name] !== void 0) continue;
|
|
1695
|
+
if (spec.kind === "int" && /At$/.test(name)) payload[name] = nowMillis;
|
|
1696
|
+
else if (spec.kind === "string" && /At$/.test(name)) payload[name] = new Date(nowMillis).toISOString();
|
|
1697
|
+
else if (spec.kind === "string" && /By$/.test(name)) payload[name] = operator;
|
|
1698
|
+
else if (spec.kind === "string" && /url$/i.test(name)) payload[name] = `${payload.issuer}/jwks.json`;
|
|
1699
|
+
else if (spec.kind === "string") payload[name] = "dev";
|
|
1700
|
+
else log2(`dev test IdP: required setAuthProvider field '${name}' (kind ${spec.kind}) is not synthesizable \u2014 the author below may refuse typed`);
|
|
1701
|
+
}
|
|
1702
|
+
return payload;
|
|
1703
|
+
}
|
|
1595
1704
|
function homeDomainOf(opts) {
|
|
1596
1705
|
if (!opts || !opts.deploy) return null;
|
|
1597
1706
|
try {
|
|
1598
1707
|
const body = JSON.parse(readFileSync(opts.deploy, "utf8"));
|
|
1708
|
+
const frameworkPaths = body.openapi?.["x-nomos-framework-routes"]?.paths ?? {};
|
|
1709
|
+
for (const pathItem of Object.values(frameworkPaths)) {
|
|
1710
|
+
const route = pathItem.post?.["x-nomos"];
|
|
1711
|
+
if (route?.directiveId === "birthHome" && typeof route.domain === "string") return route.domain;
|
|
1712
|
+
}
|
|
1599
1713
|
const domains = body.summary && body.summary.domains || [];
|
|
1600
1714
|
const hit = domains.find((d) => Array.isArray(d.directives) && d.directives.includes("seedBirthAttestation"));
|
|
1601
1715
|
return hit ? hit.domain : null;
|
|
@@ -1655,6 +1769,19 @@ async function bootstrapPlatform(dev, opts) {
|
|
|
1655
1769
|
setTestKRoot(eng, kRoot.public);
|
|
1656
1770
|
log2(`K_root ceremony: pinned LOCAL test K_root ${kRoot.public.slice(0, 16)}\u2026`);
|
|
1657
1771
|
const sP = authorKeygen(eng);
|
|
1772
|
+
const { generateKeyPairSync, sign: nodeSign } = await import("node:crypto");
|
|
1773
|
+
const { privateKey: idpPrivateKey, publicKey: idpPublicKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });
|
|
1774
|
+
const idpJwk = idpPublicKey.export({ format: "jwk" });
|
|
1775
|
+
const idpIssuer = `https://dev-idp.local/${platform}`;
|
|
1776
|
+
const idpAudience = `${platform}-app`;
|
|
1777
|
+
const idpJwks = JSON.stringify({ keys: [{ kty: "EC", crv: "P-256", kid: "dev-idp", alg: "ES256", use: "sig", x: idpJwk.x, y: idpJwk.y }] });
|
|
1778
|
+
const b64url = (b) => Buffer.from(b).toString("base64url");
|
|
1779
|
+
const mintDevToken = (claims) => {
|
|
1780
|
+
const header = b64url(JSON.stringify({ alg: "ES256", typ: "JWT", kid: "dev-idp" }));
|
|
1781
|
+
const payload = b64url(JSON.stringify({ iss: idpIssuer, aud: idpAudience, nbf: 0, exp: 4102444800, ...claims }));
|
|
1782
|
+
const si = `${header}.${payload}`;
|
|
1783
|
+
return `${si}.${b64url(nodeSign("sha256", Buffer.from(si), { key: idpPrivateKey, dsaEncoding: "ieee-p1363" }))}`;
|
|
1784
|
+
};
|
|
1658
1785
|
const platformCert = certSign(eng, {
|
|
1659
1786
|
child: platform,
|
|
1660
1787
|
founder: OPERATOR,
|
|
@@ -1663,6 +1790,9 @@ async function bootstrapPlatform(dev, opts) {
|
|
|
1663
1790
|
// P_P — the onboarding signer the platform vouches for
|
|
1664
1791
|
parentId: "root",
|
|
1665
1792
|
epoch: 0,
|
|
1793
|
+
authProviderIssuer: idpIssuer,
|
|
1794
|
+
authProviderJwks: idpJwks,
|
|
1795
|
+
authProviderAudience: idpAudience,
|
|
1666
1796
|
secret: kRoot.secret
|
|
1667
1797
|
// signed by S_root
|
|
1668
1798
|
});
|
|
@@ -1681,38 +1811,14 @@ async function bootstrapPlatform(dev, opts) {
|
|
|
1681
1811
|
let devIdP;
|
|
1682
1812
|
let pendingIdP;
|
|
1683
1813
|
{
|
|
1684
|
-
|
|
1685
|
-
const { privateKey, publicKey } = generateKeyPairSync("ec", { namedCurve: "P-256" });
|
|
1686
|
-
const jwk = publicKey.export({ format: "jwk" });
|
|
1687
|
-
const ISS = `https://dev-idp.local/${platform}`;
|
|
1688
|
-
const AUD = `${platform}-app`;
|
|
1689
|
-
const JWKS = JSON.stringify({ keys: [{ kty: "EC", crv: "P-256", kid: "dev-idp", alg: "ES256", use: "sig", x: jwk.x, y: jwk.y }] });
|
|
1690
|
-
const b64url = (b) => Buffer.from(b).toString("base64url");
|
|
1691
|
-
const mint = (claims) => {
|
|
1692
|
-
const header = b64url(JSON.stringify({ alg: "ES256", typ: "JWT", kid: "dev-idp" }));
|
|
1693
|
-
const payload = b64url(JSON.stringify({ iss: ISS, aud: AUD, nbf: 0, exp: 4102444800, ...claims }));
|
|
1694
|
-
const si = `${header}.${payload}`;
|
|
1695
|
-
return `${si}.${b64url(nodeSign("sha256", Buffer.from(si), { key: privateKey, dsaEncoding: "ieee-p1363" }))}`;
|
|
1696
|
-
};
|
|
1697
|
-
const apPayload = { issuer: ISS, keys: JWKS, audience: AUD, principalClaim: "sub", deviceBindingClaim: "nonce" };
|
|
1814
|
+
let apPayload = { issuer: idpIssuer, keys: idpJwks, audience: idpAudience, principalClaim: "sub", deviceBindingClaim: "nonce" };
|
|
1698
1815
|
try {
|
|
1699
1816
|
const deployBody = opts.deploy ? JSON.parse(readFileSync(opts.deploy, "utf8")) : null;
|
|
1700
|
-
|
|
1701
|
-
const domIface = iface.domains?.[homeDomain] ?? iface[homeDomain];
|
|
1702
|
-
const fields = domIface?.directives?.["setAuthProvider"]?.fields ?? {};
|
|
1703
|
-
for (const [name, spec] of Object.entries(fields)) {
|
|
1704
|
-
if (spec?.optional === true || apPayload[name] !== void 0) continue;
|
|
1705
|
-
if (spec?.kind === "int" && /At$/.test(name)) apPayload[name] = Date.now();
|
|
1706
|
-
else if (spec?.kind === "string" && /At$/.test(name)) apPayload[name] = (/* @__PURE__ */ new Date()).toISOString();
|
|
1707
|
-
else if (spec?.kind === "string" && /By$/.test(name)) apPayload[name] = OPERATOR;
|
|
1708
|
-
else if (spec?.kind === "string" && /url$/i.test(name)) apPayload[name] = `${ISS}/jwks.json`;
|
|
1709
|
-
else if (spec?.kind === "string") apPayload[name] = "dev";
|
|
1710
|
-
else log2(`dev test IdP: required setAuthProvider field '${name}' (kind ${spec?.kind}) is not synthesizable \u2014 the author below may refuse typed`);
|
|
1711
|
-
}
|
|
1817
|
+
apPayload = completeDevAuthProviderPayload(deployBody, homeDomain, apPayload, Date.now(), OPERATOR);
|
|
1712
1818
|
} catch (e) {
|
|
1713
1819
|
log2(`dev test IdP: BYO-shape fill failed (${errMsg(e).slice(0, 200)}) \u2014 the canonical payload stands`);
|
|
1714
1820
|
}
|
|
1715
|
-
pendingIdP = { ISS, AUD, JWKS, mint, apPayload };
|
|
1821
|
+
pendingIdP = { ISS: idpIssuer, AUD: idpAudience, JWKS: idpJwks, mint: mintDevToken, apPayload };
|
|
1716
1822
|
}
|
|
1717
1823
|
const sOp = authorKeygen(eng);
|
|
1718
1824
|
const opKeyHash = createHash("sha256").update(Buffer.from(sOp.public, "base64")).digest("hex");
|
|
@@ -1890,6 +1996,12 @@ function resolveGatewayOperation(spec, opName, method) {
|
|
|
1890
1996
|
return { op: null, ambiguous: null };
|
|
1891
1997
|
}
|
|
1892
1998
|
|
|
1999
|
+
// ../cloud/cloudflare-shell/src/kernel-registry.generated.ts
|
|
2000
|
+
var DEPLOYED_KERNELS = [
|
|
2001
|
+
{ prefix: "cf01b3ae", hash: "cf01b3ae327618b26da3af8eb6abe5e16a7f050e8a9d9b6ca92e2a1d78dd280b", version: "kernel-cf01b3ae", note: "production (this candidate)", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"] },
|
|
2002
|
+
{ prefix: "4f8ffb62", hash: "4f8ffb623c3717d973b1ced653e23f7a8f63fe73b83aa5a0f83f4dd8c46bd81f", version: "kernel-4f8ffb62", note: "test-mint (this candidate) \u2014 feature-equivalent to production", features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads", "conflictSnapshots", "ownedAudience"] }
|
|
2003
|
+
];
|
|
2004
|
+
|
|
1893
2005
|
// ../cloud/cloudflare-shell/src/staged-intents.ts
|
|
1894
2006
|
var STAGE_THRESHOLD_CHARS = 4 * 1024 * 1024;
|
|
1895
2007
|
var MAX_INLINE_INTENT_CHARS = 8 * 1024 * 1024;
|
|
@@ -2108,7 +2220,13 @@ function firstExisting(...paths) {
|
|
|
2108
2220
|
}
|
|
2109
2221
|
var TEST_MINT_MARKER = Buffer.from("set_test_k_root");
|
|
2110
2222
|
var isTestMintBytes = (bytes) => bytes.includes(TEST_MINT_MARKER);
|
|
2111
|
-
var
|
|
2223
|
+
var HISTORICAL_KERNEL_CAPABILITY_REGISTRY = [
|
|
2224
|
+
{
|
|
2225
|
+
prefix: "f50d0cc5",
|
|
2226
|
+
version: "kernel-f50d0cc5",
|
|
2227
|
+
note: "current local production build",
|
|
2228
|
+
features: ["compoundKeys", "capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads"]
|
|
2229
|
+
},
|
|
2112
2230
|
{
|
|
2113
2231
|
prefix: "846c6bf8",
|
|
2114
2232
|
version: "kernel-846c6bf8",
|
|
@@ -2128,6 +2246,10 @@ var KERNEL_CAPABILITY_REGISTRY = [
|
|
|
2128
2246
|
features: ["capturedReads", "invariantGate", "surfacedMerge", "fieldProvenance", "nullSemantics", "attestedReads"]
|
|
2129
2247
|
}
|
|
2130
2248
|
];
|
|
2249
|
+
var KERNEL_CAPABILITY_REGISTRY = [
|
|
2250
|
+
...DEPLOYED_KERNELS,
|
|
2251
|
+
...HISTORICAL_KERNEL_CAPABILITY_REGISTRY
|
|
2252
|
+
];
|
|
2131
2253
|
function capabilitiesForKernelHash(hash) {
|
|
2132
2254
|
const h = String(hash || "").toLowerCase();
|
|
2133
2255
|
const hit = KERNEL_CAPABILITY_REGISTRY.find((e) => h.startsWith(e.prefix) || e.prefix.startsWith(h.slice(0, 8)));
|
|
@@ -2367,7 +2489,10 @@ async function startDevCloud(opts = {}) {
|
|
|
2367
2489
|
dataDir,
|
|
2368
2490
|
wasmPath,
|
|
2369
2491
|
workspaces: custody.list(),
|
|
2370
|
-
...devSelf?.platformReady !== void 0 ? { platformReady: devSelf.platformReady } : {}
|
|
2492
|
+
...devSelf?.platformReady !== void 0 ? { platformReady: devSelf.platformReady } : {},
|
|
2493
|
+
// DEV/HARNESS ONLY: every peer in this ephemeral trust universe must pin the same K_root before
|
|
2494
|
+
// replaying or birthing descendants. Production bakes the one real anchor into the kernel.
|
|
2495
|
+
...devSelf?.testKRoot?.public ? { testKRootPublic: devSelf.testKRoot.public } : {}
|
|
2371
2496
|
});
|
|
2372
2497
|
}
|
|
2373
2498
|
if (url.pathname === "/dev/mint-token" && req.method === "POST") {
|
|
@@ -2500,10 +2625,19 @@ async function startDevCloud(opts = {}) {
|
|
|
2500
2625
|
const authToken = authTokenOf(req);
|
|
2501
2626
|
try {
|
|
2502
2627
|
const out = await deploy(eng, ws, ledger, usda, domainHash, dispositions, { actor, ...authToken ? { authToken } : {} });
|
|
2503
|
-
sendJson(res, {
|
|
2628
|
+
sendJson(res, {
|
|
2629
|
+
ok: true,
|
|
2630
|
+
ws,
|
|
2631
|
+
domainHash,
|
|
2632
|
+
head: out.head,
|
|
2633
|
+
installation: out.installation,
|
|
2634
|
+
staged: out.staged === true,
|
|
2635
|
+
...out.supersedes ? { supersedes: out.supersedes } : {},
|
|
2636
|
+
...out.alreadyInstalled ? { alreadyInstalled: true } : {}
|
|
2637
|
+
}, 201);
|
|
2504
2638
|
} catch (e) {
|
|
2505
2639
|
const msg = errMsg(e);
|
|
2506
|
-
const status = /deploy-did-not-advance/.test(msg) ? 409 : 422;
|
|
2640
|
+
const status = /deploy-did-not-advance|deploy-did-not-stage|deploy-predecessor|deploy-activated-candidate/.test(msg) ? 409 : 422;
|
|
2507
2641
|
sendJson(res, { ok: false, refused: true, error: msg.slice(0, 600) }, status);
|
|
2508
2642
|
}
|
|
2509
2643
|
});
|
|
@@ -2535,6 +2669,15 @@ async function startDevCloud(opts = {}) {
|
|
|
2535
2669
|
}
|
|
2536
2670
|
if (sub[0] === "intent-offers" && req.method === "POST") {
|
|
2537
2671
|
return await serialize(async () => {
|
|
2672
|
+
if (!custody.get(`holon-${ws}`)) {
|
|
2673
|
+
sendJson(res, {
|
|
2674
|
+
ok: false,
|
|
2675
|
+
retryable: true,
|
|
2676
|
+
ws,
|
|
2677
|
+
error: `custody-provisioning: workspace '${ws}' is awaiting its parent birth; Nomos will retry automatically`
|
|
2678
|
+
}, 409);
|
|
2679
|
+
return;
|
|
2680
|
+
}
|
|
2538
2681
|
const ledger = ledgerFor(ws);
|
|
2539
2682
|
await mountWorkspace(eng, ws, ledger);
|
|
2540
2683
|
const body = JSON.parse((await readBody(req)).toString("utf8") || "{}");
|
|
@@ -2721,7 +2864,8 @@ async function startDevCloud(opts = {}) {
|
|
|
2721
2864
|
if (x.kind === "sum") return sendJson(res, { ok: true, ws, ...sum(eng, ws, x.sumId, group, principal) });
|
|
2722
2865
|
if (x.kind === "extremum") return sendJson(res, { ok: true, ws, ...extremum(eng, ws, x.extremumId, x.extremumKind || url.searchParams.get("kind") || "", group, principal) });
|
|
2723
2866
|
if (x.kind === "spatial") return sendJson(res, { ok: true, ws, ...spatialWithin(eng, ws, x.spatialId, url.searchParams.get("bbox") || {}, principal) });
|
|
2724
|
-
if (x.kind === "pendingConflicts") return sendJson(res, { ok: true, ws, rows: pendingConflicts(eng, ws, principal) });
|
|
2867
|
+
if (x.kind === "pendingConflicts") return sendJson(res, { ok: true, ws, rows: pendingConflicts(eng, ws, principal, url.searchParams.get("aggregateType") || "") });
|
|
2868
|
+
if (x.kind === "pendingConflictSummary") return sendJson(res, { ok: true, ws, ...pendingConflictSummary(eng, ws, principal) });
|
|
2725
2869
|
} catch (e) {
|
|
2726
2870
|
return sendJson(res, { ok: false, error: errMsg(e).slice(0, 600) }, 403);
|
|
2727
2871
|
}
|