Flamenco/pkg/shaman/checkout/checkout.go
Sybren A. Stüvel 724938c7ae Shaman: allow Manager to determine the final checkout path
The checkout request now responds with the final checkout path. This makes
it possible for the Manager to ensure the checkout is unique.
2022-03-25 14:10:26 +01:00

71 lines
1.9 KiB
Go

package checkout
// SPDX-License-Identifier: GPL-3.0-or-later
import (
"context"
"errors"
"fmt"
"regexp"
"strings"
"git.blender.org/flamenco/pkg/api"
"git.blender.org/flamenco/pkg/shaman/filestore"
"github.com/rs/zerolog"
)
var (
ErrMissingFiles = errors.New("unknown files requested in checkout")
validCheckoutRegexp = regexp.MustCompile(`^[^/?*:;{}\\][^?*:;{}\\]*$`)
)
func (m *Manager) Checkout(ctx context.Context, checkout api.ShamanCheckout) (string, error) {
logger := (*zerolog.Ctx(ctx)).With().
Str("checkoutPath", checkout.CheckoutPath).Logger()
logger.Debug().Msg("shaman: user requested checkout creation")
// Actually create the checkout.
resolvedCheckoutInfo, err := m.PrepareCheckout(checkout.CheckoutPath)
if err != nil {
return "", err
}
// The checkout directory was created, so if anything fails now, it should be erased.
var checkoutOK bool
defer func() {
if !checkoutOK {
err := m.EraseCheckout(checkout.CheckoutPath)
if err != nil {
logger.Error().Err(err).Msg("shaman: error erasing checkout directory")
}
}
}()
for _, fileSpec := range checkout.Files {
blobPath, status := m.fileStore.ResolveFile(fileSpec.Sha, int64(fileSpec.Size), filestore.ResolveStoredOnly)
if status != filestore.StatusStored {
// Caller should upload this file before we can create the checkout.
return "", ErrMissingFiles
}
if err := m.SymlinkToCheckout(blobPath, resolvedCheckoutInfo.absolutePath, fileSpec.Path); err != nil {
return "", fmt.Errorf("symlinking %q to checkout: %w", fileSpec.Path, err)
}
}
checkoutOK = true // Prevent the checkout directory from being erased again.
logger.Info().Msg("shaman: checkout created")
return resolvedCheckoutInfo.RelativePath, nil
}
func isValidCheckoutPath(checkoutPath string) bool {
if !validCheckoutRegexp.MatchString(checkoutPath) {
return false
}
if strings.Contains(checkoutPath, "../") || strings.Contains(checkoutPath, "/..") {
return false
}
return true
}