Skip to content

ADR 0009 delivery

wiki-sync[bot] edited this page Jul 23, 2026 · 1 revision

ADR-0009: Delivery — SNS hub with channel adapters (Slack, Jira, Email)

Status: Accepted (2026-07-23)

Context

Each nightly run produces a full report — findings, drift classifications, HRI/MRI counts, recommendations, and (in advisory_pr mode) a draft-PR link. This must reach the team in two distinct forms: visibility (a digest people read) and tracked work (HRIs as durable, deduplicated tickets).

Two constraints shape the delivery design:

  • The agent processes untrusted input (HCL, tfstate), so third-party channel credentials (Slack/Jira tokens) must not live inside the agent (ADR-0002 / ADR-0007).
  • Channels should be added or removed without changing the agent.

Decision drivers

  • Decouple the agent from delivery channels.
  • Keep channel credentials out of the agent's blast radius.
  • Thin payloads; durable, idempotent tracked work; multiple channels.

Decision

Amazon SNS as the delivery hub; channel adapters own the integrations.

  1. The agent publishes one thin message to SNS — its only delivery scope is sns:Publish (ADR-0007). The full report goes to S3; the SNS message is a summary + a link to the S3 report (respecting SNS's 256 KB limit and keeping payloads small), plus the draft-PR link when present.
  2. Channel adapters subscribe to SNS and own their own integration and credentials (in Secrets Manager) — the agent never holds a channel credential:
    • Slack adapter → nightly digest + report link (visibility).
    • Jira adapteridempotent tracked tickets: one ticket per finding (keyed check_id + resource), updated on recurrence and closed on resolution — never create-new-every-night. Honours the accepted-risk register (ADR-0008) so suppressed items don't reopen tickets.
    • Email adapter (SES) → a formatted digest for stakeholders who prefer email.
  3. Channels are configurable — subscribe/unsubscribe an adapter without touching the agent.

Consequences

  • The agent is decoupled and minimal — one sns:Publish, no channel secrets; the process that ingests untrusted input can't leak a Slack/Jira token because it never has one.
  • Thin payloads — the notification links to the S3 report rather than inlining it.
  • No ticket spam — idempotent Jira keying gives one living ticket per finding; combined with the accepted-risk register, it avoids alert fatigue.
  • Clear division of purpose — Slack/Email are visibility; Jira is the durable work record.
  • More components to build and maintain — three adapters plus the topic. Accepted as the cost of decoupling and credential isolation.

Alternatives considered

Option Verdict Why
SNS hub + Slack/Jira/Email adapters Chosen Decoupled, channel-agnostic, channel secrets isolated in adapters, thin payloads.
Direct API calls from the agent (Slack/Jira SDKs in-process) Rejected Couples the agent to each channel and puts third-party credentials in the process that handles untrusted input.
Email only (SES) Rejected as sole channel No tracked work items; email kept as one channel, not the whole delivery.
EventBridge hub (API Destinations) Viable alternative API Destinations could call Slack/Jira with less Lambda glue and content-based routing; SNS is simpler and sufficient for v1 — see revisit.

Revisit trigger

  • Move the hub to EventBridge if content-based routing, native API Destinations, or event archive/replay become valuable.
  • Add PagerDuty (paging) if any finding class ever warrants urgent escalation — the nightly cadence is currently non-urgent by design.

References

  • ADR-0006 (source of the report, HRI/MRI counts, milestone)
  • ADR-0007 (sns:Publish + S3-write scope; channel credentials live in adapters, not the agent)
  • ADR-0008 (accepted-risk register the Jira adapter honours; advisory-PR link)

Clone this wiki locally