Documentation
¶
Overview ¶
Package sealruntime is the link-time seam between the messaging package and the payload-sealing codec (ADR-097). It mirrors internal/streamruntime (ADR-091): the codec registers itself from messaging/sealed's init, the app configures the runtime facts once at bootstrap, and messaging reads both without importing jose or the keystore — so a process that never imports messaging/sealed carries no sealing code. The app already links go-jose through HTTP jose; the import gate keeps `messaging` itself jose-free. It lives in the module's root internal tree because app and messaging both import it, so only go-bricks code can call Register and Configure; two indirect re-aim paths stay open (#2010, ADR-139).
Index ¶
Constants ¶
const ( MeterName = "github.com/gaborage/go-bricks/messaging/sealed" MetricOperationDuration = "seal.operation.duration" MetricOpenFailures = "seal.open.failures.total" AttrOperation = "seal.operation" AttrCode = "seal.error.code" OpSeal = "seal" OpOpen = "open" )
Metric names and attribute keys shared by the seal and open paths.
Variables ¶
var ErrKeyStoreMissing = errors.New("messaging: a seal-tagged event type needs key material; register keystore.NewModule() before the declaring module")
ErrKeyStoreMissing fires when a seal-tagged type is declared and no keystore module is registered: key material is the sole trust act, so there is nothing to seal with.
var ErrNotConfigured = errors.New("messaging: sealing runtime not configured before declarations were collected")
ErrNotConfigured fires when a seal-tagged type is declared before the app configured the sealing runtime — a wiring order mistake, never a per-message condition.
var ErrNotLinked = errors.New(
`a seal-tagged event type is declared but the sealing codec is not linked; import _ "github.com/gaborage/go-bricks/messaging/sealed"`)
ErrNotLinked fires at startup when a seal-tagged type is declared but the codec was never linked into the build.
Functions ¶
func Configure ¶
func Configure(rt *Runtime)
Configure records the runtime facts. The app is the single writer and calls it before collecting declarations; a later call replaces the facts (the app rebuilds them per process start, tests per case), and the seal instruments are rebuilt from the meter. The Activation selector is copied: a caller's later write to its own map can neither re-aim a generation after bootstrap nor race a declaration being collected.
Types ¶
type Codec ¶
type Codec interface {
ScanType(t reflect.Type) (Spec, error)
NewSealer(spec Spec, eventType string, rt *Runtime) (Sealer, error)
}
Codec is what messaging/sealed registers. ScanType returns (nil, nil) for a type that carries no seal tags; NewSealer is the producer's startup fail-fast (Activation, roles) and returns a Sealer bound to the declaration's EventType.
func Registered ¶
func Registered() Codec
Registered returns the installed codec, or nil when messaging/sealed is not linked.
type Envelope ¶
type Envelope struct {
JTI string
IssuedAt time.Time
EventType string
TenantID string
SignKid string
SignFamily string
EncKid string
}
Envelope is the verified signed envelope of one opened message — field-for-field the shape messaging exposes on Metadata, so the mapping is a struct conversion. Produced by messaging/sealed in #1359.
type KeyStore ¶
type KeyStore interface {
PublicKey(name string) (*rsa.PublicKey, error)
PrivateKey(name string) (*rsa.PrivateKey, error)
}
KeyStore is the app.KeyStore subset sealing needs: stdlib RSA types only, so this seam names nothing from jose or keystore. The codec type-asserts the value for the family enumeration the keystore also implements.
type Metrics ¶
type Metrics struct {
// contains filtered or unexported fields
}
Metrics holds the seal instruments; nil-safe so an unconfigured process records nothing.
func Instruments ¶
func Instruments() *Metrics
Instruments returns the configured instruments, or a no-op set before Configure ran.
func (*Metrics) RecordOpenFailure ¶
RecordOpenFailure counts one refused open by code (codes only — never a wire value).
type OpenRefusedError ¶
OpenRefusedError is a sealed delivery the opener refused: Code is the rule that fired, Details carries presence/length facts only (never a wire value), Recoverable marks the provisioning-recoverable unknown-generation case, and Cause keeps the codec's own error for errors.As downstream. Returned by messaging/sealed in #1359.
func (*OpenRefusedError) Error ¶
func (e *OpenRefusedError) Error() string
Error renders the code and details only.
func (*OpenRefusedError) Unwrap ¶
func (e *OpenRefusedError) Unwrap() error
Unwrap exposes the codec's error for errors.As / errors.Is.
type Opener ¶
type Opener interface {
Open(ctx context.Context, body []byte, want TenantRule, out any) (Envelope, error)
}
Opener turns one sealed delivery body back into the event (into out) and its verified Envelope, judging tid by want. Implemented by messaging/sealed in #1359.
type OpenerProvider ¶
type OpenerProvider interface {
NewOpener(spec Spec, eventType string, rt *Runtime) (Opener, error)
}
OpenerProvider is the OPTIONAL consume side of a registered Codec: the consumer door type-asserts Registered() to it. NewOpener is the consumer's startup fail-fast (families provisioned in the inherited roles) bound to the declaration's EventType. Implemented by messaging/sealed in #1359.
type Runtime ¶
type Runtime struct {
// KeyStore is the registered keystore, nil when no keystore module is registered.
KeyStore KeyStore
// Active is the messaging.seal.active selector: Logical kid -> "v<N>".
Active map[string]string
// Tenancy is the deployment's messaging tenancy as the opener must judge tid.
Tenancy Tenancy
// Meter feeds the seal metrics; nil means no-op instruments.
Meter metric.MeterProvider
}
Runtime is what the app knows and the codec needs, fixed once at bootstrap.
func Configured ¶
func Configured() *Runtime
Configured returns an independent snapshot of the runtime facts, or nil before Configure ran. The stored facts cannot be reached through the result.
type Sealer ¶
Sealer turns one event of a declared type into its sealed wire bytes and the jti it signed.
type Tenancy ¶
type Tenancy uint8
Tenancy is the consume-side tenancy fact the opener's tid rule depends on (#1309 G2/G10).
const ( // TenancyDisabled is multitenant.enabled: false — no tid rule, value surfaced only. TenancyDisabled Tenancy = iota // unless the consumer declares TenantOptional, and equality-checked against the carrier. TenancyShared // TenancyPerTenant is multitenant.enabled + per-tenant messaging — present-and-different // from the context tenant is poison, absent is accepted. TenancyPerTenant )
type TenantRule ¶
TenantRule is the tid expectation for one delivery, derived by the consumer door from Tenancy and the carrier: Required makes an absent signed tid poison; a non-empty Expected must equal a present tid. Implemented (derived) by messaging/sealed in #1359.
type Verifier ¶
Verifier checks one stored sealed body against the producer's own declaration without decrypting it; a refusal is an *OpenRefusedError, and the tid is surfaced, never judged.
type VerifierProvider ¶
type VerifierProvider interface {
NewVerifier(spec Spec, eventType string, rt *Runtime) (Verifier, error)
}
VerifierProvider is the OPTIONAL producer-side verification of a registered Codec: the typed publish door type-asserts Registered() to it at declaration, and a codec without it fails only PublishSealed, never startup.