Add bot token storage, audit logging, and HTTP APIs for bot token management#2015
Add bot token storage, audit logging, and HTTP APIs for bot token management#2015WiedersehenM wants to merge 1 commit intoweb3infra-foundation:mainfrom
Conversation
… management API
- Add BotTokenInfo DTO and extend BotsStorage to generate bot tokens using HMAC-SHA256 with an env-based secret, storing only token hashes and metadata while returning plaintext once on creation
- Implement listing, single revoke, bulk revoke, and plaintext-based lookup (with bot_ prefix) for bot tokens to support authentication flows
- Introduce AuditStorage wrapper around BaseStorage with a log_audit API using ActorTypeEnum / AuditActionEnum / TargetTypeEnum and JSON metadata
- Expose audit_storage from Storage/AppService so Mono and Ceres can record bot token lifecycle events and bot access audits
- Add bot_router with /api/v1/bots/{bot_id}/tokens CRUD-style endpoints and DTOs for creating, listing, and revoking bot tokens, including OpenAPI documentation and BOT_TAG swagger tag
- Wire bot_router into api_router and expose bots_storage() from Jupiter Storage so Mono can call bot token storage APIs
Signed-off-by: Hongze Gao <15101764808@163.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7d43d06e12
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| ..Default::default() | ||
| }; | ||
|
|
||
| let model = active.insert(self.get_connection()).await?; |
There was a problem hiding this comment.
Return 404 for unknown bots before inserting tokens
generate_bot_token writes directly to bot_tokens without first checking whether bot_id exists, so an invalid bot ID fails only at the FK constraint. That error propagates as MegaError::Db, and ApiError::from maps DB errors to HTTP 500, which contradicts the endpoint contract that advertises 404 for missing bots and makes client-side handling unreliable.
Useful? React with 👍 / 👎.
| ensure_admin(&state, &user).await?; | ||
|
|
||
| let expires_at: Option<DateTimeWithTimeZone> = req.expires_in.map(|seconds| { | ||
| let when = Utc::now() + Duration::seconds(seconds); |
There was a problem hiding this comment.
Validate expires_in bounds before adding duration
The handler applies user-provided expires_in directly via Utc::now() + Duration::seconds(seconds). For extreme i64 inputs, datetime arithmetic can overflow and panic instead of returning a client error, so a malformed admin request can trigger server-side task failure rather than a clean 400 response.
Useful? React with 👍 / 👎.
Related issue
#1999
Summary
AuditStorageas a centralized audit logging entrypoint for bot-related flows./api/v1/bots/{bot_id}/tokens.Details
Bot token storage (Jupiter)
BotTokenInfoDTO for listing bot tokens without exposing plaintext.BotsStoragewith:generate_bot_tokenthat creates high-entropy random bot tokens, Base64-encodes them, prefixes withbot_, stores only an HMAC-SHA256 hash of the token body (without prefix) inbot_tokens.token_hash, and returns the plaintext token once.list_bot_tokensto return per-bot token metadata ordered bycreated_at, without plaintext values.revoke_bot_tokenandrevoke_bot_tokens_by_botto mark tokens as revoked in an idempotent way.find_bot_by_tokenthat:bot_prefix.bot_tokens.revoked = falseandexpires_ateitherNULLor in the future.Nonewhen the token or corresponding bot record is missing.MEGA_BOT_TOKEN_HMAC_SECRET, returning a clearMegaErrorif it is missing or invalid.Audit logging (Jupiter)
audit_storage.rsdefiningAuditStorage { base: BaseStorage }.log_audit(actor_id, actor_type: ActorTypeEnum, action: AuditActionEnum, target_type: TargetTypeEnum, target_id, metadata: Option<serde_json::Value>)which:idviaIdInstance::next_id().callisto-generated types to stay aligned with the DB schema.Json.created_at = Utc::now()and inserts a row intoaudit_logs.storage::mod:pub mod audit_storage;.audit_storage: AuditStoragetoStorage/AppService, initialize it inStorage::new()andAppService::mock().pub fn audit_storage(&self) -> AuditStoragefor higher layers.actor_type = Bot,target_type,target_id, and richermetadata(bot ID, permission scope, installation targets, API path, decision results, etc.).Mono HTTP API for bot token management
bot_routerthat exposes admin-only bot token endpoints, all requiring authenticatedLoginUserand anensure_admincheck:POST /api/v1/bots/{bot_id}/tokensBotsStorage::generate_bot_token.token_plain), plus metadata.GET /api/v1/bots/{bot_id}/tokensDELETE /api/v1/bots/{bot_id}/tokens/{id}POST /api/v1/bots/{bot_id}/tokens/revoke_allBOT_TAG = "Bot Management"for OpenAPI.bot_routerin the mainapi_routerso the endpoints are served under/api/v1.bots_storage()from JupiterStorageso Mono can call:generate_bot_tokenlist_bot_tokensrevoke_bot_tokenrevoke_bot_tokens_by_bot