feat(ui): expose custom registry force sync#2869
Conversation
|
@cubic-dev-ai review |
@daryllimyt I have started the AI code review. It will take a few minutes to complete. |
|
@codex review |
|
✅ No security or compliance issues detected. Reviewed everything up to a4d7f66. Security Overview
Detected Code Changes
|
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
There was a problem hiding this comment.
1 issue found across 2 files
Confidence score: 3/5
- In
frontend/src/components/registry/workspace-actions-controls.tsx, force sync (which can delete an existing synced version) shares the sameorg:registry:updatepermission as regular sync, so users with routine update access may be able to perform a destructive action unintentionally or beyond intended privilege. Before merging, gate force sync behind a dedicated stricter RBAC scope (or equivalent explicit authorization check) and verify who currently holds that permission.
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a4d7f667ef
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| raise ScopeDeniedError( | ||
| required_scopes=["org:registry:delete"], | ||
| missing_scopes=["org:registry:delete"], | ||
| ) |
There was a problem hiding this comment.
Let scope denials propagate as 403
When a caller has org:registry:update but not org:registry:delete and sends force: true, this new check raises ScopeDeniedError from inside sync_registry_repository's try block. That route only re-raises EntitlementRequired/HTTPException before its broad except Exception, so the intended authorization failure is converted into a 500 "Unexpected error" instead of the app-level 403 scope-denied response. Re-raise or catch ScopeDeniedError in the route so missing delete scope is reported correctly.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="tracecat/registry/repositories/service.py">
<violation number="1" location="tracecat/registry/repositories/service.py:130">
P2: `ScopeDeniedError` raised here will be caught by the route handler's broad `except Exception` block in `router.py`, which converts it into a generic 500 response instead of the intended 403 scope-denied response. The route only re-raises `EntitlementRequired`/`RegistryNotFound`/`HTTPException` before its catch-all. Either add `ScopeDeniedError` to the route's explicit exception handling, or let it propagate by adding it to the re-raise conditions.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| if force and not has_scope( | ||
| self.role.scopes or frozenset(), "org:registry:delete" | ||
| ): | ||
| raise ScopeDeniedError( |
There was a problem hiding this comment.
P2: ScopeDeniedError raised here will be caught by the route handler's broad except Exception block in router.py, which converts it into a generic 500 response instead of the intended 403 scope-denied response. The route only re-raises EntitlementRequired/RegistryNotFound/HTTPException before its catch-all. Either add ScopeDeniedError to the route's explicit exception handling, or let it propagate by adding it to the re-raise conditions.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tracecat/registry/repositories/service.py, line 130:
<comment>`ScopeDeniedError` raised here will be caught by the route handler's broad `except Exception` block in `router.py`, which converts it into a generic 500 response instead of the intended 403 scope-denied response. The route only re-raises `EntitlementRequired`/`RegistryNotFound`/`HTTPException` before its catch-all. Either add `ScopeDeniedError` to the route's explicit exception handling, or let it propagate by adding it to the re-raise conditions.</comment>
<file context>
@@ -122,15 +122,23 @@ async def sync_repository(
+ if force and not has_scope(
+ self.role.scopes or frozenset(), "org:registry:delete"
+ ):
+ raise ScopeDeniedError(
+ required_scopes=["org:registry:delete"],
+ missing_scopes=["org:registry:delete"],
</file context>
Motivation
forceflag for repository syncs.Description
force-syncdialog state infrontend/src/components/registry/workspace-actions-controls.tsx.SyncRepositoryDialogcomponent to accept aforceprop, render force-specific title/warning copy, and adjust the action label accordingly infrontend/src/components/registry/dialogs/repository-sync-dialog.tsx.forcevalue in the request body to the repository sync API (requestBody: { force }).Testing
pnpm -C frontend run typecheckand it completed successfully.pnpm -C frontend exec biome check src/components/registry/dialogs/repository-sync-dialog.tsx src/components/registry/workspace-actions-controls.tsxand there were no reported issues.git diff --checkto validate whitespace/patch issues and it returned no problems.Codex Task
Summary by cubic
Adds a “Force sync from remote” option for custom registries and wires the dialog to send the
forceflag. Force sync is gated byorg:registry:deleteand is enforced server-side.New Features
org:registry:updateandorg:registry:delete).SyncRepositoryDialogacceptsforce, updates title/warning and action label, and sendsrequestBody: { force }; selecting the new item opens the dialog in force mode.Bug Fixes
org:registry:deletewhenforceis true and rejects requests missing it; the UI hides force sync without this scope.Written for commit a4d7f66. Summary will update on new commits.