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 ¶
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 ¶
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.