crossprovider

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 15, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package crossprovider models explicit, provenance-preserving transfers between OSF and Zenodo without implying mirroring or publication.

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrInvalidCheckpoint  = errors.New("invalid cross-provider checkpoint")
	ErrCheckpointMismatch = errors.New("cross-provider checkpoint does not match mapping")
	ErrIrreversible       = errors.New("cross-provider transfer has crossed an irreversible boundary")
)
View Source
var (
	ErrIntegrityMismatch           = errors.New("cross-provider destination integrity mismatch")
	ErrPublicationApprovalRequired = errors.New("cross-provider publication requires separate exact confirmation")
	ErrPublicationOutcomeUnknown   = errors.New("cross-provider publication outcome is unknown; inspect destination before retrying")
)
View Source
var ErrInvalidRequest = errors.New("invalid cross-provider transfer request")

Functions

func PublicationChallenge

func PublicationChallenge(checkpoint Checkpoint) (string, error)

PublicationChallenge returns the only accepted confirmation for the pending publish step.

Types

type AccessKind

type AccessKind string

AccessKind preserves both OSF visibility and Zenodo access vocabularies.

const (
	AccessPublic     AccessKind = "public"
	AccessPrivate    AccessKind = "private"
	AccessOpen       AccessKind = "open"
	AccessEmbargoed  AccessKind = "embargoed"
	AccessRestricted AccessKind = "restricted"
	AccessClosed     AccessKind = "closed"
)

type AccessPolicy

type AccessPolicy struct {
	Kind         AccessKind `json:"kind"`
	EmbargoUntil *time.Time `json:"embargoUntil,omitempty"`
	Conditions   string     `json:"conditions,omitempty"`
}

AccessPolicy records access semantics that must not be inferred silently.

type Checkpoint

type Checkpoint struct {
	SchemaVersion  int            `json:"schemaVersion"`
	IdempotencyKey string         `json:"idempotencyKey"`
	Destination    Destination    `json:"destination"`
	Conflict       ConflictPolicy `json:"conflict"`
	PublishIntent  PublishIntent  `json:"publishIntent"`
	Status         SagaStatus     `json:"status"`
	DestinationRef string         `json:"destinationRef,omitempty"`
	Steps          []Step         `json:"steps"`
}

Checkpoint is a versioned, serializable saga state.

func Compensate

func Compensate(ctx context.Context, checkpoint Checkpoint, compensator Compensator) (Checkpoint, error)

Compensate applies the reverse draft-only plan and marks each recovered step.

func NewCheckpoint

func NewCheckpoint(report Report) (Checkpoint, error)

NewCheckpoint constructs deterministic ordered steps from an executable report.

func (Checkpoint) CompensationPlan

func (checkpoint Checkpoint) CompensationPlan() ([]CompensationAction, error)

CompensationPlan returns reversible completed actions in reverse order.

func (*Checkpoint) Complete

func (checkpoint *Checkpoint) Complete(stepID string, result StepResult) error

Complete advances exactly the next pending or failed step.

func (*Checkpoint) Fail

func (checkpoint *Checkpoint) Fail(stepID string, cause error) error

Fail records a redacted truthful partial result for the next executable step.

func (Checkpoint) PartialResult

func (checkpoint Checkpoint) PartialResult() (PartialResult, error)

PartialResult returns file-level outcomes and whether publication occurred.

func (Checkpoint) Validate

func (checkpoint Checkpoint) Validate() error

Validate rejects tampered or internally inconsistent checkpoints.

type CompensationAction

type CompensationAction struct {
	StepID         string           `json:"stepId"`
	Kind           CompensationKind `json:"kind"`
	DestinationRef string           `json:"destinationRef,omitempty"`
	ResourceRef    string           `json:"resourceRef,omitempty"`
	RollbackRef    string           `json:"rollbackRef,omitempty"`
	File           File             `json:"file,omitempty"`
}

CompensationAction is an ordered recovery instruction.

type CompensationKind

type CompensationKind string

CompensationKind describes a reversible draft-only action.

