recording

package
v1.0.0-beta2 Latest Latest
Warning

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

Go to latest
Published: Oct 6, 2026 License: Apache-2.0 Imports: 37 Imported by: 0

Documentation

Index

Constants

View Source
const (
	CastVersion = 3

	MaximumCastLineBytes    = 1 << 20
	MaximumOutputEventBytes = 64 << 10
	DefaultMaximumCastBytes = int64(16 << 30)

	MaximumCastTerminalDimension = uint32(1<<16 - 1)
	MaximumCastExitStatus        = uint32(1<<31 - 1)
)
View Source
const (
	NativeEventSetup uint8 = iota + 1
	NativeEventOutput
	NativeEventResize
	NativeEventMarker
	NativeEventPaddingCheckpoint
	NativeEventResult
)
View Source
const (
	DefaultMaximumNativeRecordingBytes  = int64(32 << 30)
	DefaultMaximumNativeRecordingChunks = 1 << 18
)
View Source
const DefaultNativeRecordingChunkTarget = 256 << 10

Variables

This section is empty.

Functions

func EncodeNativeRecordingEvents

func EncodeNativeRecordingEvents(events []NativeCastEvent) ([]byte, error)

EncodeNativeRecordingEvents emits only deterministic integer-key CBOR maps. Cross-chunk ordering and exact Cast semantics are checked by the renderer.

func RenderNativeRecordingCast

func RenderNativeRecordingCast(groups [][]byte, header NativeRecordingHeader, seal NativeRecordingSeal, maximumCastBytes int64) ([]byte, error)

RenderNativeRecordingCast reconstructs and fully verifies the signed Cast before returning any bytes. The caller must first verify the outer container and supply its authenticated header/seal and independently decoded groups.

func VerifyNativeRecordingCheckpoint

func VerifyNativeRecordingCheckpoint(source io.ReaderAt, size int64, headPayload []byte, identity *audit.Identity, options NativeRecordingVerifyOptions) error

VerifyNativeRecordingCheckpoint authenticates an exact committed prefix of an already sealed recording without requiring its encryption recipient or any mutation capability. The caller must verify the complete seal as well.

Types

type ActiveNativeRecording

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

func (*ActiveNativeRecording) Checkpoint

func (a *ActiveNativeRecording) Checkpoint() error

func (*ActiveNativeRecording) Close

func (a *ActiveNativeRecording) Close() error

func (*ActiveNativeRecording) Seal

func (a *ActiveNativeRecording) Seal(elapsed time.Duration, result CastResult, exitStatus *uint32) (NativeRecordingSummary, error)

func (*ActiveNativeRecording) WriteMarker

func (a *ActiveNativeRecording) WriteMarker(elapsed time.Duration, label string) error

func (*ActiveNativeRecording) WriteOutput

func (a *ActiveNativeRecording) WriteOutput(elapsed time.Duration, stream OutputStream, data []byte) error

func (*ActiveNativeRecording) WriteResize

func (a *ActiveNativeRecording) WriteResize(elapsed time.Duration, columns, rows uint32) error

type ArtifactDigest

type ArtifactDigest = audit.ArtifactDigest

ArtifactDigest identifies the exact bytes of a sealed recording container. It is distinct from CastDigest, which identifies the canonical Cast content.

type CastDigest

type CastDigest [sha256.Size]byte

func (CastDigest) IsZero

func (this CastDigest) IsZero() bool

func (CastDigest) MarshalText

func (this CastDigest) MarshalText() ([]byte, error)

func (CastDigest) String

func (this CastDigest) String() string

func (*CastDigest) UnmarshalText

func (this *CastDigest) UnmarshalText(text []byte) error

type CastHeader

type CastHeader struct {
	Version   int          `json:"version"`
	Terminal  CastTerminal `json:"term"`
	Timestamp int64        `json:"timestamp"`
}

type CastMetadata

type CastMetadata struct {
	RecordingId  Id                     `json:"recordingId"`
	ConnectionId connection.Id          `json:"connectionId"`
	SessionId    session.Id             `json:"sessionId"`
	OperationId  uuid.UUID              `json:"operationId"`
	Flow         configuration.FlowName `json:"flow"`
	Task         audit.SessionTask      `json:"task"`
	Pty          bool                   `json:"pty"`
	ProducerId   audit.ProducerId       `json:"producerId"`
	StartedAt    time.Time              `json:"startedAt"`
}

type CastResult

type CastResult struct {
	Status  CastStatus `json:"status"`
	EndedAt time.Time  `json:"endedAt"`
	Reason  string     `json:"reason,omitempty"`
}

