Skip to content

Commit 3987680

Browse files
koki-developclaude
andcommitted
fix: use version-agnostic symlinks for runtime paths
Replace hardcoded version-specific paths in runtime.go (e.g. /mise/installs/go/1.26.0) with /mise/installs/<runtime>/current symlinks created during Docker build. This decouples runtime version updates from Go source code, allowing Renovate to update Dockerfile ARGs without requiring changes to runtime.go. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 15f3720 commit 3987680

4 files changed

Lines changed: 68 additions & 27 deletions

File tree

Dockerfile

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,24 @@ RUN apt-get update && \
3333
# renovate: datasource=node-version depName=node
3434
ARG NODE_VERSION=24.14.0
3535
ENV PATH="/mise/installs/node/${NODE_VERSION}/bin:$PATH"
36-
RUN mise use -g node@${NODE_VERSION}
36+
RUN mise use -g node@${NODE_VERSION} && \
37+
ln -s /mise/installs/node/${NODE_VERSION} /mise/installs/node/current
3738
COPY internal/sandbox/defaults/node-typescript/package.json internal/sandbox/defaults/node-typescript/package-lock.json /mise/ts-node-modules/
3839
RUN cd /mise/ts-node-modules && npm ci
3940

4041
# Ruby
4142
# renovate: datasource=ruby-version depName=ruby
4243
ARG RUBY_VERSION=3.4.8
4344
ENV PATH="/mise/installs/ruby/${RUBY_VERSION}/bin:$PATH"
44-
RUN mise settings ruby.compile=false && mise use -g ruby@${RUBY_VERSION}
45+
RUN mise settings ruby.compile=false && mise use -g ruby@${RUBY_VERSION} && \
46+
ln -s /mise/installs/ruby/${RUBY_VERSION} /mise/installs/ruby/current
4547

4648
# Go
4749
# renovate: datasource=golang-version depName=go
4850
ARG GO_VERSION=1.26.0
4951
ENV PATH="/mise/installs/go/${GO_VERSION}/bin:$PATH"
50-
RUN mise use -g go@${GO_VERSION}
52+
RUN mise use -g go@${GO_VERSION} && \
53+
ln -s /mise/installs/go/${GO_VERSION} /mise/installs/go/current
5154
RUN CGO_ENABLED=0 GOCACHE=/mise/go-cache go build std
5255
COPY internal/sandbox/defaults/go/go.mod.tmpl /tmp/preinstall/go.mod
5356
COPY internal/sandbox/defaults/go/go.sum.tmpl /tmp/preinstall/go.sum
@@ -59,7 +62,8 @@ RUN cd /tmp/preinstall && \
5962
# renovate: datasource=python-version depName=python
6063
ARG PYTHON_VERSION=3.13.12
6164
ENV PATH="/mise/installs/python/${PYTHON_VERSION}/bin:$PATH"
62-
RUN mise use -g python@${PYTHON_VERSION}
65+
RUN mise use -g python@${PYTHON_VERSION} && \
66+
ln -s /mise/installs/python/${PYTHON_VERSION} /mise/installs/python/current
6367

6468
# Rust
6569
# renovate: datasource=github-tags depName=rust packageName=rust-lang/rust
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Version-Agnostic Runtime Paths
2+
3+
## Problem
4+
5+
Runtime versions are defined as Dockerfile ARGs (e.g., `GO_VERSION=1.26.1`) and hardcoded in `internal/sandbox/runtime.go` as literal paths (e.g., `/mise/installs/go/1.26.0/bin/go`). When Renovate updates Dockerfile ARGs, runtime.go is not updated, causing a mismatch.
6+
7+
This affects: Node.js, Ruby, Go, Python (4 runtimes). Rust is unaffected because its paths (`/mise/cargo`, `/mise/rustup`) don't contain version numbers.
8+
9+
## Solution
10+
11+
Use version-agnostic symlinks created during Docker build.
12+
13+
### Dockerfile Changes
14+
15+
After each `mise use` command, create a `current` symlink:
16+
17+
```
18+
/mise/installs/node/current -> /mise/installs/node/${NODE_VERSION}
19+
/mise/installs/ruby/current -> /mise/installs/ruby/${RUBY_VERSION}
20+
/mise/installs/go/current -> /mise/installs/go/${GO_VERSION}
21+
/mise/installs/python/current -> /mise/installs/python/${PYTHON_VERSION}
22+
```
23+
24+
### runtime.go Changes
25+
26+
Replace all version-specific paths with `current`:
27+
28+
- `/mise/installs/node/24.14.0` -> `/mise/installs/node/current`
29+
- `/mise/installs/ruby/3.4.8` -> `/mise/installs/ruby/current`
30+
- `/mise/installs/go/1.26.0` -> `/mise/installs/go/current`
31+
- `/mise/installs/python/3.13.12` -> `/mise/installs/python/current`
32+
33+
### Out of Scope
34+
35+
- Rust `RUSTUP_TOOLCHAIN=1.94.0` env var (no version in filesystem paths)
36+
- Builder stage `golang:1.26.1-bookworm` (build toolchain, not sandbox runtime)
37+
- `go.mod` Go version

