run402-mcp
Version:
MCP server for Run402 — full-stack backend infrastructure for AI agents: Postgres, auth, storage, serverless functions and atomic deploys. Paid with x402/MPP. Includes $0.03 image generation.
100 lines • 4.93 kB
JavaScript
/**
* vault-byo-primary-bucket — local per-vault BYO credential config
* (design D2, task 3.1/3.2). Parallels `vault-mirror-config.ts` exactly,
* on purpose: same file shape, same "beside the keystore, never in
* `run402.config.json`, never a raw secret value" reasoning.
*
* A BYO vault's `storage_profile`/`byo_destination` are recorded on the
* GATEWAY's vault record (the destination ADDRESS only — see
* `vault-creation-journal.ts`'s allocation request). This file carries
* the ONE thing that must stay purely local, per D2: the credential NAME
* (an AWS profile, or the ambient environment chain) that resolves to the
* customer bucket's actual secret at USE time — resolved by
* `vault-mirror-backend.ts`, never read or cached here, never
* transmitted to run402 in any request. The destination's `region`/
* `endpoint` are ALSO local-only (the server-side address string carries
* neither), so this config persists the full `VaultMirrorDestination`,
* not just the credential.
*
* Written once by `repos create --byo` (or, for a fresh machine re-linking
* to an already-BYO vault, `Repos.byoConfigSet`), keyed by `repo_id` —
* `repo_id` only exists AFTER allocation, so this file's existence for a
* given repo is itself the local "this machine can write this vault's
* payload objects directly" fact `vault-mirror.ts`'s mirror-write hook and
* `vault-degraded-read.ts`'s fallback resolution both gate on.
*/
import { existsSync, readdirSync, unlinkSync } from "node:fs";
import { join } from "node:path";
import { LocalError } from "../errors.js";
import { VAULT_SRC_RE } from "../namespaces/vault.crypto.js";
import { readFileNoFollow, writeFileAtomic0600 } from "./vault-keystore.js";
function fail(code, message, context, details, nextActions) {
throw new LocalError(message, context, { code, details, ...(nextActions ? { next_actions: nextActions } : {}) });
}
export function byoConfigDir(keystore) {
return join(keystore.rootDir, "byo");
}
export function byoConfigPath(keystore, repoId) {
if (!VAULT_SRC_RE.test(repoId))
fail("VAULT_BAD_REPO_ID", `not a src_ id: ${repoId}`, "resolving vault byo config path");
return join(byoConfigDir(keystore), `${repoId}.json`);
}
/** Read the local BYO write-credential config for one vault, or `null` when none is configured on this machine. */
export function readByoConfig(keystore, repoId) {
const text = readFileNoFollow(byoConfigPath(keystore, repoId));
if (!text)
return null;
let parsed;
try {
parsed = JSON.parse(text);
}
catch (e) {
fail("VAULT_BYO_CONFIG_CORRUPT", `byo config for ${repoId} is not valid JSON: ${e.message}`, "reading vault byo config", { repo_id: repoId });
}
if (parsed.version !== 1 || parsed.repo_id !== repoId || !parsed.destination) {
fail("VAULT_BYO_CONFIG_CORRUPT", `byo config for ${repoId} is not a version-1 vault byo config`, "reading vault byo config", { repo_id: repoId });
}
return parsed;
}
/** Every repo id with a local BYO write config on this machine. */
export function listByoConfiguredRepoIds(keystore) {
const dir = byoConfigDir(keystore);
if (!existsSync(dir))
return [];
return readdirSync(dir)
.filter((n) => n.endsWith(".json"))
.map((n) => n.slice(0, -5))
.filter((id) => VAULT_SRC_RE.test(id))
.sort();
}
/** Set (create or replace) the local BYO write-credential config for one vault. */
export function saveByoConfig(keystore, input, now = () => new Date()) {
if (input.destination.kind === "s3" && !input.credential) {
fail("VAULT_MIRROR_CREDENTIAL_REQUIRED", "an s3 byo destination needs a credential — pass --profile <name> or --ambient", "configuring vault byo credential");
}
const existing = readByoConfig(keystore, input.repo_id);
const full = {
version: 1,
repo_id: input.repo_id,
destination: input.destination,
...(input.credential ? { credential: input.credential } : {}),
created_at: existing?.created_at ?? now().toISOString(),
updated_at: now().toISOString(),
};
writeFileAtomic0600(byoConfigPath(keystore, input.repo_id), JSON.stringify(full, null, 2));
return full;
}
/** Remove the local BYO write-credential config for one vault. Never touches the customer bucket's own bytes — this only stops THIS machine from writing/reading it as the vault's primary destination. */
export function removeByoConfig(keystore, repoId) {
const path = byoConfigPath(keystore, repoId);
if (!existsSync(path))
return { removed: false };
try {
unlinkSync(path);
}
catch (e) {
fail("VAULT_BYO_CONFIG_REMOVE_FAILED", `could not remove byo config for ${repoId}: ${e.message}`, "removing vault byo config", { repo_id: repoId });
}
return { removed: true };
}
//# sourceMappingURL=vault-byo-config.js.map