type CastStatus

type CastStatus string
const (
	CastStatusCompleted  CastStatus = "completed"
	CastStatusFailed     CastStatus = "failed"
	CastStatusIncomplete CastStatus = "incomplete"
)

type CastTerminal

type CastTerminal struct {
	Columns uint32 `json:"cols"`
	Rows    uint32 `json:"rows"`
	Type    string `json:"type,omitempty"`
}

func (CastTerminal) Validate

func (this CastTerminal) Validate() error

type CastVerification

type CastVerification struct {
	Header       CastHeader
	Metadata     CastMetadata
	Result       CastResult
	ExitStatus   *uint32
	EventCount   uint64
	OutputEvents uint64
	ResizeEvents uint64
	MarkerEvents uint64
	Digest       CastDigest
	Fingerprint  string
	Trusted      bool
}

func VerifyCast

func VerifyCast(input io.Reader, options CastVerifyOptions) (*CastVerification, error)

type CastVerifyOptions

type CastVerifyOptions struct {
	Context            context.Context
	MaximumBytes       int64
	ExpectedProducerId audit.ProducerId
	AllowUntrusted     bool
}

type CastWriter

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

func NewCastWriter

func NewCastWriter(output io.Writer, identity *audit.Identity, header CastHeader, metadata CastMetadata) (*CastWriter, error)

func (*CastWriter) Seal

func (this *CastWriter) Seal(elapsed time.Duration, result CastResult, exitStatus *uint32) (CastDigest, error)

func (*CastWriter) WriteMarker

func (this *CastWriter) WriteMarker(elapsed time.Duration, label string) error

func (*CastWriter) WriteOutput

func (this *CastWriter) WriteOutput(elapsed time.Duration, stream OutputStream, data []byte) error

func (*CastWriter) WriteResize

func (this *CastWriter) WriteResize(elapsed time.Duration, columns, rows uint32) error

type Format

type Format string
const (
	FormatCast       Format = "cast/v3"
	FormatBcast      Format = "bcast/v1"
	FormatBECastCBOR Format = "becast-cbor/v1"
)

func DetectFormat

func DetectFormat(source io.ReaderAt, size int64) (Format, error)

DetectFormat identifies a Recording by its content without verifying it.

type Id

type Id uuid.UUID

func NewId

func NewId() (Id, error)

func (Id) IsZero

func (this Id) IsZero() bool

func (Id) MarshalText

func (this Id) MarshalText() ([]byte, error)

func (Id) String

func (this Id) String() string

func (*Id) UnmarshalText

func (this *Id) UnmarshalText(text []byte) error

type InspectOptions

type InspectOptions struct {
	Context               context.Context
	MaximumContainerBytes int64
	MaximumCastBytes      int64
	MaximumChunks         uint64
	ExpectedProducerId    audit.ProducerId
	AllowUntrusted        bool
}

type Inspection

type Inspection struct {
	Format Format
	Cast   *CastVerification
	Native *NativeRecordingVerification
}

func Inspect

func Inspect(source io.ReaderAt, size int64, options InspectOptions) (*Inspection, error)

Inspect verifies one Recording artifact and identifies its format. Encrypted native content is not decrypted; only its signed outer container is inspected. Clear native content is fully verified.

type LocalNativeRecordingRepository

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

func NewLocalNativeRecordingRepository

func NewLocalNativeRecordingRepository(ctx context.Context, directory string, identity *audit.Identity, recipient *bfcrypto.AgeSshRecipient, options NativeRecordingVerifyOptions, repositoryOptions LocalRepositoryOptions) (*LocalNativeRecordingRepository, error)

func NewLocalNativeRecordingRepositoryWithArtifactPreparer

func NewLocalNativeRecordingRepositoryWithArtifactPreparer(ctx context.Context, directory string, identity *audit.Identity, recipient *bfcrypto.AgeSshRecipient, options NativeRecordingVerifyOptions, repositoryOptions LocalRepositoryOptions, preparer SealedArtifactPreparer) (*LocalNativeRecordingRepository, error)

func (*LocalNativeRecordingRepository) Close

func (*LocalNativeRecordingRepository) CloseAfterAcceptedFailure

func (r *LocalNativeRecordingRepository) CloseAfterAcceptedFailure() error

func (*LocalNativeRecordingRepository) CreateActive

func (r *LocalNativeRecordingRepository) CreateActive(ctx context.Context, header CastHeader, metadata CastMetadata, chunkTarget int) (*ActiveNativeRecording, error)

func (*LocalNativeRecordingRepository) DeleteSealed

