Files
distributor/internal/bundle/validate.go

86 lines
2.8 KiB
Go

package bundle
import (
"context"
"fmt"
"gitea.maximumdirect.net/eric/distributor/internal/storage"
)
func ValidateSourcePath(path string) error {
if err := storage.ValidatePath(path); err != nil {
return err
}
switch path {
case ManifestName, storage.StateFileName:
return fmt.Errorf("%q is reserved", path)
}
return nil
}
func Validate(ctx context.Context, backend storage.Backend, bundleRoot string) (Bundle, error) {
return validateAt(ctx, backend, bundleRoot, bundleRoot)
}
func validateAt(ctx context.Context, backend storage.Backend, bundleRoot, relativeRoot string) (Bundle, error) {
if err := storage.ValidatePrefix(bundleRoot); err != nil {
return Bundle{}, err
}
manifestPath, err := storage.Join(bundleRoot, ManifestName)
if err != nil {
return Bundle{}, err
}
manifestData, err := backend.ReadFile(ctx, manifestPath)
if err != nil {
return Bundle{}, fmt.Errorf("read manifest %q: %w", manifestPath, err)
}
manifest, err := ParseManifest(manifestData)
if err != nil {
return Bundle{}, fmt.Errorf("bundle %q: %w", displayRoot(relativeRoot), err)
}
for index, manifestFile := range manifest.Files {
filePath, err := storage.Join(bundleRoot, manifestFile.Path)
if err != nil {
return Bundle{}, fmt.Errorf("bundle %q file %q: %w", displayRoot(relativeRoot), manifestFile.Path, err)
}
entry, err := backend.Stat(ctx, filePath)
if err != nil {
return Bundle{}, fmt.Errorf("bundle %q file %q stat: %w", displayRoot(relativeRoot), manifestFile.Path, err)
}
if entry.Type != storage.EntryTypeFile {
return Bundle{}, fmt.Errorf("bundle %q file %q must be a regular file", displayRoot(relativeRoot), manifestFile.Path)
}
if entry.Size != manifestFile.Size {
return Bundle{}, fmt.Errorf("bundle %q file %q size mismatch: got %d want %d", displayRoot(relativeRoot), manifestFile.Path, entry.Size, manifestFile.Size)
}
data, err := backend.ReadFile(ctx, filePath)
if err != nil {
return Bundle{}, fmt.Errorf("bundle %q file %q read: %w", displayRoot(relativeRoot), manifestFile.Path, err)
}
actualDigest := FileDigest(data)
if actualDigest != manifestFile.SHA256 {
return Bundle{}, fmt.Errorf("bundle %q file %q sha256 mismatch: got %s want %s", displayRoot(relativeRoot), manifestFile.Path, actualDigest, manifestFile.SHA256)
}
manifest.Files[index].SHA256 = actualDigest
manifest.Files[index].Size = int64(len(data))
}
actualBundleDigest := BundleDigest(manifest.Files)
if actualBundleDigest != manifest.Digest {
return Bundle{}, fmt.Errorf("bundle %q digest mismatch: got %s want %s", displayRoot(relativeRoot), actualBundleDigest, manifest.Digest)
}
return Bundle{
RootRelativePath: relativeRoot,
Manifest: manifest,
}, nil
}
func displayRoot(root string) string {
if root == "" {
return "."
}
return root
}