
Alliance AuthのDiscord統合用のリコンシリエーション監査ツール:Authが付与したことのないAA管理ロールを保持するギルドメンバーを検出し、オペレーター制御のポリシーに基づいてそれらのロールを剥奪またはメンバーをキックします。スタンドアロンのコミュニティDjangoアプリ。
Alliance AuthのDiscord連携のための調整監査。設定されたDiscordギルドにおける実際のロール割り当てと、Alliance Auth(ユーザーごとのグループ+状態)で表現された状態を比較し、モデレーターがAAに認識されていないユーザーにAA命名ロールを手動で割り当てることのできるギャップを解消します。
ステータス: alpha(
0.1.x)。公開APIおよび設定は1.0より前に変更される可能性があります。
監査はデフォルトで安全です:
InitialAuditAcknowledgement(管理者またはシェルのみ)が必要です。reportです。破壊的なアクションはオプトインです。AuditRun、AuditFinding、AuditInvocation、ConfigChangeLog)は、マネージャーおよびインスタンスレイヤーで追加専用です。一括update() / bulk_update()はブロックされています。各ギルドメンバーは1つのカテゴリに分類されます:
| カテゴリ | 意味 |
|---|---|
unknown_guest | AAが何も知らないDiscordメンバー |
linked_no_perm | AAにIDが認識されているが、discord.access_discordがない |
bot_filtered | 設定されたボットアカウント — 決して操作しない |
オペレーターは各カテゴリを1つのアクションにマッピングします:
| アクション | 動作 |
|---|---|
report | 調査結果を記録。Discord側の変更はなし |
strip | AA管理ロールを削除 |
strip_kick | AA管理ロールを削除後、ギルドからキック |
マッピングはAA_DISCORD_AUDIT_POLICY設定です。グループごとおよび状態ごとのオーバーライドは、各カテゴリ内にネストされます。
allianceauth.services.modules.discord)がインストールおよび設定されていること(ボットトークン+ギルド)pip install aa-discord-audit
あなたの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",
]
次にマイグレーションを実行してください:```sh python manage.py migrate aa_discord_audit
`CurrentUserMiddleware` は必須です — これがないと `apps.ready()` が `ImproperlyConfigured` を発生させます。これにより `ConfigChangeLog` シグナルハンドラが管理者による編集を実際のユーザーに属性付けできるようになり、`<system>` ではなくなります。
## クイックスタート
1. `aa_discord_audit.run_audit` を監査を実行するオペレーターロールに付与します。
2. ドライラン監査を実行します: ```sh
python manage.py audit_discord_roles --action report
InitialAuditAcknowledgement 行を作成するか、python manage.py audit_acknowledge_initial を実行します。どちらも aa_discord_audit.run_audit および aa_discord_audit.acknowledge_initial_audit が必要です。manage_* コードネームは影響範囲ごとに分割されているため、manage_bot_account_uid を持つ初心者でも ManagedRoleException を編集して監査を無効化することはできません。
すべての設定はオプションです。デフォルト値は安全です。```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
## 管理コマンド
| コマンド | 目的 |
|--------------------------|------------------------------------------------------------------|
| `audit_discord_roles` | 主要エントリポイント。`--action {report,strip,strip_kick}`。 |
| `audit_discord_roles --resume <run_id>` | 既存の実行のPENDING状態の結果を再ウォーク。 |
| `audit_discord_roles --abandon <run_id>` | スタックした実行をABANDONEDとしてマーク。 |
| `audit_discord_roles --diff <run_id>` | 現在の状態を過去の実行と比較。 |
| `audit_discord_roles --explain <member_id>` | メンバーごとの分類(読み取り専用)。 |
| `audit_discord_roles --policy-preview <json>` | 仮想的なポリシーを投影。 |
| `audit_discord_roles --from-fixture <path>` | JSONスナップショットを使用してリプレイ。 |
| `audit_acknowledge_initial` | コンソールから初回実行のドライランロックを解除。 |
| `audit_benchmark` | 合成負荷によるサイジングベンチマーク([`docs/performance.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/performance.md)を参照)。 |
| `prune_audit_runs` | 保持期間の整理。 |
| `audit_abandon_stuck_runs` | クラッシュしたワーカーによってリークされたスタックしたPENDING実行を調整 — それらをABANDONEDに変更(ランブックを参照。スタックしたRUNNING実行は`audit_discord_roles --abandon`を使用)。 |
長時間実行される``audit_discord_roles``は``SIGTERM``と``SIGINT``にクリーンに反応します。実行は``INTERRUPTED``に変更され、適用ループは次の結果境界で終了するため、部分的な作業は監査証跡に永続化されます。``audit_discord_roles --resume <run_id>``は、残りの``PENDING``結果から実行を再開します。
## 定期監査(Celery beat)
`audit_orphan_members`は、Celery beatに組み込むスケジュールに従って同じビルド+適用パイプラインを実行します(デフォルトではスケジュールされていません)。無人パスは安全のためにゲートされています。
- **武装されていない限りレポートのみ。** `AA_DISCORD_AUDIT_BEAT_ALLOW_DESTRUCTIVE`が設定されていない限り、beat実行はポリシーに関係なく`report`に強制されます。手動CLI実行のために初回実行ロックを解除しても、beatは武装されません。ポリシーが破壊的であるがbeatがオプトインされていない場合、起動時に警告が発せられます。
- **帰属。** すべてのbeat実行は、承認されたシステムアクター`AuditInvocation`(`triggered_by=BEAT`)を書き込むため、監査者監査証跡は無人実行もカバーします。
- **自己修復。** ソフトタイム制限のヒットやワーカークラッシュによって座礁した実行は、次のティックで再開可能な`INTERRUPTED`状態に調整されます。`AA_DISCORD_AUDIT_BEAT_MIN_INTERVAL_MINUTES`は、誤設定された高速スケジュールに対する粗い下限です。
## Celery タスク
このパッケージは`aa_discord_audit.*`名前プレフィックスの下に5つのタスクを登録します。beatタスクのみスケジュールが必要で、残りはイベント駆動またはオンデマンドで実行されます。タスクのスケジュールはデフォルトでは設定されていません。
| タスク | 実行方法 | 説明 |
|------|-------------|--------------|
| `aa_discord_audit.audit_orphan_members` | Celery beat — スケジュール設定が必要 | 上記の無人ビルド+適用監査。武装されていない限りレポートのみ。AAの`update_groups`と`discord.user_actions.<uid>`ロックを共有します。 |
| `aa_discord_audit.retry_pending_kicks` | Celery beat — スケジュール設定が必要 | 一時的なDiscord障害によって延期されたキックを再ディスパッチするバウンドスイープ。行ごとのクールダウンを尊重し、ハードフェイルするメンバーに過剰な負荷をかけません。 |
| `aa_discord_audit.process_pending_run` | イベント駆動 — Web起動によってキューイング | Web起動が作成した`PENDING`実行を取得し、`RUNNING`に変更し、実行の固定された確認フラグに対してパイプラインを駆動します。 |
| `aa_discord_audit.prune_audit_runs` | Celery beat / cron — スケジュール設定が必要(管理コマンドでも使用可能) | 保持期間:冪等性キーの期限切れ後に行削除(**管理コマンド**とランブックを参照)。 |
| `aa_discord_audit.sample_guild_presence` | Celery beat — スケジュール設定が必要 | 軽量なRESTのみのサンプリング。ギルドメンバー/オンライン/ブースト数を最新のプレゼンススナップショットにサンプリングし、Prometheusプレゼンスゲージに提供。`AA_DISCORD_AUDIT_PRESENCE_ENABLED`でゲート。スキップガードにより誤設定された高速スケジュールを制限(下限`AA_DISCORD_AUDIT_PRESENCE_SAMPLE_INTERVAL_MINUTES`、デフォルト10)。`[metrics]`エクストラとbeatエントリの両方が存在するまで無効([`docs/METRICS.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/METRICS.md)参照)。 |
beatタスクをスケジュールするには、`local.py`の`CELERYBEAT_SCHEDULE`に追加します。例:```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
}
Authメインナビの下に Discord Audit としてマウントされます。読み取り専用のビューです。 各リストには、表示中のページだけでなく全行を対象とするサーバーサイド検索ボックスと、ドロップダウンフィルターが付いています。
ProtectedDiscordMember、初回実行ロック)が結果を決定したか。aa_discord_audit.run_audit 権限を持つオペレーターは、Audit runs ページに Launch Audit ボタンを表示します。クリックするとBootstrapモーダルが開き、設定されたポリシーモード(report-only または destructive)、初期確認状態、および Confirm Launch ボタンが表示されます。/run-launch/ にPOSTを送信すると、PENDINGの AuditRun が作成され、Celery経由で process_pending_run がエンキューされ、実行詳細ページにリダイレクトされます。
WebパスはCLIの安全ゲートを反映しています:
audit_acknowledge_initial が実行されていない場合、モーダルは Confirm Launch アクションの代わりに拒否ブロック(送信ボタンなし)を表示します。モーダルを迂回するPOST(例:curl)はサーバーサイドで拒否され、拒否は AuditInvocation に記録され、オペレーターはフラッシュメッセージとともにリダイレクトされます。was_confirmation_bypassed = user.has_perm(run_audit_destructive) and policy_has_destructive(policy)。UIには トグルはありません — 破壊権限のみが意図を決定します。run_audit のみのオペレーターが破壊的ポリシーに対して起動をトリガーすると、静かなREPORTのみの実行が行われます(CLIが --yes なしで適用するのと同じ強制です)。実行が終了状態でない間(PENDING、RUNNING、または INTERRUPTED)、実行詳細ページは5秒ごとに /runs/<pk>/state.json をポーリングし、Stateカードをその場で更新します。ポーリングは非表示のタブでは一時停止し、実行が終了状態に達するとすぐに停止します。
[metrics] エクストラの背後にあるオプションのPrometheus計装 — 存在しない場合、すべてのメトリクス呼び出しはほぼゼロコストでno-opスタブに解決されます。モジュールは協調・非依存レイヤーを提供します:django-prometheus がインストールされている場合、監査のカウンターとヒストグラムはデフォルトの prometheus_client.REGISTRY に登録され、django-prometheus の /metrics ビューが自身の系列とともにエクスポートします。```sh
pip install aa-discord-audit[metrics]
The snapshot gauges — guild presence and the per-group / per-role
membership aggregates — take a second path: they live in a dedicated
registry exported by the module's own `/audit/discord/metrics`
endpoint. django-prometheus' multiprocess collector reads only mmap
files and skips custom collectors, so these gauges need their own
scrape target. Like any `/metrics` target it is unauthenticated —
restrict it at the reverse-proxy or network layer. Both surfaces stay
inert without the `[metrics]` extra.
Metric catalog, label vocabulary, and Grafana recipes live in
[`docs/METRICS.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/METRICS.md)
(Russian translation:
[`docs/METRICS.ru.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/METRICS.ru.md)).
## Limitations
- **Single guild.** The audit reconciles the one Discord guild AA is
configured against; it does not span multiple guilds.
- **AA-managed roles only.** Strip / kick act on AA-named roles and
guild membership; roles AA does not manage are never touched.
- **No nickname auto-discovery.** Bot accounts are recognised only via
the explicit `BotAccountUid` table / `AA_DISCORD_AUDIT_BOT_UIDS` —
`AA_DISCORD_AUDIT_AUTO_DISCOVER_BY_NICKNAME` is reserved for v2 and
not implemented.
- **Alpha surface.** Settings names and the public API may change
before `1.0`.
## Documentation
- [`docs/runbook.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/runbook.md)
— operator runbook: bot Discord permissions, pre-flight checklist,
releasing the first-run lock, incident playbooks, diagnostic toggles.
- [`docs/performance.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/docs/performance.md)
— `audit_benchmark` reference numbers and sizing implications.
- [`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)
— Prometheus metric catalog, label vocabulary, Grafana recipes.
- Source code: <https://gitlab.com/eveo7/aa-discord-audit>
- Issue tracker: <https://gitlab.com/eveo7/aa-discord-audit/-/issues>
- Changelog:
[`CHANGELOG.md`](https://gitlab.com/eveo7/aa-discord-audit/-/blob/main/CHANGELOG.md)
## Development```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
ツールチェーンはuvのみです。行長は79(Python)/ 120(Markdown)です。
MIT — LICENSEを参照してください。
| Codename | Gates |
|---|
aa_discord_audit.run_audit | 管理コマンド、beat タスク、削除実行 |
aa_discord_audit.run_audit_destructive | strip / strip_kick のための Web 起動ゲート (run_audit とは別) |
aa_discord_audit.acknowledge_initial_audit | 初回 dry-run ロックの解除 |
aa_discord_audit.manage_discord_identity | DiscordIdentity 管理 |
aa_discord_audit.manage_role_exception | ManagedRoleException 管理 |
aa_discord_audit.manage_protected_member | ProtectedDiscordMember 管理 |
aa_discord_audit.manage_bot_account_uid | BotAccountUid 管理 |
aa_discord_audit.manage_finding_override | FindingActionOverride 管理 |
aa_discord_audit.view_auditrun (および関連するもの) | Auth ダッシュボードの読み取り専用監査証跡 |