OSVauco/docs/A2H2A_TICKETING_SPEC.md
Chris Christiansen 3b6e4e4890 docs/code: clarify A2H2A prototype status and disable execution
- Add Implementation Status section to A2H2A spec

- Clarify Google Chat is notification-only

- Add target approval architecture requirements

- Add critical A2H2A safety principle to RUNBOOK.md

- Remove unsafe approval/rejection endpoints from server.py

- Enforce server-side parameter_hash calculation

- Disable execution for all tools in A2H2A_TOOL_ALLOW_LIST
2026-09-04 12:00:07 +00:00

7.8 KiB

OSVxCC A2H2A Ticketing System Specification

1. Introduksjon

A2H2A (Agent-to-Human-to-Agent) er en uomgåelig Approval Gate mellom autonome observatører/analytikere og operative eksekveringsagenter. Ingen destruktive eller privilegerte handlinger skal utføres i GCP-infrastrukturen uten at autorisert operatør eksplisitt har validert og godkjent handlingen via et kryptografisk signert grensesnitt.

Implementation Status

Current prototype — proposal recording only; approval and execution disabled.

  • The prototype may accept an allow-listed ticket proposal and store it as PENDING.
  • Google Chat is notification-only. It does not verify or prove the identity of an approver.
  • The current /a2h2a/review/{ticket_id} link is conceptual only.
  • No working approval or rejection endpoint currently exists.
  • No one-time action token currently exists.
  • No execution worker currently exists.
  • No proposed tool is executable through A2H2A at this stage.

2. JSON Datamodell (a2h2a-ticket-v1.json)

{
  "ticket_id": "A2H2A-20260904-8B3D",
  "timestamp": "2026-09-04T14:20:05Z",
  "severity": "CRITICAL",
  "category": "SECURITY",
  "source": {
    "reporter": "tyr-compliance-agent",
    "trigger": "Secret scanned in public repository",
    "affected_service": "mcp-server-key",
    "project_id": "propane-will-491900-m5",
    "region": "global"
  },
  "context": {
    "summary": "En aktiv Secret Manager-nøkkel ble funnet i en offentlig Gitea-commit.",
    "evidence_logs": [
      "gitea.commit.url: https://git.vauco.no/chris/OSVauco/commit/a1b2c3d4...",
      "secret.name: projects/357036551735/secrets/mcp-server-key/versions/2"
    ]
  },
  "proposed_action": {
    "action_type": "AUTOMATED_REMEDIATION",
    "runbook_reference": "docs/RUNBOOK.md#hendelse-eksponert-hemmelighet",
    "execution_tool": "opax.secrets.rotate",
    "parameters": {
      "secret_name": "mcp-server-key",
      "disable_old_versions": true,
      "notify_channel": "#security-alerts"
    },
    "parameter_hash": "sha256:f4a2...d8e0",
    "rollback_plan": "Manuell re-aktivering av forrige hemmelighetsversjon via `gcloud secrets versions enable` etter verifisering."
  },
  "governance": {
    "approval_status": "PENDING",
    "authorized_approver": "chris.christiansen@vauco.no",
    "requires_mfa": true,
    "timeout_minutes": 15
  }
}

The ticket model is a proposal model. Fields required for secure human approval—such as approval_token_hash, verified_approver_identity, approval timestamp, token_used_at, and immutable audit-event references—are target-design fields and are not implemented in the current prototype.

3. Sikkerhetsgarantier

3.1 Constant-Time Authentication

  • Sammenligning av alle signaturer og tokens skal utføres med secrets.compare_digest eller tilsvarende for å forhindre timing-angrep.

3.2 Anti-Tampering

  • En SHA-256 hash av proposed_action.parameters skal beregnes før ticketen sendes til operatør.
  • Før eksekvering skal OPAX verifisere at hashen av parameterne den mottok for eksekvering stemmer overens med parameter_hash i den godkjente ticketen.

3.3 Replay-Beskyttelse

  • Hver callback fra Slack/Discord skal inneholde et timestamp.
  • Serveren skal avvise callbacks hvor current_time - callback_timestamp > 300 sekunder for å forhindre gjenbruk av gamle godkjenninger.

3.4 Time-To-Live (TTL)

  • Ubehandlede tickets utløper automatisk basert på alvorlighetsgrad:
    • CRITICAL: 15 minutter
    • HIGH: 60 minutter
    • MEDIUM/LOW: 24 timer

4. API-Endepunkter (Prototype)

