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

@@ -70,12 +70,9 @@ func MaterializeS3Audio(ctx context.Context, req S3MaterializeRequest) (S3Materi
if spoolPath == "" {
return S3MaterializeResult{}, fmt.Errorf("spool path is required for s3 audio download")
}
if err := downloadObjectAtomic(ctx, req.Store, key, spoolPath); err != nil {
if err := downloadObjectAtomic(ctx, req.Store, key, spoolPath, req.Object.Size); err != nil {
return S3MaterializeResult{}, fmt.Errorf("download s3 audio object %q: %w", key, err)
}
if err := validateLocalAudio(spoolPath, req.Object.Size); err != nil {
return S3MaterializeResult{}, fmt.Errorf("validate downloaded audio %q: %w", spoolPath, err)
}
checksum, err := fileops.CopyFileAtomicWithChecksum(spoolPath, req.DestPath, fileops.WorkspaceFileMode)
if err != nil {
@@ -118,15 +115,47 @@ func validateLocalAudio(path string, expectedSize int64) error {
return nil
}
func downloadObjectAtomic(ctx context.Context, store storage.ObjectStore, key, destPath string) error {
if strings.TrimSpace(destPath) == "" {
return fmt.Errorf("destination path is required")
}
dir := filepath.Dir(destPath)
if err := fileops.EnsureWorkspaceDirectory(dir); err != nil {
return fmt.Errorf("create destination directory: %w", err)
}
return fileops.DownloadAndInstall(destPath, fileops.WorkspaceFileMode, func(destination io.Writer) error {
func downloadObjectAtomic(ctx context.Context, store storage.ObjectStore, key, destPath string, expectedSize int64) error {
temporaryPath, err := writeAudioTemp(destPath, func(destination io.Writer) error {
return storage.DownloadTo(ctx, store, key, destination)
})
if err != nil {
return err
}
defer func() { _ = os.Remove(temporaryPath) }()
if err := validateLocalAudio(temporaryPath, expectedSize); err != nil {
return fmt.Errorf("validate downloaded audio: %w", err)
}
if err := fileops.InstallSiblingTempFile(temporaryPath, destPath, fileops.WorkspaceFileMode); err != nil {
return err
}
return nil
}
func writeAudioTemp(destination string, write func(io.Writer) error) (string, error) {
if strings.TrimSpace(destination) == "" {
return "", fmt.Errorf("destination path is required")
}
if write == nil {
return "", fmt.Errorf("temporary audio writer is required")
}
dir := filepath.Dir(destination)
if err := fileops.EnsureWorkspaceDirectory(dir); err != nil {
return "", fmt.Errorf("create destination directory: %w", err)
}
temporary, err := os.CreateTemp(dir, "."+filepath.Base(destination)+".tmp-*")
if err != nil {
return "", fmt.Errorf("create sibling temporary file: %w", err)
}
temporaryPath := temporary.Name()
if err := write(temporary); err != nil {
_ = temporary.Close()
_ = os.Remove(temporaryPath)
return "", fmt.Errorf("write sibling temporary file: %w", err)
}
if err := temporary.Close(); err != nil {
_ = os.Remove(temporaryPath)
return "", fmt.Errorf("close sibling temporary file: %w", err)
}
return temporaryPath, nil
}