Skip to content

Carry non-Go files into the pure-Go runtime image#882

Merged
evanphx merged 3 commits into
mainfrom
mir-1294-add-ability-for-stackbuild-to-explicitly-include-f
Jul 6, 2026
Merged

Carry non-Go files into the pure-Go runtime image#882
evanphx merged 3 commits into
mainfrom
mir-1294-add-ability-for-stackbuild-to-explicitly-include-f

Conversation

@evanphx

@evanphx evanphx commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Problem

The Go stackbuild's default pure-Go path assembles a distroless-static runtime that copied only /bin/app, silently dropping every other file in the repo (README, templates, data dirs). This broke apps like rfd that read files at runtime relative to /app.

Only this one build personality was affected — every other stack (Ruby, Python, Node, Bun, Rust) and even Go's own cgo/JS-augmented path already ship the full /app tree.

Fix

In GoStack.assembleRuntime, the distroless-static branch now copies the built /app tree onto the runtime image, excluding Go source and the module/vendor build inputs the compiled binary never needs:

ExcludePatterns: []string{"**/*.go", "go.mod", "go.sum", "vendor"}

This mirrors the CopyInfo the debian-slim branch already uses and removes a footgun from the default Go path. Rather than an explicit opt-in include list, non-Go files now travel automatically — consistent with every other stack.

Scope stays on the pure-Go branch; the debian-slim (cgo/augmented) branch is untouched.

Testing

  • New TestGoRuntimeIncludesNonGoFiles — builds a real image via buildkit and asserts app/README.md and nested app/data/seed.txt are present while app/main.go, app/go.mod, app/go.sum are excluded. ✅
  • Existing TestGo, TestGoCgo, TestGoWithVendor stay green. ✅
  • make lint clean (Go + docs). ✅

Note: these Docker-dependent stackbuild tests skip inside iso (no docker.sock); run on the host. The full pkg/stackbuild package (other stacks) was not run.

Docs

Added a "Runtime Files" note to the Go section of docs/docs/languages.md.

The Go stackbuild's default pure-Go path assembles a distroless-static
runtime that copied only /bin/app, silently dropping every other file
(README, templates, data dirs). Apps like rfd that read files at runtime
relative to /app broke as a result.

Copy the built /app tree onto the runtime, excluding Go source and the
module/vendor build inputs (**/*.go, go.mod, go.sum, vendor) that the
compiled binary never needs. This matches what every other stack already
does and removes a footgun from the default Go path.
@evanphx evanphx requested a review from a team as a code owner July 5, 2026 18:07
@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9e483fc4-13cb-40f3-bf8f-1e3c00e5be24

📥 Commits

Reviewing files that changed from the base of the PR and between c12e140 and 227710b.

📒 Files selected for processing (1)
  • pkg/stackbuild/golang.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • pkg/stackbuild/golang.go

📝 Walkthrough

Walkthrough

Changes

The Go distroless runtime copy step now excludes Go source files, go.mod, go.sum, and vendor from /app while keeping non-Go assets. The runtime comment and docs were updated to describe this behavior, and a new test checks that non-Go files are present while Go build inputs are absent from the runtime tarball.

Sequence Diagram(s)

Not applicable.

Related Issues: None provided.

Related PRs: None provided.

Suggested labels: documentation, golang, testing

Suggested reviewers: None provided.

Poem:
A runtime image trimmed with care,
Left Go build files out of there.
README stayed,
Data files stayed,
While module inputs did not share.


Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
pkg/stackbuild/golang.go (1)

351-355: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Bare go.mod/go.sum/vendor patterns only match at the root, not in nested subdirectories.

Docker/BuildKit ignore-pattern matching uses filepath.Match and patterns are anchored to the copy root unless prefixed with **/. **/*.go correctly matches Go source at any depth, but go.mod, go.sum, and vendor will only match those names at the top level of /app. For projects using Go workspaces, multi-module layouts, or a vendor/ directory nested under a subpackage, those files/dirs would still be copied into the runtime image, defeating the intent of the exclusion.

♻️ Proposed fix to make exclusions recursive
-var goRuntimeExcludePatterns = []string{"**/*.go", "go.mod", "go.sum", "vendor"}
+var goRuntimeExcludePatterns = []string{"**/*.go", "**/go.mod", "**/go.sum", "**/vendor"}

Please confirm BuildKit's ExcludePatterns semantics for github.com/moby/buildkit v0.19.0 match this understanding.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/stackbuild/golang.go` around lines 351 - 355, The runtime exclusion list
in goRuntimeExcludePatterns only uses root-anchored names for go.mod, go.sum,
and vendor, so nested modules or subpackage vendor trees can still be copied.
Update the patterns used by the golang.go stack build flow so they apply
recursively like the existing **/*.go entry, and verify against BuildKit
ExcludePatterns behavior in github.com/moby/buildkit v0.19.0 that the copy root
is matched unless prefixed with **/.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@pkg/stackbuild/golang.go`:
- Around line 351-355: The runtime exclusion list in goRuntimeExcludePatterns
only uses root-anchored names for go.mod, go.sum, and vendor, so nested modules
or subpackage vendor trees can still be copied. Update the patterns used by the
golang.go stack build flow so they apply recursively like the existing **/*.go
entry, and verify against BuildKit ExcludePatterns behavior in
github.com/moby/buildkit v0.19.0 that the copy root is matched unless prefixed
with **/.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6a1c0706-fc07-4d62-b92d-a9f2308e364e

📥 Commits

Reviewing files that changed from the base of the PR and between af5d3cb and c12e140.

📒 Files selected for processing (3)
  • docs/docs/languages.md
  • pkg/stackbuild/golang.go
  • pkg/stackbuild/stackbuild_test.go

@phinze phinze left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This inverts a call I made back in #865, where I made distroless strictly binary-only and left go:embed (or flipping on cgo/JS to route to slim) as the escape hatch. And I think you've got it right to undo it. The tell is that we broke our own rfd tool with its config-in-README trick: if we were leaning on the "files are just there" invariant without thinking about it, that invariant is worth keeping. Better to match every other stack than make Go the one that quietly drops your files.

One thing worth fixing before this goes in: you updated the user-facing docs, but the assembleRuntime header comment (around line 272) still tells the old story, calling this a binary-only image and pointing people at go:embed. That's the misleading bit now, since files come along for free. Whoever edits that function next will read the comment first.

CodeRabbit's point about vendor and go.mod only matching at the repo root is a fair catch, but it's just bloat on nested-module layouts rather than anything broken, so I'll leave that to you.

--p+🤖

evanphx added 2 commits July 6, 2026 09:33
The distroless-path bullet still described the image as binary-only and
pointed to go:embed, which is misleading now that non-Go files are
carried in automatically.
@evanphx evanphx enabled auto-merge July 6, 2026 16:44
@evanphx evanphx merged commit 15f9ea8 into main Jul 6, 2026
19 checks passed
@evanphx evanphx deleted the mir-1294-add-ability-for-stackbuild-to-explicitly-include-f branch July 6, 2026 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants