inboundscreen

package
v1.4.1 Latest Latest
Warning

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

Go to latest
Published: Jul 26, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

Documentation

Overview

Package inboundscreen is the shared inbound-protection evaluation core: the per-agent ingestion-gate escalation + piguard content scan + most-severe merge that decides whether one inbound message is delivered, flagged, held for review, or accept-then-quarantined.

It was extracted verbatim from internal/relay (screening.go) so the loopback self-send paths (internal/agent's performSelfSend and the HITL approve / TTL-approve local deliveries) can run the exact same evaluation as SMTP inbound — previously they created the inbound row with a zero-value screening verdict, silently bypassing the agent's inbound protection. The relay delegates here; behavior on the SMTP path is unchanged.

Index

Constants

View Source
const GeminiDetectorTimeout = 10 * time.Second

GeminiDetectorTimeout is the per-detector timeout used when the Gemini detector is wired in, wider than the Engine's default (5s) so the retry/backoff schedule in piguard/gemini.go (up to geminiDefaultMaxRetries retries) has room to run instead of being cut off by the engine before it can fire.

Variables

This section is empty.

Functions

func BuildEngine

func BuildEngine() *piguard.Engine

BuildEngine constructs the piguard screening engine for inbound mail. The heuristics detector is always included. The Gemini detector is added when GeminiDetectorEnabled() and GEMINI_API_KEY or GOOGLE_API_KEY is set in the environment; its prompt only classifies inbound content, so this engine (inbound-only, unlike buildAgentScreenEngine in internal/agent/api.go) is where it belongs. Used by the SMTP relay and by the loopback inbound-leg screeners.

func GeminiDetectorEnabled

func GeminiDetectorEnabled() bool

GeminiDetectorEnabled reports whether BuildEngine should even attempt to construct the Gemini detector. Defaults to true — the existing behavior, where Gemini is enabled purely by GEMINI_API_KEY/GOOGLE_API_KEY being present — unless E2A_GEMINI_DETECTOR_ENABLED is explicitly set to "false". This is an operator kill-switch/A-B toggle independent of the credential: it lets you disable Gemini (isolating whether it or heuristics is driving a given block/review outcome, or rolling back without touching secrets) without having to remove the API key.

func LoopbackGate

func LoopbackGate(agent *identity.AgentIdentity) inboundpolicy.Decision

LoopbackGate evaluates the agent's ingestion gate for the inbound leg of a loopback self-send. The message is first-party — composed by the agent itself under its API-key identity — which is the strongest possible sender authentication, so the gate sees the same facts an SMTP roundtrip of the identical message would produce: sender = the agent's own address, resolvable (it maps to this very agent), DMARC pass (own domain, DKIM-signed by the platform). The gate outcome therefore reduces to allowlist/domain membership of the agent's own address — an agent whose gating policy does not include itself gets its self-sends escalated per inbound_policy_action, exactly like the relay path would.

Types

type Result

type Result struct {
	Denorm        identity.InboundScreening
	Events        []identity.ProtectionEvent
	AppliedAction piguard.Action // most-severe of gate + scan
	Hold          bool           // applied action is review|block → suppress delivery
	Detected      bool           // a scan violation fired (used to attribute payload fields)
	Score         float64
	Action        string
	Categories    []string
	Reason        string
}

Result is the outcome of content-screening one inbound message: the denormalized verdict (incl. any review-hold status) for the message row, the audit rows to append, and (when the applied action is block) the data the email.blocked event carries.

func Evaluate

func Evaluate(ctx context.Context, engine *piguard.Engine, agent *identity.AgentIdentity, messageID, senderEmail string, body []byte, auth *emailauth.Authentication, gate inboundpolicy.Decision) Result

Evaluate runs the agent's content scan (when inbound_scan='on'), combines it with the ingestion-gate decision into one applied action, and decides whether the message is HELD (review/block) or delivered (flag/allow).

  • review → held as pending_review (awaiting a human / TTL), delivery suppressed.
  • block → accept-then-quarantine as review_rejected (dropped, no human), delivery suppressed.
  • flag → delivered + annotated (the gate's email.flagged path is unchanged).
  • allow → delivered normally.

func EvaluateLoopback

func EvaluateLoopback(ctx context.Context, engine *piguard.Engine, agent *identity.AgentIdentity, messageID string, body []byte) (Result, inboundpolicy.Decision)

EvaluateLoopback is the loopback-flavored entry point: gate + scan over the composed MIME with the agent itself as the sender and no SMTP authentication evidence (there was no wire hop). messageID must be the pre-allocated inbound row id so the audit rows and deterministic event ids anchor to it.

func (Result) Blocked

func (r Result) Blocked() bool

Blocked reports whether the applied action is block — the message is accept-then-quarantined (review_rejected). Drives the email.blocked event.

func (Result) Review

func (r Result) Review() bool

Review reports whether the applied action is review — the message is held as pending_review awaiting a human / TTL. Drives the email.review_requested event.

Jump to

Keyboard shortcuts

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