@newly/cli 0.1.120 → 0.1.122
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.
|
@@ -1305,13 +1305,15 @@ async function action(fn, opts = {}) {
|
|
|
1305
1305
|
}
|
|
1306
1306
|
function configureMachineReadableParseErrors(program) {
|
|
1307
1307
|
const output = program.configureOutput();
|
|
1308
|
+
const writeErrorLine = output.outputError ??
|
|
1309
|
+
((value, destination) => destination(value));
|
|
1308
1310
|
program.configureOutput({
|
|
1309
1311
|
...output,
|
|
1310
1312
|
outputError: (message, write) => {
|
|
1311
1313
|
const rawArgs = program.rawArgs ?? [];
|
|
1312
1314
|
const argumentsSeen = [...process.argv, ...rawArgs, ...program.args];
|
|
1313
1315
|
if (!argumentsSeen.includes('--json')) {
|
|
1314
|
-
(
|
|
1316
|
+
writeErrorLine(message, write);
|
|
1315
1317
|
return;
|
|
1316
1318
|
}
|
|
1317
1319
|
write(`${JSON.stringify({
|
package/dist/commands/sandbox.js
CHANGED
|
@@ -8,7 +8,7 @@ import { runSandboxCommand, shellCommand } from '../sandboxExec.js';
|
|
|
8
8
|
import { runSandboxShell } from '../shellSession.js';
|
|
9
9
|
import { printJson, StatusLine, style } from '../terminal.js';
|
|
10
10
|
import { noteDeprecated, registerAccessCommands } from './boxAccess.js';
|
|
11
|
-
import { renderSandbox, renderSandboxList, } from './sandboxOutput.js';
|
|
11
|
+
import { renderHeldSecrets, renderSandbox, renderSandboxList, } from './sandboxOutput.js';
|
|
12
12
|
const MAX_SANDBOX_DISK_GIB = 2048;
|
|
13
13
|
const DEFAULT_SANDBOX_TIMEOUT_SECONDS = 300;
|
|
14
14
|
const DEFAULT_BOX_CPU_CORES = 2;
|
|
@@ -260,6 +260,15 @@ function secretSelector(opts) {
|
|
|
260
260
|
out.env = env;
|
|
261
261
|
return out;
|
|
262
262
|
}
|
|
263
|
+
async function replaceSandboxSecrets(id, opts) {
|
|
264
|
+
const body = secretSelector(opts);
|
|
265
|
+
await runCloudApi().put(`/run-cloud/sandboxes/${encodeURIComponent(id)}/secrets`, body);
|
|
266
|
+
if (opts.json) {
|
|
267
|
+
printJson({ id, revoked: opts.noSecrets === true, ...body });
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
270
|
+
console.log(opts.noSecrets ? `${id}: all secrets revoked` : `${id}: secrets replaced`);
|
|
271
|
+
}
|
|
263
272
|
function collectRepeatable(value, previous) {
|
|
264
273
|
return [...previous, value];
|
|
265
274
|
}
|
|
@@ -472,17 +481,38 @@ export function registerSandbox(program) {
|
|
|
472
481
|
await new Promise((resolveDelay) => setTimeout(resolveDelay, opts.interval * 1_000));
|
|
473
482
|
}
|
|
474
483
|
}));
|
|
475
|
-
withOutput(sandbox
|
|
484
|
+
const secrets = withOutput(sandbox
|
|
476
485
|
.command('secrets')
|
|
477
|
-
.description('
|
|
486
|
+
.description('Show what secrets a sandbox holds (names and origins, never values)')
|
|
487
|
+
.argument('[id]', 'sandbox id'))
|
|
488
|
+
.showHelpAfterError("hint: `runcloud sandbox secrets set <id> …` changes what a sandbox holds; the bare form only reads it");
|
|
489
|
+
const wantsJson = (opts) => Boolean(secrets.opts().json) || Boolean(opts.json);
|
|
490
|
+
secrets.action((id, opts) => run(async () => {
|
|
491
|
+
if (!id)
|
|
492
|
+
throw new Error('which sandbox? usage: runcloud sandbox secrets <id>');
|
|
493
|
+
const { held } = (await runCloudApi().get(`/run-cloud/sandboxes/${encodeURIComponent(id)}/secrets`));
|
|
494
|
+
if (opts.json) {
|
|
495
|
+
printJson({ held });
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
console.log(renderHeldSecrets(id, held));
|
|
499
|
+
}));
|
|
500
|
+
withOutput(secrets
|
|
501
|
+
.command('set')
|
|
502
|
+
.description('Replace what a sandbox holds (a full replacement, not a merge)')
|
|
478
503
|
.argument('<id>', 'sandbox id')
|
|
479
504
|
.option('--secret-group <group>', 'attach a secret group; repeatable and ORDER MATTERS (a later group wins on a name collision)', collectRepeatable, [])
|
|
480
505
|
.option('--secret <group/name>', 'attach one secret out of a group; repeatable, same ordering', collectRepeatable, [])
|
|
481
506
|
.option('--env <NAME=VALUE>', 'literal value; applied last, so it wins; repeatable', collectRepeatable, [])).action((id, opts) => run(async () => {
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
507
|
+
if (!opts.secretGroup.length && !opts.secret.length && !opts.env.length) {
|
|
508
|
+
throw new Error('name what the sandbox should hold with --secret-group/--secret/--env, or run `runcloud sandbox secrets revoke <id>` to take everything back');
|
|
509
|
+
}
|
|
510
|
+
await replaceSandboxSecrets(id, { ...opts, json: wantsJson(opts) });
|
|
485
511
|
}));
|
|
512
|
+
withOutput(secrets
|
|
513
|
+
.command('revoke')
|
|
514
|
+
.description('Take every secret back from a sandbox')
|
|
515
|
+
.argument('<id>', 'sandbox id')).action((id, opts) => run(() => replaceSandboxSecrets(id, { noSecrets: true, json: wantsJson(opts) })));
|
|
486
516
|
withOutput(sandbox
|
|
487
517
|
.command('expose')
|
|
488
518
|
.description('Publish a sandbox guest port at a stable hostname, or change the published port')
|
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
import { formatAge, formatCpu, formatMib, formatSeconds, formatState, renderDetails, renderTable, shortDigest, style, } from '../terminal.js';
|
|
2
|
+
export function renderHeldSecrets(id, held) {
|
|
3
|
+
const heading = `Secrets held by ${id}`;
|
|
4
|
+
if (held === null) {
|
|
5
|
+
return `${style.bold(heading)}\n\nUnknown — nothing was recorded for this sandbox, so what it\nholds cannot be answered from here.\n\n${style.dim('Check the environment inside it, or run `runcloud sandbox secrets set`,')}\n${style.dim('which records what it pushes.')}`;
|
|
6
|
+
}
|
|
7
|
+
if (held.length === 0) {
|
|
8
|
+
return `${style.bold(heading)}\n\nNothing. This sandbox holds no secrets.\n\n${style.dim('Attach some:')} runcloud sandbox secrets set ${id} --secret-group <group>`;
|
|
9
|
+
}
|
|
10
|
+
return renderTable(`${heading} (${held.length})`, [
|
|
11
|
+
{ key: 'name', label: 'NAME', maxWidth: 32 },
|
|
12
|
+
{ key: 'kind', label: 'KIND' },
|
|
13
|
+
{ key: 'source', label: 'FROM', maxWidth: 28 },
|
|
14
|
+
{ key: 'digest', label: 'DIGEST' },
|
|
15
|
+
], held.map((secret) => ({
|
|
16
|
+
name: secret.name,
|
|
17
|
+
kind: secret.kind,
|
|
18
|
+
source: secret.source,
|
|
19
|
+
digest: secret.digest,
|
|
20
|
+
})));
|
|
21
|
+
}
|
|
2
22
|
function resources(record) {
|
|
3
23
|
const memory = formatMib(record.mem_mb);
|
|
4
24
|
const disk = formatMib(record.disk_mb);
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const CLI_VERSION = '0.1.
|
|
1
|
+
export const CLI_VERSION = '0.1.122';
|