Validate downloads before installing workspace files

This commit is contained in:
2026-09-02 00:37:00 +00:00
parent ba858cc997
commit 39b2665d8b
13 changed files with 204 additions and 665 deletions

View File

@@ -7,6 +7,7 @@ import (
"encoding/hex"
"fmt"
"io"
"os"
"path/filepath"
"strings"
@@ -101,10 +102,7 @@ func executeRestoreDownloadAction(
return executeRestoreAudioAction(ctx, cfg, safeLocalPath, action, store)
}
if err := fileops.EnsureWorkspaceDirectory(filepath.Dir(safeLocalPath)); err != nil {
return fmt.Errorf("create destination directory: %w", err)
}
temporary, err := fileops.DownloadToSiblingTemp(safeLocalPath, func(destination io.Writer) error {
temporaryPath, err := downloadRestoreTemp(safeLocalPath, func(destination io.Writer) error {
if len(action.VerifiedContent) > 0 {
_, err := io.Copy(destination, bytes.NewReader(action.VerifiedContent))
return err
@@ -114,13 +112,13 @@ func executeRestoreDownloadAction(
if err != nil {
return fmt.Errorf("download to temp file: %w", err)
}
defer func() { _ = temporary.Cleanup() }()
if err := verifyRestoredObject(ctx, store, action, temporary); err != nil {
defer func() { _ = os.Remove(temporaryPath) }()
if err := verifyRestoredObject(ctx, store, action, temporaryPath); err != nil {
return err
}
if isRestoreManifest(action.LocalRelativePath) {
file, err := temporary.Open()
file, err := os.Open(temporaryPath)
if err != nil {
return fmt.Errorf("open restored manifest: %w", err)
}
@@ -143,7 +141,7 @@ func executeRestoreDownloadAction(
return nil
}
if err := temporary.Install(filepath.Base(safeLocalPath), fileops.WorkspaceFileMode); err != nil {
if err := fileops.InstallSiblingTempFile(temporaryPath, safeLocalPath, fileops.WorkspaceFileMode); err != nil {
return fmt.Errorf("install file atomically: %w", err)
}
@@ -155,14 +153,42 @@ func isRestoreManifest(relativePath string) bool {
return clean == config.PathManifestFile || clean == config.PathPreviousDirSegment+"/"+config.PathManifestFile
}
func verifyRestoredObject(ctx context.Context, store storage.ObjectStore, action RestoreAction, temporary *fileops.DownloadedTempFile) error {
func downloadRestoreTemp(destination string, download func(io.Writer) error) (string, error) {
if strings.TrimSpace(destination) == "" {
return "", fmt.Errorf("restore destination path is required")
}
if download == nil {
return "", fmt.Errorf("restore temporary writer is required")
}
directory := filepath.Dir(destination)
if err := fileops.EnsureWorkspaceDirectory(directory); err != nil {
return "", fmt.Errorf("create destination directory: %w", err)
}
temporary, err := os.CreateTemp(directory, "."+filepath.Base(destination)+".tmp-*")
if err != nil {
return "", fmt.Errorf("create sibling temporary file: %w", err)
}
temporaryPath := temporary.Name()
if err := download(temporary); err != nil {
_ = temporary.Close()
_ = os.Remove(temporaryPath)
return "", err
}
if err := temporary.Close(); err != nil {
_ = os.Remove(temporaryPath)
return "", fmt.Errorf("close sibling temporary file: %w", err)
}
return temporaryPath, nil
}
func verifyRestoredObject(ctx context.Context, store storage.ObjectStore, action RestoreAction, temporaryPath string) error {
if strings.TrimSpace(action.SHA256) == "" && strings.TrimSpace(action.Generation) == "" {
return nil
}
if strings.TrimSpace(action.SHA256) == "" || strings.TrimSpace(action.Generation) == "" {
return fmt.Errorf("committed object identity for %q is incomplete", action.RemoteKey)
}
file, err := temporary.Open()
file, err := os.Open(temporaryPath)
if err != nil {
return fmt.Errorf("open downloaded object for verification: %w", err)
}