@mutmutco/cli 4.6.16 → 4.6.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.cjs +46 -17
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -27805,10 +27805,10 @@ var rollout_plan_default = {
|
|
|
27805
27805
|
note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
|
|
27806
27806
|
},
|
|
27807
27807
|
baseline: {
|
|
27808
|
-
version: "4.6.
|
|
27809
|
-
tag: "v4.6.
|
|
27810
|
-
commit: "
|
|
27811
|
-
npm: "@mutmutco/cli@4.6.
|
|
27808
|
+
version: "4.6.17",
|
|
27809
|
+
tag: "v4.6.17",
|
|
27810
|
+
commit: "efe71da889a6",
|
|
27811
|
+
npm: "@mutmutco/cli@4.6.17"
|
|
27812
27812
|
},
|
|
27813
27813
|
exitCriterion: "fleet-n-of-n",
|
|
27814
27814
|
hubOnlyShortcut: "forbidden",
|
|
@@ -27825,14 +27825,14 @@ var rollout_plan_default = {
|
|
|
27825
27825
|
repo: "mutmutco/mmi-hub",
|
|
27826
27826
|
role: "canary",
|
|
27827
27827
|
schedule: "train",
|
|
27828
|
-
v3Target: "v4.6.
|
|
27828
|
+
v3Target: "v4.6.17"
|
|
27829
27829
|
}
|
|
27830
27830
|
],
|
|
27831
27831
|
rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
|
|
27832
27832
|
rollback: {
|
|
27833
27833
|
independent: true,
|
|
27834
|
-
mechanism: "npm dist-tag latest -> 4.6.
|
|
27835
|
-
v3Target: "v4.6.
|
|
27834
|
+
mechanism: "npm dist-tag latest -> 4.6.17 and redeploy the Hub Lambda from tag v4.6.17 (efe71da889a6); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
27835
|
+
v3Target: "v4.6.17 (@mutmutco/cli@4.6.17, tag commit efe71da889a6 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
27836
27836
|
}
|
|
27837
27837
|
},
|
|
27838
27838
|
{
|
|
@@ -47165,7 +47165,7 @@ function sshRemoteCommand(remoteCommand) {
|
|
|
47165
47165
|
function shellSingleQuote(value) {
|
|
47166
47166
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
47167
47167
|
}
|
|
47168
|
-
var SSH_RECIPE_AGENT_NOTE =
|
|
47168
|
+
var SSH_RECIPE_AGENT_NOTE = '# agent callers: this is multi-line, so running it inline is denied (#1473/#2125).\n# Use `mmi-cli devops runtime box get <name> --ssh --script <path>` to write it to a file, then `bash <path>`.\n# For a multi-line remote body add --stdin (or --body <file>): the recipe then runs `sh -s` on the box,\n# and you stream the body over stdin \u2014 `bash "<path>" < "<body-file>"` \u2014 with no remote re-quoting (#9750).';
|
|
47169
47169
|
function sshRecipeScript(box, remoteCommand) {
|
|
47170
47170
|
return `#!/usr/bin/env bash
|
|
47171
47171
|
${formatSshRecipe(box, remoteCommand)}
|
|
@@ -47249,8 +47249,16 @@ function registerBoxCommands(program3) {
|
|
|
47249
47249
|
await failGraceful(e.message);
|
|
47250
47250
|
}
|
|
47251
47251
|
});
|
|
47252
|
-
box.command("get <name> [command...]").description("one box by name \u2014 its address and ssh key path; --ssh prints a ready-to-run connect recipe").option("--json", "machine-readable output").option("--ssh", "print a copy-paste ssh recipe (runs under the keyless vault wrapper and loads the key into an ssh-agent; the key is never written to a file or echoed)").option("--script <path>", "with --ssh: write the recipe to <path> and print the one line to run \u2014 the runnable form for agent callers, whose transport denies a multi-line inline body (#3385)").action(async (name, command, o) => {
|
|
47252
|
+
box.command("get <name> [command...]").description("one box by name \u2014 its address and ssh key path; --ssh prints a ready-to-run connect recipe").option("--json", "machine-readable output").option("--ssh", "print a copy-paste ssh recipe (runs under the keyless vault wrapper and loads the key into an ssh-agent; the key is never written to a file or echoed)").option("--script <path>", "with --ssh: write the recipe to <path> and print the one line to run \u2014 the runnable form for agent callers, whose transport denies a multi-line inline body (#3385)").option("--stdin", "with --ssh --script: write the recipe with remote command sh -s so a multi-line script can be piped or redirected on stdin without remote shell re-quoting (#9750)").option("--body <file>", 'with --ssh --script: same as --stdin, and name <file> in the printed run line: bash "<script>" < "<file>" (#9750)').action(async (name, command, o) => {
|
|
47253
47253
|
try {
|
|
47254
|
+
if ((o.stdin || o.body) && (!o.ssh || !o.script)) {
|
|
47255
|
+
await failGraceful("runtime box get: --stdin/--body requires --ssh --script <path> (it writes an sh -s recipe that reads the remote body from stdin)");
|
|
47256
|
+
return;
|
|
47257
|
+
}
|
|
47258
|
+
if ((o.stdin || o.body) && command && command.length) {
|
|
47259
|
+
await failGraceful("runtime box get: cannot combine --stdin/--body with trailing [command...] arguments \u2014 put the commands in the stdin body file instead");
|
|
47260
|
+
return;
|
|
47261
|
+
}
|
|
47254
47262
|
const { boxes, incomplete } = await fetchInventory();
|
|
47255
47263
|
const result = lookupBox(name, boxes, incomplete);
|
|
47256
47264
|
if (result.kind === "unknown") {
|
|
@@ -47269,16 +47277,19 @@ function registerBoxCommands(program3) {
|
|
|
47269
47277
|
await failGraceful("runtime box get: --script requires --ssh (it writes the ssh connect recipe)");
|
|
47270
47278
|
return;
|
|
47271
47279
|
}
|
|
47272
|
-
const
|
|
47280
|
+
const useStdin = Boolean(o.stdin || o.body);
|
|
47281
|
+
const remote = useStdin ? "sh -s" : command && command.length ? command.join(" ") : void 0;
|
|
47282
|
+
const stdinSource = o.body ? `"${o.body}"` : "<body.sh>";
|
|
47273
47283
|
const wroteScript = o.ssh && o.script ? o.script : null;
|
|
47284
|
+
const runLine = wroteScript ? useStdin ? `bash "${wroteScript}" < ${stdinSource}` : `bash "${wroteScript}"` : void 0;
|
|
47274
47285
|
if (wroteScript) (0, import_node_fs37.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
|
|
47275
47286
|
if (o.json) {
|
|
47276
47287
|
console.log(JSON.stringify({
|
|
47277
47288
|
box: found,
|
|
47278
47289
|
incomplete,
|
|
47279
|
-
...wroteScript ? { script: { path: wroteScript, run:
|
|
47290
|
+
...wroteScript ? { script: { path: wroteScript, run: runLine, ...useStdin ? { stdin: o.body ?? true } : {} } } : {}
|
|
47280
47291
|
}, null, 2));
|
|
47281
|
-
} else if (wroteScript) console.log(`wrote ${wroteScript} \u2014 run:
|
|
47292
|
+
} else if (wroteScript) console.log(`wrote ${wroteScript} \u2014 run: ${runLine}`);
|
|
47282
47293
|
else if (o.ssh) console.log(`${formatSshRecipe(found, remote)}
|
|
47283
47294
|
${SSH_RECIPE_AGENT_NOTE}`);
|
|
47284
47295
|
else console.log(formatBoxTable([found]));
|
|
@@ -68400,6 +68411,22 @@ function stageAllowlistConfig(project2) {
|
|
|
68400
68411
|
const stages = cfg.stages.filter((s) => ALLOWLIST_STAGES.includes(s));
|
|
68401
68412
|
return stages.length > 0 ? { key: cfg.key, stages } : null;
|
|
68402
68413
|
}
|
|
68414
|
+
function resolveStageAllowlistTarget(repo, projects) {
|
|
68415
|
+
if (!projects) return { kind: "registry-unreadable", exitCode: 1, message: "org access sync: could not read the org project registry \u2014 nothing written" };
|
|
68416
|
+
const project2 = projects.find((p) => (p.repos ?? []).some((r) => r.toLowerCase() === repo.toLowerCase())) ?? null;
|
|
68417
|
+
if (!project2) return { kind: "unregistered", exitCode: 1, message: `org access sync: ${repo} is not in the org project registry \u2014 nothing written` };
|
|
68418
|
+
if (project2.stageAllowlist == null) {
|
|
68419
|
+
return {
|
|
68420
|
+
kind: "no-opt-in",
|
|
68421
|
+
exitCode: 0,
|
|
68422
|
+
json: { repo, optIn: null, stages: [], skipped: "no-stageAllowlist" },
|
|
68423
|
+
message: `org access sync: ${repo} has no stageAllowlist opt-in \u2014 nothing to rebuild (set it with \`mmi-cli oracle org project set ${repo} --var 'stageAllowlist={"key":"<KEY>","stages":["dev"]}'\`)`
|
|
68424
|
+
};
|
|
68425
|
+
}
|
|
68426
|
+
const config = stageAllowlistConfig(project2);
|
|
68427
|
+
if (!config) return { kind: "malformed", exitCode: 1, message: `org access sync: ${repo} has a malformed stageAllowlist in the registry \u2014 set it with \`mmi-cli oracle org project set ${repo} --var 'stageAllowlist={"key":"<KEY>","stages":["dev"]}'\`` };
|
|
68428
|
+
return { kind: "sync", exitCode: 0, config };
|
|
68429
|
+
}
|
|
68403
68430
|
function developerAdminLogins(collaborators) {
|
|
68404
68431
|
const logins = /* @__PURE__ */ new Set();
|
|
68405
68432
|
for (const c of collaborators) {
|
|
@@ -72215,11 +72242,13 @@ access.command("sync [repo]").description("rebuild the stage allowlist (e.g. MM-
|
|
|
72215
72242
|
if (!repo) return fail("org access sync: pass <owner/repo> or run inside a repo checkout");
|
|
72216
72243
|
const cfg = await loadConfig();
|
|
72217
72244
|
if (!cfg.sagaApiUrl) return fail("org access sync: Hub API URL not configured");
|
|
72218
|
-
const
|
|
72219
|
-
if (
|
|
72220
|
-
|
|
72221
|
-
|
|
72222
|
-
|
|
72245
|
+
const target = resolveStageAllowlistTarget(repo, await fetchProjectsList(registryClientDeps(cfg)));
|
|
72246
|
+
if (target.kind === "no-opt-in") {
|
|
72247
|
+
console.log(o.json ? JSON.stringify(target.json, null, 2) : target.message);
|
|
72248
|
+
return;
|
|
72249
|
+
}
|
|
72250
|
+
if (target.kind !== "sync") return failGraceful(target.message);
|
|
72251
|
+
const config = target.config;
|
|
72223
72252
|
const secretsDeps = makeSecretsDeps(cfg);
|
|
72224
72253
|
const client = defaultGitHubClient();
|
|
72225
72254
|
const result = await syncStageAllowlist({
|
package/package.json
CHANGED