@marcusrbrown/infra 0.15.0 → 0.15.2
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/cli.js +58 -14
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6949,7 +6949,7 @@ import { goke } from "goke";
|
|
|
6949
6949
|
// package.json
|
|
6950
6950
|
var package_default = {
|
|
6951
6951
|
name: "@marcusrbrown/infra",
|
|
6952
|
-
version: "0.15.
|
|
6952
|
+
version: "0.15.2",
|
|
6953
6953
|
description: "Infrastructure management CLI \u2014 deploy automation, health checks, and MCP bridge",
|
|
6954
6954
|
keywords: [
|
|
6955
6955
|
"infra",
|
|
@@ -7201,8 +7201,16 @@ function readablePipe(pipe) {
|
|
|
7201
7201
|
throw new Error("CLI subprocess did not expose piped output.");
|
|
7202
7202
|
return pipe;
|
|
7203
7203
|
}
|
|
7204
|
-
|
|
7205
|
-
|
|
7204
|
+
function redactExactValues(text2, values) {
|
|
7205
|
+
let redacted = text2;
|
|
7206
|
+
for (const value of new Set(values)) {
|
|
7207
|
+
if (value.length > 0)
|
|
7208
|
+
redacted = redacted.split(value).join("[REDACTED]");
|
|
7209
|
+
}
|
|
7210
|
+
return redacted;
|
|
7211
|
+
}
|
|
7212
|
+
async function runCommand(command, args, timeoutMs = COMMAND_TIMEOUT_MS, stdin, env = process.env, redactValues = []) {
|
|
7213
|
+
const operation = redactExactValues(`${command} ${args.join(" ")}`.trim(), redactValues);
|
|
7206
7214
|
const controller = new AbortController;
|
|
7207
7215
|
let timeout;
|
|
7208
7216
|
let child;
|
|
@@ -7212,7 +7220,7 @@ async function runCommand(command, args, timeoutMs = COMMAND_TIMEOUT_MS, stdin)
|
|
|
7212
7220
|
signal: controller.signal,
|
|
7213
7221
|
stdout: "pipe",
|
|
7214
7222
|
stderr: "pipe",
|
|
7215
|
-
env
|
|
7223
|
+
env
|
|
7216
7224
|
});
|
|
7217
7225
|
} else {
|
|
7218
7226
|
child = Bun.spawn([command, ...args], {
|
|
@@ -7220,7 +7228,7 @@ async function runCommand(command, args, timeoutMs = COMMAND_TIMEOUT_MS, stdin)
|
|
|
7220
7228
|
stdin: new Blob([stdin]).stream(),
|
|
7221
7229
|
stdout: "pipe",
|
|
7222
7230
|
stderr: "pipe",
|
|
7223
|
-
env
|
|
7231
|
+
env
|
|
7224
7232
|
});
|
|
7225
7233
|
}
|
|
7226
7234
|
} catch (error) {
|
|
@@ -7245,7 +7253,11 @@ async function runCommand(command, args, timeoutMs = COMMAND_TIMEOUT_MS, stdin)
|
|
|
7245
7253
|
timeoutPromise
|
|
7246
7254
|
]);
|
|
7247
7255
|
const [stdout, stderr, exitCode] = result;
|
|
7248
|
-
return {
|
|
7256
|
+
return {
|
|
7257
|
+
stdout: redactExactValues(stdout, redactValues),
|
|
7258
|
+
stderr: redactExactValues(stderr, redactValues),
|
|
7259
|
+
exitCode
|
|
7260
|
+
};
|
|
7249
7261
|
} catch (error) {
|
|
7250
7262
|
if (controller.signal.aborted)
|
|
7251
7263
|
throw new Error(`${command} CLI timed out during ${operation}.`);
|
|
@@ -9211,8 +9223,32 @@ function parseManifest(raw) {
|
|
|
9211
9223
|
throw error;
|
|
9212
9224
|
}
|
|
9213
9225
|
}
|
|
9214
|
-
async function runAwsCommand(args) {
|
|
9215
|
-
return runCommand("aws", args);
|
|
9226
|
+
async function runAwsCommand(args, env, redactValues) {
|
|
9227
|
+
return runCommand("aws", args, undefined, undefined, env, redactValues);
|
|
9228
|
+
}
|
|
9229
|
+
var AWS_CHILD_LOCALE_KEYS = new Set(["LANG", "LANGUAGE"]);
|
|
9230
|
+
function buildAwsChildEnv(manifest, sourceEnv = process.env) {
|
|
9231
|
+
const accessKeyId = sourceEnv.AGENT_AWS_ACCESS_KEY_ID?.trim();
|
|
9232
|
+
const secretAccessKey = sourceEnv.AGENT_AWS_SECRET_ACCESS_KEY?.trim();
|
|
9233
|
+
if (!accessKeyId || !secretAccessKey) {
|
|
9234
|
+
throw new Error("Dedicated AWS credentials are required for agent storage preflight. Set AGENT_AWS_ACCESS_KEY_ID and AGENT_AWS_SECRET_ACCESS_KEY in the operator-local environment.");
|
|
9235
|
+
}
|
|
9236
|
+
const childEnv = {};
|
|
9237
|
+
for (const [key, value] of Object.entries(sourceEnv)) {
|
|
9238
|
+
if (value !== undefined && (key === "PATH" || key === "HOME" || key === "TMPDIR" || AWS_CHILD_LOCALE_KEYS.has(key) || key.startsWith("LC_"))) {
|
|
9239
|
+
childEnv[key] = value;
|
|
9240
|
+
}
|
|
9241
|
+
}
|
|
9242
|
+
childEnv.AWS_CONFIG_FILE = "/dev/null";
|
|
9243
|
+
childEnv.AWS_SHARED_CREDENTIALS_FILE = "/dev/null";
|
|
9244
|
+
childEnv.AWS_ACCESS_KEY_ID = accessKeyId;
|
|
9245
|
+
childEnv.AWS_SECRET_ACCESS_KEY = secretAccessKey;
|
|
9246
|
+
childEnv.AWS_REGION = sourceEnv.AGENT_AWS_REGION?.trim() || manifest.bucket_region;
|
|
9247
|
+
childEnv.AWS_DEFAULT_REGION = childEnv.AWS_REGION;
|
|
9248
|
+
const sessionToken = sourceEnv.AGENT_AWS_SESSION_TOKEN?.trim();
|
|
9249
|
+
if (sessionToken)
|
|
9250
|
+
childEnv.AWS_SESSION_TOKEN = sessionToken;
|
|
9251
|
+
return childEnv;
|
|
9216
9252
|
}
|
|
9217
9253
|
async function runProvisionerCommand(manifest, options) {
|
|
9218
9254
|
const args = ["run", "provision:agent", "--", "--teardown", "--manifest", "-"];
|
|
@@ -9256,8 +9292,16 @@ function canonicalBucketRegion(location) {
|
|
|
9256
9292
|
return "eu-west-1";
|
|
9257
9293
|
return String(location);
|
|
9258
9294
|
}
|
|
9259
|
-
async function verifyProvisionedResources(manifest, runAws = runAwsCommand) {
|
|
9260
|
-
|
|
9295
|
+
async function verifyProvisionedResources(manifest, runAws, awsCommand = runAwsCommand) {
|
|
9296
|
+
let executeAws;
|
|
9297
|
+
if (runAws) {
|
|
9298
|
+
executeAws = runAws;
|
|
9299
|
+
} else {
|
|
9300
|
+
const awsEnv = buildAwsChildEnv(manifest);
|
|
9301
|
+
const redactValues = [awsEnv.AWS_ACCESS_KEY_ID, awsEnv.AWS_SECRET_ACCESS_KEY, awsEnv.AWS_SESSION_TOKEN].filter((value) => value !== undefined && value.length > 0);
|
|
9302
|
+
executeAws = (args) => awsCommand(args, awsEnv, redactValues);
|
|
9303
|
+
}
|
|
9304
|
+
const roleResult = await executeAws([
|
|
9261
9305
|
"iam",
|
|
9262
9306
|
"get-role",
|
|
9263
9307
|
"--role-name",
|
|
@@ -9277,7 +9321,7 @@ async function verifyProvisionedResources(manifest, runAws = runAwsCommand) {
|
|
|
9277
9321
|
if (roleArn !== manifest.role_arn) {
|
|
9278
9322
|
throw new Error(`AWS IAM role readback does not match the handoff manifest for ${manifest.owner}/${manifest.repo}; run the provisioner first.`);
|
|
9279
9323
|
}
|
|
9280
|
-
const bucketResult = await
|
|
9324
|
+
const bucketResult = await executeAws([
|
|
9281
9325
|
"s3api",
|
|
9282
9326
|
"head-bucket",
|
|
9283
9327
|
"--bucket",
|
|
@@ -9289,7 +9333,7 @@ async function verifyProvisionedResources(manifest, runAws = runAwsCommand) {
|
|
|
9289
9333
|
if (bucketResult.exitCode !== 0) {
|
|
9290
9334
|
throw new Error(`AWS S3 bucket ${manifest.bucket} is absent, inaccessible, or owned by another account; run the provisioner first. ${bucketResult.stderr.trim()}`.trim());
|
|
9291
9335
|
}
|
|
9292
|
-
const locationResult = await
|
|
9336
|
+
const locationResult = await executeAws([
|
|
9293
9337
|
"s3api",
|
|
9294
9338
|
"get-bucket-location",
|
|
9295
9339
|
"--bucket",
|
|
@@ -9372,7 +9416,7 @@ async function prepareStorageSetup(repo, options, deps = {}) {
|
|
|
9372
9416
|
const rawManifest = await loadManifest(options.manifest ?? "-");
|
|
9373
9417
|
const manifest = parseManifest(rawManifest);
|
|
9374
9418
|
await verifyRepoIdentity(repo, manifest, deps.runGh ?? runGh);
|
|
9375
|
-
const verifyResources = deps.verifyResources ?? ((value) => verifyProvisionedResources(value, deps.runAws));
|
|
9419
|
+
const verifyResources = deps.verifyResources ?? ((value) => verifyProvisionedResources(value, deps.runAws, deps.runAwsCommand));
|
|
9376
9420
|
await verifyResources(manifest);
|
|
9377
9421
|
await verifyOidcSubject(repo, deps.runGh ?? runGh);
|
|
9378
9422
|
const verifyWorkflowSetup = deps.verifyWorkflow ?? ((value, handoff) => verifyWorkflow(value, handoff, { runGh: deps.runGh }));
|
|
@@ -9454,7 +9498,7 @@ async function runStorageTeardown(repo, options = {}, deps = {}) {
|
|
|
9454
9498
|
await runProvisioner(rawManifest, { purgeState: options.purgeState, plan: options.plan ?? false });
|
|
9455
9499
|
}
|
|
9456
9500
|
function registerAgentStorageCommand(cli) {
|
|
9457
|
-
cli.command("agent storage", "Verify the provisioned S3 handoff and wire non-secret GitHub storage variables.").option("--repo [repo]", z6.string().describe("Target GitHub repository in owner/repo format.")).option("--manifest [manifest]", z6.string().default("-").describe("Handoff manifest path, or - to read JSON from stdin.")).option("--plan", z6.boolean().optional().describe("Verify and report storage writes without mutating GitHub.")).option("--dry-run", z6.boolean().optional().describe("Alias for --plan.")).example("infra agent storage --repo owner/repo --manifest handoff.json").example("cat handoff.json | infra agent storage --repo owner/repo --manifest -").action(async (options) => {
|
|
9501
|
+
cli.command("agent storage", "Verify the provisioned S3 handoff and wire non-secret GitHub storage variables. AWS readback requires AGENT_AWS_ACCESS_KEY_ID and AGENT_AWS_SECRET_ACCESS_KEY and ignores ambient AWS_* values.").option("--repo [repo]", z6.string().describe("Target GitHub repository in owner/repo format.")).option("--manifest [manifest]", z6.string().default("-").describe("Handoff manifest path, or - to read JSON from stdin.")).option("--plan", z6.boolean().optional().describe("Verify and report storage writes without mutating GitHub.")).option("--dry-run", z6.boolean().optional().describe("Alias for --plan.")).example("infra agent storage --repo owner/repo --manifest handoff.json").example("cat handoff.json | infra agent storage --repo owner/repo --manifest -").action(async (options) => {
|
|
9458
9502
|
if (!options.repo) {
|
|
9459
9503
|
throw new Error("--repo is required for agent storage.");
|
|
9460
9504
|
}
|