diff --git a/evolution/proposals/BEP-0009-release-infrastructure-and-store-upload-pipeline.md b/evolution/proposals/BEP-0009-release-infrastructure-and-store-upload-pipeline.md index 6d677c9..9e7ba08 100644 --- a/evolution/proposals/BEP-0009-release-infrastructure-and-store-upload-pipeline.md +++ b/evolution/proposals/BEP-0009-release-infrastructure-and-store-upload-pipeline.md @@ -110,6 +110,9 @@ The same change also makes the forge itself the release authority: release tags - Configure macOS Namespace targets with the Compute API CPU-by-memory shape format. `12x28` is the Burrow large macOS baseline; platform-prefixed values such as `macos/arm64:8x16` are not accepted by the macOS launcher. +- Keep the shared Linux runner work directory out of macOS bootstraps. The + dispatcher normalizes macOS runners to `/tmp/forgejo-runner` when the shared + config points at Linux state paths such as `/var/lib/forgejo-runner`. - Run forge Namespace services with the repo-owned `nsc` package and keep it current with the token format expected by Namespace. `nsc 0.0.520` is the first required baseline for revokable token-file auth. diff --git a/services/forgejo-nsc/internal/nsc/macos.go b/services/forgejo-nsc/internal/nsc/macos.go index 9bf3837..05324eb 100644 --- a/services/forgejo-nsc/internal/nsc/macos.go +++ b/services/forgejo-nsc/internal/nsc/macos.go @@ -151,6 +151,14 @@ func readNSCBearerToken() (string, error) { return trimmed, nil } +func macosRunnerWorkDir(configured string) string { + workdir := strings.TrimSpace(configured) + if workdir == "" || strings.HasPrefix(workdir, "/var/lib/") { + return "/tmp/forgejo-runner" + } + return workdir +} + func parseMachineTypeCPUxMemGB(machineType string) (vcpu int32, memoryMB int32, err error) { parts := strings.Split(machineType, "x") if len(parts) != 2 { @@ -183,10 +191,7 @@ func (d *Dispatcher) launchMacOSRunner(ctx context.Context, runnerName string, r httpClient := &http.Client{Timeout: 60 * time.Second} client := computev1betaconnect.NewComputeServiceClient(httpClient, d.opts.ComputeBaseURL) - workdir := d.opts.WorkDir - if strings.TrimSpace(workdir) == "" { - workdir = "/tmp/forgejo-runner" - } + workdir := macosRunnerWorkDir(d.opts.WorkDir) env := map[string]string{ "FORGEJO_INSTANCE_URL": req.InstanceURL, diff --git a/services/forgejo-nsc/internal/nsc/macos_nsc.go b/services/forgejo-nsc/internal/nsc/macos_nsc.go index c22fadb..0f83b3c 100644 --- a/services/forgejo-nsc/internal/nsc/macos_nsc.go +++ b/services/forgejo-nsc/internal/nsc/macos_nsc.go @@ -296,9 +296,7 @@ func (d *Dispatcher) destroyNSCInstance(ctx context.Context, runnerName, instanc } func macosBootstrapWrapperScript(runnerName string, req LaunchRequest, executor, workdir string) string { - if strings.TrimSpace(workdir) == "" { - workdir = "/tmp/forgejo-runner" - } + workdir = macosRunnerWorkDir(workdir) // Pass all values via stdin script so secrets do not appear in the nsc ssh argv. env := map[string]string{ diff --git a/services/forgejo-nsc/internal/nsc/macos_test.go b/services/forgejo-nsc/internal/nsc/macos_test.go new file mode 100644 index 0000000..28fe86b --- /dev/null +++ b/services/forgejo-nsc/internal/nsc/macos_test.go @@ -0,0 +1,25 @@ +package nsc + +import "testing" + +func TestMacOSRunnerWorkDirUsesWritableEphemeralPath(t *testing.T) { + cases := []struct { + name string + configured string + want string + }{ + {name: "empty", configured: "", want: "/tmp/forgejo-runner"}, + {name: "linux var state", configured: "/var/lib/forgejo-runner", want: "/tmp/forgejo-runner"}, + {name: "custom tmp", configured: "/tmp/custom-runner", want: "/tmp/custom-runner"}, + {name: "home path", configured: "/Users/runner/forgejo-runner", want: "/Users/runner/forgejo-runner"}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + got := macosRunnerWorkDir(tc.configured) + if got != tc.want { + t.Fatalf("macosRunnerWorkDir(%q) = %q, want %q", tc.configured, got, tc.want) + } + }) + } +}