docs: expand adaptive Mail guidance
This commit is contained in:
@@ -196,6 +196,7 @@ manifest = ModuleManifest(
|
||||
links=(
|
||||
DocumentationLink(label="Mail profiles", href="/api/v1/mail/profiles", kind="api"),
|
||||
DocumentationLink(label="Tenant mail policy", href="/api/v1/mail/policies/tenant", kind="api"),
|
||||
DocumentationLink(label="Mail handbook", href="govoplan-mail/docs/MAIL_HANDBOOK.md", kind="repository"),
|
||||
DocumentationLink(label="Public mail module documentation", href="https://govplan.add-ideas.de/modules/mail", kind="public"),
|
||||
),
|
||||
related_modules=("campaigns",),
|
||||
@@ -203,7 +204,7 @@ manifest = ModuleManifest(
|
||||
configuration_keys=("mail_profile_policy",),
|
||||
metadata={
|
||||
"kind": "reference",
|
||||
"route": "/mail",
|
||||
"route": "/settings?section=mail-profiles",
|
||||
"screen": "Mail profiles and policy",
|
||||
"section": "Effective profile policy",
|
||||
"related_topic_ids": [
|
||||
@@ -228,15 +229,15 @@ manifest = ModuleManifest(
|
||||
),
|
||||
),
|
||||
links=(
|
||||
DocumentationLink(label="Mail profiles", href="/mail", kind="runtime"),
|
||||
DocumentationLink(label="Mail profiles", href="/settings?section=mail-profiles", kind="runtime"),
|
||||
DocumentationLink(label="Mail profiles API", href="/api/v1/mail/profiles", kind="api"),
|
||||
DocumentationLink(label="Campaigns", href="/campaigns", kind="runtime"),
|
||||
DocumentationLink(label="Mail handbook", href="govoplan-mail/docs/MAIL_HANDBOOK.md", kind="repository"),
|
||||
),
|
||||
related_modules=("campaigns", "access"),
|
||||
unlocks=("Reusable, governed delivery identities without cross-module secret duplication.",),
|
||||
metadata={
|
||||
"kind": "reference",
|
||||
"route": "/mail",
|
||||
"route": "/settings?section=mail-profiles",
|
||||
"screen": "Mail profiles",
|
||||
"section": "Profile ownership, credentials, and consumers",
|
||||
"related_topic_ids": [
|
||||
@@ -247,6 +248,159 @@ manifest = ModuleManifest(
|
||||
],
|
||||
},
|
||||
),
|
||||
DocumentationTopic(
|
||||
id="mail.workflow.choose-and-test-profile",
|
||||
title="Choose and test a reusable Mail profile",
|
||||
summary="Select a profile visible in the current context, test its SMTP or IMAP connection, and let the consuming task store only its stable reference.",
|
||||
body="Profile tests verify current connection and authentication using Mail-owned credentials. They do not prove later Campaign policy authorization, deliverability, recipient acceptance, or future availability. Use the picker rather than entering identifiers or copying transport settings into another module.",
|
||||
layer="configured",
|
||||
documentation_types=("user",),
|
||||
audience=("mail_user", "campaign_manager"),
|
||||
order=41,
|
||||
conditions=(
|
||||
DocumentationCondition(
|
||||
required_modules=("mail",),
|
||||
required_scopes=("mail:profile:read", "mail:profile:use", "mail:profile:test"),
|
||||
),
|
||||
),
|
||||
links=(
|
||||
DocumentationLink(label="Mail profiles", href="/settings?section=mail-profiles", kind="runtime"),
|
||||
DocumentationLink(label="Mail handbook", href="govoplan-mail/docs/MAIL_HANDBOOK.md", kind="repository"),
|
||||
),
|
||||
related_modules=("campaigns",),
|
||||
unlocks=("Reusable SMTP/IMAP identities that consumers can reference without handling credentials.",),
|
||||
metadata={
|
||||
"kind": "workflow",
|
||||
"route": "/settings?section=mail-profiles",
|
||||
"screen": "Mail profiles",
|
||||
"prerequisites": [
|
||||
"Mail is installed and you may read, use, and test profiles visible in the current context.",
|
||||
"A profile administrator has configured credentials and effective policy.",
|
||||
],
|
||||
"steps": [
|
||||
"Open Mail profiles and choose a visible active profile.",
|
||||
"Review its safe scope, SMTP/IMAP availability, and sender identity without expecting credential values.",
|
||||
"Run the relevant SMTP or IMAP connectivity/authentication test against a non-production target first.",
|
||||
"Return to the consuming task and select the same profile through its picker.",
|
||||
],
|
||||
"outcome": "The consuming task references an available Mail-owned profile and contains no copied transport configuration or credentials.",
|
||||
"verification": "Reload both surfaces, confirm only the stable reference is retained by the consumer, and perform the consumer's own contextual policy validation.",
|
||||
"related_topic_ids": [
|
||||
"mail.profile-ownership-and-consumers",
|
||||
"mail.reference.campaign-delivery-contract",
|
||||
],
|
||||
},
|
||||
),
|
||||
DocumentationTopic(
|
||||
id="mail.workflow.read-mailbox",
|
||||
title="Read a permitted mailbox without changing it",
|
||||
summary="Choose an IMAP-enabled profile, browse folders, and inspect bounded message content through the read-only mailbox surface.",
|
||||
body="Mailbox access requires both mailbox-read and profile-use authority for a profile visible in the actor's scope. Listing folders or messages must not mark mail read, move it, delete it, or expose unbounded content.",
|
||||
layer="configured",
|
||||
documentation_types=("user",),
|
||||
audience=("mail_user",),
|
||||
order=42,
|
||||
conditions=(
|
||||
DocumentationCondition(
|
||||
required_modules=("mail",),
|
||||
required_scopes=("mail:mailbox:read", "mail:profile:use"),
|
||||
),
|
||||
),
|
||||
links=(
|
||||
DocumentationLink(label="Mail", href="/mail", kind="runtime"),
|
||||
DocumentationLink(label="Mail handbook", href="govoplan-mail/docs/MAIL_HANDBOOK.md", kind="repository"),
|
||||
),
|
||||
unlocks=("Read-only access to an authorized operational mailbox without broadening profile administration rights.",),
|
||||
metadata={
|
||||
"kind": "workflow",
|
||||
"route": "/mail",
|
||||
"screen": "Mail",
|
||||
"prerequisites": [
|
||||
"An active visible profile has IMAP configured.",
|
||||
"You may both use that profile and read its mailbox.",
|
||||
],
|
||||
"steps": [
|
||||
"Open Mail and choose an authorized IMAP-enabled profile.",
|
||||
"Select a folder and page through its bounded message index.",
|
||||
"Open only the message needed for the task and close it when finished.",
|
||||
],
|
||||
"outcome": "The required message was inspected without changing provider mailbox state.",
|
||||
"verification": "Refresh the provider mailbox independently and confirm no read, move, delete, reply, or flag mutation was caused by GovOPlaN.",
|
||||
"related_topic_ids": [
|
||||
"mail.workflow.choose-and-test-profile",
|
||||
"mail.reference.credentials-egress-retirement",
|
||||
],
|
||||
},
|
||||
),
|
||||
DocumentationTopic(
|
||||
id="mail.reference.credentials-egress-retirement",
|
||||
title="Protect Mail credentials, network egress, and retirement",
|
||||
summary="Keep secrets Mail-owned, pin every SMTP/IMAP peer, bound responses, and delete owned credentials immediately with non-secret audit evidence.",
|
||||
body="Private-network connector access is deployment-wide, but every allowed hostname still resolves to an approved peer that is pinned at socket creation. Unsupported transports fail before connection. Deleting a profile immediately scrubs its owned encrypted SMTP/IMAP passwords and records non-secret audit when secrets existed; a scrub or audit failure rolls the action back. Destructive module retirement applies the same rule before table drop.",
|
||||
layer="evidence",
|
||||
documentation_types=("admin",),
|
||||
audience=("mail_admin", "platform_operator", "security_reviewer", "release_reviewer"),
|
||||
order=43,
|
||||
conditions=(
|
||||
DocumentationCondition(
|
||||
required_modules=("mail",),
|
||||
any_scopes=("mail:secret:manage", "mail:profile:write", "system:settings:read"),
|
||||
),
|
||||
),
|
||||
links=(
|
||||
DocumentationLink(label="Mail handbook", href="govoplan-mail/docs/MAIL_HANDBOOK.md", kind="repository"),
|
||||
DocumentationLink(label="Mail profiles API", href="/api/v1/mail/profiles", kind="api"),
|
||||
),
|
||||
related_modules=("audit",),
|
||||
unlocks=("A testable Mail trust boundary with fail-closed egress and auditable secret disposal.",),
|
||||
metadata={
|
||||
"kind": "reference",
|
||||
"route": "/settings?section=mail-profiles",
|
||||
"screen": "Mail profiles",
|
||||
"section": "Credentials, network egress, deletion, and retirement",
|
||||
"verification": "Test DNS rebinding and denied addresses, prove the connected peer is pinned, inject credential-scrub and audit failures, repeat deletion for idempotency, and run the retirement preflight against a snapshot.",
|
||||
"related_topic_ids": [
|
||||
"mail.workflow.choose-and-test-profile",
|
||||
"mail.reference.campaign-delivery-contract",
|
||||
"campaigns.reference.composition-assurance",
|
||||
],
|
||||
},
|
||||
),
|
||||
DocumentationTopic(
|
||||
id="mail.reference.campaign-delivery-contract",
|
||||
title="Integrate Campaign through the Mail delivery contract",
|
||||
summary="Campaign freezes a Mail profile reference and opaque revision; Mail re-authorizes, revision-checks, resolves credentials, and performs the effect in one call.",
|
||||
body="The mail.campaign_delivery 0.2 contract never returns decrypted credentials or resolved SMTP/IMAP configuration. Mail compares the expected random transport revision before decrypting protocol-specific credentials and returns only bounded sanitized outcomes. Campaign owns durable recipient jobs, retry, and reconciliation. Live report emailing remains disabled until the planned Mail-owned idempotent outbox and attempt ledger are implemented.",
|
||||
layer="available",
|
||||
documentation_types=("admin", "user"),
|
||||
audience=("integrator", "campaign_manager", "campaign_sender", "release_reviewer"),
|
||||
order=44,
|
||||
conditions=(
|
||||
DocumentationCondition(
|
||||
required_modules=("mail", "campaigns"),
|
||||
required_scopes=("mail:profile:use", "campaigns:campaign:read"),
|
||||
),
|
||||
),
|
||||
links=(
|
||||
DocumentationLink(label="Campaigns", href="/campaigns", kind="runtime"),
|
||||
DocumentationLink(label="Mail handbook", href="govoplan-mail/docs/MAIL_HANDBOOK.md", kind="repository"),
|
||||
DocumentationLink(label="Campaign Mail profile boundary", href="govoplan-campaign/docs/MAIL_PROFILE_BOUNDARY.md", kind="repository"),
|
||||
),
|
||||
related_modules=("campaigns", "audit"),
|
||||
unlocks=("Profile-backed campaign delivery without cross-module credential or configuration copies.",),
|
||||
metadata={
|
||||
"kind": "reference",
|
||||
"route": "/campaigns/{campaign_id}/mail-settings",
|
||||
"screen": "Campaign Mail settings",
|
||||
"section": "Mail-owned profile and transport boundary",
|
||||
"verification": "Prove stale revisions fail before credential decryption, SMTP never decrypts IMAP credentials, IMAP never decrypts SMTP credentials, provider details are sanitized, and the interface/version gate passes.",
|
||||
"related_topic_ids": [
|
||||
"mail.profile-ownership-and-consumers",
|
||||
"campaigns.mail-profile-user-journey",
|
||||
"campaigns.workflow.retry-and-reconcile",
|
||||
],
|
||||
},
|
||||
),
|
||||
),
|
||||
documentation_providers=(documentation_topics,),
|
||||
)
|
||||
|
||||
@@ -24,11 +24,29 @@ class MailManifestTests(unittest.TestCase):
|
||||
],
|
||||
)
|
||||
topics = {topic.id: topic for topic in manifest.documentation}
|
||||
self.assertTrue(
|
||||
{
|
||||
"mail.workflow.choose-and-test-profile",
|
||||
"mail.workflow.read-mailbox",
|
||||
"mail.reference.credentials-egress-retirement",
|
||||
"mail.reference.campaign-delivery-contract",
|
||||
}.issubset(topics)
|
||||
)
|
||||
ownership = topics["mail.profile-ownership-and-consumers"]
|
||||
self.assertEqual(ownership.metadata["kind"], "reference")
|
||||
self.assertEqual(ownership.metadata["route"], "/mail")
|
||||
self.assertEqual(ownership.metadata["route"], "/settings?section=mail-profiles")
|
||||
self.assertIn("campaigns.mail-profile-user-journey", ownership.metadata["related_topic_ids"])
|
||||
|
||||
mailbox = topics["mail.workflow.read-mailbox"]
|
||||
self.assertEqual(mailbox.metadata["route"], "/mail")
|
||||
self.assertEqual(
|
||||
mailbox.conditions[0].required_scopes,
|
||||
("mail:mailbox:read", "mail:profile:use"),
|
||||
)
|
||||
|
||||
campaign_contract = topics["mail.reference.campaign-delivery-contract"]
|
||||
self.assertEqual(campaign_contract.conditions[0].required_modules, ("mail", "campaigns"))
|
||||
|
||||
def test_retirement_scrubs_credentials_before_dropping_mail_tables(self) -> None:
|
||||
events: list[str] = []
|
||||
|
||||
|
||||
Reference in New Issue
Block a user