githolon 0.23.1 → 0.24.0

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.
Files changed (2) hide show
  1. package/dist/cli.mjs +70 -17
  2. package/package.json +3 -3
package/dist/cli.mjs CHANGED
@@ -20,7 +20,8 @@ __export(governance_exports, {
20
20
  keyImport: () => keyImport,
21
21
  keyShow: () => keyShow,
22
22
  resolveGovernancePrincipal: () => resolveGovernancePrincipal,
23
- signAndPostGovernance: () => signAndPostGovernance
23
+ signAndPostGovernance: () => signAndPostGovernance,
24
+ signAndPostOffer: () => signAndPostOffer
24
25
  });
25
26
  import { createHash, createPrivateKey, createPublicKey } from "node:crypto";
26
27
  import { readFileSync, writeFileSync as writeFileSync2 } from "node:fs";
@@ -56,20 +57,24 @@ function resolveGovernancePrincipal(opts) {
56
57
  }
57
58
  return principal;
58
59
  }
59
- async function signAndPostGovernance(parent, directiveId, payload, opts) {
60
+ async function signAndPostOffer(ws, domain, directiveId, payload, opts) {
60
61
  const cloud = cloudBase(opts.cloud);
61
62
  const principal = resolveGovernancePrincipal(opts);
62
- const holon = await connectGovernance(cloud, parent);
63
+ const holon = await connectGovernance(cloud, ws);
63
64
  const device = await ensureDeviceKey(holon, principal);
64
65
  const sealed = await holon.signGovernanceOffer({
66
+ domain,
65
67
  directiveId,
66
68
  payload,
67
69
  authorSecret: device.secret,
68
70
  actor: `user:${principal}`
69
71
  });
70
- const verdict = await holon.postGovernanceOffer({ directiveId, intentBytes: sealed.intentBytes, ws: parent });
72
+ const verdict = await holon.postGovernanceOffer({ directiveId, intentBytes: sealed.intentBytes, ws });
71
73
  return { ...verdict, principal };
72
74
  }
75
+ async function signAndPostGovernance(parent, directiveId, payload, opts) {
76
+ return signAndPostOffer(parent, "workspaces", directiveId, payload, opts);
77
+ }
73
78
  async function grantOrRevoke(verb, kind, subject, opts) {
74
79
  const parent = opts.parent ?? "root";
75
80
  const now = Date.now();
@@ -367,6 +372,7 @@ __export(cloud_exports, {
367
372
  wsStatus: () => wsStatus
368
373
  });
369
374
  import { chmodSync, existsSync as existsSync2, mkdirSync as mkdirSync2, readdirSync, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
375
+ import { createHash as createHash2 } from "node:crypto";
370
376
  import { join as join2 } from "node:path";
371
377
  import { homedir } from "node:os";
372
378
  function cloudBase(flag) {
@@ -645,21 +651,68 @@ async function deploy(ws, opts) {
645
651
  err2(e.message);
646
652
  return 1;
647
653
  }
654
+ const fileName = file.split("/").pop();
648
655
  const before = await fetch(`${cloud}/v2/workspaces/${ws}/domains`).then((br) => br.json()).then((bd) => bd.ok === true ? bd.domains ?? [] : []).catch(() => []);
649
- const r = await fetch(`${cloud}/v2/workspaces/${ws}/domains`, {
650
- method: "POST",
651
- headers: { "content-type": "application/json" },
652
- body: readFileSync2(file, "utf8")
653
- });
654
- const d = await r.json().catch(() => void 0);
655
- if (!r.ok || d?.ok !== true) {
656
- err2(`deploy '${ws}' failed (${r.status}): ${d ? JSON.stringify(d) : "no body"}`);
657
- return 1;
656
+ const principal = opts.principal ?? currentPrincipal();
657
+ const signed = opts.principal !== void 0 || principal !== void 0 && getDeviceKey(principal) !== void 0;
658
+ let phaseSuffix = "";
659
+ let deployedHash;
660
+ if (signed) {
661
+ let body;
662
+ try {
663
+ body = JSON.parse(readFileSync2(file, "utf8"));
664
+ } catch (e) {
665
+ err2(`deploy body ${file} is not valid JSON \u2014 recompile: ${e.message}`);
666
+ return 1;
667
+ }
668
+ const packageUsda = body.packageUsda;
669
+ if (typeof packageUsda !== "string" || packageUsda === "") {
670
+ err2(`deploy body ${file} is missing packageUsda \u2014 run \`githolon compile\` again`);
671
+ return 1;
672
+ }
673
+ const targetHash = createHash2("sha256").update(Buffer.from(packageUsda, "utf8")).digest("hex");
674
+ const { signAndPostOffer: signAndPostOffer2, resolveGovernancePrincipal: resolveGovernancePrincipal2 } = await Promise.resolve().then(() => (init_governance(), governance_exports));
675
+ let v;
676
+ try {
677
+ const who = resolveGovernancePrincipal2(opts);
678
+ const installPayload2 = {
679
+ domainHash: targetHash,
680
+ packageUsda,
681
+ installedBy: `user:${who}`,
682
+ dependencies: [],
683
+ finalizers: [],
684
+ ...body.dispositions !== void 0 && body.dispositions !== null ? { dispositions: body.dispositions } : {}
685
+ };
686
+ v = await signAndPostOffer2(ws, "nomos", "installDomain", installPayload2, opts);
687
+ } catch (e) {
688
+ err2(e.message);
689
+ return 1;
690
+ }
691
+ if (!v.ok) {
692
+ err2(`signed deploy '${ws}' refused (${v.status}): ${typeof v.body === "string" ? v.body : JSON.stringify(v.body)}`);
693
+ return 1;
694
+ }
695
+ deployedHash = targetHash;
696
+ } else {
697
+ const r = await fetch(`${cloud}/v2/workspaces/${ws}/domains`, {
698
+ method: "POST",
699
+ headers: { "content-type": "application/json" },
700
+ body: readFileSync2(file, "utf8")
701
+ });
702
+ const d = await r.json().catch(() => void 0);
703
+ if (!r.ok || d?.ok !== true) {
704
+ const txt = d ? JSON.stringify(d) : "no body";
705
+ err2(`deploy '${ws}' failed (${r.status}): ${txt}`);
706
+ if (r.status === 401 || r.status === 403 || r.status === 422 || /warrant|signed|signer|unsigned|authorship|forged|relation|installDomain/i.test(txt)) {
707
+ err2(` this workspace looks WARRANTED \u2014 re-run with --as <principal> to author a SIGNED install offer`);
708
+ err2(` (import the admin signing key first if needed: githolon key import --principal <uid> --secret <key>)`);
709
+ }
710
+ return 1;
711
+ }
712
+ const phase = d.installation?.[0]?.data?.["status.phase"];
713
+ phaseSuffix = typeof phase === "string" ? ` (${phase})` : "";
714
+ deployedHash = typeof d.domainHash === "string" ? d.domainHash : void 0;
658
715
  }
659
- const phase = d.installation?.[0]?.data?.["status.phase"];
660
- const fileName = file.split("/").pop();
661
- const phaseSuffix = typeof phase === "string" ? ` (${phase})` : "";
662
- const deployedHash = typeof d.domainHash === "string" ? d.domainHash : void 0;
663
716
  const after = await fetch(`${cloud}/v2/workspaces/${ws}/domains`).then((ar) => ar.json()).then((ad) => ad.ok === true ? ad : {}).catch(() => ({}));
664
717
  const currentHashes = new Set(Object.values(after.currentLaw ?? {}));
665
718
  const hasCurrencyData = Object.keys(after.currentLaw ?? {}).length > 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "githolon",
3
- "version": "0.23.1",
3
+ "version": "0.24.0",
4
4
  "type": "module",
5
5
  "description": "githolon — the Nomos developer CLI: Rails-style generators for @githolon/dsl domains + the package compiler. Kernel-independent.",
6
6
  "license": "SEE LICENSE IN LICENSE.md",
@@ -27,8 +27,8 @@
27
27
  },
28
28
  "dependencies": {
29
29
  "@bjorn3/browser_wasi_shim": "0.4.2",
30
- "@githolon/client": "^0.23.1",
31
- "@githolon/dsl": "^0.23.1",
30
+ "@githolon/client": "^0.24.0",
31
+ "@githolon/dsl": "^0.24.0",
32
32
  "isomorphic-git": "^1.38.4"
33
33
  },
34
34
  "devDependencies": {