internal/sandbox/runtime.go

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ type Runtime interface {
4242
BindMounts() []BindMount
4343

4444
// Env returns environment variables for the sandbox in "KEY=VALUE" format
45-
// (e.g. "PATH=/mise/installs/node/24.14.0/bin:/usr/bin").
45+
// (e.g. "PATH=/mise/installs/node/current/bin:/usr/bin").
4646
Env() []string
4747

4848
// Limits returns the nsjail resource limits for the run step.
@@ -176,15 +176,15 @@ type nodeRuntime struct{}
176176
func (nodeRuntime) Name() RuntimeName { return RuntimeNode }
177177

178178
func (nodeRuntime) Command(entryFile string) []string {
179-
return []string{"/mise/installs/node/24.14.0/bin/node", "--disable-wasm-trap-handler", entryFile}
179+
return []string{"/mise/installs/node/current/bin/node", "--disable-wasm-trap-handler", entryFile}
180180
}
181181

182182
func (nodeRuntime) BindMounts() []BindMount {
183-
return []BindMount{{Src: "/mise/installs/node/24.14.0", Dst: "/mise/installs/node/24.14.0"}}
183+
return []BindMount{{Src: "/mise/installs/node/current", Dst: "/mise/installs/node/current"}}
184184
}
185185

186186
func (nodeRuntime) Env() []string {
187-
return []string{"PATH=/mise/installs/node/24.14.0/bin:/usr/bin:/bin"}
187+
return []string{"PATH=/mise/installs/node/current/bin:/usr/bin:/bin"}
188188
}
189189

190190
// Limits returns resource limits for Node.js execution.
@@ -225,15 +225,15 @@ type rubyRuntime struct{}
225225
func (rubyRuntime) Name() RuntimeName { return RuntimeRuby }
226226

227227
func (rubyRuntime) Command(entryFile string) []string {
228-
return []string{"/mise/installs/ruby/3.4.8/bin/ruby", entryFile}
228+
return []string{"/mise/installs/ruby/current/bin/ruby", entryFile}
229229
}
230230

231231
func (rubyRuntime) BindMounts() []BindMount {
232-
return []BindMount{{Src: "/mise/installs/ruby/3.4.8", Dst: "/mise/installs/ruby/3.4.8"}}
232+
return []BindMount{{Src: "/mise/installs/ruby/current", Dst: "/mise/installs/ruby/current"}}
233233
}
234234

235235
func (rubyRuntime) Env() []string {
236-
return []string{"PATH=/mise/installs/ruby/3.4.8/bin:/usr/bin:/bin"}
236+
return []string{"PATH=/mise/installs/ruby/current/bin:/usr/bin:/bin"}
237237
}
238238

239239
// Limits returns resource limits for Ruby execution.
@@ -274,15 +274,15 @@ type pythonRuntime struct{}
274274
func (pythonRuntime) Name() RuntimeName { return RuntimePython }
275275

276276
func (pythonRuntime) Command(entryFile string) []string {
277-
return []string{"/mise/installs/python/3.13.12/bin/python3", entryFile}
277+
return []string{"/mise/installs/python/current/bin/python3", entryFile}
278278
}
279279

280280
func (pythonRuntime) BindMounts() []BindMount {
281-
return []BindMount{{Src: "/mise/installs/python/3.13.12", Dst: "/mise/installs/python/3.13.12"}}
281+
return []BindMount{{Src: "/mise/installs/python/current", Dst: "/mise/installs/python/current"}}
282282
}
283283

284284
func (pythonRuntime) Env() []string {
285-
return []string{"PATH=/mise/installs/python/3.13.12/bin:/usr/bin:/bin"}
285+
return []string{"PATH=/mise/installs/python/current/bin:/usr/bin:/bin"}
286286
}
287287

288288
// Limits returns resource limits for Python execution.
@@ -339,12 +339,12 @@ func (goRuntime) Env() []string {
339339
}
340340

341341
func (goRuntime) CompileCommand() []string {
342-
return []string{"/mise/installs/go/1.26.0/bin/go", "build", "-o", "/sandbox/main", "."}
342+
return []string{"/mise/installs/go/current/bin/go", "build", "-o", "/sandbox/main", "."}
343343
}
344344

345345
func (goRuntime) CompileBindMounts() []BindMount {
346346
return []BindMount{
347-
{Src: "/mise/installs/go/1.26.0", Dst: "/mise/installs/go/1.26.0"},
347+
{Src: "/mise/installs/go/current", Dst: "/mise/installs/go/current"},
348348
{Src: "/mise/go-cache", Dst: "/mise/go-cache"}, // pre-built Go stdlib cache (read-only)
349349
{Src: "/mise/go-modcache", Dst: "/mise/go-modcache"}, // pre-downloaded module cache (read-only)
350350
{Src: "/usr/local/bin/gocacheprog", Dst: "/usr/local/bin/gocacheprog"}, // cache helper binary; /usr/local/bin is not mounted by the base config
@@ -353,8 +353,8 @@ func (goRuntime) CompileBindMounts() []BindMount {
353353

354354
func (goRuntime) CompileEnv() []string {
355355
return []string{
356-
"PATH=/mise/installs/go/1.26.0/bin:/usr/bin:/bin",
357-
"GOROOT=/mise/installs/go/1.26.0",
356+
"PATH=/mise/installs/go/current/bin:/usr/bin:/bin",
357+
"GOROOT=/mise/installs/go/current",
358358
"GOPATH=/tmp/gopath", // writable location for module metadata and build artifacts
359359
"GOMODCACHE=/mise/go-modcache", // read-only pre-downloaded module cache from Docker image
360360
"GOCACHEPROG=/usr/local/bin/gocacheprog /mise/go-cache", // read-only cache backed by pre-built stdlib cache from Docker image
@@ -546,30 +546,30 @@ func (nodeTypeScriptRuntime) Name() RuntimeName { return RuntimeNodeTypeScript }
546546

547547
func (nodeTypeScriptRuntime) Command(entryFile string) []string {
548548
jsFile := strings.TrimSuffix(entryFile, path.Ext(entryFile)) + ".js"
549-
return []string{"/mise/installs/node/24.14.0/bin/node", "--disable-wasm-trap-handler", jsFile}
549+
return []string{"/mise/installs/node/current/bin/node", "--disable-wasm-trap-handler", jsFile}
550550
}
551551

552552
func (nodeTypeScriptRuntime) BindMounts() []BindMount {
553-
return []BindMount{{Src: "/mise/installs/node/24.14.0", Dst: "/mise/installs/node/24.14.0"}}
553+
return []BindMount{{Src: "/mise/installs/node/current", Dst: "/mise/installs/node/current"}}
554554
}
555555

556556
func (nodeTypeScriptRuntime) Env() []string {
557-
return []string{"PATH=/mise/installs/node/24.14.0/bin:/usr/bin:/bin"}
557+
return []string{"PATH=/mise/installs/node/current/bin:/usr/bin:/bin"}
558558
}
559559

560560
func (nodeTypeScriptRuntime) CompileCommand() []string {
561-
return []string{"/mise/installs/node/24.14.0/bin/node", "--disable-wasm-trap-handler", "/sandbox/node_modules/typescript/bin/tsc"}
561+
return []string{"/mise/installs/node/current/bin/node", "--disable-wasm-trap-handler", "/sandbox/node_modules/typescript/bin/tsc"}
562562
}
563563

564564
func (nodeTypeScriptRuntime) CompileBindMounts() []BindMount {
565565
return []BindMount{
566-
{Src: "/mise/installs/node/24.14.0", Dst: "/mise/installs/node/24.14.0"},
566+
{Src: "/mise/installs/node/current", Dst: "/mise/installs/node/current"},
567567
{Src: "/mise/ts-node-modules/node_modules", Dst: "/sandbox/node_modules"}, // pre-installed typescript and @types/node (read-only)
568568
}
569569
}
570570

571571
func (nodeTypeScriptRuntime) CompileEnv() []string {
572-
return []string{"PATH=/mise/installs/node/24.14.0/bin:/usr/bin:/bin"}
572+
return []string{"PATH=/mise/installs/node/current/bin:/usr/bin:/bin"}
573573
}
574574

575575
// CompileLimits returns resource limits for the TypeScript compilation step.

internal/sandbox/sandbox_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,19 +187,19 @@ func TestNodeTypeScriptRuntime_Command(t *testing.T) {
187187
t.Run("converts .ts to .js", func(t *testing.T) {
188188
t.Parallel()
189189
got := rt.Command("/sandbox/index.ts")
190-
assert.Equal(t, []string{"/mise/installs/node/24.14.0/bin/node", "--disable-wasm-trap-handler", "/sandbox/index.js"}, got)
190+
assert.Equal(t, []string{"/mise/installs/node/current/bin/node", "--disable-wasm-trap-handler", "/sandbox/index.js"}, got)
191191
})
192192

193193
t.Run("converts .tsx to .js", func(t *testing.T) {
194194
t.Parallel()
195195
got := rt.Command("/sandbox/app.tsx")
196-
assert.Equal(t, []string{"/mise/installs/node/24.14.0/bin/node", "--disable-wasm-trap-handler", "/sandbox/app.js"}, got)
196+
assert.Equal(t, []string{"/mise/installs/node/current/bin/node", "--disable-wasm-trap-handler", "/sandbox/app.js"}, got)
197197
})
198198

199199
t.Run("appends .js when no extension", func(t *testing.T) {
200200
t.Parallel()
201201
got := rt.Command("/sandbox/noext")
202-
assert.Equal(t, []string{"/mise/installs/node/24.14.0/bin/node", "--disable-wasm-trap-handler", "/sandbox/noext.js"}, got)
202+
assert.Equal(t, []string{"/mise/installs/node/current/bin/node", "--disable-wasm-trap-handler", "/sandbox/noext.js"}, got)
203203
})
204204
}
205205

0 commit comments

Comments
 (0)