Skip to content

68. Privacy allowlist for poll input drivers

Date: 2026-07-06

Status

Accepted

Context

ADR 0063 defines fullsend poll, including a jira-poll input driver that maps Jira issue fields into NormalizedEvent per the Jira poll adapter. That mapping is unfiltered: issue title, comment bodies, and label state flow directly into NormalizedEvent and are projected into agent-visible FULLSEND_WORK_ITEM_* environment variables and event_payload.comment.

This is a gap for installations where the polled Jira project is internal but the target repo is public. Jira issues can carry customer names, internal priority rationale, or references to other internal tickets — content with no equivalent in a GitHub-native dispatch, where the event source and the target repo share the same trust boundary. jira-poll is the first driver where the event source and the dispatch target do not.

The security threat model's "Indirect information disclosure" section already treats forge content flowing through an agent as a threat surface and mitigates it on the output side (SecretRedactor, ADR 0022). jira-poll introduces a new input-side question that ADR 0063 does not answer: which Jira fields should reach NormalizedEvent at all. ADR 0063 scopes poll input drivers to discovery, change detection, and coordination only ("Poll input drivers MUST NOT perform authorization policy — that is the dispatch core's responsibility") and does not address content filtering.

Decision

jira-poll (and future poll input drivers for non-forge-native sources) apply a privacy allowlist to Jira fields before constructing NormalizedEvent, inside the input driver, before the event reaches the shared dispatch core.

Configuration extends the existing poll.input_drivers block:

yaml
poll:
  input_drivers:
    - type: jira-poll
      connection: { ... }
      queries:
        - project = PROJ AND status != Done
      privacy_gate:
        allowed_fields: [summary, issue_type, priority, labels]
        comment_template: |
          Type: {issue_type}
          Priority: {priority}
          Summary: {summary}
  • Allowlist projection, default-deny. Only fields listed in allowed_fields are read into NormalizedEvent. Fields not listed (description, comment body, custom fields, reporter identity beyond role mapping) are omitted at construction time, not merely hidden from display.
  • Template-projected free text. comment_template, when set, replaces transition.comment.body/event_payload.comment with a bounded, named-slot projection instead of the verbatim Jira comment.
  • PII scan on allowlisted free text. Fields allowed through by name (e.g. summary) are still scanned for PII patterns (email, phone, SSN-shaped strings) as defense in depth, consistent with the threat model's existing content-aware redaction guidance.
  • Provenance hash. A SHA-256 hash of the pre-gate NormalizedEvent payload is attached as state.privacy_gate.source_hash, so sanitization can be verified for a given dispatched run without retaining the original Jira content anywhere downstream.

When privacy_gate is omitted, the driver defaults to the current allowlist (summary, issue_type, priority, labels) rather than the unfiltered behavior described in the Jira poll adapter — that document is updated alongside this ADR to reflect the gated mapping as the default, with an explicit opt-out for installations where the Jira project and target repo share the same trust boundary.

Consequences

  • Poll-sourced NormalizedEvents carry less Jira content by default than the original adapter mapping; harnesses that need additional fields must request them explicitly via allowed_fields.
  • jira-poll-adapter.md gains a new schema extension (privacy_gate block) that must be implemented before or alongside the jira-poll driver in the #2263 epic — this ADR should land before that implementation starts, not as a retrofit.
  • Installations that want the pre-gate behavior (single-trust-boundary Jira + target repo) can set a broad allowed_fields list or omit comment_template to pass comment bodies through unmodified.
  • Future poll input drivers for other internal sources should implement the same privacy_gate shape rather than inventing per-driver filtering.
  • Does not change dispatch-core authorization (ADR 0054), CEL trigger evaluation, or output drivers — the gate applies strictly before NormalizedEvent construction.

References