Documentation
¶
Overview ¶
Package enforce is the policy decision-point client: it signs a CheckRequest and POSTs it to prism's /v1/flyedge/check, returning a typed Decision. The JSON shapes here are the frozen wire schema shared with prism/policy-enforcer and the Python/TS SDKs.
Index ¶
- Constants
- func ContextWithAgentIdentity(ctx context.Context, sid, urn string) context.Context
- func ContextWithDelegation(ctx context.Context, token string) context.Context
- func ContextWithEndpointAgent(ctx context.Context, ea EndpointAgent) context.Context
- func ContextWithPrincipal(ctx context.Context, p Principal) context.Context
- func ContextWithTraceparent(ctx context.Context, traceparent string) context.Context
- func IdentityHeaders(ctx context.Context) map[string]string
- type Action
- type AuthContext
- type CheckRequest
- type Content
- type Decision
- type EndpointAgent
- type Enforcer
- type ExecutionContext
- type HTTPEnforcer
- func (e *HTTPEnforcer) Check(ctx context.Context, req CheckRequest) (Decision, error)
- func (e *HTTPEnforcer) GetSigned(ctx context.Context, path string, headers map[string]string) ([]byte, error)
- func (e *HTTPEnforcer) GetSignedConditional(ctx context.Context, path string, headers map[string]string) ([]byte, bool, error)
- func (e *HTTPEnforcer) PostSigned(ctx context.Context, path string, body []byte) ([]byte, error)
- type KillInfo
- type KilledError
- type Operation
- type Principal
- type Signals
- type Stage
Constants ¶
const ( // HeaderOBOPrincipal carries the on-behalf-of envelope as base64url(JSON) with NO padding // (prism decodes URL_SAFE_NO_PAD). prism extracts provider/upn (+ urn/scope) for governance. HeaderOBOPrincipal = "X-CompFly-OBO-Principal" // HeaderDelegationToken carries a compact EdDSA JWT (typ "delegation-token"); prism forwards it // to the token-service to verify and unpacks the mandate chain. The SDK just attaches the token. HeaderDelegationToken = "X-CompFly-Delegation-Token" // HeaderAgentSID is the non-human-identity subject id (plain string). HeaderAgentSID = "X-CompFly-Agent-SID" // HeaderAgentURN is the structured NHI urn (plain string), grammar // "compfly:identity:v1:<provider>:<id_type>:<k>=<v>,...". HeaderAgentURN = "X-CompFly-Agent-URN" )
Identity-attribution headers prism reads on /v1/flyedge/check. These are NOT validated credentials on their own — prism trusts them on the strength of the DID-signed channel (the Ed25519 signature covers the body + timestamp, not the header set); the real credential is the raw token in the request body. The names + value formats are the frozen wire contract, verified against prism.
const ( OriginTypeUser = "user" // direct user request (human in the loop) OriginTypeAgent = "agent" // agent-mediated request (default) OriginTypeAutonomous = "autonomous" // fully autonomous, no user context )
OriginType values for CheckRequest.OriginType (prism FlyedgeOriginType, snake_case). Use one of these — prism rejects any other value (it deserializes into a fixed enum).
Variables ¶
This section is empty.
Functions ¶
func ContextWithAgentIdentity ¶
ContextWithAgentIdentity returns a context carrying the agent's non-human-identity attribution: sid (subject id) and/or urn (structured identity). Both empty is ignored. These ride alongside the crypto DID (set by the signer) as extra attribution for the acting agent.
func ContextWithDelegation ¶
ContextWithDelegation returns a context carrying a raw delegation-token JWT (agent-to-agent authority). The enforcer attaches it as the delegation header; prism verifies it and unpacks the intent/task mandate chain encoded inside the token. Empty token is ignored.
func ContextWithEndpointAgent ¶
func ContextWithEndpointAgent(ctx context.Context, ea EndpointAgent) context.Context
ContextWithEndpointAgent returns a context carrying the endpoint-agent identity a sensor observes for this operation. Check merges it onto the request's EndpointAgent when the caller didn't set one, so a sensor sets it per event and prism resolves the exact instance. The zero value is ignored.
func ContextWithPrincipal ¶
ContextWithPrincipal returns a context carrying the end-user an agent is acting on behalf of. The enforcer attaches it as the OBO header on every signed request made with this context. The zero Principal is ignored. This is the mechanism a single served agent uses to govern per-user: set the principal for the served request, and the gateway sees who each action is for.
func ContextWithTraceparent ¶
ContextWithTraceparent attaches a W3C `traceparent` so the signed POSTs carry it. prism reads it (field[1]=trace id, field[2]=parent span) to place the check in its lifecycle span tree. Empty is ignored.
func IdentityHeaders ¶
IdentityHeaders returns the identity-attribution headers carried on ctx, ready to attach to a signed request. Empty map when none are set. These are headers only — never part of the signed body — so they never disturb the frozen /check request schema or its signature.
Types ¶
type Action ¶
type Action string
Action is the normalized decision. Block folds into Deny for callers; Warn is advisory.
type AuthContext ¶
type AuthContext struct {
Method string `json:"method,omitempty"`
UserGroups []string `json:"user_groups,omitempty"`
Department string `json:"department,omitempty"`
ClearanceLevel string `json:"clearance_level,omitempty"`
LastAuthMinutes *int64 `json:"last_auth_minutes,omitempty"`
FailedAttempts *int `json:"failed_attempts,omitempty"`
DeviceID string `json:"device_id,omitempty"`
DeviceTrustScore *float32 `json:"device_trust_score,omitempty"`
SessionAgeMinutes *int64 `json:"session_age_minutes,omitempty"`
RequiresAudit bool `json:"requires_audit,omitempty"`
DataResidency string `json:"data_residency,omitempty"`
}
AuthContext carries application auth attributes for attribute-based governance (prism FlyedgeAuthContext). Optional; pointers distinguish unset from zero.
type CheckRequest ¶
type CheckRequest struct {
RequestID string `json:"request_id"`
SessionID string `json:"session_id"`
TimestampMS int64 `json:"timestamp_ms"`
Stage Stage `json:"stage"`
ComponentType string `json:"component_type"` // e.g. LLM, TOOL
ComponentName string `json:"component_name"` // e.g. ChatAnthropic
MethodName string `json:"method_name"` // e.g. invoke
Content Content `json:"content"`
Operation Operation `json:"operation"`
// Enrichment context prism accepts and feeds to policy. All optional — unset
// fields fall back to prism's serde defaults. Framework identifies the SDK.
Framework string `json:"framework,omitempty"`
Layer string `json:"layer,omitempty"`
Provider string `json:"provider,omitempty"`
OriginType string `json:"origin_type,omitempty"`
ExecutionContext *ExecutionContext `json:"execution_context,omitempty"`
AuthContext *AuthContext `json:"auth_context,omitempty"`
EndpointAgent *EndpointAgent `json:"endpoint_agent,omitempty"`
Metadata map[string]any `json:"metadata,omitempty"`
}
CheckRequest is the body POSTed to /v1/flyedge/check. The signature is computed over the exact serialized bytes of this struct, so serialize once and sign those bytes.
type Content ¶
type Content struct {
Preview string `json:"preview"`
Full string `json:"full"`
Hash string `json:"hash"`
SizeBytes int `json:"size_bytes"`
}
Content is the payload under inspection. Full carries the text; Hash + SizeBytes are required by the gateway and filled automatically from Full when unset (see CheckRequest.fillDefaults). Preview is a short excerpt for logs.
type Decision ¶
type Decision struct {
Action Action
Reason string
Message string
Warnings []string
PolicyVersion string
RequestID string
Signals Signals
Kills []KillInfo // non-full-scope kills matching this request (model/tool)
}
Decision is the typed, normalized result the caller sees.
type EndpointAgent ¶
type EndpointAgent struct {
InstanceKey string `json:"instance_key,omitempty"` // canonical product + workspace-root identity
EndpointID string `json:"endpoint_id,omitempty"` // durable device id (the sensor install)
ProductKey string `json:"product_key,omitempty"` // normalized agent, e.g. "claude-code"
WorkContext string `json:"work_context,omitempty"` // display/evidence repository context
}
EndpointAgent carries endpoint-agent context observed by a sensor. InstanceKey is the canonical enforcement handle: it is signed in the check body and paired by Prism with the verified sensor DID and the attested product key. The remaining fields are inventory context only.
func EndpointAgentFromContext ¶
func EndpointAgentFromContext(ctx context.Context) (EndpointAgent, bool)
EndpointAgentFromContext returns the endpoint-agent identity set via ContextWithEndpointAgent, and whether one was present.
type Enforcer ¶
type Enforcer interface {
Check(ctx context.Context, req CheckRequest) (Decision, error)
}
Enforcer is the policy decision point. Implementations are swappable (HTTP client, an offline stub for tests, a record/replay fake). Check must be safe for concurrent use.
type ExecutionContext ¶
type ExecutionContext struct {
Environment string `json:"environment,omitempty"`
IsAutonomous bool `json:"is_autonomous,omitempty"`
TriggerType string `json:"trigger_type,omitempty"`
Scheduled bool `json:"scheduled,omitempty"`
EventDriven bool `json:"event_driven,omitempty"`
}
ExecutionContext describes how/where the operation runs (prism FlyedgeExecutionContext) — feeds environment/autonomy/trigger-aware policy. Optional.
type HTTPEnforcer ¶
type HTTPEnforcer struct {
// contains filtered or unexported fields
}
HTTPEnforcer calls prism /v1/flyedge/check over HTTP, signing the request body with a Signer.
func NewHTTPEnforcer ¶
NewHTTPEnforcer builds an enforcer. baseURL is the prism base (no trailing slash needed); signer may be nil; timeout bounds each call.
func (*HTTPEnforcer) Check ¶
func (e *HTTPEnforcer) Check(ctx context.Context, req CheckRequest) (Decision, error)
Check serializes req, signs the exact bytes, POSTs to /v1/flyedge/check, and returns the typed Decision. A non-2xx or transport error is returned as an error — the caller (Guard) decides fail-open vs fail-closed; this layer does not silently allow.
func (*HTTPEnforcer) GetSigned ¶
func (e *HTTPEnforcer) GetSigned(ctx context.Context, path string, headers map[string]string) ([]byte, error)
GetSigned signs and GETs path (empty body), attaching extra request headers (e.g. the X-Agent-* heartbeat headers on /v1/flyedge/config). The signature is computed over the empty body, matching prism's SHA-256(ts‖body) scheme for a body-less request. A non-2xx is an error.
func (*HTTPEnforcer) GetSignedConditional ¶
func (e *HTTPEnforcer) GetSignedConditional(ctx context.Context, path string, headers map[string]string) ([]byte, bool, error)
GetSignedConditional is GetSigned with 304 handling: a Not Modified response comes back as (nil, true, nil) rather than an error. Plain GetSigned treats every non-2xx as a failure, which is right for endpoints where 304 is meaningless — this variant exists for poll endpoints that send If-None-Match and want "nothing changed" as an ordinary outcome, not an error to swallow.
func (*HTTPEnforcer) PostSigned ¶
PostSigned signs and POSTs body to an arbitrary flyedge path (e.g. /v1/flyedge/connect, /v1/flyedge/telemetry), returning the response bytes. Reuses the same signing as Check so the connect + telemetry lifecycle calls authenticate identically. A non-2xx is an error.
type KillInfo ¶
type KillInfo struct {
KillID string `json:"kill_id"`
Scope string `json:"scope"` // full | model | tool | provider
Target string `json:"target"`
Reason string `json:"reason"`
}
KillInfo describes an active kill switch matching a request. Full-scope kills arrive as a 403 (see KilledError); non-full (model/tool) kills arrive in a 200 response's `kills` array.
type KilledError ¶
type KilledError struct{ Kill KillInfo }
KilledError is returned by Check when the gateway rejects a request with a full-scope kill switch (HTTP 403 code=KILL_SWITCH). It is distinct from a policy deny so the Guard can enforce it unconditionally (a kill must never be bypassed by fail-open).
func (*KilledError) Error ¶
func (e *KilledError) Error() string
type Operation ¶
type Operation struct {
Type string `json:"type"`
ToolName string `json:"tool_name,omitempty"`
ToolArgsHash string `json:"tool_args_hash,omitempty"`
// ToolArgsJSON carries the full tool arguments as JSON so argument-level policies can evaluate
// values (prism forwards it to the enforcer's tool_args map). Distinct from Content: Content is
// the inspected/hashed payload + preview; this is the structured args for policy.
ToolArgsJSON string `json:"tool_args_json,omitempty"`
ModelID string `json:"model_id,omitempty"`
DestDomain string `json:"dest_domain,omitempty"`
MCPServerID string `json:"mcp_server_id,omitempty"`
}
Operation describes what the agent is doing (chat completion, tool call, …).
type Principal ¶
type Principal struct {
Provider string `json:"provider,omitempty"`
TenantID string `json:"tenantId,omitempty"`
OBOID string `json:"oboId,omitempty"`
UPN string `json:"upn,omitempty"`
URN string `json:"urn,omitempty"`
// Scope is the principal's claim map (role, plan, tenant, groups, …) — the attribute bag policy
// keys on. It is sent as a JSON OBJECT (prism serializes it into obo_scope_json for the policy
// engine), NOT a pre-encoded string, so a rule reads obo.scope.<claim> directly.
Scope map[string]string `json:"scope,omitempty"`
TokenHash string `json:"tokenHash,omitempty"`
Issuer string `json:"issuer,omitempty"`
Algorithm string `json:"algorithm,omitempty"`
KeyID string `json:"keyId,omitempty"`
PresentedAt string `json:"presentedAt,omitempty"`
ExpiresAt string `json:"expiresAt,omitempty"`
}
Principal is the on-behalf-of envelope: the end-user an agent is acting for on a given request. It maps to prism's OBO header (base64url JSON). prism plucks Provider/UPN (+ URN/Scope) for policy; the remaining fields are audit metadata. The envelope is an extraction hint — the actual credential is the raw OBO token in the request body — so a full production deployment sets both this and the underlying token. Field names match the platform envelope (camelCase).