func (r *LocalNativeRecordingRepository) DeleteSealed(ctx context.Context, id Id, digest ArtifactDigest, size int64) (bool, error)

func (*LocalNativeRecordingRepository) ListSealed

func (r *LocalNativeRecordingRepository) ListSealed(ctx context.Context) ([]Id, error)

func (*LocalNativeRecordingRepository) OpenSealed

func (*LocalNativeRecordingRepository) RecordingStateExists

func (r *LocalNativeRecordingRepository) RecordingStateExists(id Id) (bool, error)

func (*LocalNativeRecordingRepository) StartupRecoveries

type LocalRepositoryOptions

type LocalRepositoryOptions struct {
	MaximumSpoolBytes uint64
	RecordingOnly     bool
}

type LocalSealedArtifact

type LocalSealedArtifact[Summary any] struct {
	// contains filtered or unexported fields
}

LocalSealedArtifact is a signature-verified, read-only handle to one local recording. ArtifactDigest describes the bytes observed while the handle was opened. Callers must keep repository storage private from processes that can modify read-only files. The caller owns the handle and must close it.

func (*LocalSealedArtifact[Summary]) ArtifactDigest

func (this *LocalSealedArtifact[Summary]) ArtifactDigest() ArtifactDigest

func (*LocalSealedArtifact[Summary]) Close

func (this *LocalSealedArtifact[Summary]) Close() error

func (*LocalSealedArtifact[Summary]) FileName

func (this *LocalSealedArtifact[Summary]) FileName() string

func (*LocalSealedArtifact[Summary]) ProducerId

func (this *LocalSealedArtifact[Summary]) ProducerId() audit.ProducerId

func (*LocalSealedArtifact[Summary]) ReadAt

func (this *LocalSealedArtifact[Summary]) ReadAt(target []byte, offset int64) (int, error)

func (*LocalSealedArtifact[Summary]) Reader

func (this *LocalSealedArtifact[Summary]) Reader() io.Reader

func (*LocalSealedArtifact[Summary]) RecordingId

func (this *LocalSealedArtifact[Summary]) RecordingId() Id

func (*LocalSealedArtifact[Summary]) RemoteArtifact

func (this *LocalSealedArtifact[Summary]) RemoteArtifact() (audit.RemoteArtifact, error)

RemoteArtifact adapts this open handle for synchronous remote publication. The caller must keep the LocalSealedArtifact open until publication returns.

func (*LocalSealedArtifact[Summary]) Size

func (this *LocalSealedArtifact[Summary]) Size() int64

func (*LocalSealedArtifact[Summary]) Summary

func (this *LocalSealedArtifact[Summary]) Summary() Summary

type NativeCastEvent

type NativeCastEvent struct {
	Kind       uint8
	Header     CastHeader
	Metadata   CastMetadata
	Elapsed    time.Duration
	Stream     OutputStream
	Data       []byte
	Columns    uint32
	Rows       uint32
	Label      string
	Result     CastResult
	ExitStatus *uint32
}

NativeCastEvent is one complete CBOR event, not a Cast line. Elapsed is an absolute nanosecond duration. Output is already split into <=64 KiB events.

type NativeDurableRecordingOutput

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

NativeDurableRecordingOutput requires an exclusively owned, empty, regular read/write file opened WITHOUT O_APPEND. It doesn't own the file or sync its parent directory; the repository adapter must do both directory sync and atomic head replacement before publishing. Any failure poisons the sink.

func NewNativeDurableRecordingOutput

func NewNativeDurableRecordingOutput(file nativeCommitFile) (*NativeDurableRecordingOutput, error)

func (*NativeDurableRecordingOutput) CommitNativeRecordingUnit

func (d *NativeDurableRecordingOutput) CommitNativeRecordingUnit(frame []byte) error

func (*NativeDurableRecordingOutput) Write

func (d *NativeDurableRecordingOutput) Write(value []byte) (int, error)

type NativeRecordingChunk

type NativeRecordingChunk = nativeRecordingChunk

type NativeRecordingHead

type NativeRecordingHead struct {
	Version       uint8    `cbor:"1,keyasint"`
	RecordingId   [16]byte `cbor:"2,keyasint"`
	ProducerId    [32]byte `cbor:"3,keyasint"`
	PrefixBytes   uint64   `cbor:"4,keyasint"`
	ChunkCount    uint64   `cbor:"5,keyasint"`
	LastUnitHash  [32]byte `cbor:"6,keyasint"`
	CastHashState [32]byte `cbor:"7,keyasint"`
	CastHashBytes uint64   `cbor:"8,keyasint"`
	Signature     []byte   `cbor:"9,keyasint"`
}