const (
	CompensationNone            CompensationKind = "none"
	CompensationDiscardDraft    CompensationKind = "discard_draft"
	CompensationDeleteFile      CompensationKind = "delete_file"
	CompensationRestoreFile     CompensationKind = "restore_file"
	CompensationRestoreMetadata CompensationKind = "restore_metadata"
)

type Compensator

type Compensator interface {
	Compensate(context.Context, CompensationAction) error
}

Compensator applies explicit draft-only recovery actions.

type ConflictPolicy

type ConflictPolicy string

ConflictPolicy controls destination collisions without implying mirroring.

const (
	ConflictFail          ConflictPolicy = "fail"
	ConflictSkipIdentical ConflictPolicy = "skip_identical"
	ConflictReplaceDraft  ConflictPolicy = "replace_draft"
)

type Creator

type Creator struct {
	Name string `json:"name"`
}

Creator is a normalized creator identity retained in provenance.

type Destination

type Destination struct {
	Provider  repository.Provider `json:"provider"`
	NativeID  string              `json:"nativeId,omitempty"`
	CreateNew bool                `json:"createNew"`
}

Destination identifies either a new destination record or a concrete draft.

type Direction

type Direction string

Direction names the only two supported provider-copy directions.

const (
	DirectionOSFToZenodo Direction = "osf_to_zenodo"
	DirectionZenodoToOSF Direction = "zenodo_to_osf"
)

type Disposition

type Disposition string

Disposition states how one source semantic is handled.

const (
	DispositionExact           Disposition = "exact"
	DispositionTransformed     Disposition = "transformed"
	DispositionPreservedNative Disposition = "preserved_native"
	DispositionBlocked         Disposition = "blocked"
)

type DraftDestination

type DraftDestination interface {
	CreateDraft(context.Context, string) (string, error)
	ApplyMetadata(context.Context, string, Metadata, Provenance, string) (string, error)
	CopyFile(context.Context, string, File, io.Reader, ConflictPolicy, string) (FileReceipt, error)
	VerifyDraft(context.Context, string, Report, string) error
	FinalizeDraft(context.Context, string, Report, string) error
}

DraftDestination performs idempotency-keyed, unpublished destination writes.

type ExecutionResult

type ExecutionResult struct {
	Checkpoint Checkpoint    `json:"checkpoint"`
	Partial    PartialResult `json:"partial"`
}

ExecutionResult always includes the latest truthful checkpoint and partial result.

func Execute

func Execute(ctx context.Context, report Report, checkpoint Checkpoint, source SourceReader, destination DraftDestination) (ExecutionResult, error)

Execute advances draft-only steps and never performs publication.

func Publish

func Publish(ctx context.Context, report Report, checkpoint Checkpoint, publisher Publisher, confirmation string) (ExecutionResult, error)

Publish executes only an already-pending publication step with exact confirmation.

type FieldMapping

type FieldMapping struct {
	SourceField string      `json:"sourceField"`
	TargetField string      `json:"targetField,omitempty"`
	Disposition Disposition `json:"disposition"`
	Reason      string      `json:"reason,omitempty"`
}

FieldMapping makes semantic preservation or loss explicit.

type File

type File struct {
	Path      string `json:"path"`
	Size      int64  `json:"size"`
	Checksum  string `json:"checksum"`
	MediaType string `json:"mediaType,omitempty"`
}

File is a logical source file with integrity metadata.

type FileReceipt

type FileReceipt struct {
	ResourceRef string `json:"resourceRef"`
	RollbackRef string `json:"rollbackRef,omitempty"`
	Size        int64  `json:"size"`
	Checksum    string `json:"checksum"`
	Skipped     bool   `json:"skipped"`
}

FileReceipt is the destination's integrity and recovery acknowledgement.

type Identifier

type Identifier struct {
	Scheme string `json:"scheme"`
	Value  string `json:"value"`
}

Identifier preserves a typed persistent or provider-native identifier.

type LocalSource

type LocalSource struct {
	Root string
}

LocalSource confines validation inputs to regular, non-symlink files below Root.

func (LocalSource) Open

func (source LocalSource) Open(_ context.Context, file File) (io.ReadCloser, error)

Open implements SourceReader without allowing absolute paths or traversal.

type Metadata

