Sync host opencode auth into guest work disks
Refresh guest opencode auth from the host at VM start so guest opencode can reuse the local login without baking secrets into managed images. Reuse the existing work-disk preparation path to copy ~/.local/share/opencode/auth.json into /root/.local/share/opencode/auth.json with mode 0600, and warn and skip when the host file is missing or unreadable so any existing guest auth stays in place. Add daemon coverage for copy, replacement, and warn-and-skip cases, document the restart behavior in the README, and validate with go test ./... plus make build. Existing VMs pick the new auth up on their next restart.
This commit is contained in:
parent
786d235f7f
commit
8bcc767824
4 changed files with 256 additions and 1 deletions
|
|
@ -31,6 +31,12 @@ var (
|
|||
vsockReadyPoll = 200 * time.Millisecond
|
||||
)
|
||||
|
||||
const (
|
||||
workDiskOpencodeAuthDirRelativePath = ".local/share/opencode"
|
||||
workDiskOpencodeAuthRelativePath = workDiskOpencodeAuthDirRelativePath + "/auth.json"
|
||||
hostOpencodeAuthDefaultDisplayPath = "~/" + workDiskOpencodeAuthRelativePath
|
||||
)
|
||||
|
||||
func (d *Daemon) CreateVM(ctx context.Context, params api.VMCreateParams) (vm model.VMRecord, err error) {
|
||||
d.mu.Lock()
|
||||
defer d.mu.Unlock()
|
||||
|
|
@ -927,6 +933,70 @@ func (d *Daemon) ensureAuthorizedKeyOnWorkDisk(ctx context.Context, vm *model.VM
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *Daemon) ensureOpencodeAuthOnWorkDisk(ctx context.Context, vm *model.VMRecord) error {
|
||||
hostAuthPath, err := resolveHostOpencodeAuthPath()
|
||||
if err != nil {
|
||||
d.warnOpencodeAuthSyncSkipped(*vm, hostOpencodeAuthDefaultDisplayPath, err)
|
||||
return nil
|
||||
}
|
||||
authData, err := os.ReadFile(hostAuthPath)
|
||||
if err != nil {
|
||||
d.warnOpencodeAuthSyncSkipped(*vm, hostAuthPath, err)
|
||||
return nil
|
||||
}
|
||||
|
||||
vmCreateStage(ctx, "prepare_work_disk", "syncing opencode auth")
|
||||
workMount, cleanupWork, err := system.MountTempDir(ctx, d.runner, vm.Runtime.WorkDiskPath, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer cleanupWork()
|
||||
|
||||
if err := d.flattenNestedWorkHome(ctx, workMount); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
authDir := filepath.Join(workMount, workDiskOpencodeAuthDirRelativePath)
|
||||
if _, err := d.runner.RunSudo(ctx, "mkdir", "-p", authDir); err != nil {
|
||||
return err
|
||||
}
|
||||
authPath := filepath.Join(workMount, workDiskOpencodeAuthRelativePath)
|
||||
|
||||
tmpFile, err := os.CreateTemp("", "banger-opencode-auth-*")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmpPath := tmpFile.Name()
|
||||
if _, err := tmpFile.Write(authData); err != nil {
|
||||
_ = tmpFile.Close()
|
||||
_ = os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
if err := tmpFile.Close(); err != nil {
|
||||
_ = os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
defer os.Remove(tmpPath)
|
||||
|
||||
_, err = d.runner.RunSudo(ctx, "install", "-m", "600", tmpPath, authPath)
|
||||
return err
|
||||
}
|
||||
|
||||
func resolveHostOpencodeAuthPath() (string, error) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(home, workDiskOpencodeAuthRelativePath), nil
|
||||
}
|
||||
|
||||
func (d *Daemon) warnOpencodeAuthSyncSkipped(vm model.VMRecord, hostPath string, err error) {
|
||||
if d.logger == nil || err == nil {
|
||||
return
|
||||
}
|
||||
d.logger.Warn("guest opencode auth sync skipped", append(vmLogAttrs(vm), "host_path", hostPath, "error", err.Error())...)
|
||||
}
|
||||
|
||||
func mergeAuthorizedKey(existing, managed []byte) []byte {
|
||||
managedLine := strings.TrimSpace(string(managed))
|
||||
if managedLine == "" {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue