Add immutable remote commit reader

This commit is contained in:
2026-08-10 19:47:12 +00:00
parent ee747243fe
commit d6deccf3e8
14 changed files with 914 additions and 98 deletions

View File

@@ -4,7 +4,6 @@ import (
"context"
"errors"
"fmt"
"os"
"strings"
"gitea.maximumdirect.net/eric/narratio/internal/adapters/storage"
@@ -44,8 +43,11 @@ type CurrentState struct {
SessionPrefix string
CurrentRunIDKey string
CurrentManifestKey string
CurrentPointerKey string
RunID string
Manifest *manifest.Manifest
Commit *RemoteCommitManifest
Pointer *CurrentCommitPointer
}
type CurrentStateValidation struct {
@@ -55,74 +57,6 @@ type CurrentStateValidation struct {
ValidateRunID bool
}
func LoadCurrentRunPointer(ctx context.Context, store storage.ObjectStore, currentRunIDKey string) (string, error) {
if store == nil {
return "", fmt.Errorf("object store is required")
}
key := strings.TrimSpace(currentRunIDKey)
if key == "" {
return "", fmt.Errorf("current run pointer key is required")
}
exists, err := store.Exists(ctx, key)
if err != nil {
return "", fmt.Errorf("check current run pointer %q: %w", key, err)
}
if !exists {
return "", &CurrentRunPointerMissingError{Key: key}
}
localPath, err := storage.DownloadObjectToTemp(ctx, store, key, "narratio-current-run-id-*.txt")
if err != nil {
return "", fmt.Errorf("download current run pointer %q: %w", key, err)
}
defer func() { _ = os.Remove(localPath) }()
data, err := os.ReadFile(localPath)
if err != nil {
return "", fmt.Errorf("read downloaded current run pointer %q: %w", key, err)
}
runID := strings.TrimSpace(string(data))
if runID == "" {
return "", fmt.Errorf("current run pointer %q is empty", key)
}
if err := ValidateRunIdentity(runID); err != nil {
return "", fmt.Errorf("current run pointer %q contains an unsafe legacy run id; migrate remote state before use: %w", key, err)
}
return runID, nil
}
func LoadCurrentManifest(ctx context.Context, store storage.ObjectStore, currentManifestKey string) (*manifest.Manifest, error) {
if store == nil {
return nil, fmt.Errorf("object store is required")
}
key := strings.TrimSpace(currentManifestKey)
if key == "" {
return nil, fmt.Errorf("current manifest key is required")
}
exists, err := store.Exists(ctx, key)
if err != nil {
return nil, fmt.Errorf("check current manifest %q: %w", key, err)
}
if !exists {
return nil, &CurrentManifestMissingError{Key: key}
}
localPath, err := storage.DownloadObjectToTemp(ctx, store, key, "narratio-current-manifest-*.json")
if err != nil {
return nil, fmt.Errorf("download current manifest %q: %w", key, err)
}
defer func() { _ = os.Remove(localPath) }()
manifestStore := &manifest.LocalStore{}
m, err := manifestStore.Load(ctx, localPath)
if err != nil {
return nil, fmt.Errorf("current manifest decode failed: %w", err)
}
return m, nil
}
func LoadCurrentState(
ctx context.Context,
store storage.ObjectStore,
@@ -133,27 +67,19 @@ func LoadCurrentState(
if prefix == "" {
return nil, fmt.Errorf("session prefix is required")
}
currentManifestKey, currentRunIDKey := ResolveCurrentStateKeys(prefix)
runID, err := LoadCurrentRunPointer(ctx, store, currentRunIDKey)
if err != nil {
return nil, err
}
m, err := LoadCurrentManifest(ctx, store, currentManifestKey)
if err != nil {
return nil, err
if store == nil {
return nil, fmt.Errorf("object store is required")
}
state := &CurrentState{
SessionPrefix: prefix,
CurrentRunIDKey: currentRunIDKey,
CurrentManifestKey: currentManifestKey,
RunID: runID,
Manifest: m,
pointerKey := S3CurrentCommitPointerKey(prefix)
pointerExists, err := store.Exists(ctx, pointerKey)
if err != nil {
return nil, fmt.Errorf("check current commit pointer %q: %w", pointerKey, err)
}
if err := ValidateCurrentStateIdentity(state, validation); err != nil {
return nil, err
if pointerExists {
return loadCommittedCurrentState(ctx, store, prefix, pointerKey, validation)
}
return state, nil
return loadLegacyCurrentState(ctx, store, prefix, validation)
}
func ValidateCurrentStateIdentity(state *CurrentState, validation CurrentStateValidation) error {