type Metadata struct {
	Title       string       `json:"title"`
	Description string       `json:"description"`
	UploadType  string       `json:"uploadType"`
	Creators    []Creator    `json:"creators"`
	Keywords    []string     `json:"keywords,omitempty"`
	Access      AccessPolicy `json:"access"`
	License     string       `json:"license,omitempty"`
	Identifiers []Identifier `json:"identifiers,omitempty"`
	Version     string       `json:"version,omitempty"`
}

Metadata is the common mapping vocabulary. Provider-native metadata remains separate.

type PartialExecutionError

type PartialExecutionError struct {
	StepID string
	Cause  error
}

PartialExecutionError identifies the step that stopped safe execution.

func (*PartialExecutionError) Error

func (err *PartialExecutionError) Error() string

func (*PartialExecutionError) Unwrap

func (err *PartialExecutionError) Unwrap() error

type PartialResult

type PartialResult struct {
	Status             SagaStatus `json:"status"`
	DestinationRef     string     `json:"destinationRef,omitempty"`
	CompletedFiles     []File     `json:"completedFiles,omitempty"`
	FailedFiles        []File     `json:"failedFiles,omitempty"`
	PendingFiles       []File     `json:"pendingFiles,omitempty"`
	CompensatedFiles   []File     `json:"compensatedFiles,omitempty"`
	AbandonedFiles     []File     `json:"abandonedFiles,omitempty"`
	Published          bool       `json:"published"`
	PublicationOutcome string     `json:"publicationOutcome"`
}

PartialResult reports file and lifecycle outcomes without claiming completion.

type Provenance

type Provenance struct {
	SourceIdentity       repository.QualifiedID `json:"sourceIdentity"`
	DestinationProvider  repository.Provider    `json:"destinationProvider"`
	CapturedAt           time.Time              `json:"capturedAt"`
	NativeMetadataSHA256 string                 `json:"nativeMetadataSha256"`
	Transformations      []FieldMapping         `json:"transformations"`
}

Provenance binds a report to the source and its native metadata digest.

type PublishIntent

type PublishIntent string

PublishIntent makes destination publication intent explicit during planning.

const (
	PublishDraftOnly PublishIntent = "draft_only"
	PublishAfterCopy PublishIntent = "publish_after_copy"
)

type Publisher

type Publisher interface {
	Publish(context.Context, string, string) error
}

Publisher is deliberately separate from DraftDestination.

type Report

type Report struct {
	Direction      Direction      `json:"direction"`
	Destination    Destination    `json:"destination"`
	PublishIntent  PublishIntent  `json:"publishIntent"`
	Conflict       ConflictPolicy `json:"conflict"`
	Target         Metadata       `json:"target"`
	Files          []File         `json:"files"`
	Fields         []FieldMapping `json:"fields"`
	NativeFields   []FieldMapping `json:"nativeFields,omitempty"`
	Blockers       []string       `json:"blockers,omitempty"`
	Executable     bool           `json:"executable"`
	IdempotencyKey string         `json:"idempotencyKey"`
	Provenance     Provenance     `json:"provenance"`
}

Report is a dry-run mapping decision. It never performs a provider write.

func BuildMapping

func BuildMapping(request Request, capturedAt time.Time) (Report, error)

BuildMapping validates explicit intent and returns a deterministic dry-run report.

type Request

type Request struct {
	Direction     Direction      `json:"direction"`
	Source        Snapshot       `json:"source"`
	Destination   Destination    `json:"destination"`
	Authorized    bool           `json:"authorized"`
	PublishIntent PublishIntent  `json:"publishIntent"`
	Conflict      ConflictPolicy `json:"conflict"`
	TargetAccess  *AccessPolicy  `json:"targetAccess,omitempty"`
	TargetLicense string         `json:"targetLicense,omitempty"`
}

Request is the complete caller intent required before planning.

type SagaStatus

type SagaStatus string

SagaStatus is the truthful aggregate state of a transfer checkpoint.

const (
	SagaPending            SagaStatus = "pending"
	SagaRunning            SagaStatus = "running"
	SagaPartial            SagaStatus = "partial"
	SagaCompleted          SagaStatus = "completed"
	SagaCompensating       SagaStatus = "compensating"
	SagaCompensationFailed SagaStatus = "compensation_failed"
	SagaCompensated        SagaStatus = "compensated"
)

