Files

104 lines
3.0 KiB
Go

package transcodenode
import (
"context"
"errors"
"os"
"path/filepath"
"runtime"
"testing"
)
type staticCatalogPaths struct {
active map[string]bool
err error
}
func (s staticCatalogPaths) IsActivePath(_ context.Context, path string) (bool, error) {
return s.active[path], s.err
}
func TestCatalogPathAuthorizerAllowsCataloguedRegularFilesAndSymlinks(t *testing.T) {
mediaPath := filepath.Join(t.TempDir(), "movie.mkv")
if err := os.WriteFile(mediaPath, []byte("media"), 0o600); err != nil {
t.Fatal(err)
}
target := filepath.Join(t.TempDir(), "outside.mkv")
if err := os.WriteFile(target, []byte("media"), 0o600); err != nil {
t.Fatal(err)
}
link := filepath.Join(t.TempDir(), "linked.mkv")
if err := os.Symlink(target, link); err != nil {
t.Skipf("symlinks not supported on this platform: %v", err)
}
authorizer := NewCatalogPathAuthorizer(staticCatalogPaths{active: map[string]bool{
mediaPath: true,
link: true,
}})
for _, path := range []string{mediaPath, link} {
allowed, err := authorizer.Allowed(context.Background(), path)
if err != nil || !allowed {
t.Fatalf("approved media path %q: allowed = %v, err = %v", path, allowed, err)
}
}
}
func TestCatalogPathAuthorizerRejectsUnsafeOrUncataloguedInputs(t *testing.T) {
existingUncatalogued := filepath.Join(t.TempDir(), "outside.mkv")
if err := os.WriteFile(existingUncatalogued, []byte("media"), 0o600); err != nil {
t.Fatal(err)
}
missingCatalogued := filepath.Join(t.TempDir(), "missing.mkv")
directoryCatalogued := t.TempDir()
authorizer := NewCatalogPathAuthorizer(staticCatalogPaths{active: map[string]bool{
missingCatalogued: true,
directoryCatalogued: true,
}})
for _, candidate := range []string{
"relative/movie.mkv",
"http://example.test/movie.mkv",
"file:" + existingUncatalogued,
"concat:" + existingUncatalogued + "|" + existingUncatalogued,
existingUncatalogued,
missingCatalogued,
directoryCatalogued,
} {
allowed, err := authorizer.Allowed(context.Background(), candidate)
if err != nil {
t.Fatalf("candidate %q: %v", candidate, err)
}
if allowed {
t.Errorf("candidate %q was allowed", candidate)
}
}
}
func TestCatalogPathAuthorizerPropagatesRepositoryErrors(t *testing.T) {
wantErr := errors.New("database unavailable")
authorizer := NewCatalogPathAuthorizer(staticCatalogPaths{err: wantErr})
allowed, err := authorizer.Allowed(context.Background(), "/media/movie.mkv")
if allowed || !errors.Is(err, wantErr) {
t.Fatalf("allowed = %v, err = %v", allowed, err)
}
}
func TestPathWithinRootRejectsSymlinkedOutputParent(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("symlink semantics differ on Windows")
}
root := t.TempDir()
outside := t.TempDir()
linkedParent := filepath.Join(root, "linked")
if err := os.Symlink(outside, linkedParent); err != nil {
t.Fatal(err)
}
if pathWithinRoot(root, filepath.Join(linkedParent, "artifact.mp4")) {
t.Fatal("output under symlinked escape was accepted")
}
if !pathWithinRoot(root, filepath.Join(root, "artifact.mp4")) {
t.Fatal("direct child output was rejected")
}
}