fix: delegate ALL cloud credentials, not just the current cloud (#2994)

delegateCloudCredentials only copied the current cloud's config file
(e.g. sprite.json when spawning on Sprite). Child VMs couldn't spawn
on other clouds because their tokens weren't forwarded.

Now iterates all known clouds and copies every credential file that
exists locally, so the agent can spawn children on any cloud.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Ahmed Abushagur 2026-03-25 19:02:42 -07:00 committed by GitHub
parent 665780b6b2
commit 7fe36b8aa0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -137,31 +137,36 @@ export async function installSpawnCli(runner: CloudRunner): Promise<void> {
}
/** Copy local cloud credentials to the remote VM for recursive spawning. */
export async function delegateCloudCredentials(runner: CloudRunner, cloudName: string): Promise<void> {
export async function delegateCloudCredentials(runner: CloudRunner, _cloudName: string): Promise<void> {
logStep("Delegating cloud credentials to VM...");
// Validate cloudName to prevent command injection via crafted cloud names
if (!/^[a-z0-9-]+$/.test(cloudName)) {
logWarn(`Invalid cloud name for credential delegation: ${cloudName}`);
return;
}
const filesToDelegate: {
localPath: string;
remotePath: string;
}[] = [];
// Current cloud's credentials
const cloudConfigPath = getSpawnCloudConfigPath(cloudName);
if (existsSync(cloudConfigPath)) {
filesToDelegate.push({
localPath: cloudConfigPath,
remotePath: `~/.config/spawn/${cloudName}.json`,
});
// Delegate ALL cloud credentials so the child VM can spawn on any cloud,
// not just the one the parent is running on.
const configDir = `${getUserHome()}/.config/spawn`;
const cloudNames = [
"hetzner",
"digitalocean",
"aws",
"gcp",
"sprite",
];
for (const cloud of cloudNames) {
const cloudConfigPath = getSpawnCloudConfigPath(cloud);
if (existsSync(cloudConfigPath)) {
filesToDelegate.push({
localPath: cloudConfigPath,
remotePath: `~/.config/spawn/${cloud}.json`,
});
}
}
// OpenRouter credentials (always needed for child spawns)
const orConfigPath = `${getUserHome()}/.config/spawn/openrouter.json`;
const orConfigPath = `${configDir}/openrouter.json`;
if (existsSync(orConfigPath)) {
filesToDelegate.push({
localPath: orConfigPath,