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 ¶
IsPermanent reports whether an error returned by Append is a permanent client error.
func IsTransient ¶
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 ¶
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 ¶
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.
type TransientError ¶
TransientError indicates the request should be retried later.
func (*TransientError) Unwrap ¶
func (e *TransientError) Unwrap() error
Unwrap returns the cause so errors.Is(err, net.ErrClosed) etc. works.