func VerifyNativeRecordingHead

func VerifyNativeRecordingHead(payload, headerPayload []byte) (NativeRecordingHead, error)

VerifyNativeRecordingHead checks head.cbor against an authenticated header. The adapter must additionally match every head field to its exact durable prefix before treating it as a recovery checkpoint.

type NativeRecordingHeader

type NativeRecordingHeader = nativeRecordingHeader

These aliases expose the fixed version-1 wire fields to a future repository adapter without changing the CBOR schemas in native-wire.go.

type NativeRecordingRecoveryResult

type NativeRecordingRecoveryResult struct {
	Verification  *NativeRecordingVerification
	AlreadySealed bool
	Truncated     bool
	Finalized     bool
}

func RecoverNativeRecording

func RecoverNativeRecording(file NativeRecoveryFile, identity *audit.Identity, recipient *bfcrypto.AgeSshRecipient, headPayload []byte, recoveredAt time.Time, options NativeRecordingVerifyOptions) (*NativeRecordingRecoveryResult, error)

RecoverNativeRecording verifies every committed unit and the exact signed head checkpoint before changing the file. It never decrypts stored chunks. The caller must hold an exclusive lock throughout, then sync the parent directory and publish only after the returned sealed file is verified.

type NativeRecordingSeal

type NativeRecordingSeal = nativeRecordingSeal

type NativeRecordingSigner

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

func NewNativeRecordingSigner

func NewNativeRecordingSigner(identity *audit.Identity) (*NativeRecordingSigner, error)

func (*NativeRecordingSigner) Chunk

func (s *NativeRecordingSigner) Chunk(c nativeRecordingChunk) ([]byte, error)

Chunk signs a bounded, already compressed (and optionally encrypted) CBOR event group. This primitive does not certify inner event or Cast semantics.

func (*NativeRecordingSigner) Head

Head returns canonical signed head.cbor bytes. Persist only after syncing the committed prefix; replace atomically and sync its parent directory.

func (*NativeRecordingSigner) Header

func (s *NativeRecordingSigner) Header(id Id, startedAt time.Time, recipient string) ([]byte, error)

Header signs a header payload; the adapter frames and commits it after the recording magic. An empty recipient means clear .bcast.

func (*NativeRecordingSigner) Seal

func (s *NativeRecordingSigner) Seal(seal nativeRecordingSeal, id Id) ([]byte, error)

Seal requires a previously signed standalone Cast digest and signature.

type NativeRecordingSummary

type NativeRecordingSummary struct {
	RecordingId          Id
	ProducerId           audit.ProducerId
	RecipientFingerprint string
	Status               CastStatus
	ChunkCount           uint64
	CastBytes            uint64
	Digest               CastDigest
	Bytes                uint64
}

type NativeRecordingUnitCommitter

type NativeRecordingUnitCommitter interface {
	io.Writer
	CommitNativeRecordingUnit(frame []byte) error
}

NativeRecordingUnitCommitter is an optional io.Writer extension. Its Write method accepts and syncs only the recording magic; each encoded unit is handed to CommitNativeRecordingUnit in its state-1 form. The implementation must sync the complete state-0 frame before writing and syncing state 1.

type NativeRecordingVerification

type NativeRecordingVerification struct {
	Header  NativeRecordingHeader
	Seal    NativeRecordingSeal
	Trusted bool
}

func ExportNativeRecordingCast

func ExportNativeRecordingCast(source io.ReaderAt, size int64, identities *bfcrypto.AgeSshIdentities, output io.Writer, options NativeRecordingVerifyOptions) (*NativeRecordingVerification, error)

ExportNativeRecordingCast emits nothing until the entire Cast passes full verification. The second pass requires the *same immutable input*. A failing output writer may still leave a partial, already verified export; callers publishing to a file must use their own atomic temporary-file protocol.

func VerifyNativeRecordingFull

func VerifyNativeRecordingFull(source io.ReaderAt, size int64, identities *bfcrypto.AgeSshIdentities, options NativeRecordingVerifyOptions) (*NativeRecordingVerification, error)

VerifyNativeRecordingFull checks the outer container before independently decoding every chunk and verifying the reconstructed Cast through a pipe. The source must remain an immutable ReaderAt snapshot for all passes.

func VerifyNativeRecordingOuter

func VerifyNativeRecordingOuter(source io.ReaderAt, size int64, options NativeRecordingVerifyOptions) (*NativeRecordingVerification, error)

VerifyNativeRecordingOuter authenticates the entire committed envelope but does not claim semantic validity for the inner CBOR event maps. No export should consume its result as proof of full verification. The ReaderAt must remain an immutable snapshot throughout verification.

