tlclient

package
v0.1.6 Latest Latest
Warning

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

Go to latest
Published: Jun 26, 2026 License: MIT Imports: 9 Imported by: 0

Documentation

Overview

Package tlclient is the HTTP client the RA uses to POST signed events to the Transparency Log. It's the client half of the outbox-delivery path; the TL's ingest handlers are the server half.

The TL exposes two ingest lanes with identical wire contracts but different envelope schemas:

  • `POST /v1/internal/agents/event` — V1 schema (reference parity)
  • `POST /v2/internal/agents/event` — V2 schema (ans extension)

The worker (internal/ra/outbox) calls Append once per claimed outbox row, passing the row's recorded `schemaVersion`; this package picks the matching URL. All other wire details (headers, response-code classification, timeouts, error typing) are version-agnostic.

Error typing is deliberately structured because the worker's retry logic depends on it:

  • TransientError — transport failure, 5xx, 429. Worker retries with capped exponential backoff.
  • PermanentError — 4xx (except 429). Worker marks the row failed with long backoff and logs at ERROR so operators see it.
  • nil (on success) — 200 OK (reference shape; `duplicate: true` on idempotent retry). Legacy 201 Created is also accepted so clients continue to work against older-build TLs.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsPermanent

func IsPermanent(err error) bool

IsPermanent reports whether an error returned by Append is a permanent client error.

func IsTransient

func IsTransient(err error) bool

IsTransient reports whether an error returned by Append is retryable. Convenience wrapper over errors.As for the worker.

Types

type AppendResult

type AppendResult struct {
	LogID     string `json:"logId"`
	Message   string `json:"message"`
	Success   bool   `json:"success"`
	LeafIndex uint64 `json:"leafIndex"`
	LeafHash  string `json:"leafHashHex"`
	Duplicate bool   `json:"duplicate"`
	TreeSize  uint64 `json:"treeSize"`
}

AppendResult is the parsed success response from the TL's ingest endpoint — same JSON shape on both V1 and V2 lanes. `LogID`, `Message`, and `Success` mirror the reference TL's AgentEventResponse; the remaining fields are ans-specific additions carrying the Merkle-tree position.

type Client

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

Client POSTs signed events to the TL.

One Client serves the whole outbox worker; its underlying *http.Client is safe for concurrent use.

func New

func New(baseURL, apiKey string, timeout time.Duration) *Client

New constructs a Client. baseURL is the TL's listen URL (no trailing slash); apiKey is the static bearer token the TL accepts.

func (*Client) Append

func (c *Client) Append(ctx context.Context, schemaVersion string, body []byte, producerSig string) (*AppendResult, error)

Append POSTs the given inner-event canonical bytes to the TL's ingest lane for the named schema version, with the producer's detached-JWS signature in the X-Signature header.

schemaVersion must be "V1" or "V2" — it selects the URL path (`/v1/internal/agents/event` vs `/v2/internal/agents/event`).

The caller is responsible for the outbox-replay invariant: `body` and `producerSig` must be the exact bytes that were originally signed and persisted. Regenerating either on retry would break TL dedup (which hashes `body`) and invalidate `producerSig`.

func (*Client) SealIdentityEvent added in v0.1.6

func (c *Client) SealIdentityEvent(ctx context.Context, innerCanonical []byte, producerSig string) error

SealIdentityEvent submits a producer-signed identity event on the IDENTITY lane and returns only after the TL acknowledges the seal — the client half of seal-before-success (design §5.6.1). Identity events never ride the outbox: delivery precedes success, and a failed delivery IS a failed operation, so errors are mapped to domain kinds the service layer can return directly:

  • transient (transport, 5xx, 429) → ErrUnavailable / 503 TL_UNAVAILABLE: retryable, the caller consumed nothing;
  • permanent (other 4xx) → ErrInternal / TL_REJECTED_EVENT: the RA produced an event the TL refuses — a pipeline bug, not weather; operators must see it.

type PermanentError

type PermanentError struct {
	Status  int
	Message string
	Body    string
}

PermanentError indicates the request will never succeed in its current form. The worker marks the outbox row failed with long backoff and logs at ERROR.

func (*PermanentError) Error

func (e *PermanentError) Error() string

Error implements error.

type TransientError

type TransientError struct {
	Status  int
	Message string
	Body    string
	Cause   error
}

TransientError indicates the request should be retried later.

func (*TransientError) Error

func (e *TransientError) Error() string

Error implements error.

func (*TransientError) Unwrap

func (e *TransientError) Unwrap() error

Unwrap returns the cause so errors.Is(err, net.ErrClosed) etc. works.

Jump to

Keyboard shortcuts

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