channel

package
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Sep 19, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

Documentation

Index

Constants

View Source
const DefaultBindingFile = ".mnemon/harness/channel/bindings.json"

DefaultBindingFile is the canonical channel-binding manifest path under the project root (P3.1).

View Source
const DefaultSyncTimeout = 10 * time.Second

DefaultSyncTimeout bounds every sync transport call (v1.1 #10): a hung remote can never wedge the caller — the in-process worker stays off the Tick path, but even its own goroutine must converge.

View Source
const MaxIngestBytes = 1 << 20

MaxIngestBytes caps an observation request body, so an oversize payload is rejected at the edge rather than buffered into memory. interim Phase-1 default; superseded by Phase-2 per-capability max_payload_bytes.

Variables

This section is empty.

Functions

func MergeBinding

func MergeBinding(path string, b ChannelBinding, credentialRef string) error

UpsertBinding inserts or replaces (by principal) b in the manifest at path, creating the file (schema_version 1) when absent and PRESERVING every other entry + their order — so `setup` manages exactly its own principal and never clobbers a user-added or sibling-loop binding. credentialRef is the token-file ref to record (project-relative or absolute, "" for header auth). MergeBinding upserts b into the binding file, UNIONing the verbs / observed types / subscription scope with any existing binding for the same principal — so installing skill after memory keeps the memory grant rather than replacing it. The existing credential ref is kept when credentialRef is empty (an idempotent token). It is the additive variant of UpsertBinding (which replaces).

func NewHTTPHandler

func NewHTTPHandler(api ServerAPI) http.Handler

NewHTTPHandler exposes a ServerAPI over net/http with the default HeaderAuthenticator (D5: production HTTP/gRPC+mTLS is a thin adapter; this is the thin adapter, gated by httptest).

func NewHTTPHandlerWithAuth

func NewHTTPHandlerWithAuth(api ServerAPI, auth Authenticator) http.Handler

NewHTTPHandlerWithAuth is NewHTTPHandler with an explicit Authenticator seam. The principal is resolved by auth; the body carries only the observation. The one ControlServer behind it stays the sole serializer — multi-execution-surface, never multi-writer.

func RemoveBinding

func RemoveBinding(path string, principal contract.ActorID) (bool, error)

RemoveBinding removes the principal's entry from the manifest at path, preserving all others, and reports whether an entry was removed. The file is left in place (with an empty bindings list when it held only that entry), so a user-managed manifest is never surprised away by an uninstall.

func SubsFromBindings

func SubsFromBindings(bindings []ChannelBinding) map[contract.ActorID]contract.Subscription

SubsFromBindings derives the per-principal subscription scopes from the bindings, so the runtime's served scope and the binding manifest come from ONE source (the binding file).

func UpsertBinding

func UpsertBinding(path string, b ChannelBinding, credentialRef string) error

func ValidateSyncEndpoint

func ValidateSyncEndpoint(endpoint string, allowInsecure bool) error

ValidateSyncEndpoint is the client half of the TLS downgrade gate: an http:// endpoint with a non-loopback host is refused unless explicitly overridden (mirroring the stage-4 listen-side loopback-only posture). https always passes; loopback plaintext stays allowed (same-machine hubs and tests are inside the T1 boundary). `sync connect` applies the same check at write time.

Types

type Authenticator

type Authenticator interface {
	Authenticate(r *http.Request) (contract.ActorID, error)
}

Authenticator resolves the authenticated edge principal from a request — the P3 seam that replaces the bare trusted X-Mnemon-Principal header. A production transport binds it to mTLS / OIDC / a local-socket peer credential; the default (HeaderAuthenticator) trusts the header, which is correct for a local/trusted transport and for httptest. The server still trusts ONLY the resolved principal, never the request body (D7/S9).

func NewBindingAuthenticator

func NewBindingAuthenticator(loaded LoadedBindings) Authenticator

NewBindingAuthenticator builds the per-principal authenticator from the loaded bindings' tokens. With no tokens it is a plain header authenticator; with all-token it requires bearers; mixed is resolved per principal.

type BindingSet

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

BindingSet indexes the channel bindings by principal. It is the in-memory authorizer source for the walking skeleton (P2.1): the smallest runtime control that turns the ChannelBinding manifest into enforcement, without yet committing a binding-file schema (P3). The actor kind rides the binding, never a separate code path (D6) — the authorizer branches on verbs/types/scope, not on the role.

func NewBindingSet

func NewBindingSet(bindings ...ChannelBinding) (*BindingSet, error)

NewBindingSet validates each binding and indexes them by principal. Duplicate principals and colliding idempotency namespaces are rejected (the namespace isolates a principal's ExternalIDs).

func (*BindingSet) Binding

func (s *BindingSet) Binding(principal contract.ActorID) (ChannelBinding, bool)

Binding returns the principal's binding (and whether one exists).

type ChannelBinding

type ChannelBinding struct {
	Principal            contract.ActorID       // the authenticated identity
	ActorKind            contract.ActorKind     // role classification (not a privilege path)
	Transport            Transport              // wire
	Endpoint             string                 // base URL / socket path
	AllowedVerbs         []Verb                 // observe / pull / status
	AllowedObservedTypes []string               // observed event types this principal may Ingest ("" or "*" = any)
	SubscriptionScope    []contract.ResourceRef // the refs this principal may pull
	IdempotencyNamespace string                 // prefix isolating this principal's ExternalIDs (cross-principal dedup isolation)
	Budget               contract.BudgetTier    // context-budget tier for this endpoint's derived mirror (P4); empty = hot (full)
}

ChannelBinding is the manifest that scopes ONE principal's access to the channel (D6). The channel is the same for every binding; the binding — never a privileged code path — is what differs a HostAgent from a ControlAgent. The server still enforces the scope at runtime (S9); the binding makes the grant explicit and auditable.

func ControlAgentBinding

func ControlAgentBinding(principal contract.ActorID, endpoint string, scope []contract.ResourceRef) ChannelBinding

func HostAgentBinding

func HostAgentBinding(principal contract.ActorID, endpoint string, scope []contract.ResourceRef) ChannelBinding

HostAgentBinding and ControlAgentBinding are the two canonical bindings over the SAME channel — the role differs ONLY by the binding (zero new surface for the control agent, D6).

func ReplicaAgentBinding

func ReplicaAgentBinding(principal contract.ActorID, endpoint string, scope []contract.ResourceRef) ChannelBinding

func (ChannelBinding) Allows

func (b ChannelBinding) Allows(v Verb) bool

Allows reports whether the binding grants verb.

func (ChannelBinding) AllowsObservedType

func (b ChannelBinding) AllowsObservedType(eventType string) bool

AllowsObservedType reports whether the binding permits Ingesting an observation of eventType. An empty AllowedObservedTypes (or a "*" entry) means any observed type.

func (ChannelBinding) ClampRefs

func (b ChannelBinding) ClampRefs(requested []contract.ResourceRef) ([]contract.ResourceRef, error)

ClampRefs clamps a requested ref set to the binding's SubscriptionScope — the team-scale authorization ceiling, implemented ONCE for pull / sync / status (hand-rolled copies had already diverged on empty-scope handling). The one implementation is contract.ClampRefs — shared with the standalone hub (syncserver), which cannot import channel — and this method DELEGATES to it: empty requested defaults to the full scope; any explicit ref outside the scope is an error; an EMPTY scope denies every explicit ref (fail closed). The ingest path keeps its documented exception (an observation naming no refs is unconstrained) at its own call site.

func (ChannelBinding) Validate

func (b ChannelBinding) Validate() error

Validate checks the binding is well-formed: a principal, a known kind, at least one verb.

type Client

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

Client is a thin edge-side HTTP client bound to one authenticated credential. It satisfies ServerAPI so an edge can speak to a remote server exactly as to an in-process one. The credential is either the trusted principal header (NewClient, local/trusted transport) or a bearer token resolved by a TokenAuthenticator (NewClientWithToken) — the P3 channel client.

func NewClient

func NewClient(baseURL string, principal contract.ActorID) *Client

func NewClientWithToken

func NewClientWithToken(baseURL, token string) *Client

NewClientWithToken binds the client to a bearer token (resolved server-side by a TokenAuthenticator) instead of the trusted principal header.

func NewSyncClient

func NewSyncClient(endpoint string, cfg SyncClientConfig) (*Client, error)

NewSyncClient builds the sync client over endpoint: fail-closed on a plaintext non-loopback endpoint (the T2 downgrade gate, v1.1 #3) and always bounded by a timeout. With a CAFile the transport trusts exactly that root — nothing else.

func (*Client) Ingest

func (c *Client) Ingest(principal contract.ActorID, env contract.ObservationEnvelope) (int64, bool, error)

Ingest satisfies ServerAPI by delegating to IngestObserve and dropping the processing metadata.

func (*Client) IngestObserve

IngestObserve POSTs the observation and returns the full channel receipt (seq, dup, processing metadata). The principal argument is ignored: the client's identity is its bound credential (the trusted header / bearer token), never a per-call claim — an edge cannot forge another's id.

func (*Client) PullProjection

func (c *Client) PullProjection(_ contract.ActorID, sub contract.Subscription) (projection.Projection, error)

PullProjection fetches the actor's scoped view from the server. The principal argument is ignored: the subscription's actor is sent in the body and the server cross-checks it against the bound credential header, so an edge cannot pull another actor's scope (D7/S9).

func (*Client) Status

Status fetches the channel status evidence for the client's bound principal (P2.3). The principal argument is ignored: identity is the bound credential, sent as the trusted header / bearer token.

func (*Client) SyncPull

func (*Client) SyncPush

func (*Client) SyncStatus

func (c *Client) SyncStatus() (contract.SyncStatusResponse, error)

SyncStatus fetches the hub's sync status evidence (counters) for the bound credential.

type HeaderAuthenticator

type HeaderAuthenticator struct{}

HeaderAuthenticator trusts the X-Mnemon-Principal header. It is the default seam impl for a local/trusted transport (and what httptest uses).

func (HeaderAuthenticator) Authenticate

func (HeaderAuthenticator) Authenticate(r *http.Request) (contract.ActorID, error)

type IngestReceipt

type IngestReceipt struct {
	Seq             int64  `json:"seq"`
	Dup             bool   `json:"dup"`
	Ticked          bool   `json:"ticked"`
	ProcessingError string `json:"processing_error,omitempty"`
}

IngestReceipt is the channel's reply to an observe: it tells the client the observation was recorded (Seq), whether it was a duplicate (Dup), whether the runtime attempted to process it with a synchronous Tick (Ticked, P2.2), and any processing error (the observation is durable regardless — a Tick failure is reported, not folded into the ingest result).

type LoadedBindings

type LoadedBindings struct {
	Bindings []ChannelBinding
	Tokens   map[string]contract.ActorID
}

LoadedBindings is the result of parsing a binding file: the channel bindings plus the bearer token -> principal map assembled from the bindings' credential_ref token files (for a TokenAuthenticator). The bindings feed RuntimeConfig.Bindings + SubsFromBindings; the tokens feed the server's authenticator.

func LoadBindingFile

func LoadBindingFile(root, path string) (LoadedBindings, error)

LoadBindingFile reads + validates the channel-binding manifest at path and assembles the bindings and bearer-token map. Relative credential_ref token paths resolve against root (the project root, absolute ones are used verbatim. It validates each entry (principal, known actor kind / verbs / transport, http endpoint non-empty), the schema version, and cross-entry uniqueness (principal, idempotency namespace, bearer token).

type ServerAPI

type ServerAPI interface {
	Ingest(principal contract.ActorID, env contract.ObservationEnvelope) (seq int64, dup bool, err error)
	PullProjection(principal contract.ActorID, sub contract.Subscription) (projection.Projection, error)
}

ServerAPI is the edge<->server boundary (D5). Production HTTP/gRPC+mTLS is a thin adapter over it (httpapi.go); the in-process implementation is *runtime.ControlServer. It grows by phase: Ingest (P0), PullProjection (P2). The channel owns this port; the runtime satisfies it structurally, so channel never imports runtime.

func NewAuthorizedAPI

func NewAuthorizedAPI(inner ServerAPI, bindings *BindingSet) ServerAPI

NewAuthorizedAPI returns inner gated by bindings. With a nil/empty BindingSet, callers should use inner directly (an unbound, trusted in-process owner such as the embedded coreengine path).

type SyncClientConfig

type SyncClientConfig struct {
	Token         string
	Timeout       time.Duration // <= 0 defaults to DefaultSyncTimeout
	CAFile        string        // PEM bundle for the remote's TLS root (e.g. mnemon-hub --dev-selfsigned cert)
	AllowInsecure bool          // explicit T2 downgrade override for a plaintext non-loopback endpoint
}

SyncClientConfig configures the replica sync client (sync-abi-v1 §8): the bearer credential, a bounded transport budget, an optional CA bundle pinning the remote's TLS root, and the explicit plaintext override.

type TokenAuthenticator

type TokenAuthenticator struct {
	Tokens map[string]contract.ActorID
}

TokenAuthenticator resolves the principal from a bearer token via a static token->principal map — a minimal non-header seam implementation (mTLS/OIDC slot in the same way). An unknown or empty token is rejected, so the body's claimed actor is never trusted.

func (TokenAuthenticator) Authenticate

func (a TokenAuthenticator) Authenticate(r *http.Request) (contract.ActorID, error)

type Transport

type Transport string

Transport names the wire a binding uses.

const (
	TransportLocal Transport = "local" // in-process / local socket, trusted header
	TransportHTTP  Transport = "http"  // loopback / network http
	TransportMTLS  Transport = "mtls"  // mutual-TLS authenticated
)

type Verb

type Verb string

Verb is a channel operation. The Agent Integration channel exposes observe (Ingest) + pull (PullProjection) + status. Replica sync gets separate verbs so a sync credential does not inherit Agent Integration access.

const (
	VerbObserve Verb = "observe"
	VerbPull    Verb = "pull"
	VerbStatus  Verb = "status"
	// The sync verb STRINGS are ABI surface owned by contract (sync-abi-v1 §1); these aliases keep
	// the channel's Verb space complete without channel becoming the wire-name authority.
	VerbSyncPush   Verb = contract.SyncVerbPush
	VerbSyncPull   Verb = contract.SyncVerbPull
	VerbSyncStatus Verb = contract.SyncVerbStatus
)

Jump to

Keyboard shortcuts

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