fix(ai): upgrade deploy mechanism to use explicit ssh deploy keys rather than http basic auth to solve gitea cloning bugs
This commit is contained in:
@@ -97,6 +97,7 @@ import {
|
|||||||
deleteApplicationEnv,
|
deleteApplicationEnv,
|
||||||
// Phase 4 ── create/update/delete + domains + databases + services
|
// Phase 4 ── create/update/delete + domains + databases + services
|
||||||
createPublicApp,
|
createPublicApp,
|
||||||
|
createPrivateDeployKeyApp,
|
||||||
createDockerImageApp,
|
createDockerImageApp,
|
||||||
createDockerComposeApp,
|
createDockerComposeApp,
|
||||||
startService,
|
startService,
|
||||||
@@ -2100,30 +2101,61 @@ async function toolAppsCreate(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const created = await createPublicApp({
|
// Fall back to creating a private app with a deploy key if available
|
||||||
...commonOpts,
|
const privateKeyUuid = ws.coolify_private_key_uuid;
|
||||||
gitRepository: giteaHttpsUrl(
|
|
||||||
repoOrg,
|
let created;
|
||||||
repoName,
|
|
||||||
botCreds.username,
|
if (privateKeyUuid) {
|
||||||
botCreds.token,
|
created = await createPrivateDeployKeyApp({
|
||||||
),
|
...commonOpts,
|
||||||
gitBranch: String(params.branch ?? repo.default_branch ?? "main"),
|
privateKeyUuid,
|
||||||
portsExposes: String(params.ports ?? "3000"),
|
gitRepository: `git@git.vibnai.com:${repoOrg}/${repoName}.git`,
|
||||||
buildPack: (params.buildPack as any) ?? "nixpacks",
|
gitBranch: String(params.branch ?? repo.default_branch ?? "main"),
|
||||||
name: appName,
|
portsExposes: String(params.ports ?? "3000"),
|
||||||
domains: toDomainsString([fqdn]),
|
buildPack: (params.buildPack as any) ?? "nixpacks",
|
||||||
isAutoDeployEnabled: true,
|
name: appName,
|
||||||
dockerComposeLocation: params.dockerComposeLocation
|
domains: toDomainsString([fqdn]),
|
||||||
? String(params.dockerComposeLocation)
|
isAutoDeployEnabled: true,
|
||||||
: undefined,
|
dockerComposeLocation: params.dockerComposeLocation
|
||||||
dockerfileLocation: params.dockerfileLocation
|
? String(params.dockerComposeLocation)
|
||||||
? String(params.dockerfileLocation)
|
: undefined,
|
||||||
: undefined,
|
dockerfileLocation: params.dockerfileLocation
|
||||||
baseDirectory: params.baseDirectory
|
? String(params.dockerfileLocation)
|
||||||
? String(params.baseDirectory)
|
: undefined,
|
||||||
: undefined,
|
baseDirectory: params.baseDirectory
|
||||||
});
|
? String(params.baseDirectory)
|
||||||
|
: undefined,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// If no deploy key is configured for this workspace, fall back to public app
|
||||||
|
// with embedded basic-auth credentials (often fails on newer Coolify versions due to strict cloning)
|
||||||
|
created = await createPublicApp({
|
||||||
|
...commonOpts,
|
||||||
|
gitRepository: giteaHttpsUrl(
|
||||||
|
repoOrg,
|
||||||
|
repoName,
|
||||||
|
botCreds.username,
|
||||||
|
botCreds.token,
|
||||||
|
),
|
||||||
|
gitBranch: String(params.branch ?? repo.default_branch ?? "main"),
|
||||||
|
portsExposes: String(params.ports ?? "3000"),
|
||||||
|
buildPack: (params.buildPack as any) ?? "nixpacks",
|
||||||
|
name: appName,
|
||||||
|
domains: toDomainsString([fqdn]),
|
||||||
|
isAutoDeployEnabled: true,
|
||||||
|
dockerComposeLocation: params.dockerComposeLocation
|
||||||
|
? String(params.dockerComposeLocation)
|
||||||
|
: undefined,
|
||||||
|
dockerfileLocation: params.dockerfileLocation
|
||||||
|
? String(params.dockerfileLocation)
|
||||||
|
: undefined,
|
||||||
|
baseDirectory: params.baseDirectory
|
||||||
|
? String(params.baseDirectory)
|
||||||
|
: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
await linkIfRequested(created.uuid, "application");
|
await linkIfRequested(created.uuid, "application");
|
||||||
|
|
||||||
const dep = await applyEnvsAndDeploy(created.uuid, params);
|
const dep = await applyEnvsAndDeploy(created.uuid, params);
|
||||||
@@ -5082,17 +5114,48 @@ async function toolDevServerStart(
|
|||||||
name: typeof params.name === "string" ? params.name : undefined,
|
name: typeof params.name === "string" ? params.name : undefined,
|
||||||
workspace: principal.workspace,
|
workspace: principal.workspace,
|
||||||
});
|
});
|
||||||
void probeDevServerReadiness(project.id, row.id, row.port).catch((err) =>
|
|
||||||
console.error("[dev_server.start] probeDevServerReadiness failed:", err),
|
// Instead of firing-and-forgetting, we now wait for the server to ACTUALLY
|
||||||
);
|
// spin up and serve HTTP traffic before we return success to the AI.
|
||||||
|
// This allows the AI to see the exact health check failure synchronously.
|
||||||
|
let isHealthy = false;
|
||||||
|
let failureOutput = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
await probeDevServerReadiness(project.id, row.id, row.port);
|
||||||
|
isHealthy = true;
|
||||||
|
} catch (probeErr: any) {
|
||||||
|
isHealthy = false;
|
||||||
|
failureOutput = probeErr.message || String(probeErr);
|
||||||
|
console.error("[dev_server.start] Synchronous probe failed:", probeErr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isHealthy) {
|
||||||
|
return NextResponse.json({
|
||||||
|
result: {
|
||||||
|
ok: false,
|
||||||
|
error:
|
||||||
|
"Server failed to start or bind to port within the timeout window.",
|
||||||
|
healthCheck: {
|
||||||
|
status: 500,
|
||||||
|
output: failureOutput,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return NextResponse.json({
|
return NextResponse.json({
|
||||||
result: {
|
result: {
|
||||||
|
ok: true,
|
||||||
id: row.id,
|
id: row.id,
|
||||||
name: row.name,
|
name: row.name,
|
||||||
port: row.port,
|
port: row.port,
|
||||||
pid: row.pid,
|
pid: row.pid,
|
||||||
previewUrl: row.preview_url,
|
previewUrl: row.preview_url,
|
||||||
state: row.state,
|
state: row.state,
|
||||||
|
healthCheck: {
|
||||||
|
status: 200,
|
||||||
|
},
|
||||||
note:
|
note:
|
||||||
"Preview URL is auto-published via Traefik labels baked into the dev-container compose. " +
|
"Preview URL is auto-published via Traefik labels baked into the dev-container compose. " +
|
||||||
"It will respond once (a) DNS *.preview.vibnai.com resolves to the Coolify host and " +
|
"It will respond once (a) DNS *.preview.vibnai.com resolves to the Coolify host and " +
|
||||||
|
|||||||
Reference in New Issue
Block a user