Use stable verified Notarius reference snapshots

This commit is contained in:
2026-09-16 17:53:29 +00:00
parent 5202f16972
commit e13d87a077
8 changed files with 469 additions and 101 deletions

View File

@@ -10,6 +10,8 @@ import (
"gitea.maximumdirect.net/eric/narratio/internal/pathsafe"
)
const sha256HexLength = 64
// SessionPaths contains canonical local paths for one session work directory.
type SessionPaths struct {
WorkspaceRoot string
@@ -28,6 +30,7 @@ type SessionPaths struct {
CurrentDir string
RunsDir string
PreviousDir string
CacheDir string
PreviousManifestPath string
PreviousArtifactsDir string
ManifestPath string
@@ -108,17 +111,37 @@ func SessionRunNotariusLogPathForCampaign(rootDir, campaign, sessionID, runID st
return filepath.Join(SessionRunExtractDirForCampaign(rootDir, campaign, sessionID, runID), "notarius.stderr.log")
}
// SessionRunNotariusReferencesDirForCampaign returns the invocation-local
// directory containing verified reference snapshots supplied to Notarius.
func SessionRunNotariusReferencesDirForCampaign(rootDir, campaign, sessionID, runID string) string {
return filepath.Join(SessionRunExtractDirForCampaign(rootDir, campaign, sessionID, runID), "references")
}
// SessionRunNotariusOutputRootForCampaign returns the invocation-local Notarius output root.
func SessionRunNotariusOutputRootForCampaign(rootDir, campaign, sessionID, runID string) string {
return filepath.Join(SessionRunExtractDirForCampaign(rootDir, campaign, sessionID, runID), "notarius-output")
}
// SessionNotariusReferenceCacheDir returns the stable cache root for verified
// reference snapshots supplied to Notarius.
func SessionNotariusReferenceCacheDir(paths SessionPaths) string {
return filepath.Join(paths.CacheDir, "notarius", "references")
}
// SessionNotariusReferenceSnapshotPath returns the content-addressed path for
// one verified prepared reference snapshot.
func SessionNotariusReferenceSnapshotPath(paths SessionPaths, checksum, preparedBasename string) (string, error) {
if len(checksum) != sha256HexLength {
return "", fmt.Errorf("reference checksum must be a full lowercase SHA-256 digest")
}
for _, character := range checksum {
if (character < '0' || character > '9') && (character < 'a' || character > 'f') {
return "", fmt.Errorf("reference checksum must be a full lowercase SHA-256 digest")
}
}
if err := pathsafe.ValidateOpaqueSegment(preparedBasename); err != nil {
return "", fmt.Errorf("prepared reference basename: %w", err)
}
return pathsafe.JoinSlashRelativeUnderRoot(
SessionNotariusReferenceCacheDir(paths),
checksum+"/"+preparedBasename,
)
}
// SessionNotariusBundleDirForCampaign returns one immutable durable bundle destination.
func SessionNotariusBundleDirForCampaign(rootDir, campaign, sessionID, runID string) string {
return filepath.Join(
@@ -268,6 +291,7 @@ func buildSessionPathsFromRoot(workspaceRoot, campaign, sessionID, root string)
CurrentDir: filepath.Join(root, config.PathCurrentDirSegment),
RunsDir: filepath.Join(root, config.PathRunsDirSegment),
PreviousDir: filepath.Join(root, config.PathPreviousDirSegment),
CacheDir: filepath.Join(root, config.PathCacheDirSegment),
PreviousManifestPath: filepath.Join(root, config.PathPreviousDirSegment, config.PathManifestFile),
PreviousArtifactsDir: filepath.Join(root, config.PathPreviousDirSegment, config.PathArtifactsDirSegment),
ManifestPath: filepath.Join(root, config.PathManifestFile),

View File

@@ -2,6 +2,7 @@ package artifacts
import (
"path/filepath"
"strings"
"testing"
)
@@ -54,7 +55,6 @@ func TestSessionNotariusPathsForCampaign(t *testing.T) {
{name: "extract directory", got: SessionRunExtractDirForCampaign(root, campaign, sessionID, runID), want: extractDir},
{name: "receipt", got: SessionRunNotariusReceiptPathForCampaign(root, campaign, sessionID, runID), want: filepath.Join(extractDir, "notarius.receipt.json")},
{name: "stderr", got: SessionRunNotariusLogPathForCampaign(root, campaign, sessionID, runID), want: filepath.Join(extractDir, "notarius.stderr.log")},
{name: "references", got: SessionRunNotariusReferencesDirForCampaign(root, campaign, sessionID, runID), want: filepath.Join(extractDir, "references")},
{name: "output root", got: SessionRunNotariusOutputRootForCampaign(root, campaign, sessionID, runID), want: filepath.Join(extractDir, "notarius-output")},
{name: "durable bundle", got: SessionNotariusBundleDirForCampaign(root, campaign, sessionID, runID), want: filepath.Join(root, "work", campaign, sessionID, "artifacts", "notarius", runID)},
}
@@ -67,6 +67,43 @@ func TestSessionNotariusPathsForCampaign(t *testing.T) {
}
}
func TestSessionNotariusReferenceSnapshotPath(t *testing.T) {
paths := buildSessionPaths("/tmp/workspace", "forsaken", "2026-04-19")
checksum := strings.Repeat("a", 64)
got, err := SessionNotariusReferenceSnapshotPath(paths, checksum, "party.yml")
if err != nil {
t.Fatalf("SessionNotariusReferenceSnapshotPath() error = %v", err)
}
wantRoot := filepath.Join(paths.Root, "cache", "notarius", "references")
if root := SessionNotariusReferenceCacheDir(paths); root != wantRoot {
t.Fatalf("SessionNotariusReferenceCacheDir() = %q, want %q", root, wantRoot)
}
if want := filepath.Join(wantRoot, checksum, "party.yml"); got != want {
t.Fatalf("SessionNotariusReferenceSnapshotPath() = %q, want %q", got, want)
}
}
func TestSessionNotariusReferenceSnapshotPathRejectsUnsafeIdentity(t *testing.T) {
paths := buildSessionPaths("/tmp/workspace", "forsaken", "2026-04-19")
validChecksum := strings.Repeat("a", 64)
for _, test := range []struct {
name, checksum, basename string
}{
{name: "short digest", checksum: "abc", basename: "party.yml"},
{name: "uppercase digest", checksum: strings.Repeat("A", 64), basename: "party.yml"},
{name: "nonhex digest", checksum: strings.Repeat("g", 64), basename: "party.yml"},
{name: "empty basename", checksum: validChecksum},
{name: "nested basename", checksum: validChecksum, basename: "nested/party.yml"},
{name: "parent basename", checksum: validChecksum, basename: ".."},
} {
t.Run(test.name, func(t *testing.T) {
if got, err := SessionNotariusReferenceSnapshotPath(paths, test.checksum, test.basename); err == nil {
t.Fatalf("SessionNotariusReferenceSnapshotPath() = %q, want error", got)
}
})
}
}
func TestSessionPreviousPathsForCampaign(t *testing.T) {
root := "/tmp/workspace"
previousDir := SessionPreviousDirForCampaign(root, "forsaken", "2026-04-19")