
Auditoria de reconciliação para a integração do Discord do Alliance Auth: encontra membros do servidor que possuem funções gerenciadas pelo AA que o Auth nunca concedeu e remove ou expulsa-os sob uma política controlada pelo operador. Aplicativo Django comunitário independente.
Auditoria de reconciliação para a integração Discord do Alliance Auth. Compara as atribuições reais de cargos no servidor Discord configurado contra o estado expresso no Alliance Auth (Grupos + Estado por utilizador) e fecha a lacuna pela qual moderadores podem atribuir manualmente cargos com nomes AA a utilizadores que o AA desconhece.
Estado: alpha (
0.1.x). A API pública e as configurações podem ainda ser alteradas antes da versão1.0.
A auditoria é segura por defeito:
InitialAuditAcknowledgement explícito (apenas administrador ou shell).report para todas as categorias — ações
destrutivas são opt-in.AuditRun, AuditFinding, AuditInvocation,
ConfigChangeLog) são apenas de adição (append-only) ao nível do gestor e das
instâncias; atualizações em massa update() / bulk_update() estão bloqueadas.Cada membro do servidor é classificado numa das seguintes categorias:
| Categoria | Significado |
|---|---|
unknown_guest | Membro do Discord que o AA desconhece completamente |
linked_no_perm | Identidade conhecida do AA mas sem discord.access_discord |
bot_filtered | Conta de bot configurada — nunca é alvo de ação |
O operador mapeia cada categoria para uma ação:
| Ação | Comportamento |
|---|---|
report | Registar a descoberta; sem alteração no Discord |
strip | Remover cargos geridos pelo AA |
strip_kick | Remover cargos geridos pelo AA e expulsar do servidor |
O mapeamento é a configuração AA_DISCORD_AUDIT_POLICY; sobreposições por grupo e
por estado aninham-se dentro de cada categoria.
allianceauth.services.modules.discord) instalado e configurado
(token do bot + servidor)pip install aa-discord-audit
No seu Auth `local.py`:```python
# `aa_discord_audit` must appear AFTER
# `allianceauth.services.modules.discord` so the discord module's
# models load first; `apps.ready()` raises `ImproperlyConfigured`
# otherwise.
INSTALLED_APPS += ["aa_discord_audit"]
MIDDLEWARE += [
"aa_discord_audit.current_user.CurrentUserMiddleware",
]
Em seguida, execute as migrações:```sh python manage.py migrate aa_discord_audit
O `CurrentUserMiddleware` é obrigatório — `apps.ready()` levanta
`ImproperlyConfigured` se estiver faltando. É o que permite que o
manipulador de sinal `ConfigChangeLog` atribua edições de admin a um usuário real
em vez de `<system>`.
## Início rápido
1. Conceda `aa_discord_audit.run_audit` à função de operador que executa
auditorias.
2. Execute uma auditoria de simulação: ```sh
python manage.py audit_discord_roles --action report
InitialAuditAcknowledgement através do admin, ou execute
python manage.py audit_acknowledge_initial. Ambos requerem
aa_discord_audit.run_audit e
aa_discord_audit.acknowledge_initial_audit.Os codinomes manage_* são divididos por raio de explosão para que um júnior com
manage_bot_account_uid não possa também desarmar a auditoria editando
ManagedRoleException.
Todas as configurações são opcionais. Os padrões são seguros.```python
AA_DISCORD_AUDIT_POLICY = { "unknown_guest": "report", "linked_no_perm": "report", # "linked_no_perm": { # "default": "strip", # "by_state": {"Guest": "report"}, # "by_group": {"Directors": "report"}, # }, }
AA_DISCORD_AUDIT_NOTIFY_ADMINS = True
AA_DISCORD_AUDIT_WEBHOOK_URL = None
AA_DISCORD_AUDIT_BOT_UIDS = []
AA_DISCORD_AUDIT_AUTO_DISCOVER_BY_NICKNAME = False
AA_DISCORD_AUDIT_RUN_RETENTION_DAYS = 180 AA_DISCORD_AUDIT_RETENTION_OPT_OUT_ACKNOWLEDGED = False
AA_DISCORD_AUDIT_IDEMPOTENCY_KEY_TTL_DAYS = 0
AA_DISCORD_AUDIT_RUN_DEADLINE_MINUTES = 60
AA_DISCORD_AUDIT_RUN_RATE_LIMIT_PER_DAY = 5 AA_DISCORD_AUDIT_RUN_RATE_LIMIT_DISABLED = False
AA_DISCORD_AUDIT_WEBHOOK_TIMEOUT = 10 AA_DISCORD_AUDIT_WEBHOOK_MAX_RETRIES = 3
AA_DISCORD_AUDIT_USE_BULK_ROLE_STRIP = False
AA_DISCORD_AUDIT_BEAT_ALLOW_DESTRUCTIVE = False
AA_DISCORD_AUDIT_BEAT_MIN_INTERVAL_MINUTES = 0
AA_DISCORD_AUDIT_CLI_ACTOR = None
AA_DISCORD_AUDIT_PRESENCE_ENABLED = True
AA_DISCORD_AUDIT_PRESENCE_SAMPLE_INTERVAL_MINUTES = 10
AA_DISCORD_AUDIT_METRICS_MEMBERS_BY_GROUP = True
AA_DISCORD_AUDIT_METRICS_MEMBERS_BY_ROLE = False
## Comandos de gerenciamento
| Comando | Propósito |
|--------------------------|------------------------------------------------------------------|
| `audit_discord_roles` | Ponto de entrada principal. `--action {report,strip,strip_kick}`. |
| `audit_discord_roles --resume <run_id>` | Revisitar resultados PENDING de uma execução existente. |
| `audit_discord_roles --abandon <run_id>` | Marcar uma execução travada como ABANDONED. |
| `audit_discord_roles --diff <run_id>` | Comparar estado atual com uma execução histórica. |
| `audit_discord_roles --explain <member_id>` | Classificação por membro (somente leitura). |
| `audit_discord_roles --policy-preview <json>` | Projetar uma política hipotética. |
| `audit_discord_roles --from-fixture <path>` | Reproduzir contra um snapshot JSON. |
| `audit_acknowledge_initial` | Liberar o bloqueio de dry-run da primeira execução a partir do console. |
| `audit_benchmark` | Benchmark de dimensionamento de carga sintética (veja [`docs/performance.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/performance.md)). |
| `prune_audit_runs` | Poda de retenção. |
| `audit_abandon_stuck_runs` | Reconciliar execuções PENDING travadas que vazaram de um worker que crashou — define como ABANDONED (veja o runbook; uma execução RUNNING travada usa `audit_discord_roles --abandon`). |
Uma execução de longa duração de ``audit_discord_roles`` reage limpa a ``SIGTERM``
e ``SIGINT``: a execução é definida como ``INTERRUPTED`` e o loop de aplicação
sai no próximo limite de descoberta para que o trabalho parcial seja
durável no registro de auditoria. ``audit_discord_roles --resume <run_id>``
retoma a execução a partir dos achados ``PENDING`` restantes.
## Auditoria periódica (Celery beat)
`audit_orphan_members` executa o mesmo pipeline de build + apply em um
agendamento que você configura no Celery beat (não é agendado por padrão).
O caminho não supervisionado é controlado por segurança:
- **Apenas relatório a menos que armada.** Uma execução do beat é coagida a `report`
independentemente da política a menos que `AA_DISCORD_AUDIT_BEAT_ALLOW_DESTRUCTIVE`
esteja definida — liberar o bloqueio único de primeira execução para uma execução manual via CLI
não arma o beat. Um aviso na inicialização é acionado quando a política é
destrutiva, mas o beat não está ativado.
- **Atribuída.** Cada execução do beat escreve um `AuditInvocation` aceito de ator do sistema
(`triggered_by=BEAT`), para que o rastro de auditoria do auditor
cubra também execuções não supervisionadas.
- **Auto-recuperação.** Uma execução interrompida por um limite de tempo suave ou uma queda de worker
é reconciliada ao estado `INTERRUPTED` retomável no próximo
tick. `AA_DISCORD_AUDIT_BEAT_MIN_INTERVAL_MINUTES` é um piso aproximado
contra um agendamento rápido mal configurado.
## Tarefas do Celery
O pacote registra cinco tarefas sob o prefixo de nome `aa_discord_audit.*`.
Apenas as tarefas do beat precisam de um agendamento; as demais são orientadas a eventos
ou executadas sob demanda. Nenhuma é agendada para você.
| Tarefa | Como executa | O que faz |
|------|-------------|--------------|
| `aa_discord_audit.audit_orphan_members` | Celery beat — você agenda | A auditoria não supervisionada de build + apply descrita acima. Apenas relatório a menos que armada; compartilha o bloqueio `discord.user_actions.<uid>` com `update_groups` do AA. |
| `aa_discord_audit.retry_pending_kicks` | Celery beat — você agenda | Varredura limitada que reenvia expulsões adiadas por uma falha transitória do Discord, respeitando um cooldown por linha para que um membro com falha persistente não seja sobrecarregado. |
| `aa_discord_audit.process_pending_run` | Orientado a eventos — enfileirado por um lançamento web | Pega a execução `PENDING` criada por um lançamento web, define como `RUNNING` e conduz o pipeline de acordo com a flag de confirmação congelada da execução. |
| `aa_discord_audit.prune_audit_runs` | Celery beat / cron — você agenda (também um comando de gerenciamento) | Retenção: expiração de chave de idempotência e depois exclusão de linha (veja **Comandos de gerenciamento** e o runbook). |
| `aa_discord_audit.sample_guild_presence` | Celery beat — você agenda | Amostragem leve, apenas REST, das contagens de membros do servidor / online / boosts no snapshot de presença mais recente para os medidores de presença do Prometheus. Controlado por `AA_DISCORD_AUDIT_PRESENCE_ENABLED`; um guarda de salto limita um agendamento rápido mal configurado (piso `AA_DISCORD_AUDIT_PRESENCE_SAMPLE_INTERVAL_MINUTES`, padrão 10). Inativo até que tanto o extra `[metrics]` quanto uma entrada do beat estejam presentes (veja [`docs/METRICS.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/METRICS.md)). |
Para agendar as tarefas do beat, adicione-as a `CELERYBEAT_SCHEDULE` em seu
`local.py`, por exemplo:```python
CELERYBEAT_SCHEDULE["aa_discord_audit_sample_guild_presence"] = {
"task": "aa_discord_audit.sample_guild_presence",
"schedule": 600, # seconds; honoured no finer than the sampler floor
}
Montado na navegação principal do Auth como Discord Audit. Visualizações somente leitura; cada lista possui uma caixa de pesquisa no servidor que corresponde a cada linha — não apenas a página em exibição — juntamente com seus filtros suspensos:
ProtectedDiscordMember, bloqueio de primeira execução) decidiu o resultado.Operadores com a permissão aa_discord_audit.run_audit veem um botão Iniciar Auditoria na página Execuções de auditoria. Clicar nele abre um modal Bootstrap que exibe o modo de política configurado (somente relatório ou destrutivo), o estado de reconhecimento inicial e um botão Confirmar Início. Enviar POSTs para /run-launch/, que cria um AuditRun PENDENTE, enfileira process_pending_run via Celery e redireciona para a página de detalhes da execução.
O caminho web espelha as barreiras de segurança da CLI:
audit_acknowledge_initial não foi executado, o modal exibe um bloco de recusa (sem botão de envio) em vez da ação Confirmar Início. Um POST que ignora o modal (ex.: curl) é recusado no servidor, a recusa é registrada em AuditInvocation, e o operador é redirecionado com uma mensagem flash.was_confirmation_bypassed = user.has_perm(run_audit_destructive) and policy_has_destructive(policy). A interface não tem alternância — apenas a permissão destrutiva determina a intenção. Um operador apenas com run_audit que aciona uma inicialização contra uma política destrutiva recebe uma execução silenciosa SOMENTE RELATÓRIO (a mesma coerção que a CLI aplica sem --yes).Enquanto uma execução está em um estado não terminal (PENDING, RUNNING ou INTERRUPTED), a página de detalhes da execução consulta /runs/<pk>/state.json a cada cinco segundos e atualiza o cartão State no local. A consulta pausa em guias ocultas e para assim que a execução atinge um estado terminal.
Instrumentação opcional do Prometheus por trás do extra [metrics] — ausente, toda chamada de métrica resolve para um stub sem operação com custo próximo de zero. O módulo fornece uma camada de cooperar-não-depender: quando o django-prometheus está instalado, os contadores e histogramas da auditoria registram-se no prometheus_client.REGISTRY padrão e a visualização /metrics do django-prometheus os exporta junto com suas próprias séries.```sh
pip install aa-discord-audit[metrics]
As métricas de snapshot — presença na guilda e os agregados de associação por grupo/por cargo — seguem um segundo caminho: elas residem em um registro dedicado exportado pelo próprio endpoint `/audit/discord/metrics` do módulo. O coletor multiprocesso do django-prometheus lê apenas arquivos mmap e ignora coletores personalizados, portanto essas métricas precisam de seu próprio alvo de scraping. Como qualquer alvo `/metrics`, ele não é autenticado — restrinja-o no proxy reverso ou na camada de rede. Ambas as superfícies permanecem inertes sem o extra `[metrics]`.
O catálogo de métricas, o vocabulário de rótulos e as receitas Grafana estão em
[`docs/METRICS.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/METRICS.md)
(tradução em russo:
[`docs/METRICS.ru.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/METRICS.ru.md)).
## Limitações
- **Única guilda.** A auditoria reconcilia a única guilda do Discord para a qual o AA está configurado; não abrange várias guildas.
- **Apenas cargos gerenciados pelo AA.** As ações de remover/expulsar atuam sobre cargos nomeados pelo AA e associação à guilda; cargos que o AA não gerencia nunca são tocados.
- **Sem descoberta automática de apelidos.** Contas de bot são reconhecidas apenas através da tabela explícita `BotAccountUid` / `AA_DISCORD_AUDIT_BOT_UIDS` — `AA_DISCORD_AUDIT_AUTO_DISCOVER_BY_NICKNAME` está reservado para v2 e não implementado.
- **Superfície alfa.** Os nomes das configurações e a API pública podem mudar antes da versão `1.0`.
## Documentação
- [`docs/runbook.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/runbook.md)
— runbook do operador: permissões do bot Discord, lista de verificação pré-voo,
liberação do bloqueio de primeira execução, playbooks de incidentes,
alternadores de diagnóstico.
- [`docs/performance.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/performance.md)
— números de referência do `audit_benchmark` e implicações de dimensionamento.
- [`docs/METRICS.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/METRICS.md)
/ [`docs/METRICS.ru.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/METRICS.ru.md)
— catálogo de métricas Prometheus, vocabulário de rótulos, receitas Grafana.
- Código-fonte: <https://gitlab.com/eveo7/aa-discord-audit>
- Rastreador de problemas: <https://gitlab.com/eveo7/aa-discord-audit/-/issues>
- Changelog:
[`CHANGELOG.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/CHANGELOG.md)
## Desenvolvimento```sh
make dev # uv sync --all-groups + pre-commit install
make tests # uv run nox -s tests
make lint # uv run nox -s lint
make typecheck # mypy + basedpyright
make coverage # term + html + xml report
make package # uv build
Toolchain é apenas uv. Comprimento da linha é 79 (Python) / 120 (Markdown).
MIT — veja LICENSE.
| Codename | Portões |
|---|
aa_discord_audit.run_audit | comando de gerenciamento, tarefa (beat), run delete |
aa_discord_audit.run_audit_destructive | portão de lançamento web para strip / strip_kick (separado de run_audit) |
aa_discord_audit.acknowledge_initial_audit | libera o bloqueio de dry-run da primeira execução |
aa_discord_audit.manage_discord_identity | admin DiscordIdentity |
aa_discord_audit.manage_role_exception | admin ManagedRoleException |
aa_discord_audit.manage_protected_member | admin ProtectedDiscordMember |
aa_discord_audit.manage_bot_account_uid | admin BotAccountUid |
aa_discord_audit.manage_finding_override | admin FindingActionOverride |
aa_discord_audit.view_auditrun (e amigos) | trilha de auditoria apenas leitura no painel Auth |