chore(erc20-bridge): protect admin actions#1151
Conversation
WalkthroughAdds runtime access-control checks to six ERC20 bridge admin actions (lock/unlock/issue on sepolia and mainnet), gating execution on membership in system:erc20_bridge_writer. Wallet balance helpers remain unchanged. No action signatures changed. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant C as Caller (@caller)
participant A as Admin Action (SQL)
participant AC as Access Control
participant B as Bridge Function
C->>A: Invoke admin action (lock/unlock/issue)
A->>AC: are_members_of('system','erc20_bridge_writer', LOWER(@caller))
alt has permission
A->>B: Call lock_admin / unlock / issue (args)
B-->>A: Result
A-->>C: Success
else lacks permission
A-->>C: ERROR: caller lacks role system:erc20_bridge_writer
end
note over A,AC: Permission check occurs before any bridge operation
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Suggested reviewers
Pre-merge checks (5 passed)✅ Passed checks (5 passed)
Poem
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. ✨ Finishing Touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Time Submission Status
|
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (5)
internal/migrations/erc20-bridge/001-actions.sql (5)
35-47: Same access-control notes as above.See earlier comments on amount validation, deduping the role check, and auditing.
53-65: Same access-control notes as above.Replicate amount validation, helper-based role check, and auditing.
77-89: Same access-control notes as above (mainnet lock).Apply the same improvements here.
95-107: Same access-control notes as above (mainnet unlock).Apply the same improvements here.
113-125: Same access-control notes as above (mainnet issue).Apply the same improvements here.
🧹 Nitpick comments (3)
internal/migrations/erc20-bridge/001-actions.sql (3)
17-29: Deduplicate the role check into a reusable helper to reduce repetition and drift.All six actions repeat the same loop. Extract to a small PRIVATE VIEW action (or function) and call it, keeping the single source of truth for the role name and logic.
For example, add near the top of this file:
-- Helper: returns TRUE iff the caller is an erc20_bridge_writer CREATE OR REPLACE ACTION _has_erc20_bridge_writer_role($w TEXT) PRIVATE VIEW RETURNS (ok BOOL) { $w := LOWER($w); for $row in are_members_of('system', 'erc20_bridge_writer', ARRAY[$w]) { if $row.is_member { return true; } } return false; };Then replace in each admin action:
- $lower_caller TEXT := LOWER(@caller); - $has_permission BOOL := false; - for $row in are_members_of('system', 'erc20_bridge_writer', ARRAY[$lower_caller]) { - if $row.wallet = $lower_caller AND $row.is_member { - $has_permission := true; - break; - } - } - if NOT $has_permission { + if NOT _has_erc20_bridge_writer_role(@caller) { ERROR('Caller does not have the required system:erc20_bridge_writer role to <op>.'); }Replace with lock/unlock/issue accordingly.
Also applies to: 35-47, 53-65, 77-89, 95-107, 113-125
31-31: Prefer passing a pre-cast variable instead of repeating the cast at call sites.Minor readability and avoids double parse/cast costs once you introduce $amt.
Also applies to: 49-49, 67-67, 91-91, 109-109, 127-127
17-29: Include caller and params in error/audit for traceability.Optional: emit an audit event/row on both success and authorization failure (operation, caller, to/wallet, amount). Greatly helps incident response.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
internal/migrations/erc20-bridge/001-actions.sql(2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: acceptance-test
- GitHub Check: lint
🔇 Additional comments (2)
internal/migrations/erc20-bridge/001-actions.sql (2)
17-29: Access control check looks correct and aligns with the PR objective.Lowercasing the caller and verifying membership in system:erc20_bridge_writer before invoking the bridge op is sound.
16-32: No exposure of underlying bridge functions: Verified via ripgrep that there are no PUBLIC ACTION definitions forsepolia_bridge.lock_admin/unlock/issueormainnet_bridge.lock_admin/unlock/issueanywhere in the repository.
Related Problem
resolves: https://github.com/trufnetwork/truf-network/issues/1186
How Has This Been Tested?
without the role
Using
erc20_bridge_writerrole walletSummary by CodeRabbit