Validate portable workspace identifiers

This commit is contained in:
2026-08-10 17:35:52 +00:00
parent 0b40cf8026
commit 1dccf5f140
31 changed files with 490 additions and 48 deletions

View File

@@ -6,6 +6,7 @@ import (
"strings"
"gitea.maximumdirect.net/eric/narratio/internal/config"
"gitea.maximumdirect.net/eric/narratio/internal/pathsafe"
)
func resolveCampaignConfigPath(pipelineCfg *config.PipelineConfig, campaignIDFlag, campaignFileFlag string) (string, error) {
@@ -33,12 +34,8 @@ func resolveCampaignConfigPath(pipelineCfg *config.PipelineConfig, campaignIDFla
}
func validateCampaignIDToken(campaignID string) error {
if filepath.IsAbs(campaignID) ||
strings.Contains(campaignID, "/") ||
strings.Contains(campaignID, `\`) ||
campaignID == "." ||
campaignID == ".." {
return fmt.Errorf("campaign id %q must be a single path segment", campaignID)
if err := pathsafe.ValidateOpaqueSegment(campaignID); err != nil {
return fmt.Errorf("campaign id %q must be a single path segment and opaque identifier: %w", campaignID, err)
}
return nil
}

View File

@@ -0,0 +1,16 @@
package app
import (
"testing"
"gitea.maximumdirect.net/eric/narratio/internal/artifacts"
)
func mustPreviousArtifactPathForCampaign(t *testing.T, root, campaign, sessionID, relative string) string {
t.Helper()
path, err := artifacts.SessionPreviousArtifactPathForCampaign(root, campaign, sessionID, relative)
if err != nil {
t.Fatalf("SessionPreviousArtifactPathForCampaign() error = %v", err)
}
return path
}

View File

@@ -277,7 +277,7 @@ func cleanupFixtureConfig(t *testing.T) (*config.Config, cleanupSeed) {
runWorkDir := artifacts.SessionRunRootForCampaign(cfg.Pipeline.Workspace.Root, cfg.Session.Campaign, cfg.Session.SessionID, runID)
otherRunDir := artifacts.SessionRunRootForCampaign(cfg.Pipeline.Workspace.Root, cfg.Session.Campaign, cfg.Session.SessionID, "20260516T010204Z-5e6f7a8b")
spoolAudioDir := artifacts.SessionSpoolAudioDir(cfg.Pipeline.Spool.Root, cfg.Session.Campaign, cfg.Session.SessionID, runID)
previousCachePath := artifacts.SessionPreviousArtifactPathForCampaign(
previousCachePath := mustPreviousArtifactPathForCampaign(t,
cfg.Pipeline.Workspace.Root,
cfg.Session.Campaign,
cfg.Session.SessionID,