> ## Documentation Index
> Fetch the complete documentation index at: https://chatcli.edilsonfreitas.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Auditoria e Compliance

> Registros AuditEvent gravados pelos controllers do operator, ClusterRoles do Kubernetes para os CRDs da plataforma, relatório de compliance sob demanda e exportação JSON para ingestão em SIEM.

A plataforma AIOps do ChatCLI registra as etapas-chave do pipeline — ciclo de vida da Issue, execução de remediações, gates de aprovação, entregas de notificação, alertas de burn rate de SLO e violações de SLA — como recursos `AuditEvent`. Junto com as ClusterRoles da plataforma e um relatório de compliance sob demanda, isso dá uma trilha consultável do que a automação fez e quando.

<Info>
  Um AuditEvent é um CRD que só tem `spec` (sem subresource `status`). O
  operator cria AuditEvents e nunca os atualiza nem apaga, mas nada no cluster
  **garante** a imutabilidade: não existe admission webhook, e a ClusterRole
  `chatcli-role-admin` distribuída com a plataforma pode dar `update`/`patch`
  em AuditEvents (`chatcli-role-superadmin` também pode dar `delete`). Se você
  precisa de uma trilha à prova de adulteração, veja
  [Imutabilidade](#annotation-de-imutabilidade) e envie os eventos para um
  sistema externo.
</Info>

## Por que Audit Trail para AIOps

Quando uma plataforma toma decisões autônomas em infraestrutura de produção, a rastreabilidade deixa de ser opcional:

<CardGroup cols={2}>
  <Card title="Responsabilização" icon="user-shield">
    Quando uma remediação começou, ficou aguardando aprovação, foi aprovada,
    rejeitada ou expirou? Qual controller fez isso? Cada uma dessas etapas
    deixa um registro.
  </Card>

  <Card title="Investigação Pós-Incidente" icon="magnifying-glass">
    Todo evento carrega um `correlationId` (o nome da Issue), então a trilha de
    um incidente — criação, remediação, notificações, resolução — sai com um
    único filtro.
  </Card>

  <Card title="Compliance Regulatório" icon="scale-balanced">
    Evidência para auditorias de controle de mudanças (SOC 2, ISO 27001,
    PCI-DSS e similares): registro das ações automatizadas mais RBAC
    documentado. A plataforma fornece os registros; ela não é certificada em
    nenhum framework.
  </Card>

  <Card title="Melhoria Contínua" icon="chart-line">
    MTTD, MTTR, taxa de sucesso das remediações e resultado das aprovações,
    calculados sob demanda a partir dos CRDs da plataforma.
  </Card>
</CardGroup>

## AuditEvent CRD

O `AuditEvent` só tem `spec`, sem `status`. Short name: `ae`.

### Especificação Completa

Um evento real, como o controller de remediação grava quando um plano começa a executar:

```yaml theme={"system"}
apiVersion: platform.chatcli.io/v1alpha1
kind: AuditEvent
metadata:
  name: audit-1773930600123456789-a7f3b2
  namespace: production                  # namespace do recurso afetado
  labels:
    platform.chatcli.io/event-type: remediation_started
    platform.chatcli.io/severity: info
  annotations:
    platform.chatcli.io/immutable: "true"
spec:
  # Tipo do evento (string livre; veja a lista abaixo)
  eventType: remediation_started

  # Quando o evento foi registrado (RFC 3339, precisão de segundos)
  timestamp: "2026-03-19T14:30:00Z"

  # Quem executou a ação
  actor:
    type: controller                     # sempre "controller" nos eventos do operator
    name: RemediationReconciler
    controller: remediation-controller

  # Recurso afetado
  resource:
    kind: RemediationPlan
    name: api-server-pod-restart-1773930000-plan-1
    namespace: production
    uid: 6f1c2d0a-4b7e-4f35-9a51-0c8e2b7d9e14

  # Detalhes específicos do evento (mapa de strings)
  details:
    issue: api-server-pod-restart-1773930000
    attempt: "1"
    strategy: "Roll back to the previous revision"
    agentic: "false"

  # Agrupa eventos relacionados: o nome da Issue (o nome do SLO em slo_violation)
  correlationId: api-server-pod-restart-1773930000

  # info | warning | critical (padrão "info")
  severity: info
```

Referência de campos (`operator/api/v1alpha1/auditevent_types.go`):

| Campo | Tipo | Observações |
| - | - | - |
| `eventType` | string | Obrigatório. Sem validação de enum. |
| `actor.type` / `actor.name` / `actor.controller` | string | `type` e `name` obrigatórios. |
| `resource.kind` / `.name` / `.namespace` / `.uid` | string | `uid` opcional. |
| `details` | map\[string]string | Opcional. Valores longos são truncados (200-300 caracteres). |
| `severity` | string | Padrão `info`. O operator grava `info`, `warning` ou `critical`. |
| `correlationId` | string | Opcional. |
| `timestamp` | time | Obrigatório. |

### Tipos de Evento (EventType)

O operator emite **14** tipos de evento, a mesma lista que o comentário do campo `eventType` no CRD documenta. Todos são gravados com `actor.type: controller`, exceto uma aprovação ou rejeição decidida por pessoas (veja a aba Governança):

<Tabs>
  <Tab title="Incidentes">
    | EventType | Gravado quando | Actor / recurso | Severidade | Chaves em `details` |
    | - | - | - | - | - |
    | `issue_created` | Uma Issue nova ganha seu AIInsight e passa para `Analyzing` | `IssueReconciler` / Issue | info | `severity`, `resource`, `description` |
    | `issue_resolved` | Uma Issue é resolvida: remediação verificada, auto-resolve ou restauração humana após contenção | `IssueReconciler` / Issue | info | `resolution`, `attempts` |
    | `issue_escalated` | Todas as tentativas de remediação falharam (`MaxAttemptsReached`) | `IssueReconciler` / Issue | warning | `severity`, `attempts` |
    | `issue_contained` | Uma ação de contenção silenciou o workload e um humano precisa restaurar o serviço | `IssueReconciler` / Issue | warning | `severity`, `attempts`, `required_action` |
  </Tab>

  <Tab title="Remediação">
    | EventType | Gravado quando | Actor / recurso | Severidade | Chaves em `details` |
    | - | - | - | - | - |
    | `remediation_started` | Um RemediationPlan entra em `Executing` | `RemediationReconciler` / RemediationPlan | info | `issue`, `attempt`, `strategy`, `agentic` |
    | `remediation_completed` | A verificação de saúde pós-execução passou | `RemediationReconciler` / RemediationPlan | info | `issue`, `result` |
    | `remediation_failed` | Um plano termina `Failed` ou `RolledBack` (uma vez, na transição) | `RemediationReconciler` / RemediationPlan | warning | `issue`, `result`, `attempt` |
  </Tab>

  <Tab title="Governança">
    | EventType | Gravado quando | Actor / recurso | Severidade | Chaves em `details` |
    | - | - | - | - | - |
    | `approval_requested` | Um plano fica parado em `WaitingApproval` por uma ApprovalPolicy, pelo tier do cluster ou pelo decision engine | `RemediationReconciler` / ApprovalRequest | info | `issue`, `plan`, `rule` |
    | `approval_approved` | O plano sai de `WaitingApproval` porque o pedido foi aprovado | os aprovadores (`user`), ou `ApprovalReconciler` numa auto-aprovação / ApprovalRequest | info | `issue`, `decision`, `auto`, `approvers` |
    | `approval_rejected` | ...porque o pedido foi rejeitado | os aprovadores que rejeitaram (`user`) / ApprovalRequest | warning | `issue`, `decision`, `auto`, `approvers` |
    | `approval_expired` | ...porque o pedido expirou | `ApprovalReconciler` / ApprovalRequest | warning | `issue`, `decision`, `auto`, `approvers` (vazio) |

    Os quatro eventos de aprovação são gravados pelo controller de remediação (`actor.controller: remediation-controller`): `approval_requested` quando ele estaciona o plano, os outros três uma vez por decisão, quando o plano sai de `WaitingApproval`. Numa decisão humana, o evento diz **quem** decidiu: `actor.type: user` e `actor.name` (e o detalhe `approvers`) são os aprovadores registrados em `status.decisions` do ApprovalRequest com aquela decisão, separados por vírgula (veja [Workflow de Aprovação](/pt/kubernetes/aiops/approval-workflow)). Uma auto-aprovação ou uma expiração não tem aprovador, então o actor é `controller` / `ApprovalReconciler`. Uma regra de ApprovalPolicy em modo `auto` sem `autoApproveConditions` não estaciona o plano, então não gera eventos de aprovação; uma com condições o estaciona e os gera como qualquer outra regra.
  </Tab>

  <Tab title="Alertas e entrega">
    | EventType | Gravado quando | Actor / recurso | Severidade | Chaves em `details` |
    | - | - | - | - | - |
    | `notification_sent` | Cada tentativa de entrega de um canal de NotificationPolicy ou de escalonamento, com sucesso ou falha | `NotificationReconciler` / Issue | info (warning na falha) | `channel`, `success`, `error` |
    | `slo_violation` | Uma janela de burn rate passa a disparar em um ServiceLevelObjective | `SLOReconciler` / ServiceLevelObjective | warning | `window`, `burn_rate` |
    | `sla_breach` | Um IncidentSLA registra violação de resposta ou de resolução | `SLAReconciler` / Issue | critical | `type`, `elapsed`, `threshold` |
  </Tab>
</Tabs>

<Warning>
  Nenhum outro tipo de evento é gravado. Nomes que materiais antigos listavam,
  como `approval_granted` (o nome real é `approval_approved`), `pattern_learned`,
  `config_changed`, `cluster_connected`, `cluster_disconnected`,
  `escalation_triggered`, `postmortem_created` e `runbook_generated`, nunca aparecem.
  Experimentos de chaos, os vereditos de confiança do decision engine, a
  análise de IA, a detecção de anomalias, a federação e as chamadas à API REST
  **não** geram AuditEvents próprios. Não construa alertas nem relatórios em
  cima desses nomes.
</Warning>

### AuditActor

O campo `actor` identifica quem ou o que executou a ação:

| Tipo | Descrição | Exemplo |
| - | - | - |
| `controller` | Controller do operator | `IssueReconciler`, `RemediationReconciler`, `ApprovalReconciler`, `NotificationReconciler`, `SLOReconciler`, `SLAReconciler` |
| `user` | Os aprovadores de uma decisão humana `approval_approved` / `approval_rejected`, como registrados em `status.decisions` | `alice (api-key: ops-team)` |
| `system` | Aceito pelo schema (string livre), mas nunca gravado pelo operator | — |

Outras ações humanas (dar acknowledge ou snooze em um incidente, edições via `kubectl`) não viram AuditEvents. Para saber quem alterou qual objeto, use o audit log do API server do Kubernetes.

### AuditResource

O campo `resource` identifica o recurso Kubernetes afetado:

```go theme={"system"}
type AuditResource struct {
    Kind      string `json:"kind"`
    Name      string `json:"name"`
    Namespace string `json:"namespace"`
    UID       string `json:"uid,omitempty"`
}
```

### Formato de Nome e Namespace

Cada AuditEvent recebe o nome:

```
audit-{unix-nanossegundos}-{6-caracteres-aleatorios}
```

Exemplo: `audit-1773930600123456789-a7f3b2`.

O evento é criado **no namespace do recurso afetado** (o namespace da Issue, do RemediationPlan, do ApprovalRequest ou do SLO), e não no namespace do operator. Consulte com `-A` ou com o namespace do workload.

Só duas labels são definidas: `platform.chatcli.io/event-type` e `platform.chatcli.io/severity`. Não existe label de correlação; filtre por `spec.correlationId` (exemplos abaixo).

### Annotation de Imutabilidade

Todo AuditEvent é criado com a annotation `platform.chatcli.io/immutable: "true"`. O operator não traz admission webhook, então a annotation é só um marcador. Para tornar a trilha resistente a adulteração:

* faça valer a annotation com uma regra de policy engine (Kyverno, Gatekeeper) que rejeite `UPDATE` e `DELETE` em recursos que a carregam, exceto para o seu job de retenção;
* revise quem tem `update`/`patch`/`delete` em `auditevents` (a própria ServiceAccount do operator, `chatcli-role-admin` e `chatcli-role-superadmin` têm);
* exporte os eventos para um SIEM ou para um storage write-once.

O operator grava AuditEvents em modo best-effort: se um create falha, o controller loga o erro e segue em frente, então uma lacuna na trilha não bloqueia a remediação.

## Audit Recorder

O `AuditRecorder` (`operator/controllers/audit_recorder.go`) é o componente interno que os controllers chamam para gravar AuditEvents. Ele não é uma API pública nem ponto de extensão: um único recorder é criado na inicialização e compartilhado pelos reconcilers de Issue, Remediation, Notification, SLO e SLA. Os reconcilers de Approval, Chaos, Federation, AIInsight, Anomaly e PostMortem não têm um.

### Qual Controller Grava o Quê

| Controller | Eventos |
| - | - |
| Issue | `issue_created`, `issue_resolved`, `issue_escalated`, `issue_contained` |
| Remediation | `remediation_started`, `remediation_completed`, `remediation_failed`, `approval_requested`, `approval_approved`, `approval_rejected`, `approval_expired` |
| Notification | `notification_sent` |
| SLO | `slo_violation` |
| SLA | `sla_breach` |

### Exemplo de Evento Gerado

Uma violação de SLA, como o controller de SLA grava:

```yaml theme={"system"}
apiVersion: platform.chatcli.io/v1alpha1
kind: AuditEvent
metadata:
  name: audit-1773934200987654321-k2m9qz
  namespace: production
  labels:
    platform.chatcli.io/event-type: sla_breach
    platform.chatcli.io/severity: critical
  annotations:
    platform.chatcli.io/immutable: "true"
spec:
  eventType: sla_breach
  timestamp: "2026-03-19T15:30:00Z"
  actor:
    type: controller
    name: SLAReconciler
    controller: sla-controller
  resource:
    kind: Issue
    name: api-server-pod-restart-1773930000
    namespace: production
    uid: 0b7e3c1d-92a4-4c1e-8f60-5d2a9e3b7c48
  details:
    type: resolution
    elapsed: 1h0m12s
    threshold: 1h0m0s
  correlationId: api-server-pod-restart-1773930000
  severity: critical
```

## Compliance Reporter

O `ComplianceReporter` calcula um relatório sob demanda, servido pela API REST em `GET /api/v1/analytics/compliance` (role viewer). Nada é agendado nem armazenado: cada chamada lista os CRDs da plataforma e calcula os números.

### Solicitando um Relatório

```bash theme={"system"}
curl -s -H "X-API-Key: $CHATCLI_API_KEY" \
  "http://chatcli-operator.chatcli-system.svc:8090/api/v1/analytics/compliance?namespace=production" | jq .
```

| Parâmetro | Descrição |
| - | - |
| `namespace` | Limita a um namespace (padrão: todos) |
| `from`, `to` | RFC 3339. Um **período absoluto**: com os dois, exatamente `[from, to]`; só com `from`, até agora; só com `to`, os 7 dias que terminam em `to`. Padrão: os últimos 7 dias. |

O relatório cobre objetos **criados** dentro do período (por `metadata.creationTimestamp`). Ele lê Issues, RemediationPlans, ApprovalRequests, IncidentSLAs e AuditEvents — os AuditEvents só alimentam o resumo de auditoria; os demais números vêm dos próprios recursos.

A resposta embrulha o relatório em `spec`. As chaves são PascalCase (fixadas por tags JSON explícitas), e **durações são inteiros em nanossegundos**:

```json theme={"system"}
{
  "apiVersion": "v1",
  "kind": "ComplianceReport",
  "spec": {
    "Period": { "Start": "2026-03-12T14:00:00Z", "End": "2026-03-19T14:00:00Z" },
    "IncidentMetrics": { "...": "..." },
    "RemediationMetrics": { "...": "..." },
    "SLAMetrics": { "...": "..." },
    "ApprovalMetrics": { "...": "..." },
    "AuditSummary": { "...": "..." },
    "IncidentSLAs": [ { "...": "..." } ]
  }
}
```

### Métricas do Relatório

<Tabs>
  <Tab title="Métricas de Incidentes">
    Calculadas a partir das Issues criadas na janela.

    | Campo | Cálculo |
    | - | - |
    | `TotalIncidents` | Issues criadas na janela |
    | `BySeverity`, `ByState` | Contagens por `spec.severity` e `status.state` |
    | `MTTD` | `avg(status.detectedAt - metadata.creationTimestamp)`: o tempo entre a criação do objeto Issue e o controller carimbar `detectedAt`. **Não** é o tempo entre o início do problema e sua detecção, e costuma ficar perto de zero. |
    | `MTTR` | `avg(status.resolvedAt - status.detectedAt)` nas Issues resolvidas |
    | `MeanRemediationAttempts` | `sum(status.remediationAttempts) / TotalIncidents` |

    ```json theme={"system"}
    "IncidentMetrics": {
      "TotalIncidents": 47,
      "BySeverity": { "critical": 2, "high": 8, "medium": 22, "low": 15 },
      "ByState": { "Resolved": 41, "Escalated": 3, "Contained": 1, "Analyzing": 2 },
      "MTTD": 850000000,
      "MTTR": 510000000000,
      "MeanRemediationAttempts": 1.3
    }
    ```
  </Tab>

  <Tab title="Métricas de Remediação">
    Calculadas a partir dos RemediationPlans criados na janela.

    | Campo | Cálculo |
    | - | - |
    | `TotalRemediations` | Planos criados na janela |
    | `SuccessRate` | `Completed / (Completed + Failed + RolledBack) * 100` — um **percentual** (0-100) |
    | `ByActionType` | Por tipo de ação em `spec.actions`: `Count`, `Success` (plano `Completed`), `Failed` (plano `Failed`; planos `RolledBack` não entram aqui) |
    | `AutoRemediatedCount` | Número de planos `Completed`, tenham passado por aprovação ou não |
    | `AgenticCount` | Planos com `spec.agenticMode: true` |

    ```json theme={"system"}
    "RemediationMetrics": {
      "TotalRemediations": 52,
      "SuccessRate": 88.5,
      "ByActionType": {
        "RollbackDeployment": { "Count": 15, "Success": 14, "Failed": 1 },
        "RestartDeployment":  { "Count": 18, "Success": 17, "Failed": 1 },
        "ScaleDeployment":    { "Count": 10, "Success": 9,  "Failed": 1 }
      },
      "AutoRemediatedCount": 46,
      "AgenticCount": 7
    }
    ```
  </Tab>

  <Tab title="Métricas de SLA">
    Com recursos **IncidentSLA** no escopo, esta seção conta o que o
    controller deles registrou em cada Issue criada no período (annotation
    `platform.chatcli.io/sla-violated`), e `IncidentSLAs[]` lista cada SLA
    com os próprios contadores (veja [SLOs e SLAs](/pt/kubernetes/aiops/slo-sla)).
    Sem nenhum IncidentSLA, ela volta a uma aproximação: uma Issue `Escalated`
    conta como violação de resolução.

    | Campo | Cálculo |
    | - | - |
    | `CompliancePercentage` | `(TotalIncidents - Issues com violação) / TotalIncidents * 100`; 100 quando não há Issues |
    | `ResolutionSLAViolations` | Issues com violação de `resolution` (aproximação: Issues no estado `Escalated`) |
    | `ResponseSLAViolations` | Issues com violação de `response` (aproximação: 0) |
    | `AverageResponseTime` | `avg(status.detectedAt - metadata.creationTimestamp)` |
    | `AverageResolutionTime` | `avg(status.resolvedAt - metadata.creationTimestamp)` |

    ```json theme={"system"}
    "SLAMetrics": {
      "CompliancePercentage": 93.6,
      "ResponseSLAViolations": 1,
      "ResolutionSLAViolations": 3,
      "AverageResponseTime": 850000000,
      "AverageResolutionTime": 511000000000
    },
    "IncidentSLAs": [
      {
        "Name": "critical-sla", "Namespace": "production", "Severity": "critical",
        "ResponseTime": "5m", "ResolutionTime": "1h",
        "CompliancePercentage": 97.5, "ActiveViolations": 1,
        "TotalViolations": 3, "TotalIssuesTracked": 120
      }
    ]
    ```
  </Tab>

  <Tab title="Métricas de Aprovação">
    Calculadas a partir dos ApprovalRequests criados na janela.

    | Campo | Cálculo |
    | - | - |
    | `TotalRequests` | ApprovalRequests criados na janela |
    | `AutoApproved` / `ManualApproved` | Pedidos `Approved` separados por `status.autoApproved` |
    | `Rejected`, `Expired` | Pedidos nesses estados |
    | `AverageDecisionTime` | `avg(status.approvedAt - metadata.creationTimestamp)` nos pedidos aprovados que têm `approvedAt` |

    ```json theme={"system"}
    "ApprovalMetrics": {
      "TotalRequests": 12,
      "AutoApproved": 0,
      "ManualApproved": 8,
      "Rejected": 2,
      "Expired": 2,
      "AverageDecisionTime": 270000000000
    }
    ```
  </Tab>
</Tabs>

### Audit Summary

Contagem dos AuditEvents criados na janela, por severidade e por tipo de evento:

```json theme={"system"}
"AuditSummary": {
  "TotalEvents": 312,
  "BySeverity": { "info": 251, "warning": 55, "critical": 6 },
  "ByEventType": {
    "issue_created": 47,
    "issue_resolved": 41,
    "issue_escalated": 3,
    "remediation_started": 52,
    "remediation_completed": 46,
    "remediation_failed": 6,
    "approval_requested": 12,
    "approval_approved": 8,
    "approval_rejected": 2,
    "approval_expired": 2,
    "notification_sent": 87,
    "sla_breach": 6
  }
}
```

## Roles de RBAC do Kubernetes

A plataforma traz **4 ClusterRoles** para pessoas e ferramentas que trabalham com os CRDs da plataforma via `kubectl`. Elas são criadas pelo Helm chart do operator (`rbac.create: true`, o padrão) ou pelo `make deploy` (`operator/config/rbac/role.yaml`), nunca pelo operator em runtime (hardening H5: o operator não tem permissão para criar ClusterRoles, e nada no operator vincula essas roles — o vínculo é feito por você).

### Definição de Roles

<Tabs>
  <Tab title="Viewer">
    **`chatcli-role-viewer`** — acesso somente leitura aos CRDs ligados a incidentes.

    ```yaml theme={"system"}
    rules:
      - apiGroups: ["platform.chatcli.io"]
        resources:
          - issues
          - anomalies
          - aiinsights
          - postmortems
          - auditevents
          - servicelevelobjectives
          - incidentslas
          - remediationplans
          - runbooks
          - approvalrequests
        verbs: ["get", "list", "watch"]
    ```

    Não inclui: policies (Approval, Notification, Escalation), ChaosExperiments, ClusterRegistrations, SourceRepositories, Instances.
  </Tab>

  <Tab title="Operator">
    **`chatcli-role-operator`** — viewer, mais `update`/`patch` em Issues, ApprovalRequests e PostMortems.

    ```yaml theme={"system"}
    rules:
      - apiGroups: ["platform.chatcli.io"]
        resources: [issues, anomalies, aiinsights, postmortems, auditevents,
                    servicelevelobjectives, incidentslas, remediationplans,
                    runbooks, approvalrequests]
        verbs: ["get", "list", "watch"]
      - apiGroups: ["platform.chatcli.io"]
        resources: ["issues", "approvalrequests", "postmortems"]
        verbs: ["update", "patch"]
    ```

    Isso basta para aprovar ou rejeitar com as annotations `platform.chatcli.io/approve` / `platform.chatcli.io/reject` (veja [Workflow de Aprovação](/pt/kubernetes/aiops/approval-workflow)). Sem verbos `create` e sem acesso ao subresource `/status`.
  </Tab>

  <Tab title="Admin">
    **`chatcli-role-admin`** — `update`/`patch` nos CRDs de incidente (**incluindo `auditevents`**), mais gestão completa de Runbooks, NotificationPolicies, ServiceLevelObjectives e IncidentSLAs.

    ```yaml theme={"system"}
    rules:
      - apiGroups: ["platform.chatcli.io"]
        resources: [issues, anomalies, aiinsights, postmortems, auditevents,
                    servicelevelobjectives, incidentslas, remediationplans,
                    approvalrequests]
        verbs: ["get", "list", "watch", "update", "patch"]
      - apiGroups: ["platform.chatcli.io"]
        resources: [runbooks, notificationpolicies, servicelevelobjectives, incidentslas]
        verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
    ```

    Não inclui: ApprovalPolicies, EscalationPolicies, ChaosExperiments, ClusterRegistrations, SourceRepositories, Instances.
  </Tab>

  <Tab title="SuperAdmin">
    **`chatcli-role-superadmin`** — CRUD completo nos 17 CRDs da plataforma (incluindo `delete` em `auditevents`) e `get`/`update`/`patch` nos subresources `/status` deles.

    Não concede nada fora do grupo `platform.chatcli.io`: nenhum objeto de RBAC, nenhum ConfigMap, nenhum Secret.
  </Tab>
</Tabs>

### Concedendo uma Role

Vincule uma role a um usuário ou grupo como qualquer ClusterRole:

```yaml theme={"system"}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: chatcli-role-operator-sre
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: chatcli-role-operator
subjects:
  - kind: Group
    name: sre-oncall
    apiGroup: rbac.authorization.k8s.io
```

Use um `RoleBinding` com namespace apontando para a mesma ClusterRole para limitar o acesso a um namespace. Revogar é apagar o binding. Mudanças de role aparecem no audit log do Kubernetes; os AuditEvents do operator cobrem o que os controllers fazem, não quem recebeu qual role.

<Note>
  A API REST e o dashboard usam um modelo próprio, API keys com `viewer`, `operator` ou `admin`, descrito em [Web Dashboard](/pt/kubernetes/aiops/web-dashboard). As ClusterRoles acima são para pessoas e ferramentas que chegam aos CRDs via `kubectl`.
</Note>

## API REST de Auditoria

A API REST do operator (porta 8090, header `X-API-Key`, qualquer role a partir de `viewer`) expõe dois endpoints somente leitura. Ambos aceitam apenas `GET`.

### GET /api/v1/audit

Lista eventos, filtrados e paginados em memória, **do mais recente para o mais antigo** pelo `timestamp` (o horário de criação quando ele falta; empates por nome), então cada página é um trecho estável da trilha.

**Parâmetros de query:**

| Parâmetro | Tipo | Descrição | Exemplo |
| - | - | - | - |
| `namespace` | string | Limita a um namespace (padrão: todos) | `production` |
| `type` | string | Match exato de `eventType` | `remediation_failed` |
| `severity` | string | Match exato de severidade | `warning` |
| `resource` | string | Match exato de `resource.name` | `api-server-pod-restart-1773930000` |
| `from` | RFC 3339 | Eventos a partir de, por `spec.timestamp` | `2026-03-18T00:00:00Z` |
| `to` | RFC 3339 | Eventos até | `2026-03-19T23:59:59Z` |
| `page` | int | Número da página (padrão 1) | `2` |
| `pageSize` | int | Tamanho da página (padrão 20, máx. 100) | `50` |

Não há filtro por actor nem por correlation ID; para pegar todos os eventos de um incidente, filtre `correlationId` no cliente (veja os exemplos com kubectl e `jq` abaixo).

**Exemplo de requisição:**

```bash theme={"system"}
curl -s -H "X-API-Key: $CHATCLI_API_KEY" \
  "http://chatcli-operator.chatcli-system.svc:8090/api/v1/audit?type=remediation_failed&from=2026-03-18T00:00:00Z&to=2026-03-19T23:59:59Z&pageSize=10" | jq .
```

**Exemplo de resposta:**

```json theme={"system"}
{
  "apiVersion": "v1",
  "kind": "AuditEventList",
  "metadata": { "totalCount": 3, "page": 1, "pageSize": 10 },
  "items": [
    {
      "name": "audit-1773931800456789123-p4x8nb",
      "namespace": "production",
      "eventType": "remediation_failed",
      "severity": "warning",
      "actorType": "controller",
      "actorName": "RemediationReconciler",
      "resourceKind": "RemediationPlan",
      "resourceName": "api-server-pod-restart-1773930000-plan-1",
      "resourceNamespace": "production",
      "correlationId": "api-server-pod-restart-1773930000",
      "detail": "issue=api-server-pod-restart-1773930000; result=Approval request expired without decision; attempt=1",
      "timestamp": "2026-03-19T14:50:00Z",
      "creationTimestamp": "2026-03-19T14:50:00Z"
    }
  ]
}
```

A visão REST achata o registro: `details` vira uma única string `detail` com pares `chave=valor` unidos por `; ` (sem ordem fixa), e `actor.controller` e `resource.uid` são descartados. Use `kubectl get auditevent <nome> -o yaml` para ver o objeto completo.

### GET /api/v1/audit/export

Aceita os mesmos filtros (`namespace`, `type`, `severity`, `resource`, `from`, `to`), mas **sem paginação**, e devolve todos os eventos correspondentes como um documento JSON para download (`Content-Disposition: attachment; filename=audit-events-<timestamp>.json`):

```bash theme={"system"}
curl -s -H "X-API-Key: $CHATCLI_API_KEY" -o audit-export.json \
  "http://chatcli-operator.chatcli-system.svc:8090/api/v1/audit/export?from=2026-03-18T14:00:00Z&to=2026-03-19T14:00:00Z"

jq '.totalCount' audit-export.json
```

**Formato de exportação** — um único objeto JSON indentado (não é NDJSON), cujos `items` têm o mesmo formato do endpoint de listagem:

```json theme={"system"}
{
  "apiVersion": "v1",
  "kind": "AuditEventExport",
  "exportedAt": "2026-03-19T14:00:05Z",
  "totalCount": 312,
  "items": [
    { "name": "audit-1773930600123456789-a7f3b2", "eventType": "remediation_started", "...": "..." }
  ]
}
```

Use `jq -c '.items[]'` para transformar em um evento por linha.

<Note>
  A API REST tem rate limit de 600 requisições por minuto por API key
  válida (30 por minuto por host de cliente sem chave). O acesso a ela só é logado no stdout do operator (`[REST] método
      caminho status duração role=...`); chamadas REST não criam AuditEvents.
</Note>

## Integração com SIEM

Não existe push nativo para SIEM. Consulte o endpoint de exportação de forma agendada e encaminhe para Splunk, Elastic, Datadog ou qualquer outro coletor. Os exemplos abaixo usam `alpine` com `curl` e `jq`, e uma API key guardada em um Secret (`chatcli-audit-exporter`, chave `api-key`, com uma key `viewer`).

### Splunk

<Steps>
  <Step title="Configure o HEC (HTTP Event Collector)">
    Crie um token HEC no Splunk para receber os eventos da plataforma AIOps.
  </Step>

  <Step title="Crie o CronJob de exportação">
    ```yaml theme={"system"}
    apiVersion: batch/v1
    kind: CronJob
    metadata:
      name: audit-export-splunk
      namespace: chatcli-system
    spec:
      schedule: "*/15 * * * *"   # A cada 15 minutos
      jobTemplate:
        spec:
          template:
            spec:
              containers:
                - name: exporter
                  image: alpine:3.22
                  command:
                    - /bin/sh
                    - -c
                    - |
                      set -eu
                      apk add --no-cache curl jq >/dev/null
                      # Últimos 20 minutos (5 min de sobreposição; deduplique por "name" no Splunk)
                      FROM=$(date -u -d "@$(( $(date +%s) - 1200 ))" +%Y-%m-%dT%H:%M:%SZ)
                      TO=$(date -u +%Y-%m-%dT%H:%M:%SZ)

                      curl -sf -H "X-API-Key: $CHATCLI_API_KEY" \
                        "http://chatcli-operator.chatcli-system.svc:8090/api/v1/audit/export?from=$FROM&to=$TO" \
                        | jq -c '.items[] | {event: ., sourcetype: "chatcli:audit"}' > /tmp/events.json

                      # O HEC aceita vários eventos em uma requisição
                      [ -s /tmp/events.json ] && curl -sf -X POST \
                        "https://splunk.example.com:8088/services/collector/event" \
                        -H "Authorization: Splunk $SPLUNK_HEC_TOKEN" \
                        --data-binary @/tmp/events.json
                  env:
                    - name: CHATCLI_API_KEY
                      valueFrom:
                        secretKeyRef:
                          name: chatcli-audit-exporter
                          key: api-key
                    - name: SPLUNK_HEC_TOKEN
                      valueFrom:
                        secretKeyRef:
                          name: splunk-credentials
                          key: hec-token
              restartPolicy: OnFailure
    ```
  </Step>

  <Step title="Crie o índice e os dashboards">
    Configure um índice dedicado `chatcli_audit` no Splunk e crie dashboards
    para visualizar eventos por tipo, severidade e namespace.
  </Step>
</Steps>

### Elasticsearch

```yaml theme={"system"}
apiVersion: batch/v1
kind: CronJob
metadata:
  name: audit-export-elastic
  namespace: chatcli-system
spec:
  schedule: "*/15 * * * *"
  jobTemplate:
    spec:
      template:
        spec:
          containers:
            - name: exporter
              image: alpine:3.22
              command:
                - /bin/sh
                - -c
                - |
                  set -eu
                  apk add --no-cache curl jq >/dev/null
                  FROM=$(date -u -d "@$(( $(date +%s) - 1200 ))" +%Y-%m-%dT%H:%M:%SZ)
                  TO=$(date -u +%Y-%m-%dT%H:%M:%SZ)

                  # Bulk API; o nome do evento como _id torna a sobreposição idempotente
                  curl -sf -H "X-API-Key: $CHATCLI_API_KEY" \
                    "http://chatcli-operator.chatcli-system.svc:8090/api/v1/audit/export?from=$FROM&to=$TO" \
                    | jq -c '.items[] | {index: {_id: .name}}, .' > /tmp/bulk.ndjson

                  [ -s /tmp/bulk.ndjson ] && curl -sf -X POST \
                    "https://elastic.example.com:9200/chatcli-audit/_bulk" \
                    -H "Content-Type: application/x-ndjson" \
                    -u "$ELASTIC_USER:$ELASTIC_PASS" \
                    --data-binary @/tmp/bulk.ndjson
              env:
                - name: CHATCLI_API_KEY
                  valueFrom:
                    secretKeyRef:
                      name: chatcli-audit-exporter
                      key: api-key
                - name: ELASTIC_USER
                  valueFrom:
                    secretKeyRef:
                      name: elastic-credentials
                      key: username
                - name: ELASTIC_PASS
                  valueFrom:
                    secretKeyRef:
                      name: elastic-credentials
                      key: password
          restartPolicy: OnFailure
```

<Tip>
  Se a API REST do operator roda com TLS (`CHATCLI_AIOPS_TLS_CERT` /
  `CHATCLI_AIOPS_TLS_KEY`), troque as URLs para `https://` e passe a CA com
  `--cacert`.
</Tip>

## Comandos kubectl

<Accordion title="Consultas de auditoria comuns via kubectl">
  ```bash theme={"system"}
  # Listar todos os eventos de auditoria (eles ficam nos namespaces dos workloads)
  kubectl get auditevents -A
  # Colunas: EVENTTYPE, ACTOR, RESOURCE, SEVERITY, AGE (short name: ae)

  # Filtrar por tipo de evento
  kubectl get ae -A -l platform.chatcli.io/event-type=remediation_failed

  # Filtrar por severidade
  kubectl get ae -A -l platform.chatcli.io/severity=critical

  # Todos os eventos de um incidente (correlationId = nome da Issue), em ordem
  kubectl get ae -n production -o json | \
    jq -r '.items | map(select(.spec.correlationId == "api-server-pod-restart-1773930000"))
           | sort_by(.spec.timestamp)[] | "\(.spec.timestamp) \(.spec.eventType)"'

  # Ver detalhes de um evento específico
  kubectl get ae audit-1773930600123456789-a7f3b2 -n production -o yaml

  # Contar eventos por tipo
  kubectl get ae -A -o json | \
    jq '[.items[].spec.eventType] | group_by(.) | map({type: .[0], count: length})'

  # Conferir as ClusterRoles da plataforma e quem está vinculado a elas
  kubectl get clusterroles | grep chatcli-role-
  kubectl get clusterrolebindings -o json | \
    jq -r '.items[] | select(.roleRef.name | startswith("chatcli-role-"))
           | "\(.metadata.name): \(.roleRef.name) -> \([.subjects[]?.name] | join(","))"'

  # Relatório de compliance dos últimos 7 dias (via REST)
  curl -s -H "X-API-Key: $CHATCLI_API_KEY" \
    "http://chatcli-operator.chatcli-system.svc:8090/api/v1/analytics/compliance?namespace=production" | jq .spec
  ```
</Accordion>

## Retenção de Eventos

<Note>
  O operator nunca apaga AuditEvents — não há TTL, configuração de retenção
  nem owner reference, então eles não são coletados junto com a Issue. Cada
  evento é um objeto no etcd; configure um job de retenção para manter a
  contagem sob controle.
</Note>

```yaml theme={"system"}
# Apaga AuditEvents com mais de 90 dias, em todos os namespaces
apiVersion: v1
kind: ServiceAccount
metadata:
  name: audit-retention
  namespace: chatcli-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: audit-retention
rules:
  - apiGroups: ["platform.chatcli.io"]
    resources: ["auditevents"]
    verbs: ["list", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: audit-retention
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: audit-retention
subjects:
  - kind: ServiceAccount
    name: audit-retention
    namespace: chatcli-system
---
apiVersion: batch/v1
kind: CronJob
metadata:
  name: audit-retention
  namespace: chatcli-system
spec:
  schedule: "0 2 * * 0"    # Todo domingo às 02:00
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: audit-retention
          containers:
            - name: cleanup
              # Qualquer imagem que traga kubectl e um shell POSIX
              image: registry.example.com/tools/kubectl-shell:1.31
              command:
                - /bin/sh
                - -c
                - |
                  CUTOFF=$(date -u -d "@$(( $(date +%s) - 90*86400 ))" +%Y-%m-%dT%H:%M:%SZ)
                  kubectl get auditevents -A --no-headers \
                    -o custom-columns=NS:.metadata.namespace,NAME:.metadata.name,TS:.spec.timestamp | \
                  awk -v c="$CUTOFF" '$3 < c {print $1, $2}' | \
                  while read -r ns name; do
                    kubectl delete auditevent -n "$ns" "$name"
                  done
          restartPolicy: OnFailure
```

Exporte para o seu SIEM antes que a janela de retenção feche se precisar guardar os eventos por mais tempo.

## Trilha de Auditoria do Servidor

Os AuditEvents acima cobrem o **operator**. O **servidor** ChatCLI (`chatcli server`, o pod que uma Instance executa) tem uma trilha separada, em arquivo: defina `spec.server.security.auditLogPath` na Instance (vira `CHATCLI_AUDIT_LOG_PATH`) com um caminho **absoluto**, e cada chamada gRPC é anexada como uma linha JSON encadeada por hash (`kind: "grpc"`: ação, actor, role, IP do chamador, resultado, duração), intercalada com as entradas de requisições LLM na mesma cadeia verificável. Detalhes e verificação (`/config security verify-audit`) estão em [Segurança](/pt/security/overview).

O pod da Instance tem root filesystem somente leitura; só `/tmp` e `/home/chatcli/.chatcli` são graváveis, ambos volumes `emptyDir` perdidos no restart. Para manter o arquivo entre restarts, habilite `spec.persistence` e aponte o caminho para dentro do volume de sessões, por exemplo `/home/chatcli/.chatcli/sessions/audit.jsonl`.

<Warning>
  O **operator** em si não grava audit log em arquivo. Ele não lê
  `CHATCLI_AUDIT_LOG_PATH`; o valor `security.auditLogPath` do chart do
  operator ainda renderiza essa variável, mas não tem efeito.
</Warning>

## Próximos Passos

<CardGroup cols={2}>
  <Card title="Workflow de Aprovação" icon="user-check" href="/pt/kubernetes/aiops/approval-workflow">
    Como os planos são estacionados e decididos — a origem dos eventos
    `approval_*`, incluindo os gates criados pelo decision engine e pelo tier
    do cluster.
  </Card>

  <Card title="SLOs e SLAs" icon="gauge-high" href="/pt/kubernetes/aiops/slo-sla">
    Alertas de burn rate e timers de SLA por trás de `slo_violation` e
    `sla_breach`, e o compliance de SLA real por severidade.
  </Card>

  <Card title="Web Dashboard" icon="browser" href="/pt/kubernetes/aiops/web-dashboard">
    A visão de auditoria, as API keys e as roles da REST.
  </Card>

  <Card title="Plataforma AIOps" icon="brain" href="/pt/kubernetes/aiops-platform">
    Voltar para a visão geral da plataforma AIOps.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.