reportjson

package
v0.2.1 Latest Latest
Warning

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

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

Documentation

Overview

Package reportjson is the versioned, redacted JSON codec for eval reports and a file sink that persists them. It is the report's untrusted deserialization boundary: a report is one report/v1 envelope carrying an explicit version discriminator and a payload. Decode reads the version first and rejects unknown or missing versions before trusting the payload (fail-closed), bounds the input size, requires exactly one valid-UTF-8 JSON value, and validates the reconstructed assessments against the strict eval domain types.

The wire form is REDACTED BY DEFAULT and CANONICAL. It carries only safe fields: sample and evaluator identities, assessment statuses, finite measurements, finding CODES and severities (never a finding's free-text message), already-redacted evidence payloads (hashes, classifications, counts, message indexes, redacted excerpts — never raw text), provenance, timings, and a safe classification of any target-stage error (never its raw cause). It never marshals the raw Observation (conversation text, tool arguments/results, or the raw trace); the design records reports as redacted evidence plus references to separately controlled raw traces. Decoding therefore yields the redacted projection: Samples[].Observation is the zero value and Finding.Message is empty. The JSON form is not a lossless Observation round-trip; it IS a byte-stable fixed point over the safe fields.

Encoding is deterministic: samples, assessments, measurements, findings, and evidence are emitted in a canonical order independent of input order, and the Summary status map is emitted in a fixed status order rather than map-iteration order. Non-finite measurement values are rejected fail-closed.

Index

Constants

View Source
const MaxReportBytes = 64 << 20 // 64 MiB

MaxReportBytes bounds an encoded report at the untrusted decode boundary. It rejects an oversized document before it can exhaust memory. Conservative starting value; tune to real report sizes later.

Variables

This section is empty.

Functions

func Decode

func Decode(data []byte) (eval.Report, error)

Decode reads a report/v1 document and returns the redacted report view. It is the untrusted boundary and the fuzz target: for any input it returns either a valid redacted report or a typed error, and never panics. Enforced in order: the size bound, valid UTF-8, exactly one JSON value (no trailing data), a known version, strict field decoding, finite measurement values, domain validation of every reconstructed assessment, and finally the whole-report invariants via eval.Report.Validate (identity, timestamp ordering, trial indexes, sample and evaluator uniqueness, and summary/provenance consistency).

func Encode

func Encode(r eval.Report) ([]byte, error)

Encode serializes a valid report to its canonical, redacted report/v1 wire form. It rejects a report that fails eval.Report.Validate before JSON serialization can normalize a malformed identity, rejects any non-finite measurement value fail-closed, drops all raw content (conversation, finding messages, target-error causes), and emits every collection in a canonical order so the same report always encodes to identical bytes.

Types

type DecodedTargetError

type DecodedTargetError struct {
	Class TargetErrorClass
}

DecodedTargetError is the typed, content-free cause reconstructed from a decoded report's safe target-error classification. A decoded report's SampleReport.TargetErr wraps one of these instead of the original (unrecovered) cause, so callers can still classify the failure via errors.As without any raw cause text ever having been serialized.

func (*DecodedTargetError) Error

func (e *DecodedTargetError) Error() string

type DirectoryError

type DirectoryError struct {
	Dir   string
	Cause error
}

DirectoryError reports that the sink directory itself could not be opened as an os.Root. Dir is the caller-supplied (safe) directory; Cause is exposed via Unwrap.

func (*DirectoryError) Error

func (e *DirectoryError) Error() string

func (*DirectoryError) Unwrap

func (e *DirectoryError) Unwrap() error

type EncodeError

type EncodeError struct {
	Cause error
}

EncodeError reports that a report could not be serialized. Cause is exposed via Unwrap. It is an encode-side failure, not a decode-boundary rejection.

func (*EncodeError) Error

func (e *EncodeError) Error() string

func (*EncodeError) Unwrap

func (e *EncodeError) Unwrap() error

type FileSink

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

FileSink writes each report as a redacted report/v1 JSON file under a fixed directory. The zero value is not usable; construct one with NewFileSink. It is safe for concurrent use: each WriteReport opens its own os.Root and uses a randomly named temp file, so concurrent writes of distinct reports do not collide.

func NewFileSink

func NewFileSink(dir string) *FileSink

NewFileSink returns a FileSink that writes reports under dir. The directory must already exist; it is opened as an os.Root on each write so a report ID cannot escape it. dir is treated as a safe, caller-supplied locator.

func (*FileSink) WriteReport

func (s *FileSink) WriteReport(ctx context.Context, r eval.Report) error

WriteReport encodes r to its canonical redacted wire form and writes it atomically to <dir>/<id>.json. It fails closed: a report ID that is empty, contains a path separator, is a traversal element, or resolves outside the sink root is refused with a typed error and nothing is written. The context is honoured before the write begins.

type InvalidReportError

type InvalidReportError struct {
	Cause error
}

InvalidReportError reports that a decoded report was well-formed JSON but a reconstructed part failed domain validation. Cause is the eval package's own typed validation error — itself free of untrusted content — and is exposed via Unwrap so callers can classify it.

func (*InvalidReportError) Error

func (e *InvalidReportError) Error() string

func (*InvalidReportError) Unwrap

func (e *InvalidReportError) Unwrap() error

type InvalidReportIDError

type InvalidReportIDError struct {
	Reason string
}

InvalidReportIDError reports that a report's ID could not be used as a single, safe filename component (it was empty, or contained a path separator or a "." or ".." traversal element). Reason is drawn from a fixed vocabulary; the offending ID is caller-supplied and withheld.

func (*InvalidReportIDError) Error

func (e *InvalidReportIDError) Error() string

type MalformedReportError

type MalformedReportError struct {
	Reason string
}

MalformedReportError reports that the bytes were not exactly one well-formed report/v1 document. Reason is drawn only from the fixed vocabulary above, so no untrusted content leaks.

func (*MalformedReportError) Error

func (e *MalformedReportError) Error() string

type NonFiniteValueError

type NonFiniteValueError struct{}

NonFiniteValueError reports that a measurement carried a NaN or ±Inf value, which JSON cannot represent and which the codec rejects fail-closed. No value is embedded (it is not finite and not safe to render as a number).

func (*NonFiniteValueError) Error

func (e *NonFiniteValueError) Error() string

type PathEscapeError

type PathEscapeError struct {
	Dir   string
	Cause error
}

PathEscapeError reports that a report's derived file name resolved outside the caller-provided sink directory — for example via a symlink or a "../" traversal — and was refused by the os.Root-scoped writer. Dir is the caller-supplied (safe) directory; Cause is the underlying os error, exposed via Unwrap but never rendered.

func (*PathEscapeError) Error

func (e *PathEscapeError) Error() string

func (*PathEscapeError) Unwrap

func (e *PathEscapeError) Unwrap() error

type ReportTooLargeError

type ReportTooLargeError struct {
	Size int
	Max  int
}

ReportTooLargeError reports that an encoded report exceeded MaxReportBytes. Only safe integers are carried; no report content is embedded.

func (*ReportTooLargeError) Error

func (e *ReportTooLargeError) Error() string

type TargetErrorClass

type TargetErrorClass string

TargetErrorClass is the safe, content-free classification of a target-stage failure recorded on the wire. The raw TargetError.Cause is never serialized; only this closed classification is.

const (
	// TargetErrorTimeout: the target stage exceeded its deadline.
	TargetErrorTimeout TargetErrorClass = "timeout"
	// TargetErrorCancelled: the target stage was cancelled.
	TargetErrorCancelled TargetErrorClass = "cancelled"
	// TargetErrorInvalidObservation: the target produced an observation that
	// failed domain validation.
	TargetErrorInvalidObservation TargetErrorClass = "invalid_observation"
	// TargetErrorFailed: the target stage failed for another reason.
	TargetErrorFailed TargetErrorClass = "failed"
)

func (TargetErrorClass) Validate

func (c TargetErrorClass) Validate() error

Validate reports whether c is a known TargetErrorClass. The zero value is not a member, so an unset or unknown class is rejected fail-closed.

type UnknownVersionError

type UnknownVersionError struct {
	// Version is a bounded, safe rendering of the offending token, or "" when it
	// was missing or withheld.
	Version string
}

UnknownVersionError reports that a report's version discriminator was missing or names a wire version this codec does not implement. The version token may originate from untrusted input, so it is bounded and withheld when hostile; Version is either a short, valid token or "" when redacted.

func (*UnknownVersionError) Error

func (e *UnknownVersionError) Error() string

type WriteError

type WriteError struct {
	Cause error
}

WriteError reports that writing, syncing, or renaming the report file failed. Cause is exposed via Unwrap.

func (*WriteError) Error

func (e *WriteError) Error() string

func (*WriteError) Unwrap

func (e *WriteError) Unwrap() error

Jump to

Keyboard shortcuts

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