4.1 POST /api/v1/a2h2a/tickets

  1. Motta ticket-payload fra en autorisert intern agent (f.eks. TYR).
  2. Valider payloaden mot en Pydantic-modell basert på schemaet over.
  3. Beregn parameter_hash server-side.
  4. Lagre ticketen i en Firestore-collection (a2h2a_tickets) med status PENDING.
  5. Formater og send en Google Chat-melding med et konseptuelt link til en fremtidig godkjennings-UI.

Google Chat delivers a notification and review link only; it must never be used as evidence of the approver's identity or as the authority to execute a tool.

Target Approval Architecture — Required Before Production

The eventual review URL may use: /a2h2a/review/{ticket_id}?token=<opaque-random-token>

  • The token is generated with a cryptographically secure random generator.
  • The raw token is returned once in the notification link and is never persisted.
  • Only the SHA-256 token hash is stored server-side.
  • Approval/rejection backend verifies IAP-verified identity, PENDING state, TTL, unused matching token hash, authorized approver, server-side canonical parameter hash, and tool allow-list.
  • Approval only updates the ticket state.
  • A separate worker later executes only server-stored, immutable, approved actions.
  • Every audit event is a target requirement; do not claim it is already implemented.

Target audit requirements

Immutable audit events for proposal, approval, rejection, expiry, execution start, execution success, execution failure, and rollback are required before production activation; they are not implemented in the current prototype.

5. Google Chat / Slack Block Kit Payload (Konseptuelt Eksempel)

{
  "blocks": [
    {
      "type": "header",
      "text": {
        "type": "plain_text",
        "text": "🚨 A2H2A Godkjenning Kreves: CRITICAL"
      }
    },
    {
      "type": "section",
      "fields": [
        {"type": "mrkdwn", "text": "*Kategori:*
SECURITY"},
        {"type": "mrkdwn", "text": "*Tjeneste:*
mcp-server-key"},
        {"type": "mrkdwn", "text": "*Handling:*
`opax.secrets.rotate`"},
        {"type": "mrkdwn", "text": "*Tidsfrist:*
15 minutter"}
      ]
    },
    {
      "type": "section",
      "text": {
        "type": "mrkdwn",
        "text": "*Sammendrag:*
En aktiv Secret Manager-nøkkel ble funnet i en offentlig Gitea-commit."
      }
    },
    {
      "type": "actions",
      "elements": [
        {
          "type": "button",
          "text": {
            "type": "plain_text",
            "text": "✅ Godkjenn",
            "emoji": true
          },
          "style": "primary",
          "value": "approve_A2H2A-20260904-8B3D"
        },
        {
          "type": "button",
          "text": {
            "type": "plain_text",
            "text": "❌ Avvis",
            "emoji": true
          },
          "style": "danger",
          "value": "reject_A2H2A-20260904-8B3D"
        }
      ]
    }
  ]
}

6. Eksempel-Ticket (SECRET_EXPOSURE)

{
  "ticket_id": "A2H2A-20260904-1C4F",
  "timestamp": "2026-09-04T18:05:10Z",
  "severity": "CRITICAL",
  "category": "SECURITY",
  "source": {
    "reporter": "tyr-scanner-agent",
    "trigger": "Audit log anomaly: Unexpected access to mcp-server-key v2",
    "affected_service": "mcp-server-key",
    "project_id": "propane-will-491900-m5",
    "region": "global"
  },
  "context": {
    "summary": "Mistenkelig tilgang til mcp-server-key v2 fra en ukjent IP-adresse (35.22.88.101) utenfor GCP-nettverket.",
    "evidence_logs": [
      "log_explorer_link: https://console.cloud.google.com/logs/query;query=..."
    ]
  },
  "proposed_action": {
    "action_type": "AUTOMATED_REMEDIATION",
    "runbook_reference": "docs/RUNBOOK.md#hendelse-eksponert-hemmelighet",
    "execution_tool": "opax.secrets.rotate",
    "parameters": {
      "secret_name": "mcp-server-key",
      "disable_old_versions": true,
      "notify_channel": "#security-alerts"
    },
    "parameter_hash": "sha256:f4a26901a511e6cb716b5a86552631521a0e71383921034293739886313ad8e0",
    "rollback_plan": "Manuell re-aktivering av forrige hemmelighetsversjon (v3) via `gcloud secrets versions enable` etter verifisering."
  },
  "governance": {
    "approval_status": "PENDING",
    "authorized_approver": "chris.christiansen@vauco.no",
    "requires_mfa": true,
    "timeout_minutes": 15
  }
}