Validate published output declarations
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/artifactpolicy"
|
||||
"gitea.maximumdirect.net/eric/narratio/internal/config"
|
||||
)
|
||||
|
||||
@@ -14,6 +15,13 @@ type ImmutableRunObjectKey struct {
|
||||
RelativePath string
|
||||
}
|
||||
|
||||
// PublishedOutputObjectKey identifies a published destination beneath one
|
||||
// immutable run in a session.
|
||||
type PublishedOutputObjectKey struct {
|
||||
RunID string
|
||||
Destination string
|
||||
}
|
||||
|
||||
// ParseImmutableRunObjectKey proves that key belongs to one immutable run in
|
||||
// the expected campaign/session namespace and returns its run and relative path.
|
||||
func ParseImmutableRunObjectKey(sessionPrefix, key string) (ImmutableRunObjectKey, error) {
|
||||
@@ -41,6 +49,34 @@ func ParseImmutableRunObjectKey(sessionPrefix, key string) (ImmutableRunObjectKe
|
||||
return ImmutableRunObjectKey{RunID: runID, RelativePath: relativePath}, nil
|
||||
}
|
||||
|
||||
// ParsePublishedOutputObjectKey proves that key is in the published-output
|
||||
// namespace of one immutable run in the expected session.
|
||||
func ParsePublishedOutputObjectKey(sessionPrefix, key string) (PublishedOutputObjectKey, error) {
|
||||
identity, err := ParseImmutableRunObjectKey(sessionPrefix, key)
|
||||
if err != nil {
|
||||
return PublishedOutputObjectKey{}, err
|
||||
}
|
||||
destination, ok := strings.CutPrefix(identity.RelativePath, "published/")
|
||||
if !ok || destination == "" {
|
||||
return PublishedOutputObjectKey{}, fmt.Errorf("immutable object key %q is outside its immutable run published-output prefix", key)
|
||||
}
|
||||
if err := validateRemoteObjectKey(destination); err != nil {
|
||||
return PublishedOutputObjectKey{}, fmt.Errorf("immutable object key %q has invalid published destination: %w", key, err)
|
||||
}
|
||||
return PublishedOutputObjectKey{RunID: identity.RunID, Destination: destination}, nil
|
||||
}
|
||||
|
||||
func validateCanonicalPublishSource(source string) error {
|
||||
classified, err := artifactpolicy.ClassifySource(source)
|
||||
if err != nil || classified.Kind == artifactpolicy.SourceKindPreviousArtifact {
|
||||
return fmt.Errorf("source %q is not a supported publish source", source)
|
||||
}
|
||||
if classified.ID != source {
|
||||
return fmt.Errorf("source %q is not canonical", source)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateRemoteSessionPrefix(sessionPrefix string) error {
|
||||
if sessionPrefix == "" || strings.TrimSpace(sessionPrefix) != sessionPrefix || strings.Contains(sessionPrefix, `\`) || !strings.HasSuffix(sessionPrefix, "/") {
|
||||
return fmt.Errorf("session prefix %q must be a canonical relative object prefix", sessionPrefix)
|
||||
|
||||
Reference in New Issue
Block a user