/** * owner-identity.ts, who "the owner" is, for the one exemption that names them. * * ── Why an exemption exists at all ──────────────────────────────────────── * * The taint rule refuses an outward action whose content derives from * untrusted input. Applied without exception it refuses the most ordinary * thing an assistant that reads mail does: telling the owner what arrived. * "What came in overnight" is a summary that NECESSARILY reuses the words of * what came in, so it trips the check every time. * * The owner is the trust root, not a third party. Sending them a summary is * not an outward effect in the sense the rule guards, it is the assistant * reporting, which is the point of it reading their mail at all. * * So exactly one exemption: a send whose every recipient is the owner alone. * * ── What the exemption is NOT ───────────────────────────────────────────── * * - Not a domain. `@example.com` would exempt every colleague, and a * forward to a colleague is a third-party disclosure. * - Not a pattern. No plus-address matching, no prefix rules. An alias the * agent minted for a signup is not a channel for reporting. * - Not "internal". There is no such tier; see security/untrusted-content.ts. * - Not partial. A send addressed to the owner AND anyone else is NOT exempt, * because that is precisely how an attacker would use it: name the owner * first and slip a second recipient in beside them. * * ── Where the identity comes from, and what it would take to spoof ──────── * * ONLY from configuration the owner set, read through an injected reader: * `email.fromAddress`, `email.username`, and the daemon's own * `surfaces.email.from` / `.user` / `.username`. * * Never from anything a message can influence, not a `From:` header, not * `Reply-To:`, not delivery evidence, not the ledger, not the body. A * recipient the content chose is the attack, so content is not consulted. * * To spoof this an attacker must change the owner's stored mail configuration. * That requires either an authenticated write to the daemon's config API, or * inducing the agent to call a config-setting tool. Both are strictly stronger * capabilities than sending mail: anything able to rewrite daemon config can * also disable this guard outright, repoint the SMTP server, or read the * credential store. The exemption is therefore not the weakest link in its own * chain, it sits behind a capability that already implies compromise. * * What it does NOT survive: an owner who has never configured a from-address. * Then there is no owner identity, `ownerAddresses` is empty, and the * exemption cannot fire, the refusal stays. That is the correct failure * direction, and it is why this returns a set rather than a best guess. */ /** Reads a configuration value. Never reads message content. */ export type OwnerConfigReader = (key: string) => unknown; /** * The config paths that name the owner's own mailbox. * * All are daemon-owned (see config/config-ownership.ts), so they resolve from * the daemon tier rather than from whichever surface happened to be running. */ export declare const OWNER_ADDRESS_CONFIG_KEYS: readonly string[]; /** Lowercase, strip a display name and angle brackets. No plus-address folding. */ export declare function normalizeOwnerAddress(value: string): string; /** * The owner's own addresses, from configuration only. * * Empty when nothing is configured, which disables the exemption rather than * widening it. */ export declare function resolveOwnerAddresses(getConfig: OwnerConfigReader): ReadonlySet; /** * Split a recipient field into individual addresses. * * A single `to` string can carry several recipients. Treating it as one opaque * value is how "the owner, and also the attacker" would pass. */ export declare function splitRecipients(recipientField: string): readonly string[]; /** * True when EVERY recipient is the owner alone. * * `false` for an empty recipient list and for an empty owner set: an exemption * that fires on "nothing configured" or "nobody addressed" is an exemption * that fires by accident. */ export declare function isSendToOwnerOnly(recipientField: string | undefined, ownerAddresses: ReadonlySet): boolean; //# sourceMappingURL=owner-identity.d.ts.map