Skip to content

Add bot token storage, audit logging, and HTTP APIs for bot token management#2015

Open
WiedersehenM wants to merge 1 commit intoweb3infra-foundation:mainfrom
WiedersehenM:feature/bot-token
Open

Add bot token storage, audit logging, and HTTP APIs for bot token management#2015
WiedersehenM wants to merge 1 commit intoweb3infra-foundation:mainfrom
WiedersehenM:feature/bot-token

Conversation

@WiedersehenM
Copy link
Contributor

Related issue

#1999

Summary

  • Add secure, HMAC-based bot token storage in Jupiter, exposing only non-plaintext DTOs.
  • Introduce AuditStorage as a centralized audit logging entrypoint for bot-related flows.
  • Add Mono-layer HTTP APIs for bot token lifecycle management under /api/v1/bots/{bot_id}/tokens.

Details

  • Bot token storage (Jupiter)

    • Add BotTokenInfo DTO for listing bot tokens without exposing plaintext.
    • Extend BotsStorage with:
      • generate_bot_token that creates high-entropy random bot tokens, Base64-encodes them, prefixes with bot_, stores only an HMAC-SHA256 hash of the token body (without prefix) in bot_tokens.token_hash, and returns the plaintext token once.
      • list_bot_tokens to return per-bot token metadata ordered by created_at, without plaintext values.
      • revoke_bot_token and revoke_bot_tokens_by_bot to mark tokens as revoked in an idempotent way.
      • find_bot_by_token that:
        • Accepts tokens with or without the bot_ prefix.
        • Computes the HMAC-SHA256 hash of the token body and looks it up in bot_tokens.
        • Enforces revoked = false and expires_at either NULL or in the future.
        • Returns None when the token or corresponding bot record is missing.
    • Load the HMAC key from MEGA_BOT_TOKEN_HMAC_SECRET, returning a clear MegaError if it is missing or invalid.
  • Audit logging (Jupiter)

    • Introduce new module audit_storage.rs defining AuditStorage { base: BaseStorage }.
    • Implement log_audit(actor_id, actor_type: ActorTypeEnum, action: AuditActionEnum, target_type: TargetTypeEnum, target_id, metadata: Option<serde_json::Value>) which:
      • Generates a new id via IdInstance::next_id().
      • Fills all enum fields using callisto-generated types to stay aligned with the DB schema.
      • Converts optional JSON metadata into Json.
      • Sets created_at = Utc::now() and inserts a row into audit_logs.
    • Update storage::mod:
      • Register pub mod audit_storage;.
      • Add audit_storage: AuditStorage to Storage / AppService, initialize it in Storage::new() and AppService::mock().
      • Expose pub fn audit_storage(&self) -> AuditStorage for higher layers.
    • Intended usage:
      • Record bot token lifecycle events (generate / revoke / revoke_all).
      • Record bot-initiated business API calls with appropriate actor_type = Bot, target_type, target_id, and richer metadata (bot ID, permission scope, installation targets, API path, decision results, etc.).
  • Mono HTTP API for bot token management

    • Add bot_router that exposes admin-only bot token endpoints, all requiring authenticated LoginUser and an ensure_admin check:
      • POST /api/v1/bots/{bot_id}/tokens
        • Creates a new bot token using Jupiter BotsStorage::generate_bot_token.
        • Returns the plaintext token once (token_plain), plus metadata.
      • GET /api/v1/bots/{bot_id}/tokens
        • Lists existing tokens for a bot without exposing plaintext values.
      • DELETE /api/v1/bots/{bot_id}/tokens/{id}
        • Revokes a single token; the operation is idempotent.
      • POST /api/v1/bots/{bot_id}/tokens/revoke_all
        • Revokes all tokens for the given bot; also idempotent.
    • Define request/response DTOs for token creation and listing; tag endpoints and schemas with BOT_TAG = "Bot Management" for OpenAPI.
    • Register bot_router in the main api_router so the endpoints are served under /api/v1.
    • Expose bots_storage() from Jupiter Storage so Mono can call:
      • generate_bot_token
      • list_bot_tokens
      • revoke_bot_token
      • revoke_bot_tokens_by_bot

… 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>
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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?;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge 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 👍 / 👎.

let resp = CreateBotTokenResponse {
id: model.id,
token_name: model.token_name,
expires_at: model.expires_at.map(|dt| dt.with_timezone(&Utc)),

Check failure

Code scanning / CodeQL

Cleartext logging of sensitive information High

This operation writes
secret
to a log file.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant