buckyos 0.7.119 → 0.7.121
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/cli/README.md +24 -3
- package/cli/core/app.ts +28 -0
- package/cli/deno.json +2 -1
- package/cli/dist/cli.mjs +777 -169
- package/cli/dist/cli.mjs.map +1 -1
- package/cli/modules/app.ts +213 -94
- package/cli/modules/provision.ts +690 -0
- package/cli/runtime/host.ts +25 -2
- package/cli/runtime/host_deno.ts +4 -0
- package/cli/runtime/host_node.ts +4 -0
- package/cli/version.ts +1 -1
- package/dist/browser.cjs +1 -1
- package/dist/browser.mjs +124 -124
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +124 -124
- package/dist/{ndm_proxy-c00bc561.mjs → ndm_proxy-8f547002.mjs} +113 -216
- package/dist/ndm_proxy-8f547002.mjs.map +1 -0
- package/dist/ndm_proxy-93a8869b.js +13 -0
- package/dist/ndm_proxy-93a8869b.js.map +1 -0
- package/dist/ndn_types-44c69036.js +2 -0
- package/dist/ndn_types-44c69036.js.map +1 -0
- package/dist/{ndn_types-f6c08d20.mjs → ndn_types-d768245f.mjs} +149 -39
- package/dist/ndn_types-d768245f.mjs.map +1 -0
- package/dist/node.cjs +1 -1
- package/dist/node.mjs +124 -124
- package/dist/provision.cjs +6 -6
- package/dist/provision.cjs.map +1 -1
- package/dist/provision.d.ts +2 -0
- package/dist/provision.d.ts.map +1 -1
- package/dist/provision.mjs +1084 -35
- package/dist/provision.mjs.map +1 -1
- package/dist/provision_activate.d.ts +146 -0
- package/dist/provision_activate.d.ts.map +1 -0
- package/dist/{tus_client-573066b3.mjs → tus_client-b1c35e8c.mjs} +2 -2
- package/dist/{tus_client-573066b3.mjs.map → tus_client-b1c35e8c.mjs.map} +1 -1
- package/dist/{tus_client-83ad0f4f.js → tus_client-d0798623.js} +2 -2
- package/dist/{tus_client-83ad0f4f.js.map → tus_client-d0798623.js.map} +1 -1
- package/package.json +1 -1
- package/dist/ndm_proxy-68354a89.js +0 -13
- package/dist/ndm_proxy-68354a89.js.map +0 -1
- package/dist/ndm_proxy-c00bc561.mjs.map +0 -1
- package/dist/ndn_types-859bbd48.js +0 -2
- package/dist/ndn_types-859bbd48.js.map +0 -1
- package/dist/ndn_types-f6c08d20.mjs.map +0 -1
package/cli/dist/cli.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { fileURLToPath } from "node:url";
|
|
|
3
3
|
import * as nodePath from "node:path";
|
|
4
4
|
import { resolve as resolve$5, dirname as dirname$3 } from "node:path";
|
|
5
5
|
import { BuckyOSSDK, RuntimeType, buckyos, namelib, VerifyHubClient, createAppInstanceId, parseSessionTokenClaims, ndn, ndm_proxy } from "buckyos/node";
|
|
6
|
+
import * as provisionSdk from "buckyos/provision";
|
|
6
7
|
import { createHash } from "node:crypto";
|
|
7
8
|
import { readFile, writeFile, readdir, stat, lstat, realpath, mkdtemp, rename, rm, mkdir, chmod, symlink, copyFile, open } from "node:fs/promises";
|
|
8
9
|
import { createReadStream, createWriteStream } from "node:fs";
|
|
@@ -21,6 +22,7 @@ const EXIT_AUTH = 3;
|
|
|
21
22
|
const EXIT_PERMISSION = 4;
|
|
22
23
|
const EXIT_UNAVAILABLE = 5;
|
|
23
24
|
const EXIT_OPERATION = 6;
|
|
25
|
+
const EXIT_PARTIAL = 7;
|
|
24
26
|
const EXIT_TIMEOUT = 8;
|
|
25
27
|
const EXIT_INTERNAL = 9;
|
|
26
28
|
class ToolError extends Error {
|
|
@@ -506,15 +508,21 @@ function buildDistributionPolicy(options) {
|
|
|
506
508
|
if (options.distribution === "system")
|
|
507
509
|
readPaths.add(buckyosRoot);
|
|
508
510
|
const parsed = collectArgumentPaths(argv);
|
|
511
|
+
if (options.distribution === "system" && parsed.module === "app" && ["fetch", "install"].includes(parsed.verb ?? "")) {
|
|
512
|
+
writePaths.add(path.join(buckyosRoot, "cache", "control_panel", "pikg_staging", "incoming"));
|
|
513
|
+
}
|
|
509
514
|
for (const candidate of parsed.read)
|
|
510
515
|
readPaths.add(resolveInputPath(candidate, cwd, path));
|
|
516
|
+
for (const candidate of parsed.readParents) {
|
|
517
|
+
readPaths.add(path.dirname(resolveInputPath(candidate, cwd, path)));
|
|
518
|
+
}
|
|
511
519
|
for (const candidate of parsed.write)
|
|
512
520
|
writePaths.add(resolveInputPath(candidate, cwd, path));
|
|
513
521
|
for (const candidate of parsed.writeParents) {
|
|
514
522
|
writePaths.add(path.dirname(resolveInputPath(candidate, cwd, path)));
|
|
515
523
|
}
|
|
516
524
|
const subprocesses = parsed.module === "pikg" && ["init", "build"].includes(parsed.verb ?? "") ? ["docker"] : [];
|
|
517
|
-
const network = parsed.module !== void 0 && !["pikg", "command", "completion", "config"].includes(parsed.module);
|
|
525
|
+
const network = parsed.module !== void 0 && !["pikg", "command", "completion", "config", "provision"].includes(parsed.module);
|
|
518
526
|
const allowedEnvironment = options.distribution === "developer" ? TOOL_ENVIRONMENT_NAMES.filter((name) => name !== "BUCKYOS_ROOT") : TOOL_ENVIRONMENT_NAMES;
|
|
519
527
|
return Object.freeze({
|
|
520
528
|
name: options.distribution === "system" ? "system-default" : "developer-default",
|
|
@@ -539,6 +547,7 @@ function resolveInputPath(value, cwd, path) {
|
|
|
539
547
|
}
|
|
540
548
|
function collectArgumentPaths(argv) {
|
|
541
549
|
const read = [];
|
|
550
|
+
const readParents = [];
|
|
542
551
|
const write = [];
|
|
543
552
|
const writeParents = [];
|
|
544
553
|
let module;
|
|
@@ -614,6 +623,14 @@ function collectArgumentPaths(argv) {
|
|
|
614
623
|
write.push(value);
|
|
615
624
|
else if (name === "file" && module === "system-config" && verb === "set-file") {
|
|
616
625
|
read.push(value);
|
|
626
|
+
} else if (name === "root" && module === "provision") {
|
|
627
|
+
read.push(value);
|
|
628
|
+
if (verb === "activate")
|
|
629
|
+
write.push(value);
|
|
630
|
+
} else if (name === "owner-key-backup" && module === "provision") {
|
|
631
|
+
readParents.push(value);
|
|
632
|
+
if (verb === "activate")
|
|
633
|
+
writeParents.push(value);
|
|
617
634
|
} else if (!valueOptions.has(name))
|
|
618
635
|
continue;
|
|
619
636
|
continue;
|
|
@@ -629,7 +646,7 @@ function collectArgumentPaths(argv) {
|
|
|
629
646
|
writeParents.push(token);
|
|
630
647
|
}
|
|
631
648
|
}
|
|
632
|
-
return { read, write, writeParents, module, verb };
|
|
649
|
+
return { read, readParents, write, writeParents, module, verb };
|
|
633
650
|
}
|
|
634
651
|
function policyView(host2) {
|
|
635
652
|
return {
|
|
@@ -2477,7 +2494,7 @@ function replPrompt(config) {
|
|
|
2477
2494
|
return `buckyos[${profile}|${zone}|${identity}]> `;
|
|
2478
2495
|
}
|
|
2479
2496
|
const EMPTY_INPUT$1 = { type: "object", properties: {}, additionalProperties: false };
|
|
2480
|
-
const OBJECT_OUTPUT$
|
|
2497
|
+
const OBJECT_OUTPUT$8 = { type: "object", additionalProperties: true };
|
|
2481
2498
|
function createAuthModule() {
|
|
2482
2499
|
return {
|
|
2483
2500
|
name: "auth",
|
|
@@ -2487,7 +2504,7 @@ function createAuthModule() {
|
|
|
2487
2504
|
verb: "whoami",
|
|
2488
2505
|
summary: "Show the effective principal and application identity",
|
|
2489
2506
|
inputSchema: EMPTY_INPUT$1,
|
|
2490
|
-
outputSchema: OBJECT_OUTPUT$
|
|
2507
|
+
outputSchema: OBJECT_OUTPUT$8,
|
|
2491
2508
|
resultSchemaVersion: 1,
|
|
2492
2509
|
access: { mode: "fixed", level: "read" },
|
|
2493
2510
|
asyncMode: "sync",
|
|
@@ -2505,7 +2522,7 @@ function createAuthModule() {
|
|
|
2505
2522
|
verb: "session-status",
|
|
2506
2523
|
summary: "Show the in-memory session state without exposing credentials",
|
|
2507
2524
|
inputSchema: EMPTY_INPUT$1,
|
|
2508
|
-
outputSchema: OBJECT_OUTPUT$
|
|
2525
|
+
outputSchema: OBJECT_OUTPUT$8,
|
|
2509
2526
|
resultSchemaVersion: 1,
|
|
2510
2527
|
access: { mode: "fixed", level: "read" },
|
|
2511
2528
|
asyncMode: "sync",
|
|
@@ -2526,7 +2543,7 @@ const EMPTY_INPUT = {
|
|
|
2526
2543
|
properties: {},
|
|
2527
2544
|
additionalProperties: false
|
|
2528
2545
|
};
|
|
2529
|
-
const OBJECT_OUTPUT$
|
|
2546
|
+
const OBJECT_OUTPUT$7 = { type: "object", additionalProperties: true };
|
|
2530
2547
|
function createCoreModules(registry) {
|
|
2531
2548
|
return [createCommandModule(registry), createConfigModule(), createCompletionModule(registry)];
|
|
2532
2549
|
}
|
|
@@ -2539,7 +2556,7 @@ function createCommandModule(registry) {
|
|
|
2539
2556
|
verb: "list",
|
|
2540
2557
|
summary: "List registered modules and commands",
|
|
2541
2558
|
inputSchema: EMPTY_INPUT,
|
|
2542
|
-
outputSchema: OBJECT_OUTPUT$
|
|
2559
|
+
outputSchema: OBJECT_OUTPUT$7,
|
|
2543
2560
|
resultSchemaVersion: 1,
|
|
2544
2561
|
access: { mode: "fixed", level: "read" },
|
|
2545
2562
|
asyncMode: "sync",
|
|
@@ -2572,7 +2589,7 @@ function createCommandModule(registry) {
|
|
|
2572
2589
|
required: ["target_module", "target_verb"],
|
|
2573
2590
|
additionalProperties: false
|
|
2574
2591
|
},
|
|
2575
|
-
outputSchema: OBJECT_OUTPUT$
|
|
2592
|
+
outputSchema: OBJECT_OUTPUT$7,
|
|
2576
2593
|
resultSchemaVersion: 1,
|
|
2577
2594
|
access: { mode: "fixed", level: "read" },
|
|
2578
2595
|
asyncMode: "sync",
|
|
@@ -2594,7 +2611,7 @@ function createConfigModule() {
|
|
|
2594
2611
|
verb: "list",
|
|
2595
2612
|
summary: "List the global configuration and available profiles",
|
|
2596
2613
|
inputSchema: EMPTY_INPUT,
|
|
2597
|
-
outputSchema: OBJECT_OUTPUT$
|
|
2614
|
+
outputSchema: OBJECT_OUTPUT$7,
|
|
2598
2615
|
resultSchemaVersion: 1,
|
|
2599
2616
|
access: { mode: "fixed", level: "read" },
|
|
2600
2617
|
asyncMode: "sync",
|
|
@@ -2625,7 +2642,7 @@ function createConfigModule() {
|
|
|
2625
2642
|
},
|
|
2626
2643
|
additionalProperties: false
|
|
2627
2644
|
},
|
|
2628
|
-
outputSchema: OBJECT_OUTPUT$
|
|
2645
|
+
outputSchema: OBJECT_OUTPUT$7,
|
|
2629
2646
|
resultSchemaVersion: 1,
|
|
2630
2647
|
access: { mode: "fixed", level: "read" },
|
|
2631
2648
|
asyncMode: "sync",
|
|
@@ -2635,11 +2652,11 @@ function createConfigModule() {
|
|
|
2635
2652
|
"buckyos config get zone --profile-name production"
|
|
2636
2653
|
],
|
|
2637
2654
|
handler: async (ctx, input) => {
|
|
2638
|
-
const profileName = optionalString$
|
|
2655
|
+
const profileName = optionalString$4(input.profile_name);
|
|
2639
2656
|
const value = profileName ? await ctx.configStore.readProfile(profileName) : await ctx.configStore.readConfig();
|
|
2640
2657
|
if (!value)
|
|
2641
2658
|
throw new UsageError("PROFILE_NOT_FOUND", `profile not found: ${profileName}`);
|
|
2642
|
-
const key = optionalString$
|
|
2659
|
+
const key = optionalString$4(input.key);
|
|
2643
2660
|
if (!key)
|
|
2644
2661
|
return { value };
|
|
2645
2662
|
if (!Object.hasOwn(value, key)) {
|
|
@@ -2671,7 +2688,7 @@ function createConfigModule() {
|
|
|
2671
2688
|
required: ["key", "value"],
|
|
2672
2689
|
additionalProperties: false
|
|
2673
2690
|
},
|
|
2674
|
-
outputSchema: OBJECT_OUTPUT$
|
|
2691
|
+
outputSchema: OBJECT_OUTPUT$7,
|
|
2675
2692
|
resultSchemaVersion: 1,
|
|
2676
2693
|
access: { mode: "fixed", level: "write" },
|
|
2677
2694
|
asyncMode: "sync",
|
|
@@ -2683,7 +2700,7 @@ function createConfigModule() {
|
|
|
2683
2700
|
handler: async (ctx, input) => {
|
|
2684
2701
|
const key = String(input.key);
|
|
2685
2702
|
const rawValue = String(input.value);
|
|
2686
|
-
const profileName = optionalString$
|
|
2703
|
+
const profileName = optionalString$4(input.profile_name);
|
|
2687
2704
|
if (profileName) {
|
|
2688
2705
|
validateProfileName(profileName);
|
|
2689
2706
|
const profile = await ctx.configStore.readProfile(profileName) ?? { schema_version: 1 };
|
|
@@ -2711,7 +2728,7 @@ function createConfigModule() {
|
|
|
2711
2728
|
required: ["profile_name"],
|
|
2712
2729
|
additionalProperties: false
|
|
2713
2730
|
},
|
|
2714
|
-
outputSchema: OBJECT_OUTPUT$
|
|
2731
|
+
outputSchema: OBJECT_OUTPUT$7,
|
|
2715
2732
|
resultSchemaVersion: 1,
|
|
2716
2733
|
access: { mode: "fixed", level: "write" },
|
|
2717
2734
|
asyncMode: "sync",
|
|
@@ -2743,7 +2760,7 @@ function createConfigModule() {
|
|
|
2743
2760
|
properties: { effective: { type: "boolean" } },
|
|
2744
2761
|
additionalProperties: false
|
|
2745
2762
|
},
|
|
2746
|
-
outputSchema: OBJECT_OUTPUT$
|
|
2763
|
+
outputSchema: OBJECT_OUTPUT$7,
|
|
2747
2764
|
resultSchemaVersion: 1,
|
|
2748
2765
|
access: { mode: "fixed", level: "read" },
|
|
2749
2766
|
asyncMode: "sync",
|
|
@@ -2829,7 +2846,7 @@ function outputValue(value) {
|
|
|
2829
2846
|
}
|
|
2830
2847
|
return value;
|
|
2831
2848
|
}
|
|
2832
|
-
function optionalString$
|
|
2849
|
+
function optionalString$4(value) {
|
|
2833
2850
|
return typeof value === "string" && value ? value : void 0;
|
|
2834
2851
|
}
|
|
2835
2852
|
function completionScript(registry, shell) {
|
|
@@ -2888,7 +2905,7 @@ function createSystemModule() {
|
|
|
2888
2905
|
};
|
|
2889
2906
|
}
|
|
2890
2907
|
const SERVICE_NAME = "system_config";
|
|
2891
|
-
const OBJECT_OUTPUT$
|
|
2908
|
+
const OBJECT_OUTPUT$6 = { type: "object", additionalProperties: false };
|
|
2892
2909
|
const KEY_INPUT = {
|
|
2893
2910
|
type: "object",
|
|
2894
2911
|
properties: { key: { type: "string", minLength: 1 } },
|
|
@@ -2906,7 +2923,7 @@ function createSystemConfigModule() {
|
|
|
2906
2923
|
positionals: [{ name: "key", description: "System-config key" }],
|
|
2907
2924
|
inputSchema: KEY_INPUT,
|
|
2908
2925
|
outputSchema: {
|
|
2909
|
-
...OBJECT_OUTPUT$
|
|
2926
|
+
...OBJECT_OUTPUT$6,
|
|
2910
2927
|
properties: {
|
|
2911
2928
|
key: { type: "string" },
|
|
2912
2929
|
value: { type: "string" },
|
|
@@ -2949,7 +2966,7 @@ function createSystemConfigModule() {
|
|
|
2949
2966
|
additionalProperties: false
|
|
2950
2967
|
},
|
|
2951
2968
|
outputSchema: {
|
|
2952
|
-
...OBJECT_OUTPUT$
|
|
2969
|
+
...OBJECT_OUTPUT$6,
|
|
2953
2970
|
properties: {
|
|
2954
2971
|
key: { type: "string" },
|
|
2955
2972
|
items: { type: "array", items: { type: "string" } }
|
|
@@ -3003,7 +3020,7 @@ function setCommand() {
|
|
|
3003
3020
|
additionalProperties: false
|
|
3004
3021
|
},
|
|
3005
3022
|
outputSchema: {
|
|
3006
|
-
...OBJECT_OUTPUT$
|
|
3023
|
+
...OBJECT_OUTPUT$6,
|
|
3007
3024
|
properties: { key: { type: "string" }, updated: { type: "boolean" } },
|
|
3008
3025
|
required: ["key", "updated"]
|
|
3009
3026
|
},
|
|
@@ -3042,7 +3059,7 @@ function setFileCommand() {
|
|
|
3042
3059
|
additionalProperties: false
|
|
3043
3060
|
},
|
|
3044
3061
|
outputSchema: {
|
|
3045
|
-
...OBJECT_OUTPUT$
|
|
3062
|
+
...OBJECT_OUTPUT$6,
|
|
3046
3063
|
properties: { key: { type: "string" }, updated: { type: "boolean" } },
|
|
3047
3064
|
required: ["key", "updated"]
|
|
3048
3065
|
},
|
|
@@ -3079,7 +3096,7 @@ function mutationCommand(options) {
|
|
|
3079
3096
|
additionalProperties: false
|
|
3080
3097
|
},
|
|
3081
3098
|
outputSchema: {
|
|
3082
|
-
...OBJECT_OUTPUT$
|
|
3099
|
+
...OBJECT_OUTPUT$6,
|
|
3083
3100
|
properties: {
|
|
3084
3101
|
key: { type: "string" },
|
|
3085
3102
|
[options.resultProperty]: { type: "boolean" }
|
|
@@ -4127,7 +4144,7 @@ function validateServiceConfigTips(value, label) {
|
|
|
4127
4144
|
} else {
|
|
4128
4145
|
throw invalid("schema", `${label}.service_endpoints.${name}.expose.route.type is invalid`);
|
|
4129
4146
|
}
|
|
4130
|
-
optionalString$
|
|
4147
|
+
optionalString$3(expose.scope, `${label}.service_endpoints.${name}.expose.scope`);
|
|
4131
4148
|
optionalBoolean(
|
|
4132
4149
|
expose.allow_guest,
|
|
4133
4150
|
`${label}.service_endpoints.${name}.expose.allow_guest`
|
|
@@ -4181,7 +4198,7 @@ function validateServiceConfigTips(value, label) {
|
|
|
4181
4198
|
throw invalid("schema", `${label}.rdb_instances.${name}.schema.${backend} is invalid`);
|
|
4182
4199
|
}
|
|
4183
4200
|
}
|
|
4184
|
-
optionalString$
|
|
4201
|
+
optionalString$3(database.connection, `${label}.rdb_instances.${name}.connection`);
|
|
4185
4202
|
}
|
|
4186
4203
|
if (config.instance_volume !== void 0) {
|
|
4187
4204
|
const volume = expectObject$3(config.instance_volume, `${label}.instance_volume`);
|
|
@@ -4209,8 +4226,8 @@ function validateServiceConfigTips(value, label) {
|
|
|
4209
4226
|
validateStringMap(environment2.description ?? {}, `${label}.bash_envs.${name}.description`);
|
|
4210
4227
|
}
|
|
4211
4228
|
validateStringMap(config.runtime_caps ?? {}, `${label}.runtime_caps`);
|
|
4212
|
-
optionalString$
|
|
4213
|
-
optionalString$
|
|
4229
|
+
optionalString$3(config.container_param, `${label}.container_param`);
|
|
4230
|
+
optionalString$3(config.start_param, `${label}.start_param`);
|
|
4214
4231
|
return config;
|
|
4215
4232
|
}
|
|
4216
4233
|
function appDocObjectId(value) {
|
|
@@ -4604,7 +4621,7 @@ function validateAppDocShape(appDoc) {
|
|
|
4604
4621
|
}
|
|
4605
4622
|
if (appDoc.name !== void 0)
|
|
4606
4623
|
expectNonEmptyString(appDoc.name, "APPDOC.name");
|
|
4607
|
-
optionalString$
|
|
4624
|
+
optionalString$3(appDoc.copyright, "APPDOC.copyright");
|
|
4608
4625
|
for (const field of ["tags", "categories"]) {
|
|
4609
4626
|
const values = appDoc[field];
|
|
4610
4627
|
if (values !== void 0 && (!Array.isArray(values) || values.length === 0 || values.some((value) => typeof value !== "string"))) {
|
|
@@ -4814,7 +4831,7 @@ function optionalBoolean(value, label) {
|
|
|
4814
4831
|
throw invalid("schema", `${label} must be boolean`);
|
|
4815
4832
|
}
|
|
4816
4833
|
}
|
|
4817
|
-
function optionalString$
|
|
4834
|
+
function optionalString$3(value, label) {
|
|
4818
4835
|
if (value !== void 0 && typeof value !== "string") {
|
|
4819
4836
|
throw invalid("schema", `${label} must be a string`);
|
|
4820
4837
|
}
|
|
@@ -4848,7 +4865,7 @@ function invalid(stage, message, entry) {
|
|
|
4848
4865
|
function stableJsonDigest(value) {
|
|
4849
4866
|
return sha256Bytes(new TextEncoder().encode(ndn.toCanonicalJsonString(value)));
|
|
4850
4867
|
}
|
|
4851
|
-
const PACKAGE_VERSION = "0.7.
|
|
4868
|
+
const PACKAGE_VERSION = "0.7.121";
|
|
4852
4869
|
const TOOL_VERSION = PACKAGE_VERSION;
|
|
4853
4870
|
const SDK_VERSION = PACKAGE_VERSION;
|
|
4854
4871
|
const PROTOCOL_VERSION = "1";
|
|
@@ -4865,7 +4882,7 @@ const VERSION$1 = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/;
|
|
|
4865
4882
|
const SHA256_ID = /^sha256:[0-9a-f]{64}$/;
|
|
4866
4883
|
const OBJECT_ID = /^(?:appdoc|pkg):[0-9a-f]{64}$/;
|
|
4867
4884
|
const SAFE_GENERATED_FILE = /^[A-Za-z0-9._-]+$/;
|
|
4868
|
-
const OBJECT_OUTPUT$
|
|
4885
|
+
const OBJECT_OUTPUT$5 = { type: "object", additionalProperties: true };
|
|
4869
4886
|
function packageEnvironmentQualifier(key, selector) {
|
|
4870
4887
|
const effective = selector ?? derivedSelector(key);
|
|
4871
4888
|
const os = effective?.os;
|
|
@@ -4902,7 +4919,7 @@ function createPikgModule(dependencies = {}) {
|
|
|
4902
4919
|
properties: { meta_dir: { type: "string", minLength: 1 } },
|
|
4903
4920
|
additionalProperties: false
|
|
4904
4921
|
},
|
|
4905
|
-
outputSchema: OBJECT_OUTPUT$
|
|
4922
|
+
outputSchema: OBJECT_OUTPUT$5,
|
|
4906
4923
|
resultSchemaVersion: 1,
|
|
4907
4924
|
access: { mode: "fixed", level: "read" },
|
|
4908
4925
|
asyncMode: "sync",
|
|
@@ -4949,7 +4966,7 @@ function createPikgModule(dependencies = {}) {
|
|
|
4949
4966
|
},
|
|
4950
4967
|
additionalProperties: false
|
|
4951
4968
|
},
|
|
4952
|
-
outputSchema: OBJECT_OUTPUT$
|
|
4969
|
+
outputSchema: OBJECT_OUTPUT$5,
|
|
4953
4970
|
resultSchemaVersion: 1,
|
|
4954
4971
|
access: { mode: "fixed", level: "write" },
|
|
4955
4972
|
asyncMode: "sync",
|
|
@@ -4973,7 +4990,7 @@ function createPikgModule(dependencies = {}) {
|
|
|
4973
4990
|
properties: { meta_dir: { type: "string", minLength: 1 } },
|
|
4974
4991
|
additionalProperties: false
|
|
4975
4992
|
},
|
|
4976
|
-
outputSchema: OBJECT_OUTPUT$
|
|
4993
|
+
outputSchema: OBJECT_OUTPUT$5,
|
|
4977
4994
|
resultSchemaVersion: 1,
|
|
4978
4995
|
access: { mode: "fixed", level: "write" },
|
|
4979
4996
|
asyncMode: "sync",
|
|
@@ -4994,7 +5011,7 @@ function createPikgModule(dependencies = {}) {
|
|
|
4994
5011
|
properties: { dist_dir: { type: "string", minLength: 1 } },
|
|
4995
5012
|
additionalProperties: false
|
|
4996
5013
|
},
|
|
4997
|
-
outputSchema: OBJECT_OUTPUT$
|
|
5014
|
+
outputSchema: OBJECT_OUTPUT$5,
|
|
4998
5015
|
resultSchemaVersion: 1,
|
|
4999
5016
|
access: { mode: "fixed", level: "write" },
|
|
5000
5017
|
asyncMode: "sync",
|
|
@@ -5014,7 +5031,7 @@ function createPikgModule(dependencies = {}) {
|
|
|
5014
5031
|
required: ["pikg_path"],
|
|
5015
5032
|
additionalProperties: false
|
|
5016
5033
|
},
|
|
5017
|
-
outputSchema: OBJECT_OUTPUT$
|
|
5034
|
+
outputSchema: OBJECT_OUTPUT$5,
|
|
5018
5035
|
resultSchemaVersion: 1,
|
|
5019
5036
|
access: { mode: "fixed", level: "read" },
|
|
5020
5037
|
asyncMode: "sync",
|
|
@@ -5035,7 +5052,7 @@ function createPikgModule(dependencies = {}) {
|
|
|
5035
5052
|
properties: { meta_dir: { type: "string", minLength: 1 } },
|
|
5036
5053
|
additionalProperties: false
|
|
5037
5054
|
},
|
|
5038
|
-
outputSchema: OBJECT_OUTPUT$
|
|
5055
|
+
outputSchema: OBJECT_OUTPUT$5,
|
|
5039
5056
|
resultSchemaVersion: 1,
|
|
5040
5057
|
access: { mode: "fixed", level: "destructive" },
|
|
5041
5058
|
asyncMode: "sync",
|
|
@@ -6226,16 +6243,16 @@ async function observeTask(ctx, taskId) {
|
|
|
6226
6243
|
const envelope = expectObject$2(response, "TaskManager get_task response");
|
|
6227
6244
|
const task = expectObject$2(envelope.task ?? envelope, "TaskManager task");
|
|
6228
6245
|
const phase = expectString$2(task.phase, "task.phase");
|
|
6229
|
-
const outcome = optionalString$
|
|
6246
|
+
const outcome = optionalString$2(task.outcome);
|
|
6230
6247
|
const taskError = isObject$1(task.error) ? task.error : void 0;
|
|
6231
6248
|
return {
|
|
6232
6249
|
revision: typeof task.revision === "number" ? task.revision : void 0,
|
|
6233
6250
|
phase,
|
|
6234
6251
|
outcome,
|
|
6235
|
-
message: optionalString$
|
|
6252
|
+
message: optionalString$2(task.message),
|
|
6236
6253
|
error: taskError ? {
|
|
6237
|
-
code: optionalString$
|
|
6238
|
-
message: optionalString$
|
|
6254
|
+
code: optionalString$2(taskError.code),
|
|
6255
|
+
message: optionalString$2(taskError.message),
|
|
6239
6256
|
retryable: typeof taskError.retryable === "boolean" ? taskError.retryable : void 0,
|
|
6240
6257
|
details: isObject$1(taskError.detail) ? taskError.detail : void 0
|
|
6241
6258
|
} : void 0,
|
|
@@ -6255,7 +6272,7 @@ function normalizeTaskErrorCode(code, outcome) {
|
|
|
6255
6272
|
return code.trim().replaceAll(/[^A-Za-z0-9]+/g, "_").toUpperCase();
|
|
6256
6273
|
return outcome === "Canceled" ? "CANCELED" : "TASK_FAILED";
|
|
6257
6274
|
}
|
|
6258
|
-
function optionalString$
|
|
6275
|
+
function optionalString$2(value) {
|
|
6259
6276
|
return typeof value === "string" ? value : void 0;
|
|
6260
6277
|
}
|
|
6261
6278
|
function expectString$2(value, label) {
|
|
@@ -6295,7 +6312,7 @@ const CONTROL_PANEL_SERVICE = "control-panel";
|
|
|
6295
6312
|
const PLAN_SCHEMA_VERSION = 4;
|
|
6296
6313
|
const STAGING_RELEASE_TIMEOUT_MS = 5e3;
|
|
6297
6314
|
const ZIP_LOCAL_MAGIC = [80, 75, 3, 4];
|
|
6298
|
-
const OBJECT_OUTPUT$
|
|
6315
|
+
const OBJECT_OUTPUT$4 = { type: "object", additionalProperties: true };
|
|
6299
6316
|
const INSTALL_POLICIES = [
|
|
6300
6317
|
"strict-public",
|
|
6301
6318
|
"normal",
|
|
@@ -6314,7 +6331,7 @@ function createAppModule(dependencies = {}) {
|
|
|
6314
6331
|
lifecycleCommand("start", "Start an installed App"),
|
|
6315
6332
|
lifecycleCommand("stop", "Stop an installed App"),
|
|
6316
6333
|
restartCommand(),
|
|
6317
|
-
statusCommand()
|
|
6334
|
+
statusCommand$1()
|
|
6318
6335
|
];
|
|
6319
6336
|
return {
|
|
6320
6337
|
name: "app",
|
|
@@ -6351,7 +6368,7 @@ function fetchCommand(dependencies) {
|
|
|
6351
6368
|
target: { type: "object", additionalProperties: true },
|
|
6352
6369
|
install_params: { type: "object", additionalProperties: true }
|
|
6353
6370
|
}),
|
|
6354
|
-
outputSchema: OBJECT_OUTPUT$
|
|
6371
|
+
outputSchema: OBJECT_OUTPUT$4,
|
|
6355
6372
|
resultSchemaVersion: 1,
|
|
6356
6373
|
access: { mode: "fixed", level: "read" },
|
|
6357
6374
|
asyncMode: "sync",
|
|
@@ -6368,7 +6385,7 @@ function listCommand$1() {
|
|
|
6368
6385
|
verb: "list",
|
|
6369
6386
|
summary: "List visible installed Apps",
|
|
6370
6387
|
inputSchema: emptyInputSchema(),
|
|
6371
|
-
outputSchema: OBJECT_OUTPUT$
|
|
6388
|
+
outputSchema: OBJECT_OUTPUT$4,
|
|
6372
6389
|
resultSchemaVersion: 1,
|
|
6373
6390
|
access: { mode: "fixed", level: "read" },
|
|
6374
6391
|
asyncMode: "sync",
|
|
@@ -6426,7 +6443,7 @@ function installCommand(dependencies) {
|
|
|
6426
6443
|
no_wait: { type: "boolean" },
|
|
6427
6444
|
policy: { type: "string", enum: [...INSTALL_POLICIES] }
|
|
6428
6445
|
}),
|
|
6429
|
-
outputSchema: OBJECT_OUTPUT$
|
|
6446
|
+
outputSchema: OBJECT_OUTPUT$4,
|
|
6430
6447
|
resultSchemaVersion: 1,
|
|
6431
6448
|
access: { mode: "fixed", level: "write" },
|
|
6432
6449
|
asyncMode: "either",
|
|
@@ -6470,7 +6487,7 @@ function upgradeCommand(dependencies) {
|
|
|
6470
6487
|
},
|
|
6471
6488
|
additionalProperties: false
|
|
6472
6489
|
},
|
|
6473
|
-
outputSchema: OBJECT_OUTPUT$
|
|
6490
|
+
outputSchema: OBJECT_OUTPUT$4,
|
|
6474
6491
|
resultSchemaVersion: 1,
|
|
6475
6492
|
access: { mode: "fixed", level: "write" },
|
|
6476
6493
|
asyncMode: "either",
|
|
@@ -6587,7 +6604,7 @@ function restartCommand() {
|
|
|
6587
6604
|
examples: ["buckyos app restart app1"]
|
|
6588
6605
|
};
|
|
6589
6606
|
}
|
|
6590
|
-
function statusCommand() {
|
|
6607
|
+
function statusCommand$1() {
|
|
6591
6608
|
return {
|
|
6592
6609
|
verb: "status",
|
|
6593
6610
|
summary: "Show desired, task, scheduled, runtime, version, and readiness state",
|
|
@@ -6599,7 +6616,7 @@ function statusCommand() {
|
|
|
6599
6616
|
properties: { app_name: { type: "string", minLength: 1 } },
|
|
6600
6617
|
additionalProperties: false
|
|
6601
6618
|
},
|
|
6602
|
-
outputSchema: OBJECT_OUTPUT$
|
|
6619
|
+
outputSchema: OBJECT_OUTPUT$4,
|
|
6603
6620
|
resultSchemaVersion: 1,
|
|
6604
6621
|
access: { mode: "fixed", level: "read" },
|
|
6605
6622
|
asyncMode: "sync",
|
|
@@ -6640,7 +6657,7 @@ async function fetchApp(ctx, input, dependencies) {
|
|
|
6640
6657
|
const source = await prepareSource(ctx, input, "inspect", dependencies);
|
|
6641
6658
|
try {
|
|
6642
6659
|
let inspection = await inspectSource(ctx, source, input);
|
|
6643
|
-
const planPathInput = optionalString(input.plan);
|
|
6660
|
+
const planPathInput = optionalString$1(input.plan);
|
|
6644
6661
|
let planPath;
|
|
6645
6662
|
if (planPathInput) {
|
|
6646
6663
|
inspection = await finalizePlanChoices(ctx, source, input, inspection);
|
|
@@ -6664,7 +6681,7 @@ async function fetchApp(ctx, input, dependencies) {
|
|
|
6664
6681
|
}
|
|
6665
6682
|
async function installApp(ctx, input, dependencies) {
|
|
6666
6683
|
rejectDryRunNoWait(input);
|
|
6667
|
-
const submittedPlan = optionalString(input.plan) ? await readPlanFile(resolveFromCwd(ctx, String(input.plan))) : void 0;
|
|
6684
|
+
const submittedPlan = optionalString$1(input.plan) ? await readPlanFile(resolveFromCwd(ctx, String(input.plan))) : void 0;
|
|
6668
6685
|
const source = await prepareSource(ctx, input, "install", dependencies);
|
|
6669
6686
|
let keepStaging = false;
|
|
6670
6687
|
try {
|
|
@@ -6709,7 +6726,7 @@ async function installApp(ctx, input, dependencies) {
|
|
|
6709
6726
|
...sourceRpcParams(source),
|
|
6710
6727
|
...planScopeAndOptions(inspection.plan),
|
|
6711
6728
|
options: installOptions(input),
|
|
6712
|
-
plan: submittedPlan ??
|
|
6729
|
+
plan: submittedPlan ?? inspection.plan,
|
|
6713
6730
|
approved_plan_fingerprint: expectString$1(inspection.plan, "plan_fingerprint"),
|
|
6714
6731
|
idempotency_key: idempotencyKey(ctx)
|
|
6715
6732
|
};
|
|
@@ -6781,6 +6798,7 @@ async function upgradeApps(ctx, input, dependencies) {
|
|
|
6781
6798
|
...sourceRpcParams(source),
|
|
6782
6799
|
...planScopeAndOptions(inspection.plan),
|
|
6783
6800
|
options: installOptions(input),
|
|
6801
|
+
plan: inspection.plan,
|
|
6784
6802
|
approved_plan_fingerprint: expectString$1(inspection.plan, "plan_fingerprint"),
|
|
6785
6803
|
idempotency_key: idempotencyKey(ctx)
|
|
6786
6804
|
}),
|
|
@@ -6852,47 +6870,90 @@ async function prepareSource(ctx, input, purpose, dependencies) {
|
|
|
6852
6870
|
const classified = await classifySource(ctx, input);
|
|
6853
6871
|
if (classified.kind === "catalog")
|
|
6854
6872
|
return classified;
|
|
6855
|
-
const
|
|
6856
|
-
const
|
|
6857
|
-
|
|
6858
|
-
|
|
6859
|
-
|
|
6873
|
+
const host2 = getHost();
|
|
6874
|
+
const localDirectory = localPikgDirectory(ctx);
|
|
6875
|
+
let directory;
|
|
6876
|
+
let localFileId;
|
|
6877
|
+
if (localDirectory) {
|
|
6878
|
+
try {
|
|
6879
|
+
await host2.mkdir(localDirectory, { recursive: true, mode: 448 });
|
|
6880
|
+
directory = localDirectory;
|
|
6881
|
+
localFileId = crypto.randomUUID().replaceAll("-", "");
|
|
6882
|
+
} catch (error) {
|
|
6883
|
+
if (!isHostError(error, "PermissionDenied") && !isHostError(error, "NotFound"))
|
|
6884
|
+
throw error;
|
|
6885
|
+
}
|
|
6860
6886
|
}
|
|
6861
|
-
if (
|
|
6862
|
-
|
|
6863
|
-
|
|
6864
|
-
"the staged PIKG does not match the client byte snapshot",
|
|
6865
|
-
EXIT_OPERATION,
|
|
6866
|
-
false,
|
|
6867
|
-
{
|
|
6868
|
-
expected_digest: snapshot.digest,
|
|
6869
|
-
staged_digest: metadata.pikg_digest,
|
|
6870
|
-
expected_size: snapshot.size,
|
|
6871
|
-
staged_size: metadata.size
|
|
6872
|
-
}
|
|
6873
|
-
);
|
|
6887
|
+
if (!localFileId) {
|
|
6888
|
+
await host2.mkdir(ctx.configStore.root, { recursive: true, mode: 448 });
|
|
6889
|
+
directory = await host2.makeTempDir({ dir: ctx.configStore.root, prefix: ".pikg-" });
|
|
6874
6890
|
}
|
|
6875
|
-
|
|
6876
|
-
|
|
6891
|
+
let path = host2.path.join(directory, `${localFileId ?? "source"}.pikg`);
|
|
6892
|
+
const snapshotAt = (destination) => classified.kind === "url" ? downloadPikg(classified.url, destination, dependencies.download, ctx.signal) : readPikg(classified.path, destination, ctx.signal);
|
|
6893
|
+
try {
|
|
6894
|
+
let snapshot;
|
|
6895
|
+
try {
|
|
6896
|
+
snapshot = await snapshotAt(path);
|
|
6897
|
+
} catch (error) {
|
|
6898
|
+
if (!localFileId || !isHostError(error, "PermissionDenied"))
|
|
6899
|
+
throw error;
|
|
6900
|
+
await host2.remove(path).catch(() => {
|
|
6901
|
+
});
|
|
6902
|
+
localFileId = void 0;
|
|
6903
|
+
await host2.mkdir(ctx.configStore.root, { recursive: true, mode: 448 });
|
|
6904
|
+
directory = await host2.makeTempDir({ dir: ctx.configStore.root, prefix: ".pikg-" });
|
|
6905
|
+
path = host2.path.join(directory, "source.pikg");
|
|
6906
|
+
snapshot = await snapshotAt(path);
|
|
6907
|
+
}
|
|
6908
|
+
snapshot.localFileId = localFileId;
|
|
6909
|
+
const stage = dependencies.stagePikg ?? stagePikg;
|
|
6910
|
+
const metadata = await stage(ctx, snapshot, purpose);
|
|
6911
|
+
if (metadata.schema_version !== PLAN_SCHEMA_VERSION) {
|
|
6912
|
+
throw new ToolError("UNSUPPORTED_SCHEMA_VERSION", "staging returned a non-v4 schema");
|
|
6913
|
+
}
|
|
6914
|
+
if (metadata.pikg_digest !== snapshot.digest || metadata.size !== snapshot.size) {
|
|
6915
|
+
throw new ToolError(
|
|
6916
|
+
"PIKG_DIGEST_MISMATCH",
|
|
6917
|
+
"the staged PIKG does not match the client byte snapshot",
|
|
6918
|
+
EXIT_OPERATION,
|
|
6919
|
+
false,
|
|
6920
|
+
{
|
|
6921
|
+
expected_digest: snapshot.digest,
|
|
6922
|
+
staged_digest: metadata.pikg_digest,
|
|
6923
|
+
expected_size: snapshot.size,
|
|
6924
|
+
staged_size: metadata.size
|
|
6925
|
+
}
|
|
6926
|
+
);
|
|
6927
|
+
}
|
|
6928
|
+
if (metadata.purpose !== purpose) {
|
|
6929
|
+
throw new ToolError(
|
|
6930
|
+
"INVALID_SERVICE_RESPONSE",
|
|
6931
|
+
"staging purpose does not match the request",
|
|
6932
|
+
9
|
|
6933
|
+
);
|
|
6934
|
+
}
|
|
6935
|
+
return {
|
|
6936
|
+
kind: snapshot.kind,
|
|
6937
|
+
display: snapshot.display,
|
|
6938
|
+
snapshot,
|
|
6939
|
+
staging: metadata,
|
|
6940
|
+
serviceSource: { kind: "local_pikg", staging_handle: metadata.handle }
|
|
6941
|
+
};
|
|
6942
|
+
} finally {
|
|
6943
|
+
await host2.remove(localFileId ? path : directory, { recursive: !localFileId }).catch(() => {
|
|
6944
|
+
});
|
|
6877
6945
|
}
|
|
6878
|
-
return {
|
|
6879
|
-
kind: snapshot.kind,
|
|
6880
|
-
display: snapshot.display,
|
|
6881
|
-
snapshot,
|
|
6882
|
-
staging: metadata,
|
|
6883
|
-
serviceSource: { kind: "local_pikg", staging_handle: metadata.handle }
|
|
6884
|
-
};
|
|
6885
6946
|
}
|
|
6886
6947
|
async function classifySource(ctx, input) {
|
|
6887
|
-
const positional = optionalString(input.source);
|
|
6888
|
-
const pikg = optionalString(input.pikg);
|
|
6948
|
+
const positional = optionalString$1(input.source);
|
|
6949
|
+
const pikg = optionalString$1(input.pikg);
|
|
6889
6950
|
if (positional && pikg) {
|
|
6890
6951
|
throw new UsageError("ARGUMENT_CONFLICT", "<source> and --pikg are mutually exclusive");
|
|
6891
6952
|
}
|
|
6892
6953
|
const raw = pikg ?? positional;
|
|
6893
6954
|
if (!raw)
|
|
6894
6955
|
throw new UsageError("MISSING_ARGUMENT", "source or --pikg is required");
|
|
6895
|
-
const forced = pikg ? "pikg" : optionalString(input.from);
|
|
6956
|
+
const forced = pikg ? "pikg" : optionalString$1(input.from);
|
|
6896
6957
|
if (pikg && forced && forced !== "pikg") {
|
|
6897
6958
|
throw new UsageError("ARGUMENT_CONFLICT", "--pikg conflicts with --from");
|
|
6898
6959
|
}
|
|
@@ -6929,69 +6990,106 @@ async function classifySource(ctx, input) {
|
|
|
6929
6990
|
serviceSource: { kind: "identifier", identifier }
|
|
6930
6991
|
};
|
|
6931
6992
|
}
|
|
6932
|
-
|
|
6993
|
+
function localPikgDirectory(ctx) {
|
|
6994
|
+
const root = getHost().policy.buckyosRoot;
|
|
6995
|
+
const hostname = new URL(ctx.connection.endpoint).hostname;
|
|
6996
|
+
if (!root || !["localhost", "127.0.0.1", "[::1]"].includes(hostname))
|
|
6997
|
+
return void 0;
|
|
6998
|
+
return getHost().path.join(root, "cache", "control_panel", "pikg_staging", "incoming");
|
|
6999
|
+
}
|
|
7000
|
+
async function* fileChunks(file, size) {
|
|
7001
|
+
const buffer = new Uint8Array(size);
|
|
7002
|
+
while (true) {
|
|
7003
|
+
let used = 0;
|
|
7004
|
+
while (used < buffer.length) {
|
|
7005
|
+
const read = await file.read(buffer.subarray(used));
|
|
7006
|
+
if (read === null)
|
|
7007
|
+
break;
|
|
7008
|
+
if (read === 0)
|
|
7009
|
+
throw new UsageError("PIKG_READ_FAILED", "PIKG read made no progress");
|
|
7010
|
+
used += read;
|
|
7011
|
+
}
|
|
7012
|
+
if (used === 0)
|
|
7013
|
+
break;
|
|
7014
|
+
yield buffer.subarray(0, used);
|
|
7015
|
+
}
|
|
7016
|
+
}
|
|
7017
|
+
async function writePikgSnapshot(path, chunks, signal) {
|
|
7018
|
+
const output = await getHost().open(path, { write: true, createNew: true, mode: 384 });
|
|
7019
|
+
const hash = getHost().createHash("sha256");
|
|
7020
|
+
const magic = new Uint8Array(ZIP_LOCAL_MAGIC.length);
|
|
7021
|
+
let size = 0;
|
|
7022
|
+
try {
|
|
7023
|
+
for await (const chunk of chunks) {
|
|
7024
|
+
signal.throwIfAborted();
|
|
7025
|
+
if (size < magic.length)
|
|
7026
|
+
magic.set(chunk.subarray(0, magic.length - size), size);
|
|
7027
|
+
hash.update(chunk);
|
|
7028
|
+
size += chunk.length;
|
|
7029
|
+
if (!Number.isSafeInteger(size))
|
|
7030
|
+
throw new UsageError("PIKG_TOO_LARGE", "PIKG is too large");
|
|
7031
|
+
let offset = 0;
|
|
7032
|
+
while (offset < chunk.length) {
|
|
7033
|
+
const written = await output.write(chunk.subarray(offset));
|
|
7034
|
+
if (written === 0)
|
|
7035
|
+
throw new UsageError("PIKG_WRITE_FAILED", "PIKG write made no progress");
|
|
7036
|
+
offset += written;
|
|
7037
|
+
}
|
|
7038
|
+
}
|
|
7039
|
+
validatePikgSnapshot(magic.subarray(0, Math.min(size, magic.length)));
|
|
7040
|
+
await output.sync();
|
|
7041
|
+
return { path, size, digest: hash.digestHex() };
|
|
7042
|
+
} finally {
|
|
7043
|
+
await output.close();
|
|
7044
|
+
}
|
|
7045
|
+
}
|
|
7046
|
+
async function readPikg(source, destination, signal) {
|
|
6933
7047
|
let file;
|
|
6934
7048
|
try {
|
|
6935
|
-
file = await getHost().open(
|
|
7049
|
+
file = await getHost().open(source, { read: true });
|
|
6936
7050
|
} catch (error) {
|
|
6937
7051
|
throw new UsageError("PIKG_READ_FAILED", `failed to open PIKG: ${errorMessage(error)}`);
|
|
6938
7052
|
}
|
|
6939
7053
|
try {
|
|
6940
|
-
const
|
|
6941
|
-
if (!
|
|
7054
|
+
const before = await file.stat();
|
|
7055
|
+
if (!before.isFile)
|
|
6942
7056
|
throw new UsageError("INVALID_PIKG_SOURCE", "PIKG source is not a file");
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
let offset = 0;
|
|
6948
|
-
while (offset < bytes.length) {
|
|
6949
|
-
const read = await file.read(bytes.subarray(offset));
|
|
6950
|
-
if (read === null)
|
|
6951
|
-
break;
|
|
6952
|
-
offset += read;
|
|
7057
|
+
const snapshot = await writePikgSnapshot(destination, fileChunks(file, 256 * 1024), signal);
|
|
7058
|
+
const after = await file.stat();
|
|
7059
|
+
if (snapshot.size !== before.size || before.size !== after.size || before.mtime?.getTime() !== after.mtime?.getTime()) {
|
|
7060
|
+
throw new UsageError("PIKG_READ_FAILED", "PIKG changed while being read");
|
|
6953
7061
|
}
|
|
6954
|
-
|
|
6955
|
-
throw new UsageError("PIKG_READ_FAILED", "PIKG changed size while being read");
|
|
6956
|
-
}
|
|
6957
|
-
validatePikgSnapshot(bytes);
|
|
6958
|
-
return {
|
|
6959
|
-
kind,
|
|
6960
|
-
display: path,
|
|
6961
|
-
bytes,
|
|
6962
|
-
digest: await sha256Id(bytes),
|
|
6963
|
-
size: bytes.length
|
|
6964
|
-
};
|
|
7062
|
+
return { kind: "pikg", display: source, ...snapshot };
|
|
6965
7063
|
} finally {
|
|
6966
7064
|
await file.close();
|
|
6967
7065
|
}
|
|
6968
7066
|
}
|
|
6969
|
-
async function downloadPikg(url, downloader, signal) {
|
|
6970
|
-
let
|
|
7067
|
+
async function downloadPikg(url, destination, downloader, signal) {
|
|
7068
|
+
let chunks;
|
|
6971
7069
|
try {
|
|
6972
|
-
|
|
7070
|
+
chunks = downloader ? [await downloader(url, signal)] : await defaultDownload(url, signal);
|
|
7071
|
+
const snapshot = await writePikgSnapshot(destination, chunks, signal);
|
|
7072
|
+
return { kind: "url", display: safeUrl(url), ...snapshot };
|
|
6973
7073
|
} catch (error) {
|
|
6974
|
-
if (error instanceof ToolError)
|
|
7074
|
+
if (error instanceof ToolError || isHostError(error, "PermissionDenied"))
|
|
6975
7075
|
throw error;
|
|
7076
|
+
signal.throwIfAborted();
|
|
6976
7077
|
throw new ToolError(
|
|
6977
7078
|
"PIKG_DOWNLOAD_FAILED",
|
|
6978
7079
|
`failed to download PIKG: ${errorMessage(error)}`,
|
|
6979
7080
|
5,
|
|
6980
7081
|
true
|
|
6981
7082
|
);
|
|
7083
|
+
} finally {
|
|
7084
|
+
if (chunks instanceof ReadableStream && !chunks.locked)
|
|
7085
|
+
await chunks.cancel().catch(() => {
|
|
7086
|
+
});
|
|
6982
7087
|
}
|
|
6983
|
-
validatePikgSnapshot(bytes);
|
|
6984
|
-
return {
|
|
6985
|
-
kind: "url",
|
|
6986
|
-
display: safeUrl(url),
|
|
6987
|
-
bytes,
|
|
6988
|
-
digest: await sha256Id(bytes),
|
|
6989
|
-
size: bytes.length
|
|
6990
|
-
};
|
|
6991
7088
|
}
|
|
6992
7089
|
async function defaultDownload(url, signal) {
|
|
6993
7090
|
const response = await fetch(url, { method: "GET", redirect: "follow", signal });
|
|
6994
|
-
if (!response.ok) {
|
|
7091
|
+
if (!response.ok || !response.body) {
|
|
7092
|
+
await response.body?.cancel();
|
|
6995
7093
|
throw new ToolError(
|
|
6996
7094
|
"PIKG_DOWNLOAD_FAILED",
|
|
6997
7095
|
`PIKG download returned HTTP ${response.status}`,
|
|
@@ -6999,46 +7097,84 @@ async function defaultDownload(url, signal) {
|
|
|
6999
7097
|
response.status >= 500
|
|
7000
7098
|
);
|
|
7001
7099
|
}
|
|
7002
|
-
return
|
|
7100
|
+
return response.body;
|
|
7003
7101
|
}
|
|
7004
7102
|
async function stagePikg(ctx, snapshot, purpose) {
|
|
7103
|
+
const identity = { pikg_digest: snapshot.digest, size: snapshot.size, purpose };
|
|
7104
|
+
if (snapshot.localFileId) {
|
|
7105
|
+
try {
|
|
7106
|
+
const value2 = expectObject$1(
|
|
7107
|
+
await callControl(ctx, "apps.staging.finalize", {
|
|
7108
|
+
...identity,
|
|
7109
|
+
local_file_id: snapshot.localFileId
|
|
7110
|
+
}),
|
|
7111
|
+
"apps.staging.finalize response"
|
|
7112
|
+
);
|
|
7113
|
+
return parseStagingMetadata(value2);
|
|
7114
|
+
} catch (error) {
|
|
7115
|
+
if (!errorMessage(error).includes("LOCAL_PIKG_UNAVAILABLE"))
|
|
7116
|
+
throw error;
|
|
7117
|
+
}
|
|
7118
|
+
}
|
|
7005
7119
|
const session = ctx.session;
|
|
7006
7120
|
if (!session)
|
|
7007
7121
|
throw new ToolError("AUTH_REQUIRED", "authenticated session is required", 3);
|
|
7008
7122
|
const token = (await session.ensureValid()).token;
|
|
7009
|
-
const hash = ndn.sha256Bytes(snapshot.bytes);
|
|
7010
|
-
const chunkId = ndn.ChunkId.fromMix256Result(snapshot.size, hash).toString();
|
|
7011
7123
|
const proxy = ndm_proxy.createNdmProxyClient({
|
|
7012
7124
|
endpoint: gatewayOrigin(ctx.connection.endpoint),
|
|
7013
7125
|
sessionToken: token,
|
|
7014
7126
|
fetcher: (request, init) => fetch(normalizeNdmRequestUrl(request), { ...init, signal: ctx.signal })
|
|
7015
7127
|
});
|
|
7016
|
-
let
|
|
7128
|
+
let fileObjectId;
|
|
7017
7129
|
try {
|
|
7018
|
-
await
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
}
|
|
7029
|
-
|
|
7030
|
-
|
|
7130
|
+
const file = await getHost().open(snapshot.path, { read: true });
|
|
7131
|
+
const chunks = new ndn.SimpleChunkList();
|
|
7132
|
+
const hash = getHost().createHash("sha256");
|
|
7133
|
+
try {
|
|
7134
|
+
for await (const bytes of fileChunks(file, 32 * 1024 * 1024)) {
|
|
7135
|
+
ctx.signal.throwIfAborted();
|
|
7136
|
+
hash.update(bytes);
|
|
7137
|
+
const chunk = ndn.ChunkId.fromMix256Result(bytes.length, ndn.sha256Bytes(bytes));
|
|
7138
|
+
await proxy.putChunk(chunk.toString(), bytes);
|
|
7139
|
+
chunks.appendChunk(chunk);
|
|
7140
|
+
}
|
|
7141
|
+
} finally {
|
|
7142
|
+
await file.close();
|
|
7143
|
+
}
|
|
7144
|
+
if (chunks.total_size !== snapshot.size || hash.digestHex() !== snapshot.digest) {
|
|
7145
|
+
throw new ToolError("PIKG_DIGEST_MISMATCH", "PIKG snapshot changed during upload");
|
|
7146
|
+
}
|
|
7147
|
+
let content = chunks.body[0].toString();
|
|
7148
|
+
if (chunks.body.length > 1) {
|
|
7149
|
+
const [id2, body2] = chunks.genObjId();
|
|
7150
|
+
await proxy.putObject({ obj_id: id2.toString(), obj_data: body2 });
|
|
7151
|
+
content = id2.toString();
|
|
7152
|
+
}
|
|
7153
|
+
const fileObject = new ndn.FileObject(`${snapshot.digest}.pikg`, snapshot.size, content);
|
|
7154
|
+
const [id, body] = fileObject.genObjId();
|
|
7155
|
+
await proxy.putObject({ obj_id: id.toString(), obj_data: body });
|
|
7156
|
+
fileObjectId = id.toString();
|
|
7031
7157
|
} catch (error) {
|
|
7032
|
-
if (
|
|
7158
|
+
if (error instanceof ToolError)
|
|
7033
7159
|
throw error;
|
|
7160
|
+
ctx.signal.throwIfAborted();
|
|
7034
7161
|
throw new ToolError(
|
|
7035
7162
|
"PIKG_UPLOAD_FAILED",
|
|
7036
|
-
`failed to upload PIKG
|
|
7163
|
+
`failed to upload PIKG: ${errorMessage(error)}`,
|
|
7037
7164
|
5,
|
|
7038
|
-
true
|
|
7039
|
-
{ finalize_error: errorMessage(error) }
|
|
7165
|
+
true
|
|
7040
7166
|
);
|
|
7041
7167
|
}
|
|
7168
|
+
const value = expectObject$1(
|
|
7169
|
+
await callControl(ctx, "apps.staging.finalize", {
|
|
7170
|
+
...identity,
|
|
7171
|
+
source_obj_id: fileObjectId
|
|
7172
|
+
}),
|
|
7173
|
+
"apps.staging.finalize response"
|
|
7174
|
+
);
|
|
7175
|
+
return parseStagingMetadata(value);
|
|
7176
|
+
}
|
|
7177
|
+
function parseStagingMetadata(value) {
|
|
7042
7178
|
return {
|
|
7043
7179
|
schema_version: expectNumber(value, "schema_version"),
|
|
7044
7180
|
handle: expectString$1(value, "handle"),
|
|
@@ -7138,11 +7274,11 @@ async function observeInstallTask(ctx, taskId) {
|
|
|
7138
7274
|
const sanitizedDetails = error && isObject(error.details) ? sanitizeAppOutput(error.details) : void 0;
|
|
7139
7275
|
return {
|
|
7140
7276
|
phase: expectString$1(status, "task_phase"),
|
|
7141
|
-
outcome: optionalString(status.task_outcome),
|
|
7277
|
+
outcome: optionalString$1(status.task_outcome),
|
|
7142
7278
|
message: installProgressMessage(status),
|
|
7143
7279
|
error: error ? {
|
|
7144
|
-
code: optionalString(error.code),
|
|
7145
|
-
message: optionalString(error.message),
|
|
7280
|
+
code: optionalString$1(error.code),
|
|
7281
|
+
message: optionalString$1(error.message),
|
|
7146
7282
|
retryable: typeof error.retryable === "boolean" ? error.retryable : void 0,
|
|
7147
7283
|
details: isObject(sanitizedDetails) ? sanitizedDetails : void 0
|
|
7148
7284
|
} : void 0,
|
|
@@ -7240,7 +7376,7 @@ function installedScope(details) {
|
|
|
7240
7376
|
};
|
|
7241
7377
|
}
|
|
7242
7378
|
function installOptions(input) {
|
|
7243
|
-
const policy2 = optionalString(input.policy) ?? "normal";
|
|
7379
|
+
const policy2 = optionalString$1(input.policy) ?? "normal";
|
|
7244
7380
|
return { policy: policy2.replaceAll("-", "_").toUpperCase() };
|
|
7245
7381
|
}
|
|
7246
7382
|
function sourceSummary(source) {
|
|
@@ -7522,11 +7658,6 @@ function validatePikgSnapshot(bytes) {
|
|
|
7522
7658
|
throw new UsageError("INVALID_PIKG", "PIKG magic mismatch: expected a ZIP container");
|
|
7523
7659
|
}
|
|
7524
7660
|
}
|
|
7525
|
-
async function sha256Id(bytes) {
|
|
7526
|
-
const digestInput = Uint8Array.from(bytes);
|
|
7527
|
-
const digest = new Uint8Array(await crypto.subtle.digest("SHA-256", digestInput.buffer));
|
|
7528
|
-
return [...digest].map((byte) => byte.toString(16).padStart(2, "0")).join("");
|
|
7529
|
-
}
|
|
7530
7661
|
function gatewayOrigin(endpoint) {
|
|
7531
7662
|
const url = new URL(endpoint);
|
|
7532
7663
|
const marker = url.pathname.indexOf("/kapi");
|
|
@@ -7569,13 +7700,13 @@ function parseEmbeddedJson(message) {
|
|
|
7569
7700
|
}
|
|
7570
7701
|
function readinessValue(inspection, field) {
|
|
7571
7702
|
const readiness = isObject(inspection.status.readiness) ? inspection.status.readiness : void 0;
|
|
7572
|
-
return readiness ? optionalString(readiness[field]) : void 0;
|
|
7703
|
+
return readiness ? optionalString$1(readiness[field]) : void 0;
|
|
7573
7704
|
}
|
|
7574
7705
|
function planUse(plan) {
|
|
7575
|
-
return optionalString(plan.plan_use);
|
|
7706
|
+
return optionalString$1(plan.plan_use);
|
|
7576
7707
|
}
|
|
7577
7708
|
function installProgressMessage(status) {
|
|
7578
|
-
const stage = optionalString(status.stage);
|
|
7709
|
+
const stage = optionalString$1(status.stage);
|
|
7579
7710
|
const progress = isObject(status.progress) ? status.progress : void 0;
|
|
7580
7711
|
const percent = progress && typeof progress.percent === "number" ? `${progress.percent}%` : void 0;
|
|
7581
7712
|
return [stage, percent].filter(Boolean).join(" ") || void 0;
|
|
@@ -7599,7 +7730,7 @@ function selectorCommand(options) {
|
|
|
7599
7730
|
required: ["app_name"],
|
|
7600
7731
|
additionalProperties: false
|
|
7601
7732
|
},
|
|
7602
|
-
outputSchema: OBJECT_OUTPUT$
|
|
7733
|
+
outputSchema: OBJECT_OUTPUT$4,
|
|
7603
7734
|
resultSchemaVersion: 1,
|
|
7604
7735
|
access: { mode: "fixed", level: options.access },
|
|
7605
7736
|
asyncMode: options.asyncMode,
|
|
@@ -7681,7 +7812,7 @@ function expectNumber(object, property) {
|
|
|
7681
7812
|
}
|
|
7682
7813
|
return value;
|
|
7683
7814
|
}
|
|
7684
|
-
function optionalString(value) {
|
|
7815
|
+
function optionalString$1(value) {
|
|
7685
7816
|
return typeof value === "string" && value.trim() ? value : void 0;
|
|
7686
7817
|
}
|
|
7687
7818
|
function optionalNumber(value) {
|
|
@@ -7826,7 +7957,7 @@ function splitServices(value) {
|
|
|
7826
7957
|
return [...new Set(items.map((item) => String(item).trim()).filter(Boolean))];
|
|
7827
7958
|
}
|
|
7828
7959
|
const CONTROL_PANEL$2 = "control-panel";
|
|
7829
|
-
const OBJECT_OUTPUT$
|
|
7960
|
+
const OBJECT_OUTPUT$3 = { type: "object", additionalProperties: true };
|
|
7830
7961
|
function createDiagnosticModule(dependencies = {}) {
|
|
7831
7962
|
return {
|
|
7832
7963
|
name: "diagnostic",
|
|
@@ -7865,7 +7996,7 @@ function collectCommand() {
|
|
|
7865
7996
|
required: ["services"],
|
|
7866
7997
|
additionalProperties: false
|
|
7867
7998
|
},
|
|
7868
|
-
outputSchema: OBJECT_OUTPUT$
|
|
7999
|
+
outputSchema: OBJECT_OUTPUT$3,
|
|
7869
8000
|
resultSchemaVersion: 1,
|
|
7870
8001
|
access: { mode: "fixed", level: "privileged" },
|
|
7871
8002
|
asyncMode: "task",
|
|
@@ -7919,7 +8050,7 @@ function exportCommand$1(dependencies) {
|
|
|
7919
8050
|
required: ["bundle_id", "path"],
|
|
7920
8051
|
additionalProperties: false
|
|
7921
8052
|
},
|
|
7922
|
-
outputSchema: OBJECT_OUTPUT$
|
|
8053
|
+
outputSchema: OBJECT_OUTPUT$3,
|
|
7923
8054
|
resultSchemaVersion: 1,
|
|
7924
8055
|
access: { mode: "fixed", level: "privileged" },
|
|
7925
8056
|
asyncMode: "sync",
|
|
@@ -7961,7 +8092,7 @@ function compact$2(value) {
|
|
|
7961
8092
|
return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== void 0));
|
|
7962
8093
|
}
|
|
7963
8094
|
const CONTROL_PANEL$1 = "control-panel";
|
|
7964
|
-
const OBJECT_OUTPUT$
|
|
8095
|
+
const OBJECT_OUTPUT$2 = { type: "object", additionalProperties: true };
|
|
7965
8096
|
function createLogModule(dependencies = {}) {
|
|
7966
8097
|
return {
|
|
7967
8098
|
name: "log",
|
|
@@ -8022,7 +8153,7 @@ function tailCommand(dependencies) {
|
|
|
8022
8153
|
}
|
|
8023
8154
|
],
|
|
8024
8155
|
inputSchema: filterSchema({ from: { type: "string", enum: ["start", "end"] } }),
|
|
8025
|
-
outputSchema: OBJECT_OUTPUT$
|
|
8156
|
+
outputSchema: OBJECT_OUTPUT$2,
|
|
8026
8157
|
resultSchemaVersion: 1,
|
|
8027
8158
|
access: { mode: "fixed", level: "read" },
|
|
8028
8159
|
asyncMode: "stream",
|
|
@@ -8078,7 +8209,7 @@ function exportCommand(dependencies) {
|
|
|
8078
8209
|
...filterSchema({ path: { type: "string", minLength: 1 } }),
|
|
8079
8210
|
required: ["path"]
|
|
8080
8211
|
},
|
|
8081
|
-
outputSchema: OBJECT_OUTPUT$
|
|
8212
|
+
outputSchema: OBJECT_OUTPUT$2,
|
|
8082
8213
|
resultSchemaVersion: 1,
|
|
8083
8214
|
access: { mode: "fixed", level: "read" },
|
|
8084
8215
|
asyncMode: "sync",
|
|
@@ -8214,7 +8345,7 @@ function abortableSleep(milliseconds, signal) {
|
|
|
8214
8345
|
}
|
|
8215
8346
|
const TASK_MANAGER = "task-manager";
|
|
8216
8347
|
const CONTROL_PANEL = "control-panel";
|
|
8217
|
-
const OBJECT_OUTPUT = { type: "object", additionalProperties: true };
|
|
8348
|
+
const OBJECT_OUTPUT$1 = { type: "object", additionalProperties: true };
|
|
8218
8349
|
function createTaskModule() {
|
|
8219
8350
|
return {
|
|
8220
8351
|
name: "task",
|
|
@@ -8317,7 +8448,7 @@ function getCommand() {
|
|
|
8317
8448
|
required: ["task_id"],
|
|
8318
8449
|
additionalProperties: false
|
|
8319
8450
|
},
|
|
8320
|
-
outputSchema: OBJECT_OUTPUT,
|
|
8451
|
+
outputSchema: OBJECT_OUTPUT$1,
|
|
8321
8452
|
resultSchemaVersion: 1,
|
|
8322
8453
|
access: { mode: "fixed", level: "read" },
|
|
8323
8454
|
asyncMode: "sync",
|
|
@@ -8358,7 +8489,7 @@ function waitCommand() {
|
|
|
8358
8489
|
summary: "Stream changes until a Task becomes terminal",
|
|
8359
8490
|
positionals: [{ name: "task_id", description: "Opaque Task ID", required: true }],
|
|
8360
8491
|
inputSchema: taskIdSchema(),
|
|
8361
|
-
outputSchema: OBJECT_OUTPUT,
|
|
8492
|
+
outputSchema: OBJECT_OUTPUT$1,
|
|
8362
8493
|
resultSchemaVersion: 1,
|
|
8363
8494
|
access: { mode: "fixed", level: "read" },
|
|
8364
8495
|
asyncMode: "stream",
|
|
@@ -8409,7 +8540,7 @@ function cancelCommand() {
|
|
|
8409
8540
|
required: ["task_id"],
|
|
8410
8541
|
additionalProperties: false
|
|
8411
8542
|
},
|
|
8412
|
-
outputSchema: OBJECT_OUTPUT,
|
|
8543
|
+
outputSchema: OBJECT_OUTPUT$1,
|
|
8413
8544
|
resultSchemaVersion: 1,
|
|
8414
8545
|
access: { mode: "fixed", level: "write" },
|
|
8415
8546
|
asyncMode: "sync",
|
|
@@ -8452,7 +8583,7 @@ function retryCommand() {
|
|
|
8452
8583
|
required: ["task_id"],
|
|
8453
8584
|
additionalProperties: false
|
|
8454
8585
|
},
|
|
8455
|
-
outputSchema: OBJECT_OUTPUT,
|
|
8586
|
+
outputSchema: OBJECT_OUTPUT$1,
|
|
8456
8587
|
resultSchemaVersion: 1,
|
|
8457
8588
|
access: { mode: "fixed", level: "write" },
|
|
8458
8589
|
asyncMode: "either",
|
|
@@ -8525,6 +8656,459 @@ function compact(value) {
|
|
|
8525
8656
|
function invalidResponse(label) {
|
|
8526
8657
|
throw new ToolError("INVALID_SERVICE_RESPONSE", `${label} is invalid`, EXIT_INTERNAL);
|
|
8527
8658
|
}
|
|
8659
|
+
const sdk = provisionSdk;
|
|
8660
|
+
const OBJECT_OUTPUT = { type: "object", additionalProperties: true };
|
|
8661
|
+
const ROOT_OPTION = {
|
|
8662
|
+
name: "root",
|
|
8663
|
+
description: "Installed BuckyOS root on this machine (BUCKYOS_ROOT); read by status/check, written by activate",
|
|
8664
|
+
type: "string",
|
|
8665
|
+
required: true
|
|
8666
|
+
};
|
|
8667
|
+
const TARGET_OPTIONS = [
|
|
8668
|
+
ROOT_OPTION,
|
|
8669
|
+
{
|
|
8670
|
+
name: "domain",
|
|
8671
|
+
description: "Fixed public host name; Owner DID and Zone DID become did:web:<domain>",
|
|
8672
|
+
type: "string",
|
|
8673
|
+
required: true
|
|
8674
|
+
},
|
|
8675
|
+
{
|
|
8676
|
+
name: "owner-name",
|
|
8677
|
+
property: "owner_name",
|
|
8678
|
+
description: "Local administrator / OwnerDocument name (lowercase DNS label)",
|
|
8679
|
+
type: "string",
|
|
8680
|
+
required: true
|
|
8681
|
+
},
|
|
8682
|
+
{
|
|
8683
|
+
name: "owner-key-backup",
|
|
8684
|
+
property: "owner_key_backup",
|
|
8685
|
+
description: "New file for the Owner private-key recovery copy; its directory must exist and the file must not",
|
|
8686
|
+
type: "string",
|
|
8687
|
+
required: true
|
|
8688
|
+
},
|
|
8689
|
+
{
|
|
8690
|
+
name: "public-ip",
|
|
8691
|
+
property: "public_ip",
|
|
8692
|
+
description: "Fixed public IP used only for the A/AAAA record instructions",
|
|
8693
|
+
type: "string"
|
|
8694
|
+
},
|
|
8695
|
+
{
|
|
8696
|
+
name: "rtcp-port",
|
|
8697
|
+
property: "rtcp_port",
|
|
8698
|
+
description: "RTCP port, default 2980",
|
|
8699
|
+
type: "integer"
|
|
8700
|
+
},
|
|
8701
|
+
{
|
|
8702
|
+
name: "guest-access",
|
|
8703
|
+
property: "guest_access",
|
|
8704
|
+
description: "Enable guest access in the first-boot configuration",
|
|
8705
|
+
type: "boolean"
|
|
8706
|
+
}
|
|
8707
|
+
];
|
|
8708
|
+
const TARGET_INPUT_PROPERTIES = {
|
|
8709
|
+
root: { type: "string", minLength: 1 },
|
|
8710
|
+
domain: { type: "string", minLength: 1 },
|
|
8711
|
+
owner_name: { type: "string", minLength: 1 },
|
|
8712
|
+
owner_key_backup: { type: "string", minLength: 1 },
|
|
8713
|
+
public_ip: { type: "string" },
|
|
8714
|
+
rtcp_port: { type: "integer", minimum: 1 },
|
|
8715
|
+
guest_access: { type: "boolean" }
|
|
8716
|
+
};
|
|
8717
|
+
const TARGET_REQUIRED = ["root", "domain", "owner_name", "owner_key_backup"];
|
|
8718
|
+
const POLICY_NOTE = "Paths are read from argv by the launcher to grant the minimal filesystem permissions; root and owner_key_backup given only inside --input are limited to the policy roots (cwd, and the paired BUCKYOS_ROOT of the system distribution).";
|
|
8719
|
+
function createProvisionModule(dependencies = {}) {
|
|
8720
|
+
const deps = {
|
|
8721
|
+
inspect: dependencies.inspect ?? sdk.inspectActivationRoot,
|
|
8722
|
+
check: dependencies.check ?? sdk.checkOfflineActivation,
|
|
8723
|
+
activate: dependencies.activate ?? sdk.activateOfflineZone
|
|
8724
|
+
};
|
|
8725
|
+
return {
|
|
8726
|
+
name: "provision",
|
|
8727
|
+
summary: "Activate an installed BuckyOS root on this machine (first Zone, Owner, and OOD)",
|
|
8728
|
+
commands: [statusCommand(deps), checkCommand(deps), activateCommand(deps)]
|
|
8729
|
+
};
|
|
8730
|
+
}
|
|
8731
|
+
function statusCommand(deps) {
|
|
8732
|
+
return {
|
|
8733
|
+
verb: "status",
|
|
8734
|
+
summary: "Inspect the local activation material of an installed BuckyOS root",
|
|
8735
|
+
description: "Read-only. Reports not_installed, unactivated, partial, configured, or invalid from the files under the root; configured only means the first-boot material is complete and internally consistent (startup_required=true). Service health, DNS, TLS, and public DID discovery are not checked. " + POLICY_NOTE,
|
|
8736
|
+
options: [ROOT_OPTION],
|
|
8737
|
+
inputSchema: {
|
|
8738
|
+
type: "object",
|
|
8739
|
+
properties: { root: { type: "string", minLength: 1 } },
|
|
8740
|
+
required: ["root"],
|
|
8741
|
+
additionalProperties: false
|
|
8742
|
+
},
|
|
8743
|
+
outputSchema: {
|
|
8744
|
+
...OBJECT_OUTPUT,
|
|
8745
|
+
properties: {
|
|
8746
|
+
root: { type: "string" },
|
|
8747
|
+
state: {
|
|
8748
|
+
type: "string",
|
|
8749
|
+
enum: ["not_installed", "unactivated", "partial", "configured", "invalid"]
|
|
8750
|
+
},
|
|
8751
|
+
startup_required: { type: "boolean" }
|
|
8752
|
+
},
|
|
8753
|
+
required: ["root", "state", "startup_required"]
|
|
8754
|
+
},
|
|
8755
|
+
resultSchemaVersion: 1,
|
|
8756
|
+
access: { mode: "fixed", level: "read" },
|
|
8757
|
+
asyncMode: "sync",
|
|
8758
|
+
requiresSession: false,
|
|
8759
|
+
execution: "local",
|
|
8760
|
+
networkAccess: false,
|
|
8761
|
+
examples: ["buckyos provision status --root /opt/buckyos"],
|
|
8762
|
+
handler: async (ctx, input) => {
|
|
8763
|
+
const root = resolvePath(ctx, requiredString(input, "root"));
|
|
8764
|
+
await assertHostAccess(root, "read");
|
|
8765
|
+
return statusView(await runSdk(() => deps.inspect(root)));
|
|
8766
|
+
}
|
|
8767
|
+
};
|
|
8768
|
+
}
|
|
8769
|
+
function checkCommand(deps) {
|
|
8770
|
+
return {
|
|
8771
|
+
verb: "check",
|
|
8772
|
+
summary: "Validate activation parameters and the target root without writing anything",
|
|
8773
|
+
description: "Read-only precheck shared with activate: parameters, target state, and the owner key backup location. No keys are generated, no backup is written, and no operation is produced; activate re-validates the target itself. Fails with the first problem code when the target is not ready. " + POLICY_NOTE,
|
|
8774
|
+
options: TARGET_OPTIONS,
|
|
8775
|
+
inputSchema: {
|
|
8776
|
+
type: "object",
|
|
8777
|
+
properties: TARGET_INPUT_PROPERTIES,
|
|
8778
|
+
required: TARGET_REQUIRED,
|
|
8779
|
+
additionalProperties: false
|
|
8780
|
+
},
|
|
8781
|
+
outputSchema: {
|
|
8782
|
+
...OBJECT_OUTPUT,
|
|
8783
|
+
properties: {
|
|
8784
|
+
ready: { type: "boolean" },
|
|
8785
|
+
root: { type: "string" },
|
|
8786
|
+
state: { type: "string" }
|
|
8787
|
+
},
|
|
8788
|
+
required: ["ready", "root", "state"]
|
|
8789
|
+
},
|
|
8790
|
+
resultSchemaVersion: 1,
|
|
8791
|
+
access: { mode: "fixed", level: "read" },
|
|
8792
|
+
asyncMode: "sync",
|
|
8793
|
+
requiresSession: false,
|
|
8794
|
+
execution: "local",
|
|
8795
|
+
networkAccess: false,
|
|
8796
|
+
examples: [
|
|
8797
|
+
"buckyos provision check --root /opt/buckyos --domain corp.example.com --owner-name admin --owner-key-backup /secure-backup/corp-owner.pem"
|
|
8798
|
+
],
|
|
8799
|
+
handler: async (ctx, input) => {
|
|
8800
|
+
const options = activationOptions(ctx, input);
|
|
8801
|
+
await assertHostAccess(options.rootDir, "read");
|
|
8802
|
+
await assertHostAccess(getHost().path.dirname(options.ownerKeyBackupPath), "read");
|
|
8803
|
+
const precheck = await runSdk(() => deps.check(options));
|
|
8804
|
+
if (!precheck.ready)
|
|
8805
|
+
throw precheckError(precheck);
|
|
8806
|
+
return precheckView(precheck);
|
|
8807
|
+
}
|
|
8808
|
+
};
|
|
8809
|
+
}
|
|
8810
|
+
function activateCommand(deps) {
|
|
8811
|
+
return {
|
|
8812
|
+
verb: "activate",
|
|
8813
|
+
summary: "Activate the root: create the first Zone, Owner, and OOD identity and the first-boot configuration",
|
|
8814
|
+
description: "Privileged local write. Generates random Ed25519 Owner/device keys and current-time documents, saves the Owner private-key backup, then commits the identity, Zone, and start_config files; etc/node_identity.json is written last because node-daemon treats it as the activation switch. The administrator password is read from the secret admin_password field of --input JSON or from a hidden terminal prompt; there is no --admin-password option. Non-interactive runs require --yes. Repeated, partial, and invalid targets are rejected; there is no --force. After success restart BuckyOS through the installer or node control entry; this command never reports the Zone as online. " + POLICY_NOTE,
|
|
8815
|
+
options: TARGET_OPTIONS,
|
|
8816
|
+
inputSchema: {
|
|
8817
|
+
type: "object",
|
|
8818
|
+
properties: {
|
|
8819
|
+
...TARGET_INPUT_PROPERTIES,
|
|
8820
|
+
admin_password: {
|
|
8821
|
+
type: "string",
|
|
8822
|
+
secret: true,
|
|
8823
|
+
description: "Administrator password (secret; --input JSON or hidden prompt only)"
|
|
8824
|
+
}
|
|
8825
|
+
},
|
|
8826
|
+
required: TARGET_REQUIRED,
|
|
8827
|
+
additionalProperties: false
|
|
8828
|
+
},
|
|
8829
|
+
outputSchema: {
|
|
8830
|
+
...OBJECT_OUTPUT,
|
|
8831
|
+
properties: {
|
|
8832
|
+
root: { type: "string" },
|
|
8833
|
+
state: { type: "string", enum: ["configured"] },
|
|
8834
|
+
startup_required: { type: "boolean" }
|
|
8835
|
+
},
|
|
8836
|
+
required: ["root", "state", "startup_required"]
|
|
8837
|
+
},
|
|
8838
|
+
resultSchemaVersion: 1,
|
|
8839
|
+
access: { mode: "fixed", level: "privileged" },
|
|
8840
|
+
asyncMode: "sync",
|
|
8841
|
+
requiresSession: false,
|
|
8842
|
+
execution: "local",
|
|
8843
|
+
networkAccess: false,
|
|
8844
|
+
examples: [
|
|
8845
|
+
"buckyos provision activate --root /opt/buckyos --domain corp.example.com --owner-name admin --owner-key-backup /secure-backup/corp-owner.pem",
|
|
8846
|
+
"buckyos --non-interactive --yes --input activation.json provision activate --root /opt/buckyos --owner-key-backup /secure-backup/corp-owner.pem"
|
|
8847
|
+
],
|
|
8848
|
+
handler: async (ctx, input) => {
|
|
8849
|
+
const options = activationOptions(ctx, input);
|
|
8850
|
+
const backupDirectory = getHost().path.dirname(options.ownerKeyBackupPath);
|
|
8851
|
+
await assertHostAccess(options.rootDir, "read");
|
|
8852
|
+
await assertHostAccess(options.rootDir, "write");
|
|
8853
|
+
await assertHostAccess(backupDirectory, "read");
|
|
8854
|
+
await assertHostAccess(backupDirectory, "write");
|
|
8855
|
+
const precheck = await runSdk(() => deps.check(options));
|
|
8856
|
+
if (!precheck.ready)
|
|
8857
|
+
throw precheckError(precheck);
|
|
8858
|
+
const adminPassword = await obtainAdminPassword(ctx, input);
|
|
8859
|
+
await confirmActivation(ctx, precheck);
|
|
8860
|
+
const result = await runSdk(
|
|
8861
|
+
() => deps.activate({ ...options, adminPassword, traceId: ctx.traceId })
|
|
8862
|
+
);
|
|
8863
|
+
return resultView(ctx, input, result);
|
|
8864
|
+
}
|
|
8865
|
+
};
|
|
8866
|
+
}
|
|
8867
|
+
function activationOptions(ctx, input) {
|
|
8868
|
+
return {
|
|
8869
|
+
rootDir: resolvePath(ctx, requiredString(input, "root")),
|
|
8870
|
+
domain: requiredString(input, "domain"),
|
|
8871
|
+
ownerName: requiredString(input, "owner_name"),
|
|
8872
|
+
ownerKeyBackupPath: resolvePath(ctx, requiredString(input, "owner_key_backup")),
|
|
8873
|
+
publicIp: optionalString(input, "public_ip"),
|
|
8874
|
+
rtcpPort: typeof input.rtcp_port === "number" ? input.rtcp_port : void 0,
|
|
8875
|
+
guestAccess: input.guest_access === true
|
|
8876
|
+
};
|
|
8877
|
+
}
|
|
8878
|
+
function requiredString(input, key) {
|
|
8879
|
+
const value = optionalString(input, key);
|
|
8880
|
+
if (!value)
|
|
8881
|
+
throw new UsageError("INVALID_ARGUMENT", `${key} is required`);
|
|
8882
|
+
return value;
|
|
8883
|
+
}
|
|
8884
|
+
function optionalString(input, key) {
|
|
8885
|
+
const value = input[key];
|
|
8886
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
8887
|
+
}
|
|
8888
|
+
function resolvePath(ctx, value) {
|
|
8889
|
+
const path = getHost().path;
|
|
8890
|
+
return path.isAbsolute(value) ? path.resolve(value) : path.resolve(ctx.cwd, value);
|
|
8891
|
+
}
|
|
8892
|
+
async function assertHostAccess(path, operation) {
|
|
8893
|
+
try {
|
|
8894
|
+
await getHost().assertAccess(path, operation);
|
|
8895
|
+
} catch (error) {
|
|
8896
|
+
if (isHostError(error, "PermissionDenied")) {
|
|
8897
|
+
throw new ToolError(
|
|
8898
|
+
"HOST_ACCESS_DENIED",
|
|
8899
|
+
`${error.message}; pass the path on the command line (--root / --owner-key-backup) so the launcher can grant it`,
|
|
8900
|
+
EXIT_PERMISSION,
|
|
8901
|
+
false,
|
|
8902
|
+
{ path, operation }
|
|
8903
|
+
);
|
|
8904
|
+
}
|
|
8905
|
+
throw error;
|
|
8906
|
+
}
|
|
8907
|
+
}
|
|
8908
|
+
async function obtainAdminPassword(ctx, input) {
|
|
8909
|
+
if (typeof input.admin_password === "string")
|
|
8910
|
+
return input.admin_password;
|
|
8911
|
+
if (ctx.config.nonInteractive) {
|
|
8912
|
+
throw new UsageError(
|
|
8913
|
+
"SECRET_REQUIRED",
|
|
8914
|
+
"admin_password must be provided through --input JSON in non-interactive mode"
|
|
8915
|
+
);
|
|
8916
|
+
}
|
|
8917
|
+
if (!ctx.io.inputIsTerminal) {
|
|
8918
|
+
throw new UsageError(
|
|
8919
|
+
"SECRET_INPUT_UNAVAILABLE",
|
|
8920
|
+
"the administrator password requires an interactive terminal or --input JSON"
|
|
8921
|
+
);
|
|
8922
|
+
}
|
|
8923
|
+
const host2 = getHost();
|
|
8924
|
+
let password;
|
|
8925
|
+
let confirmation;
|
|
8926
|
+
try {
|
|
8927
|
+
password = await host2.readSecret("Administrator password: ");
|
|
8928
|
+
confirmation = await host2.readSecret("Confirm administrator password: ");
|
|
8929
|
+
} catch (error) {
|
|
8930
|
+
if (isHostError(error, "PermissionDenied")) {
|
|
8931
|
+
throw new UsageError("SECRET_INPUT_UNAVAILABLE", error.message);
|
|
8932
|
+
}
|
|
8933
|
+
throw error;
|
|
8934
|
+
}
|
|
8935
|
+
if (password !== confirmation) {
|
|
8936
|
+
throw new UsageError("PASSWORD_MISMATCH", "the administrator passwords do not match");
|
|
8937
|
+
}
|
|
8938
|
+
return password;
|
|
8939
|
+
}
|
|
8940
|
+
async function confirmActivation(ctx, precheck) {
|
|
8941
|
+
if (ctx.confirmed)
|
|
8942
|
+
return;
|
|
8943
|
+
if (ctx.config.nonInteractive) {
|
|
8944
|
+
throw new ToolError(
|
|
8945
|
+
"CONFIRMATION_REQUIRED",
|
|
8946
|
+
"provision activate requires --yes in non-interactive mode",
|
|
8947
|
+
EXIT_PERMISSION
|
|
8948
|
+
);
|
|
8949
|
+
}
|
|
8950
|
+
if (!ctx.io.inputIsTerminal) {
|
|
8951
|
+
throw new ToolError(
|
|
8952
|
+
"CONFIRMATION_REQUIRED",
|
|
8953
|
+
"provision activate requires an interactive terminal or --yes",
|
|
8954
|
+
EXIT_PERMISSION
|
|
8955
|
+
);
|
|
8956
|
+
}
|
|
8957
|
+
await ctx.io.stderr(
|
|
8958
|
+
[
|
|
8959
|
+
"Activation summary",
|
|
8960
|
+
` BUCKYOS_ROOT : ${precheck.rootDir}`,
|
|
8961
|
+
` Owner/Zone : ${precheck.zoneDid}`,
|
|
8962
|
+
` Device : ${precheck.deviceDid}`,
|
|
8963
|
+
` Admin : ${precheck.ownerName}`,
|
|
8964
|
+
` Network : ${"wan"} (no SN, no BNS)`,
|
|
8965
|
+
` RTCP port : ${precheck.rtcpPort}`,
|
|
8966
|
+
` Guest access : ${precheck.guestAccess}`,
|
|
8967
|
+
` Owner backup : ${precheck.ownerKeyBackup.path}`,
|
|
8968
|
+
""
|
|
8969
|
+
].join("\n")
|
|
8970
|
+
);
|
|
8971
|
+
const answer = (await ctx.io.prompt("Write this activation to disk? [y/N] "))?.trim().toLowerCase();
|
|
8972
|
+
if (answer !== "y" && answer !== "yes") {
|
|
8973
|
+
throw new ToolError("CONFIRMATION_DECLINED", "activation was declined", EXIT_PERMISSION);
|
|
8974
|
+
}
|
|
8975
|
+
}
|
|
8976
|
+
function isSdkError(error) {
|
|
8977
|
+
return error instanceof Error && error.name === "ActivationError" && typeof error.code === "string";
|
|
8978
|
+
}
|
|
8979
|
+
async function runSdk(run) {
|
|
8980
|
+
try {
|
|
8981
|
+
return await run();
|
|
8982
|
+
} catch (error) {
|
|
8983
|
+
if (isSdkError(error)) {
|
|
8984
|
+
const exitCode = error.code === "INVALID_ARGUMENT" ? EXIT_USAGE : error.code === "ACTIVATION_COMMIT_FAILED" ? EXIT_PARTIAL : EXIT_OPERATION;
|
|
8985
|
+
throw new ToolError(error.code, error.message, exitCode, false, error.details ?? {});
|
|
8986
|
+
}
|
|
8987
|
+
throw error;
|
|
8988
|
+
}
|
|
8989
|
+
}
|
|
8990
|
+
function precheckError(precheck) {
|
|
8991
|
+
const [first] = precheck.problems;
|
|
8992
|
+
const single = precheck.problems.length === 1;
|
|
8993
|
+
return new ToolError(
|
|
8994
|
+
single ? first.code : "ACTIVATION_PRECHECK_FAILED",
|
|
8995
|
+
single ? first.message : `activation precheck failed: ${precheck.problems.map((p) => p.message).join("; ")}`,
|
|
8996
|
+
EXIT_OPERATION,
|
|
8997
|
+
false,
|
|
8998
|
+
precheckView(precheck)
|
|
8999
|
+
);
|
|
9000
|
+
}
|
|
9001
|
+
function statusView(status) {
|
|
9002
|
+
return {
|
|
9003
|
+
root: status.rootDir,
|
|
9004
|
+
state: status.state,
|
|
9005
|
+
startup_required: status.startupRequired,
|
|
9006
|
+
observed_at: status.observedAt,
|
|
9007
|
+
zone_did: status.zoneDid,
|
|
9008
|
+
owner_did: status.ownerDid,
|
|
9009
|
+
device_did: status.deviceDid,
|
|
9010
|
+
device_name: status.deviceName,
|
|
9011
|
+
access_hostname: status.accessHostname,
|
|
9012
|
+
files: status.files.map((file) => ({
|
|
9013
|
+
path: file.path,
|
|
9014
|
+
role: file.role,
|
|
9015
|
+
required: file.required,
|
|
9016
|
+
secret: file.secret,
|
|
9017
|
+
present: file.present
|
|
9018
|
+
})),
|
|
9019
|
+
problems: status.problems,
|
|
9020
|
+
warnings: status.warnings,
|
|
9021
|
+
lock: status.lock ? {
|
|
9022
|
+
path: status.lock.path,
|
|
9023
|
+
stage: status.lock.stage,
|
|
9024
|
+
trace_id: status.lock.traceId,
|
|
9025
|
+
started_at: status.lock.startedAt,
|
|
9026
|
+
domain: status.lock.domain,
|
|
9027
|
+
committed_files: status.lock.committedFiles,
|
|
9028
|
+
owner_key_backup: status.lock.ownerKeyBackupPath,
|
|
9029
|
+
corrupt: status.lock.corrupt
|
|
9030
|
+
} : null
|
|
9031
|
+
};
|
|
9032
|
+
}
|
|
9033
|
+
function precheckView(precheck) {
|
|
9034
|
+
return {
|
|
9035
|
+
ready: precheck.ready,
|
|
9036
|
+
root: precheck.rootDir,
|
|
9037
|
+
state: precheck.state,
|
|
9038
|
+
domain: precheck.domain,
|
|
9039
|
+
owner_name: precheck.ownerName,
|
|
9040
|
+
owner_did: precheck.ownerDid,
|
|
9041
|
+
zone_did: precheck.zoneDid,
|
|
9042
|
+
device_did: precheck.deviceDid,
|
|
9043
|
+
device_name: precheck.deviceName,
|
|
9044
|
+
access_hostname: precheck.accessHostname,
|
|
9045
|
+
rtcp_port: precheck.rtcpPort,
|
|
9046
|
+
guest_access: precheck.guestAccess,
|
|
9047
|
+
public_ip: precheck.publicIp,
|
|
9048
|
+
dns_records: precheck.dnsRecords,
|
|
9049
|
+
owner_key_backup: {
|
|
9050
|
+
path: precheck.ownerKeyBackup.path,
|
|
9051
|
+
directory_exists: precheck.ownerKeyBackup.directoryExists,
|
|
9052
|
+
exists: precheck.ownerKeyBackup.exists
|
|
9053
|
+
},
|
|
9054
|
+
planned_files: precheck.plannedFiles,
|
|
9055
|
+
problems: precheck.problems,
|
|
9056
|
+
target: statusView(precheck.status)
|
|
9057
|
+
};
|
|
9058
|
+
}
|
|
9059
|
+
function resultView(ctx, input, result) {
|
|
9060
|
+
const dnsNotes = [
|
|
9061
|
+
...result.dnsRecords.map((record) => `${record.type} ${record.name} ${record.value}`),
|
|
9062
|
+
...result.publicIp ? [] : [`A/AAAA ${result.domain} <this node's fixed public IP>`],
|
|
9063
|
+
`The address record is also saved in etc/zone_dns_records.json under ${result.rootDir}.`,
|
|
9064
|
+
`Local boot uses etc/${result.domain}.zone.json; no DNS BOOT/PKX/DEV records are required.`,
|
|
9065
|
+
"TLS/ACME is not provided by SN in this mode; configure it on the public gateway."
|
|
9066
|
+
];
|
|
9067
|
+
return {
|
|
9068
|
+
root: result.rootDir,
|
|
9069
|
+
state: result.state,
|
|
9070
|
+
startup_required: result.startupRequired,
|
|
9071
|
+
domain: result.domain,
|
|
9072
|
+
owner_name: result.ownerName,
|
|
9073
|
+
owner_did: result.ownerDid,
|
|
9074
|
+
zone_did: result.zoneDid,
|
|
9075
|
+
device_did: result.deviceDid,
|
|
9076
|
+
device_name: result.deviceName,
|
|
9077
|
+
access_hostname: result.accessHostname,
|
|
9078
|
+
rtcp_port: result.rtcpPort,
|
|
9079
|
+
guest_access: result.guestAccess,
|
|
9080
|
+
public_ip: result.publicIp,
|
|
9081
|
+
document_iat: result.documentIat,
|
|
9082
|
+
document_exp: result.documentExp,
|
|
9083
|
+
owner_key_backup: result.ownerKeyBackup,
|
|
9084
|
+
dns_records: result.dnsRecords,
|
|
9085
|
+
dns_notes: dnsNotes,
|
|
9086
|
+
committed_files: result.committedFiles,
|
|
9087
|
+
warnings: result.warnings,
|
|
9088
|
+
next_steps: [
|
|
9089
|
+
"Restart BuckyOS through the installer or the node control entry to leave activation mode and boot the new Zone.",
|
|
9090
|
+
"Check the running Zone afterwards with system status; activation does not verify service health, DNS, or TLS.",
|
|
9091
|
+
`Keep the Owner private-key backup ${result.ownerKeyBackup.path} offline; it is the only recovery copy.`
|
|
9092
|
+
],
|
|
9093
|
+
audit: {
|
|
9094
|
+
module: ctx.command.module,
|
|
9095
|
+
verb: ctx.command.verb,
|
|
9096
|
+
trace_id: ctx.traceId,
|
|
9097
|
+
tool_version: TOOL_VERSION,
|
|
9098
|
+
input_fingerprint: inputFingerprint(input)
|
|
9099
|
+
}
|
|
9100
|
+
};
|
|
9101
|
+
}
|
|
9102
|
+
function inputFingerprint(input) {
|
|
9103
|
+
const material = {};
|
|
9104
|
+
for (const key of Object.keys(TARGET_INPUT_PROPERTIES).sort()) {
|
|
9105
|
+
if (input[key] !== void 0)
|
|
9106
|
+
material[key] = input[key];
|
|
9107
|
+
}
|
|
9108
|
+
const hash = getHost().createHash("sha256");
|
|
9109
|
+
hash.update(new TextEncoder().encode(JSON.stringify(material)));
|
|
9110
|
+
return hash.digestHex();
|
|
9111
|
+
}
|
|
8528
9112
|
const VERSION = TOOL_VERSION;
|
|
8529
9113
|
class BuckyOSToolApplication {
|
|
8530
9114
|
#environment;
|
|
@@ -8541,7 +9125,8 @@ class BuckyOSToolApplication {
|
|
|
8541
9125
|
dependencies.pikg,
|
|
8542
9126
|
dependencies.app,
|
|
8543
9127
|
dependencies.log,
|
|
8544
|
-
dependencies.diagnostic
|
|
9128
|
+
dependencies.diagnostic,
|
|
9129
|
+
dependencies.provision
|
|
8545
9130
|
);
|
|
8546
9131
|
this.#environment = dependencies.environment ?? readEnvironment();
|
|
8547
9132
|
this.#cwd = dependencies.cwd ?? getHost().cwd();
|
|
@@ -8627,6 +9212,8 @@ class BuckyOSToolApplication {
|
|
|
8627
9212
|
`);
|
|
8628
9213
|
return EXIT_SUCCESS;
|
|
8629
9214
|
}
|
|
9215
|
+
if (command.execution === "local")
|
|
9216
|
+
assertNoSessionOptions(invocation.global, command);
|
|
8630
9217
|
const setup = await this.#resolveForCommand(command, invocation.global);
|
|
8631
9218
|
const inputObject = invocation.global.input ? await this.#readInputObject(invocation.global.input) : void 0;
|
|
8632
9219
|
const parsed = parseCommandArgs(command, invocation.actionArgv, inputObject);
|
|
@@ -8872,7 +9459,7 @@ class BuckyOSToolApplication {
|
|
|
8872
9459
|
return parsed;
|
|
8873
9460
|
}
|
|
8874
9461
|
}
|
|
8875
|
-
function createRegistry(pikgDependencies, appDependencies, logDependencies, diagnosticDependencies) {
|
|
9462
|
+
function createRegistry(pikgDependencies, appDependencies, logDependencies, diagnosticDependencies, provisionDependencies) {
|
|
8876
9463
|
const registry = new CommandRegistry();
|
|
8877
9464
|
for (const module of createCoreModules(registry))
|
|
8878
9465
|
registry.register(module);
|
|
@@ -8884,8 +9471,26 @@ function createRegistry(pikgDependencies, appDependencies, logDependencies, diag
|
|
|
8884
9471
|
registry.register(createTaskModule());
|
|
8885
9472
|
registry.register(createLogModule(logDependencies));
|
|
8886
9473
|
registry.register(createDiagnosticModule(diagnosticDependencies));
|
|
9474
|
+
registry.register(createProvisionModule(provisionDependencies));
|
|
8887
9475
|
return registry;
|
|
8888
9476
|
}
|
|
9477
|
+
function assertNoSessionOptions(global, command) {
|
|
9478
|
+
for (const [name, value] of [
|
|
9479
|
+
["profile", global.profile],
|
|
9480
|
+
["zone", global.zone],
|
|
9481
|
+
["endpoint", global.endpoint],
|
|
9482
|
+
["identity", global.identity],
|
|
9483
|
+
["session-token", global.sessionToken],
|
|
9484
|
+
["session-token-file", global.sessionTokenFile]
|
|
9485
|
+
]) {
|
|
9486
|
+
if (value !== void 0) {
|
|
9487
|
+
throw new UsageError(
|
|
9488
|
+
"ARGUMENT_CONFLICT",
|
|
9489
|
+
`--${name} cannot be combined with the local command ${command.module} ${command.verb}`
|
|
9490
|
+
);
|
|
9491
|
+
}
|
|
9492
|
+
}
|
|
9493
|
+
}
|
|
8889
9494
|
const unavailableClients = {
|
|
8890
9495
|
call: () => Promise.reject(new ToolError("INTERNAL_ERROR", "service clients are unavailable", 9))
|
|
8891
9496
|
};
|
|
@@ -9153,6 +9758,9 @@ class NodeHost {
|
|
|
9153
9758
|
throw translateNodeError(error, path);
|
|
9154
9759
|
}
|
|
9155
9760
|
}
|
|
9761
|
+
async assertAccess(path, operation) {
|
|
9762
|
+
await this.assertPath(path, operation);
|
|
9763
|
+
}
|
|
9156
9764
|
createHash(_algorithm) {
|
|
9157
9765
|
const hash = createHash("sha256");
|
|
9158
9766
|
return {
|