Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 27 additions & 21 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,27 @@ async function startBlacksmithBuilder(
inputs: Inputs,
): Promise<{ addr: string | null; exposeId: string }> {
try {
// If buildkitd is already running, skip - the builder is already initialized.
try {
const { stdout } = await execAsync("pgrep buildkitd");
if (stdout.trim()) {
core.info(
`Detected existing buildkitd process (PID: ${stdout.trim()}). ` +
`Skipping builder setup - builder is already initialized.`,
);
return { addr: null, exposeId: "" };
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nofallback check bypassed when buildkitd already running

Low Severity

When buildkitd is already running, the early return { addr: null, exposeId: "" } bypasses the nofallback check in the catch block. The fallback path at line 643+ has no nofallback guard of its own, so if toolkit.builder.inspect() returns null, a local docker-container builder is silently created even when nofallback is true. Previously, detecting a running buildkitd threw an error that respected the nofallback flag.

Additional Locations (1)
Fix in Cursor Fix in Web

Copy link
Author

@chadxz chadxz Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this scenario, buildkitd is already running from a prior invocation in the same job - the Blacksmith builder setup already succeeded. There's nothing to "fall back" from, so I don't think nofallback applies here. We're reusing the existing (already working) builder, not necessarily falling back to a local one.

If we later enrich the toolkit.builder.inspect() check to validate that the existing builder is specifically a Blacksmith builder, it may make sense to wire in specific nofallback handling at that point.

}
} catch (error) {
if ((error as { code?: number }).code !== 1) {
// pgrep returns exit code 1 when no process found, which is what we want
// Any other error code indicates a real problem
throw new Error(
`Failed to check for existing buildkitd process: ${(error as Error).message}`,
);
}
// Exit code 1 means no buildkitd process found, which is good - we can proceed
}

// Setup sticky disk
const stickyDiskStartTime = Date.now();
const stickyDiskSetup = await setupStickyDisk();
Expand Down Expand Up @@ -464,25 +485,6 @@ async function startBlacksmithBuilder(
parallelism = inputs["max-parallelism"];
}

// Check if buildkitd is already running before starting
try {
const { stdout } = await execAsync("pgrep buildkitd");
if (stdout.trim()) {
throw new Error(
`Detected existing buildkitd process (PID: ${stdout.trim()}). Refusing to start to avoid conflicts.`,
);
}
} catch (error) {
if ((error as { code?: number }).code !== 1) {
// pgrep returns exit code 1 when no process found, which is what we want
// Any other error code indicates a real problem
throw new Error(
`Failed to check for existing buildkitd process: ${(error as Error).message}`,
);
}
// Exit code 1 means no buildkitd process found, which is good - we can proceed
}

// Check for potential boltdb corruption
const boltdbIntegrity = await checkBoltDbIntegrity(
inputs["skip-integrity-check"],
Expand Down Expand Up @@ -639,8 +641,12 @@ void actionsToolkit.run(
core.info("Blacksmith builder is ready for use by Docker");
});
} else {
// Fallback to local builder
core.warning("Failed to setup Blacksmith builder, using local builder");
// Fallback: either Blacksmith builder setup failed, or buildkitd was
// already running. In both cases, reuse whatever builder is already
// configured.
core.warning(
"Blacksmith builder setup skipped or failed, checking for existing configured builder",
);
await core.group(`Checking for configured builder`, async () => {
try {
const builder = await toolkit.builder.inspect();
Expand Down
Loading