From f74a17c124b03a9e570e0ad1b83ac3fb20569e8a Mon Sep 17 00:00:00 2001 From: Conrad Kramer Date: Wed, 18 Mar 2026 22:54:33 -0700 Subject: [PATCH] Use NSC keychain for macOS fallback --- .../forgejo-nsc/internal/nsc/macos_nsc.go | 51 ++++++++++++++++--- 1 file changed, 43 insertions(+), 8 deletions(-) diff --git a/services/forgejo-nsc/internal/nsc/macos_nsc.go b/services/forgejo-nsc/internal/nsc/macos_nsc.go index c22fadb..6e7273f 100644 --- a/services/forgejo-nsc/internal/nsc/macos_nsc.go +++ b/services/forgejo-nsc/internal/nsc/macos_nsc.go @@ -14,6 +14,18 @@ import ( "time" ) +func nscCLIEnv() []string { + env := os.Environ() + out := env[:0] + for _, entry := range env { + if strings.HasPrefix(entry, "NSC_TOKEN_FILE=") { + continue + } + out = append(out, entry) + } + return out +} + func normalizeMacOSNSCMachineType(machineType string) (normalized string, changed bool, err error) { vcpu, memoryMB, err := parseMachineTypeCPUxMemGB(machineType) if err != nil { @@ -56,10 +68,6 @@ func (d *Dispatcher) launchMacOSRunnerViaNSC(ctx context.Context, runnerName str if machineType == "" { return errors.New("machine_type is required for macos runners") } - if strings.TrimSpace(os.Getenv("NSC_TOKEN_FILE")) == "" { - // The Burrow forge host feeds NSC_TOKEN_FILE from the intake-backed runtime token. - return errors.New("NSC_TOKEN_FILE is required for macos runners") - } selectors := macosSelectorsArg(d.opts.MacosBaseImageID) if selectors == "" { @@ -141,6 +149,7 @@ func (d *Dispatcher) launchMacOSRunnerViaNSC(ctx context.Context, runnerName str defer cancel() cmd := exec.CommandContext(createCtx, d.opts.BinaryPath, args...) + cmd.Env = nscCLIEnv() var buf bytes.Buffer cmd.Stdout = &buf cmd.Stderr = &buf @@ -210,10 +219,9 @@ func (d *Dispatcher) launchMacOSRunnerViaNSC(ctx context.Context, runnerName str defer d.destroyNSCInstance(context.Background(), runnerName, instanceID) script := macosBootstrapWrapperScript(runnerName, req, d.opts.Executor, d.opts.WorkDir) - // Use the Compute SSH config endpoint (direct TCP) instead of `nsc ssh`, which - // relies on a websocket-based SSH proxy that is not supported by the - // revokable tenant token we run the dispatcher with. - if err := d.runMacOSComputeSSHScript(ctx, runnerName, instanceID, script); err != nil { + // The CLI fallback is explicitly keychain-backed and does not rely on the + // service bearer token, so use `nsc ssh` end-to-end here. + if err := d.runMacOSNSCSSHScript(ctx, runnerName, instanceID, script); err != nil { return err } return nil @@ -285,6 +293,7 @@ func (d *Dispatcher) destroyNSCInstance(ctx context.Context, runnerName, instanc args := []string{"destroy", "--force", instanceID} args = prependNSCRegionArgs(args, d.opts.ComputeBaseURL) cmd := exec.CommandContext(ctx, d.opts.BinaryPath, args...) + cmd.Env = nscCLIEnv() var buf bytes.Buffer cmd.Stdout = &buf cmd.Stderr = &buf @@ -336,6 +345,32 @@ func shellSingleQuote(value string) string { return "'" + strings.ReplaceAll(value, "'", `'\"'\"'`) + "'" } +func (d *Dispatcher) runMacOSNSCSSHScript(ctx context.Context, runnerName, instanceID, script string) error { + sshCtx, cancel := context.WithTimeout(ctx, 5*time.Minute) + defer cancel() + + args := []string{"ssh", "--disable-pty", instanceID, "/bin/bash"} + args = prependNSCRegionArgs(args, d.opts.ComputeBaseURL) + + cmd := exec.CommandContext(sshCtx, d.opts.BinaryPath, args...) + cmd.Env = nscCLIEnv() + cmd.Stdin = strings.NewReader(script) + + var buf bytes.Buffer + cmd.Stdout = &buf + cmd.Stderr = &buf + + if err := cmd.Run(); err != nil { + if errors.Is(sshCtx.Err(), context.DeadlineExceeded) { + return fmt.Errorf("nsc ssh timed out after %s\n%s", 5*time.Minute, strings.TrimSpace(buf.String())) + } + return fmt.Errorf("nsc ssh runner bootstrap failed: %w\n%s", err, strings.TrimSpace(buf.String())) + } + + d.log.Info("macos runner bootstrap completed via nsc ssh", "runner", runnerName, "instance", instanceID) + return nil +} + func prependNSCRegionArgs(args []string, computeBaseURL string) []string { region := strings.TrimSpace(os.Getenv("NSC_REGION")) if region == "" {