type Snapshot

type Snapshot struct {
	Identity       repository.QualifiedID    `json:"identity"`
	Metadata       Metadata                  `json:"metadata"`
	Files          []File                    `json:"files"`
	NativeMetadata repository.NativeMetadata `json:"nativeMetadata"`
}

Snapshot is an immutable transfer input captured by a concrete provider adapter.

type SourceReader

type SourceReader interface {
	Open(context.Context, File) (io.ReadCloser, error)
}

SourceReader opens one file from the immutable source snapshot.

type Step

type Step struct {
	ID                   string           `json:"id"`
	Kind                 StepKind         `json:"kind"`
	State                StepState        `json:"state"`
	File                 File             `json:"file,omitempty"`
	Attempts             int              `json:"attempts"`
	Error                string           `json:"error,omitempty"`
	DestinationRef       string           `json:"destinationRef,omitempty"`
	RollbackRef          string           `json:"rollbackRef,omitempty"`
	Skipped              bool             `json:"skipped,omitempty"`
	Compensation         CompensationKind `json:"compensation"`
	RequiresConfirmation bool             `json:"requiresConfirmation"`
}

Step records one operation and enough information for replay/compensation.

func Resume

func Resume(report Report, checkpoint Checkpoint) ([]Step, error)

Resume validates report/checkpoint identity and returns the remaining steps.

type StepKind

type StepKind string

StepKind identifies one ordered transfer operation.

const (
	StepCreateDestination StepKind = "create_destination"
	StepApplyMetadata     StepKind = "apply_metadata"
	StepCopyFile          StepKind = "copy_file"
	StepVerifyDraft       StepKind = "verify_draft"
	StepFinalizeDraft     StepKind = "finalize_draft"
	StepPublish           StepKind = "publish"
)

type StepResult

type StepResult struct {
	DestinationRef string `json:"destinationRef,omitempty"`
	RollbackRef    string `json:"rollbackRef,omitempty"`
	Skipped        bool   `json:"skipped,omitempty"`
}

StepResult records non-secret output required by later or compensating steps.

type StepState

type StepState string

StepState is a replay-safe operation state.

const (
	StepPending     StepState = "pending"
	StepCompleted   StepState = "completed"
	StepFailed      StepState = "failed"
	StepCompensated StepState = "compensated"
	StepAbandoned   StepState = "abandoned"
)

type ZenodoSandboxDestination

type ZenodoSandboxDestination struct {
	// contains filtered or unexported fields
}

ZenodoSandboxDestination applies cross-provider writes to unpublished Zenodo sandbox depositions. It intentionally does not implement Publisher.

func NewZenodoSandboxDestination

func NewZenodoSandboxDestination(baseURL, token string) (*ZenodoSandboxDestination, error)

NewZenodoSandboxDestination creates a deposit:write-only destination.

func (*ZenodoSandboxDestination) ApplyMetadata

func (destination *ZenodoSandboxDestination) ApplyMetadata(ctx context.Context, draftID string, metadata Metadata, _ Provenance, _ string) (string, error)

func (*ZenodoSandboxDestination) Compensate

func (destination *ZenodoSandboxDestination) Compensate(ctx context.Context, action CompensationAction) error

func (*ZenodoSandboxDestination) CopyFile

func (destination *ZenodoSandboxDestination) CopyFile(ctx context.Context, draftID string, file File, reader io.Reader, conflict ConflictPolicy, stepID string) (FileReceipt, error)

func (*ZenodoSandboxDestination) CreateDraft

func (destination *ZenodoSandboxDestination) CreateDraft(ctx context.Context, stepID string) (string, error)

func (*ZenodoSandboxDestination) FinalizeDraft

func (destination *ZenodoSandboxDestination) FinalizeDraft(ctx context.Context, draftID string, report Report, stepID string) error

func (*ZenodoSandboxDestination) VerifyDraft

func (destination *ZenodoSandboxDestination) VerifyDraft(ctx context.Context, draftID string, report Report, _ string) error

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL