Pure authorization module added in crates/polymarket-fetch/src/authz.rs as Task 2 of the autotrade foundation plan on branch autotrade-foundation. Provides owner-scope gating for Telegram commands that can trigger real trades.

Location

  • File: crates/polymarket-fetch/src/authz.rs
  • Module declared in main.rs alongside the other top-level mod declarations

Public Surface

ItemKindPurpose
ScopeenumPublic or Owner — the authorization level a command requires
AuthzenumAllowed or Denied — the result of an authorization check
OwnerSetstructWraps HashSet<i64> of Telegram user IDs permitted as owners
authorize(scope, user_id, owners)fnReturns Authz::Allowed iff scope is Public OR the user ID is in the owner set
scope_for(command)fnMaps a command name string to its required Scope

scope_for routing

  • "autotrade"Scope::Owner
  • anything else → Scope::Public

New owner-only commands from future tasks are added here. This is the single routing table for command authorization.

OwnerSet::parse_csv

Parses a comma-separated string of i64 Telegram user IDs. Garbage tokens (non-numeric, empty, whitespace) are silently ignored rather than panicking. Intended to accept the TELEGRAM_OWNER_IDS environment variable directly.

Design Notes

Intentionally pure

The module has zero I/O — no env reads, no DB, no async. Every function is deterministic and tested in isolation. The environment variable parsing happens at the call site (main.rs / wiring layer in Task 3), not here.

Temporary dead-code suppression

#![allow(dead_code)] is set at the module level because nothing in main.rs consumes authz yet. Task 3 (Wire owner-auth into run_command) will import and call these functions; at that point the allow can be removed. Do not remove it earlier or the build will warn on all 6 public items.

Clippy Compliance

The module compiles clean under clippy --workspace --all-targets -- -D warnings (pedantic + nursery profile used by scripts/gate.sh). Key attributes applied:

  • #[must_use] on OwnerSet::contains, OwnerSet::is_empty, authorize, and scope_for — required by clippy pedantic

Tests

6 unit tests, all passing:

  1. parse_csv_empty — empty string yields empty set
  2. parse_csv_garbage_ignored — non-numeric tokens dropped silently
  3. public_scope_always_allowedScope::Public with any user ID → Allowed
  4. owner_scope_allowed_for_owner — known ID in set → Allowed
  5. owner_scope_denied_for_stranger — unknown ID → Denied
  6. scope_for_autotrade"autotrade" maps to Scope::Owner

Relationship to Autotrade Plan

This is Task 2 of the autotrade foundation. The full task sequence:

  1. Task 1 — vendor + pin rs-clob-client-v2 into crates/polymarket-clob/
  2. Task 2authz.rs (this note)
  3. Task 3 — wire authz::authorize + authz::scope_for into run_command in main.rs; the #![allow(dead_code)] is removed here

The module is referenced in the broader engine design under the “Control” section — owner-only Telegram, OFF/DRY_RUN/LIVE kill-switch, scope-gated command dispatch.