type NativeRecordingVerifyOptions

type NativeRecordingVerifyOptions struct {
	ExpectedProducerId    audit.ProducerId
	AllowUntrusted        bool
	MaximumContainerBytes int64
	MaximumCastBytes      int64
	MaximumChunks         uint64
	Context               context.Context
}

type NativeRecordingWriter

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

NativeRecordingWriter emits signed framed units. Plain io.Writer is only for in-memory/tests: it cannot durably sync the body and commit bit. A NativeRecordingUnitCommitter (such as NativeDurableRecordingOutput) commits each unit before the writer updates its hash chain. The repository still owns locking, quota, signed-head replacement and directory sync.

func NewNativeRecordingWriter

func NewNativeRecordingWriter(output io.Writer, identity *audit.Identity, recipient *bfcrypto.AgeSshRecipient, header CastHeader, metadata CastMetadata, chunkTarget int, options NativeRecordingWriterLimits) (*NativeRecordingWriter, error)

func (*NativeRecordingWriter) Checkpoint

func (w *NativeRecordingWriter) Checkpoint() ([]byte, error)

Checkpoint returns signed head.cbor bytes for the last completed chunk. It must be persisted only after the owning adapter has committed and synced the exact prefix, atomically replaced head.cbor, and synced its directory.

func (*NativeRecordingWriter) Flush

func (w *NativeRecordingWriter) Flush() error

Flush ends a nonfinal group with exactly the same Cast padding comment as the decoder will regenerate. Plain io.Writer has no durability guarantee.

func (*NativeRecordingWriter) Seal

func (w *NativeRecordingWriter) Seal(elapsed time.Duration, result CastResult, exitStatus *uint32) (NativeRecordingSummary, error)

Seal writes the final signed chunk and seal. It never writes a .cast file.

func (*NativeRecordingWriter) WriteMarker

func (w *NativeRecordingWriter) WriteMarker(elapsed time.Duration, label string) error

func (*NativeRecordingWriter) WriteOutput

func (w *NativeRecordingWriter) WriteOutput(elapsed time.Duration, stream OutputStream, data []byte) error

func (*NativeRecordingWriter) WriteResize

func (w *NativeRecordingWriter) WriteResize(elapsed time.Duration, columns, rows uint32) error

type NativeRecordingWriterLimits

type NativeRecordingWriterLimits struct {
	MaximumContainerBytes int64
	MaximumCastBytes      int64
	MaximumChunks         uint64
}

type NativeRecoveryFile

type NativeRecoveryFile interface {
	RecoveryFile
	io.WriterAt
}

NativeRecoveryFile must be exclusively locked by its owner. The writer uses WriteAt rather than append mode to commit a complete frame only after Sync.

type OutputStream

type OutputStream string
const (
	OutputStreamTerminal OutputStream = "terminal"
	OutputStreamStdout   OutputStream = "stdout"
	OutputStreamStderr   OutputStream = "stderr"
)

type RecoveredNativeRecording

type RecoveredNativeRecording struct {
	Summary       NativeRecordingSummary
	Truncated     bool
	AlreadySealed bool
}

type RecoveryFile

type RecoveryFile interface {
	io.ReaderAt
	io.Writer
	io.Seeker
	Truncate(size int64) error
	Sync() error
}

type SealedArtifactLifecyclePreparer

type SealedArtifactLifecyclePreparer interface {
	PrepareLifecycle(context.Context, audit.RemoteArtifact, time.Time, CastDigest, bool) error
	PromoteLifecycle(context.Context, audit.RemoteArtifact) error
}

type SealedArtifactPreparer

type SealedArtifactPreparer interface {
	Prepare(context.Context, audit.RemoteArtifact, time.Time) error
	Require(context.Context, audit.RemoteArtifact) error
}

SealedArtifactPreparer persists and validates metadata required by a sealed artifact before publication and during crash recovery.

type SealedArtifactQuotaBinder

type SealedArtifactQuotaBinder interface {
	BindSealedArtifactQuota(audit.RemoteArtifactReceiptQuota)
}

type SealedArtifactStateCleaner

type SealedArtifactStateCleaner interface {
	CleanupOrphanedSealedArtifactState(context.Context) error
}

type SealedArtifactStateRecoverer

type SealedArtifactStateRecoverer interface {
	RecoverSealedArtifactState(context.Context) error
}

SealedArtifactStateRecoverer repairs preparer-owned state before the local repository recovers recordings that may require spool capacity.

Jump to

Keyboard shortcuts

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