Skip to content

[P0] Write surface — gated, dual-control, defer-by-default (epic, 10 sub-items) #20

@se-jo-ma

Description

@se-jo-ma

Problem

Today every adapter's execute() is read-only. Per design-docs/05-ecosystem-roadmap.md:481-521, real-world remediation pipelines (CR creation, doc publish, KG writeback) need the broker to propose writes while keeping the governance + attestation chain. Callers currently bypass the broker for any mutation, losing the policy chain entirely.

Hard requirements (10 sub-items)

All required before any write surface ships:

  • Two-key control. Write fires only when (1) policy engine returns allow AND (2) separate configurable approval channel signs off (HITL token / Bosun rule / attestation chain prereq). No single rule authorizes write end-to-end.
  • Per-source write_allowed: false default. Source config explicitly opts in. Adapters that don't override awrite() raise WriteNotSupportedError rather than silently fall back to read.
  • Per-purpose write_allowed_purposes allowlist distinct from allowed_purposes. Read + write get separate gates.
  • Idempotency tokens. Every write carries caller-supplied key; adapter dedupes within configurable TTL window so retries/replays don't produce duplicate side effects.
  • Write attestation. JWS chain extended with separate write_attestation claim block: request hash, dedupe key, second-key signature. Fresh attestation sandwich around every write.
  • Default-off rule pack. Ship nautilus-write-default-deny in built-ins so fresh broker cannot write anything until operator wires the pack.
  • Audit fields. event_type: write_request distinct from request; dry_run: bool envelope flag stamped into audit so prod runs and rehearsals visible at a glance.
  • Write rate limit. Per-source max_writes_per_minute cap with hard ceiling. Exceeding cap escalates to deny and rage-quits session.
  • Reverse-proxy / break-glass mode. Every write endpoint flippable read-only at runtime via SIGHUP / config reload without redeploy.
  • Adapter.awrite() Protocol method alongside execute() — signature TBD as part of design spike.

Design references

  • design-docs/05-ecosystem-roadmap.md:481-521 — full spec
  • nautilus/adapters/servicenow.py:258 — cited canonical example of GET-only adapter
  • Related: Harbor v0.x cve_remediation pilot drove this requirement

Acceptance (per sub-item)

Each checkbox above is its own PR. This umbrella issue closes only when all 10 ship + integration test exercises a write request through full two-key + dual attestation + audit path.

Priority

P0 — largest single block of unimplemented design; blocks remediation pipelines that need broker governance.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P0Critical: security/trust gap, blocks releaseenhancementNew feature or requestepicMulti-issue rollupsecuritySecurity or attestation gapsize/XLEpic / multi-week / spans subsystems

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions