@tinycloud/cli 1.5.0-beta.12 → 1.5.0-beta.13
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/README.md +58 -0
- package/dist/legacy-entry.js +270 -58
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +1 -1
- package/skills/tc-cli/REFERENCE.md +22 -1
package/README.md
CHANGED
|
@@ -87,6 +87,7 @@ tc kv list
|
|
|
87
87
|
tc secrets network init
|
|
88
88
|
printf '%s' "$ANTHROPIC_API_KEY" | tc secrets put ANTHROPIC_API_KEY --stdin
|
|
89
89
|
tc secrets get ANTHROPIC_API_KEY
|
|
90
|
+
tc secrets run ANTHROPIC_API_KEY -- python train.py # the value only in the command's environment
|
|
90
91
|
|
|
91
92
|
# Ask the owner for a secret an agent needs, then wait for it
|
|
92
93
|
# (call TinyCloud's CLI by absolute path: a bare `tc` can be iproute2's /usr/sbin/tc)
|
|
@@ -138,6 +139,7 @@ tc delegation create --to did:pkh:eip155:1:0x...
|
|
|
138
139
|
| `tc secrets network show` | Show a secrets decryption network |
|
|
139
140
|
| `tc secrets network init` | Create or fetch the default secrets network |
|
|
140
141
|
| `tc secrets network grant` | Grant `tinycloud.encryption/decrypt` on a secrets network |
|
|
142
|
+
| `tc secrets run` | Run a command with secrets in its environment |
|
|
141
143
|
| `tc secrets request` | Print a Secret Manager link asking the owner to add secrets (offline) |
|
|
142
144
|
| `tc secrets wait` | Wait until secrets exist and are readable (never signs in; needs a stored session; exit 8 pending, 130 interrupted) |
|
|
143
145
|
| `tc secrets manage` | Print or open the Secret Manager page, `{url, opened}` |
|
|
@@ -159,6 +161,62 @@ still exits 0 and installs the rest. If the schema fails after notes were
|
|
|
159
161
|
written, it says "notes saved; tables not set up: run again"; running it again
|
|
160
162
|
is safe.
|
|
161
163
|
|
|
164
|
+
### Running a command with secrets
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
tc secrets run NAME... [--map NAME=ENV_VAR]... [--scope S] [--space S] [--delegation SOURCE] [--private-key HEX] -- <command> [args...]
|
|
168
|
+
|
|
169
|
+
tc secrets run ANTHROPIC_API_KEY OPENAI_API_KEY -- python train.py
|
|
170
|
+
tc secrets run --map ANTHROPIC_KEY=ANTHROPIC_API_KEY -- node server.js
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`tc secrets run` reads every named secret as `tc secrets get` does, then
|
|
174
|
+
starts `<command>` directly, without a shell, with each value in its
|
|
175
|
+
environment: under the secret's name, or under `ENV_VAR` for `--map
|
|
176
|
+
NAME=ENV_VAR`. A value replaces an inherited variable of the same name.
|
|
177
|
+
tc doesn't pass its own `TC_PRIVATE_KEY` to the command. To give the command
|
|
178
|
+
a key from a secret, use `--map NAME=TC_PRIVATE_KEY`.
|
|
179
|
+
Everything after the first `--`, including any further `--`, goes to the
|
|
180
|
+
command unchanged. The command uses tc's stdin, stdout and stderr; tc itself
|
|
181
|
+
writes nothing to stdout, and its own messages go to stderr.
|
|
182
|
+
|
|
183
|
+
Name at least one secret, as an argument or with `--map`. `ENV_VAR` must
|
|
184
|
+
match `[A-Za-z_][A-Za-z0-9_]*`, and two secrets cannot be mapped to the same
|
|
185
|
+
variable (exit 2). If any secret cannot be read, the command does not start
|
|
186
|
+
and tc exits with the code and error `tc secrets get` gives for that secret.
|
|
187
|
+
Otherwise tc exits with the command's exit code. If the command was ended by
|
|
188
|
+
SIGINT, SIGTERM, SIGHUP, SIGKILL, SIGALRM or SIGUSR2, tc ends by the same
|
|
189
|
+
signal (or exits with 128 plus the signal number if that signal doesn't end
|
|
190
|
+
tc). If any other signal ended it, such as SIGQUIT or SIGSEGV, tc exits with
|
|
191
|
+
128 plus the signal number instead, so tc does not cause a core dump
|
|
192
|
+
(SIGUSR1 and SIGPIPE are left out too: Node uses SIGUSR1 for its inspector
|
|
193
|
+
and ignores SIGPIPE).
|
|
194
|
+
|
|
195
|
+
SIGINT, SIGTERM, SIGHUP and SIGQUIT sent to tc go to the command. When tc
|
|
196
|
+
runs in the foreground of a terminal, it doesn't pass on SIGINT, SIGQUIT or
|
|
197
|
+
SIGHUP: the terminal already sends them (Ctrl-C, Ctrl-\, hangup) to the
|
|
198
|
+
command, so the command normally gets each one once. tc checks whether it's
|
|
199
|
+
in the foreground using `/proc`, or `ps` where `/proc` isn't available. If
|
|
200
|
+
neither works, it passes the signals on. When tc runs in the background, it
|
|
201
|
+
passes them on, so a signal sent to the whole job (for example `kill -INT
|
|
202
|
+
%1`) can reach the command twice.
|
|
203
|
+
|
|
204
|
+
From a script, stop the command by sending SIGTERM to tc's process ID. tc
|
|
205
|
+
passes it on, waits for the command to exit, then exits the way the command
|
|
206
|
+
did (the command's own exit code if it handles SIGTERM itself). If the
|
|
207
|
+
command ignores SIGTERM, tc keeps waiting.
|
|
208
|
+
|
|
209
|
+
A command that does not exist exits 127; one that cannot be executed, or
|
|
210
|
+
cannot be started for another reason, exits 126. These cases print one plain
|
|
211
|
+
line on stderr, even with `--json`: `tc secrets run: <command>: command not
|
|
212
|
+
found`, `…: permission denied` or `…: cannot run (<error code>)`.
|
|
213
|
+
|
|
214
|
+
Limits: `tc secrets run` keeps values out of the command line, your shell
|
|
215
|
+
history and tc's own output. It doesn't hide them from the command: the
|
|
216
|
+
command, and anything it starts, receives the values and can print, log or
|
|
217
|
+
pass them on. Other programs running as the same user can often read a
|
|
218
|
+
process's environment too.
|
|
219
|
+
|
|
162
220
|
## Global Options
|
|
163
221
|
|
|
164
222
|
```
|
package/dist/legacy-entry.js
CHANGED
|
@@ -39188,7 +39188,7 @@ init_constants();
|
|
|
39188
39188
|
import { CLI_NAME as CLI_NAME32 } from "@tinycloud/operations/cli-name";
|
|
39189
39189
|
import { readFile as readFile14 } from "fs/promises";
|
|
39190
39190
|
import { join as join17 } from "path";
|
|
39191
|
-
import { homedir, hostname, userInfo } from "os";
|
|
39191
|
+
import { constants as osConstants, homedir, hostname, userInfo } from "os";
|
|
39192
39192
|
import { appSecretScope } from "@tinycloud/sdk-core";
|
|
39193
39193
|
import { invokeOperation as invokeOperation3 } from "@tinycloud/operations";
|
|
39194
39194
|
import { isLocalOwnerProfile as isLocalOwnerProfile4, ownerSessionLacksProof as ownerSessionLacksProof5 } from "@tinycloud/operations/profile";
|
|
@@ -39209,6 +39209,7 @@ import {
|
|
|
39209
39209
|
} from "@tinycloud/operations/secret-capabilities";
|
|
39210
39210
|
import { invokeSecretsGetWithLocalAuthorityRetry } from "@tinycloud/operations/cli-runtime";
|
|
39211
39211
|
init_sdk();
|
|
39212
|
+
init_replication_registry();
|
|
39212
39213
|
init_session_expired();
|
|
39213
39214
|
init_space();
|
|
39214
39215
|
|
|
@@ -39274,14 +39275,14 @@ function runProbeChild(request, options = {}) {
|
|
|
39274
39275
|
const args = options.argv ?? probeChildArgv(request);
|
|
39275
39276
|
const budgetMs = options.budgetMs ?? ATTEMPT_BUDGET_MS;
|
|
39276
39277
|
const killGraceMs = options.killGraceMs ?? KILL_GRACE_MS;
|
|
39277
|
-
const
|
|
39278
|
+
const spawn3 = options.spawn ?? nodeSpawn;
|
|
39278
39279
|
const signal = options.signal;
|
|
39279
39280
|
return new Promise((resolve9) => {
|
|
39280
39281
|
if (signal?.aborted) {
|
|
39281
39282
|
resolve9({ kind: "cancelled" });
|
|
39282
39283
|
return;
|
|
39283
39284
|
}
|
|
39284
|
-
const child =
|
|
39285
|
+
const child = spawn3(command, args, { env: process.env, stdio: ["ignore", "pipe", "pipe"] });
|
|
39285
39286
|
let outcome;
|
|
39286
39287
|
let stdout = Buffer.alloc(0);
|
|
39287
39288
|
let stderr = Buffer.alloc(0);
|
|
@@ -39393,6 +39394,75 @@ function parseStatusEnvelope(line) {
|
|
|
39393
39394
|
return void 0;
|
|
39394
39395
|
}
|
|
39395
39396
|
|
|
39397
|
+
// src/lib/run-command.ts
|
|
39398
|
+
import { execFileSync, spawn as spawn2 } from "child_process";
|
|
39399
|
+
import { existsSync, readFileSync as readFileSync2 } from "fs";
|
|
39400
|
+
var FORWARDED_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP", "SIGQUIT"];
|
|
39401
|
+
var TERMINAL_SIGNALS = { SIGINT: true, SIGQUIT: true, SIGHUP: true };
|
|
39402
|
+
function psGroupArgs(pid) {
|
|
39403
|
+
return ["-o", "pgid=", "-o", "tpgid=", "-p", String(pid)];
|
|
39404
|
+
}
|
|
39405
|
+
function parsePsGroups(output2) {
|
|
39406
|
+
const columns = output2.trim().split(/\s+/);
|
|
39407
|
+
if (columns.length !== 2) return void 0;
|
|
39408
|
+
const group = Number(columns[0]);
|
|
39409
|
+
const foreground = Number(columns[1]);
|
|
39410
|
+
return Number.isSafeInteger(group) && Number.isSafeInteger(foreground) ? { group, foreground } : void 0;
|
|
39411
|
+
}
|
|
39412
|
+
function processGroups() {
|
|
39413
|
+
try {
|
|
39414
|
+
const stat8 = readFileSync2("/proc/self/stat", "utf8");
|
|
39415
|
+
const fields = stat8.slice(stat8.lastIndexOf(")") + 2).split(" ");
|
|
39416
|
+
return { group: Number(fields[2]), foreground: Number(fields[5]) };
|
|
39417
|
+
} catch {
|
|
39418
|
+
}
|
|
39419
|
+
try {
|
|
39420
|
+
const ps = existsSync("/bin/ps") ? "/bin/ps" : "/usr/bin/ps";
|
|
39421
|
+
return parsePsGroups(execFileSync(ps, psGroupArgs(process.pid), {
|
|
39422
|
+
env: {},
|
|
39423
|
+
encoding: "utf8",
|
|
39424
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
39425
|
+
timeout: 2e3
|
|
39426
|
+
}));
|
|
39427
|
+
} catch {
|
|
39428
|
+
return void 0;
|
|
39429
|
+
}
|
|
39430
|
+
}
|
|
39431
|
+
function inTerminalForeground() {
|
|
39432
|
+
const groups = processGroups();
|
|
39433
|
+
return groups !== void 0 && groups.foreground > 0 && groups.group === groups.foreground;
|
|
39434
|
+
}
|
|
39435
|
+
function runCommand(argv, env) {
|
|
39436
|
+
return new Promise((resolve9) => {
|
|
39437
|
+
let child;
|
|
39438
|
+
try {
|
|
39439
|
+
child = spawn2(argv[0], argv.slice(1), { stdio: "inherit", env, shell: false });
|
|
39440
|
+
} catch (error) {
|
|
39441
|
+
const code5 = error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
39442
|
+
resolve9({ kind: "not_started", ...code5 === void 0 ? {} : { errno: code5 } });
|
|
39443
|
+
return;
|
|
39444
|
+
}
|
|
39445
|
+
const forward = (signal) => {
|
|
39446
|
+
if (TERMINAL_SIGNALS[signal] && inTerminalForeground()) return;
|
|
39447
|
+
child.kill(signal);
|
|
39448
|
+
};
|
|
39449
|
+
for (const signal of FORWARDED_SIGNALS) process.on(signal, forward);
|
|
39450
|
+
const settle = (outcome) => {
|
|
39451
|
+
for (const signal of FORWARDED_SIGNALS) process.off(signal, forward);
|
|
39452
|
+
resolve9(outcome);
|
|
39453
|
+
};
|
|
39454
|
+
child.on("error", (error) => {
|
|
39455
|
+
if (child.pid === void 0) settle({ kind: "not_started", ...error.code === void 0 ? {} : { errno: error.code } });
|
|
39456
|
+
});
|
|
39457
|
+
child.once("exit", (code5, signal) => {
|
|
39458
|
+
settle(signal !== null ? { kind: "signaled", signal } : { kind: "exited", code: code5 ?? 1 });
|
|
39459
|
+
});
|
|
39460
|
+
});
|
|
39461
|
+
}
|
|
39462
|
+
|
|
39463
|
+
// src/commands/secrets.ts
|
|
39464
|
+
init_safe_text();
|
|
39465
|
+
|
|
39396
39466
|
// src/lib/secrets-wait.ts
|
|
39397
39467
|
init_constants();
|
|
39398
39468
|
init_errors();
|
|
@@ -40347,6 +40417,153 @@ function outputSecretDoctor(result) {
|
|
|
40347
40417
|
process.stdout.write(theme.warn(`${failed} secrets check${failed > 1 ? "s" : ""} need attention.`) + "\n");
|
|
40348
40418
|
}
|
|
40349
40419
|
}
|
|
40420
|
+
async function resolveSecretReadTarget(ctx, name, options) {
|
|
40421
|
+
const scopeOptions = resolveSecretScope(options);
|
|
40422
|
+
const legacySpaceUri = await resolveSecretSpace(options.space, ctx.profile);
|
|
40423
|
+
const resolved = resolveSecretPath2(name, scopeOptions);
|
|
40424
|
+
return { name, scopeOptions, scope: resolved.scope, legacySpaceUri, secretPath: resolved.permissionPaths.vault };
|
|
40425
|
+
}
|
|
40426
|
+
async function readSecret(params) {
|
|
40427
|
+
const { ctx, target, options } = params;
|
|
40428
|
+
const { name } = target;
|
|
40429
|
+
if (options.delegation) {
|
|
40430
|
+
const delegated = await resolveDelegatedSecretSource(
|
|
40431
|
+
options.delegation,
|
|
40432
|
+
target.secretPath,
|
|
40433
|
+
target.legacySpaceUri ?? SECRETS_SPACE2
|
|
40434
|
+
);
|
|
40435
|
+
const effectiveHost = params.host ?? delegated.delegation.host ?? ctx.host;
|
|
40436
|
+
const delegatedCtx = { ...ctx, host: effectiveHost };
|
|
40437
|
+
const local = effectiveLocal(await ProfileManager.getProfile(ctx.profile).catch(() => null), options);
|
|
40438
|
+
const node = await ensureSecretsNode(delegatedCtx, options);
|
|
40439
|
+
const value = await withSpinner(
|
|
40440
|
+
`Getting secret ${name}...`,
|
|
40441
|
+
() => readDelegatedSecretValue({
|
|
40442
|
+
node,
|
|
40443
|
+
delegation: delegated.delegation,
|
|
40444
|
+
delegationCid: delegated.delegation.cid,
|
|
40445
|
+
permissions: delegated.permissions,
|
|
40446
|
+
secretPath: target.secretPath,
|
|
40447
|
+
space: target.legacySpaceUri ?? SECRETS_SPACE2,
|
|
40448
|
+
name,
|
|
40449
|
+
...target.scope === void 0 ? {} : { scope: target.scope },
|
|
40450
|
+
local
|
|
40451
|
+
})
|
|
40452
|
+
);
|
|
40453
|
+
return { value };
|
|
40454
|
+
}
|
|
40455
|
+
const privateKey = authOptions(options)?.privateKey;
|
|
40456
|
+
const spaceUri = privateKey !== void 0 && options.space !== void 0 && !options.space.startsWith("tinycloud:") ? options.space : target.legacySpaceUri;
|
|
40457
|
+
const result = await invokeCanonicalSecretGet({
|
|
40458
|
+
ctx,
|
|
40459
|
+
name,
|
|
40460
|
+
...target.scopeOptions?.scope === void 0 ? {} : { scope: target.scopeOptions.scope },
|
|
40461
|
+
...spaceUri === void 0 ? {} : { space: spaceUri },
|
|
40462
|
+
options,
|
|
40463
|
+
label: `Getting secret ${name}...`,
|
|
40464
|
+
openKeyAcquisition: params.openKeyAcquisition
|
|
40465
|
+
});
|
|
40466
|
+
if (result.status !== "ok") {
|
|
40467
|
+
try {
|
|
40468
|
+
throwCanonicalSecretGetError(result, name);
|
|
40469
|
+
} catch (error) {
|
|
40470
|
+
throw withOperationWarnings(error, result.warnings);
|
|
40471
|
+
}
|
|
40472
|
+
}
|
|
40473
|
+
return { value: result.output.value, warnings: result.warnings };
|
|
40474
|
+
}
|
|
40475
|
+
var ENV_VAR_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
40476
|
+
function argvAfterSeparator(cmd) {
|
|
40477
|
+
let root = cmd;
|
|
40478
|
+
while (root.parent) root = root.parent;
|
|
40479
|
+
const raw = "rawArgs" in root ? root.rawArgs : void 0;
|
|
40480
|
+
if (!Array.isArray(raw)) return void 0;
|
|
40481
|
+
const args = raw.map(String);
|
|
40482
|
+
const withValue = (flag) => root.options.some((option) => option.required && (option.long === flag || option.short === flag));
|
|
40483
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
40484
|
+
const arg = args[index];
|
|
40485
|
+
if (arg === "--") return args.slice(index + 1);
|
|
40486
|
+
if (arg.startsWith("--")) {
|
|
40487
|
+
if (withValue(arg)) index += 1;
|
|
40488
|
+
continue;
|
|
40489
|
+
}
|
|
40490
|
+
if (arg.length < 2 || !arg.startsWith("-")) continue;
|
|
40491
|
+
for (let char = 1; char < arg.length; char += 1) {
|
|
40492
|
+
const option = root.options.find((candidate) => candidate.short === `-${arg[char]}`);
|
|
40493
|
+
if (option === void 0) break;
|
|
40494
|
+
if (option.required) {
|
|
40495
|
+
if (char === arg.length - 1) index += 1;
|
|
40496
|
+
break;
|
|
40497
|
+
}
|
|
40498
|
+
}
|
|
40499
|
+
}
|
|
40500
|
+
return void 0;
|
|
40501
|
+
}
|
|
40502
|
+
function secretRunPlan(cmd, operands, maps) {
|
|
40503
|
+
const usage3 = `${CLI_NAME32} secrets run NAME... [--map NAME=ENV_VAR] -- <command> [args...]`;
|
|
40504
|
+
const after = argvAfterSeparator(cmd);
|
|
40505
|
+
if (after === void 0 || after.length > operands.length) {
|
|
40506
|
+
throw new CLIError("USAGE_ERROR", `Put the command after \`--\`: ${usage3}`, ExitCode.USAGE_ERROR);
|
|
40507
|
+
}
|
|
40508
|
+
const [program, ...args] = after;
|
|
40509
|
+
if (program === void 0) {
|
|
40510
|
+
throw new CLIError("USAGE_ERROR", `Add the command to run after \`--\`: ${usage3}`, ExitCode.USAGE_ERROR);
|
|
40511
|
+
}
|
|
40512
|
+
const exports = [];
|
|
40513
|
+
for (const name of operands.slice(0, operands.length - after.length)) {
|
|
40514
|
+
if (!ENV_VAR_RE.test(name)) {
|
|
40515
|
+
throw new CLIError(
|
|
40516
|
+
"USAGE_ERROR",
|
|
40517
|
+
`${JSON.stringify(name)} can't be used as an environment variable name. Use \`--map ${name}=ENV_VAR\` to choose one.`,
|
|
40518
|
+
ExitCode.USAGE_ERROR
|
|
40519
|
+
);
|
|
40520
|
+
}
|
|
40521
|
+
exports.push({ name, variable: name });
|
|
40522
|
+
}
|
|
40523
|
+
for (const map of maps) {
|
|
40524
|
+
const equals7 = map.indexOf("=");
|
|
40525
|
+
const variable = map.slice(equals7 + 1);
|
|
40526
|
+
if (equals7 <= 0 || !ENV_VAR_RE.test(variable)) {
|
|
40527
|
+
throw new CLIError(
|
|
40528
|
+
"USAGE_ERROR",
|
|
40529
|
+
`Invalid \`--map ${JSON.stringify(map)}\`: use NAME=ENV_VAR, where ENV_VAR starts with a letter or _ and uses only letters, digits and _.`,
|
|
40530
|
+
ExitCode.USAGE_ERROR
|
|
40531
|
+
);
|
|
40532
|
+
}
|
|
40533
|
+
exports.push({ name: map.slice(0, equals7), variable });
|
|
40534
|
+
}
|
|
40535
|
+
if (exports.length === 0) {
|
|
40536
|
+
throw new CLIError("USAGE_ERROR", `Name at least one secret: ${usage3}`, ExitCode.USAGE_ERROR);
|
|
40537
|
+
}
|
|
40538
|
+
const variables = /* @__PURE__ */ new Set();
|
|
40539
|
+
for (const { variable } of exports) {
|
|
40540
|
+
if (variables.has(variable)) {
|
|
40541
|
+
throw new CLIError("USAGE_ERROR", `Two secrets are mapped to ${variable}. Give each its own variable.`, ExitCode.USAGE_ERROR);
|
|
40542
|
+
}
|
|
40543
|
+
variables.add(variable);
|
|
40544
|
+
}
|
|
40545
|
+
return { command: [program, ...args], exports };
|
|
40546
|
+
}
|
|
40547
|
+
var RERAISED_SIGNALS = {
|
|
40548
|
+
SIGINT: true,
|
|
40549
|
+
SIGTERM: true,
|
|
40550
|
+
SIGHUP: true,
|
|
40551
|
+
SIGKILL: true,
|
|
40552
|
+
SIGALRM: true,
|
|
40553
|
+
SIGUSR2: true
|
|
40554
|
+
};
|
|
40555
|
+
var TC_CREDENTIAL_VARIABLES = ["TC_PRIVATE_KEY"];
|
|
40556
|
+
function exitAsCommand(outcome, program) {
|
|
40557
|
+
if (outcome.kind === "exited") return process.exit(outcome.code);
|
|
40558
|
+
if (outcome.kind === "signaled") {
|
|
40559
|
+
if (RERAISED_SIGNALS[outcome.signal]) process.kill(process.pid, outcome.signal);
|
|
40560
|
+
return process.exit(128 + (osConstants.signals[outcome.signal] ?? 0));
|
|
40561
|
+
}
|
|
40562
|
+
const reason = outcome.errno === "ENOENT" ? "command not found" : outcome.errno === "EACCES" ? "permission denied" : `cannot run (${outcome.errno ?? "unknown error"})`;
|
|
40563
|
+
process.stderr.write(`${CLI_NAME32} secrets run: ${safeInline(program)}: ${reason}
|
|
40564
|
+
`);
|
|
40565
|
+
return process.exit(outcome.errno === "ENOENT" ? 127 : 126);
|
|
40566
|
+
}
|
|
40350
40567
|
function registerSecretsCommand(program, openKeyAcquisition) {
|
|
40351
40568
|
const secrets = program.command("secrets").description("Encrypted secrets management");
|
|
40352
40569
|
const network = secrets.command("network").description("Manage the default secrets encryption network");
|
|
@@ -40514,66 +40731,23 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
40514
40731
|
try {
|
|
40515
40732
|
const globalOpts = cmd.optsWithGlobals();
|
|
40516
40733
|
const ctx = await ProfileManager.resolveContext(globalOpts);
|
|
40517
|
-
const
|
|
40518
|
-
const legacySpaceUri = await resolveSecretSpace(options.space, ctx.profile);
|
|
40519
|
-
const secretPath = resolveSecretPath2(name, scopeOptions).permissionPaths.vault;
|
|
40734
|
+
const target = await resolveSecretReadTarget(ctx, name, options);
|
|
40520
40735
|
if (options.output) await validatePrivateOutput(options.output, "Secret output");
|
|
40736
|
+
const secret = await readSecret({ ctx, host: globalOpts.host, target, options, openKeyAcquisition });
|
|
40737
|
+
const value = secret.value;
|
|
40521
40738
|
if (options.delegation) {
|
|
40522
|
-
const delegated = await resolveDelegatedSecretSource(
|
|
40523
|
-
options.delegation,
|
|
40524
|
-
secretPath,
|
|
40525
|
-
legacySpaceUri ?? SECRETS_SPACE2
|
|
40526
|
-
);
|
|
40527
|
-
const effectiveHost = globalOpts.host ?? delegated.delegation.host ?? ctx.host;
|
|
40528
|
-
const delegatedCtx = { ...ctx, host: effectiveHost };
|
|
40529
|
-
const local = effectiveLocal(await ProfileManager.getProfile(ctx.profile).catch(() => null), options);
|
|
40530
|
-
const scope = resolveSecretPath2(name, scopeOptions).scope;
|
|
40531
|
-
const node = await ensureSecretsNode(delegatedCtx, options);
|
|
40532
|
-
const value2 = await withSpinner(
|
|
40533
|
-
`Getting secret ${name}...`,
|
|
40534
|
-
() => readDelegatedSecretValue({
|
|
40535
|
-
node,
|
|
40536
|
-
delegation: delegated.delegation,
|
|
40537
|
-
delegationCid: delegated.delegation.cid,
|
|
40538
|
-
permissions: delegated.permissions,
|
|
40539
|
-
secretPath,
|
|
40540
|
-
space: legacySpaceUri ?? SECRETS_SPACE2,
|
|
40541
|
-
name,
|
|
40542
|
-
...scope === void 0 ? {} : { scope },
|
|
40543
|
-
local
|
|
40544
|
-
})
|
|
40545
|
-
);
|
|
40546
40739
|
if (options.output) {
|
|
40547
|
-
await writePrivateOutput(options.output,
|
|
40740
|
+
await writePrivateOutput(options.output, value, "Secret output");
|
|
40548
40741
|
outputJson({ name, written: options.output });
|
|
40549
40742
|
return;
|
|
40550
40743
|
}
|
|
40551
40744
|
if (options.raw) {
|
|
40552
|
-
process.stdout.write(
|
|
40745
|
+
process.stdout.write(value);
|
|
40553
40746
|
return;
|
|
40554
40747
|
}
|
|
40555
|
-
outputJson({ name, value
|
|
40748
|
+
outputJson({ name, value });
|
|
40556
40749
|
return;
|
|
40557
40750
|
}
|
|
40558
|
-
const privateKey = authOptions(options)?.privateKey;
|
|
40559
|
-
const spaceUri = privateKey !== void 0 && options.space !== void 0 && !options.space.startsWith("tinycloud:") ? options.space : legacySpaceUri;
|
|
40560
|
-
const result = await invokeCanonicalSecretGet({
|
|
40561
|
-
ctx,
|
|
40562
|
-
name,
|
|
40563
|
-
...scopeOptions?.scope === void 0 ? {} : { scope: scopeOptions.scope },
|
|
40564
|
-
...spaceUri === void 0 ? {} : { space: spaceUri },
|
|
40565
|
-
options,
|
|
40566
|
-
label: `Getting secret ${name}...`,
|
|
40567
|
-
openKeyAcquisition
|
|
40568
|
-
});
|
|
40569
|
-
if (result.status !== "ok") {
|
|
40570
|
-
try {
|
|
40571
|
-
throwCanonicalSecretGetError(result, name);
|
|
40572
|
-
} catch (error) {
|
|
40573
|
-
throw withOperationWarnings(error, result.warnings);
|
|
40574
|
-
}
|
|
40575
|
-
}
|
|
40576
|
-
const value = result.output.value;
|
|
40577
40751
|
try {
|
|
40578
40752
|
if (options.output) {
|
|
40579
40753
|
await writePrivateOutput(options.output, value, "Secret output");
|
|
@@ -40584,9 +40758,47 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
40584
40758
|
outputJson({ name, value });
|
|
40585
40759
|
}
|
|
40586
40760
|
} catch (error) {
|
|
40587
|
-
throw withOperationWarnings(error,
|
|
40761
|
+
throw withOperationWarnings(error, secret.warnings);
|
|
40588
40762
|
}
|
|
40589
|
-
outputWarnings(operationWarnings(
|
|
40763
|
+
outputWarnings(operationWarnings(secret.warnings));
|
|
40764
|
+
} catch (error) {
|
|
40765
|
+
return handleError(error);
|
|
40766
|
+
}
|
|
40767
|
+
});
|
|
40768
|
+
secrets.command("run [names...]").description("Run a command with secrets in its environment").usage("[options] [names...] -- <command> [args...]").option(
|
|
40769
|
+
"--map <NAME=ENV_VAR>",
|
|
40770
|
+
"Give secret NAME to the command as environment variable ENV_VAR (repeatable)",
|
|
40771
|
+
(value, previous) => [...previous ?? [], value]
|
|
40772
|
+
).option("--scope <scope>", "Logical secret scope").option("--space <name|uri>", "Target a non-default secrets space (short name or full URI)").option("--delegation <source>", "Delegation file path or imported profile name").option("--private-key <hex>", "Ethereum private key (or set TC_PRIVATE_KEY)").action(async (operands, options, cmd) => {
|
|
40773
|
+
try {
|
|
40774
|
+
const plan = secretRunPlan(cmd, operands, options.map ?? []);
|
|
40775
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
40776
|
+
const ctx = await ProfileManager.resolveContext(globalOpts);
|
|
40777
|
+
const targets = [];
|
|
40778
|
+
for (const name of new Set(plan.exports.map((entry) => entry.name))) {
|
|
40779
|
+
targets.push(await resolveSecretReadTarget(ctx, name, options));
|
|
40780
|
+
}
|
|
40781
|
+
const values = /* @__PURE__ */ new Map();
|
|
40782
|
+
let warnings = [];
|
|
40783
|
+
for (const target of targets) {
|
|
40784
|
+
const secret = await readSecret({ ctx, host: globalOpts.host, target, options, openKeyAcquisition });
|
|
40785
|
+
if (secret.value.includes("\0")) {
|
|
40786
|
+
throw new CLIError(
|
|
40787
|
+
"SECRET_NOT_EXPORTABLE",
|
|
40788
|
+
`Secret "${target.name}" contains a NUL character, so it can't be put in an environment variable. The command wasn't started.`,
|
|
40789
|
+
ExitCode.ERROR
|
|
40790
|
+
);
|
|
40791
|
+
}
|
|
40792
|
+
values.set(target.name, secret.value);
|
|
40793
|
+
warnings = mergeWarnings(warnings, secret.warnings ?? []);
|
|
40794
|
+
}
|
|
40795
|
+
outputWarnings(operationWarnings(warnings));
|
|
40796
|
+
await closeReplication();
|
|
40797
|
+
const env = { ...process.env };
|
|
40798
|
+
for (const variable of TC_CREDENTIAL_VARIABLES) delete env[variable];
|
|
40799
|
+
for (const entry of plan.exports) env[entry.variable] = values.get(entry.name);
|
|
40800
|
+
values.clear();
|
|
40801
|
+
exitAsCommand(await runCommand(plan.command, env), plan.command[0]);
|
|
40590
40802
|
} catch (error) {
|
|
40591
40803
|
return handleError(error);
|
|
40592
40804
|
}
|
|
@@ -41048,7 +41260,7 @@ async function writeShareOutput(directory, filename, bytes, force) {
|
|
|
41048
41260
|
init_profiles();
|
|
41049
41261
|
|
|
41050
41262
|
// src/share/html-folder.ts
|
|
41051
|
-
import { constants as constants2, existsSync } from "fs";
|
|
41263
|
+
import { constants as constants2, existsSync as existsSync2 } from "fs";
|
|
41052
41264
|
import { lstat as lstat11, open as open14, readdir as readdir7, realpath as realpath3, stat as stat7 } from "fs/promises";
|
|
41053
41265
|
import { basename as basename5, dirname as dirname9, isAbsolute, join as join19, relative as relativePath, resolve as resolve7, sep as sep4 } from "path";
|
|
41054
41266
|
|
|
@@ -41986,7 +42198,7 @@ function isRaceError(error) {
|
|
|
41986
42198
|
}
|
|
41987
42199
|
var PROC_FD = "/proc/self/fd";
|
|
41988
42200
|
async function linuxDescriptorPath(fd) {
|
|
41989
|
-
if (process.platform !== "linux" || !
|
|
42201
|
+
if (process.platform !== "linux" || !existsSync2(PROC_FD)) return void 0;
|
|
41990
42202
|
return realpath3(`${PROC_FD}/${fd}`);
|
|
41991
42203
|
}
|
|
41992
42204
|
async function parentChainIsRealDirectories(root, path) {
|
|
@@ -43623,11 +43835,11 @@ function plural(count, label) {
|
|
|
43623
43835
|
init_theme();
|
|
43624
43836
|
init_errors();
|
|
43625
43837
|
import { execSync } from "child_process";
|
|
43626
|
-
import { readFileSync as
|
|
43838
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
43627
43839
|
var PACKAGE_NAME = "@tinycloud/cli";
|
|
43628
43840
|
function getCurrentVersion() {
|
|
43629
43841
|
const pkg = JSON.parse(
|
|
43630
|
-
|
|
43842
|
+
readFileSync3(new URL("../package.json", import.meta.url), "utf-8")
|
|
43631
43843
|
);
|
|
43632
43844
|
return pkg.version;
|
|
43633
43845
|
}
|