Add Readonly mode in AI Workspace#2250
Conversation
|
Warning Review limit reached
More reviews will be available in 48 minutes and 51 seconds. Learn how PR review limits work. Your organization has run out of usage credits. Purchase more credits in the billing tab to continue. ⌛ How to resolve this issue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits. 🚦 How do rate limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, the refill rate gradually slows as usage increases. The highest same-day bursts are limited more strictly. Please see our Fair Usage Limits Policy for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR introduces a gateway-managed read-only mode across the AI Workspace portal. Three core interfaces ( Suggested Reviewers
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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 |
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@portals/ai-workspace/src/pages/appShell/appShellPages/externalServers/ExternalServersDeploy.tsx`:
- Around line 103-110: The conditional at line 103 in the ExternalServersDeploy
component currently checks only `server?.readOnly`, which treats null/undefined
as falsey and shows the GatewayDeployMainSection before server metadata is
resolved. Gate the deployment UI until the server metadata is fully resolved by
adding an additional check to verify that the server data has been fetched
(check if server exists and is loaded, not just the readOnly property) before
rendering either the Alert or GatewayDeployMainSection component.
In
`@portals/ai-workspace/src/pages/appShell/appShellPages/proxies/LLMProxyDeploy.tsx`:
- Line 31: Update the destructuring from the useProxy hook to also extract
isLoading and error properties (in addition to the existing proxy variable).
Then add a loading/error state check before rendering GatewayDeployMainSection
around lines 70-77 to prevent rendering the section while proxy data is still
being fetched or if an error occurs, ensuring the read-only gating is properly
enforced during the loading phase.
In
`@portals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderDeploymentsCard.tsx`:
- Line 129: The isReadOnlyProvider boolean computed on line 129 is not being
used to gate API key actions in the card. Update the disabled prop logic for the
DisabledActionTooltip component and related action handlers in the range of
lines 464-473 to include isReadOnlyProvider in the disabled condition alongside
the existing gateway availability check. This ensures that when a provider is
read-only, the API key create and delete actions are properly disabled
regardless of gateway availability.
In
`@portals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderGuardrailsTab.tsx`:
- Line 163: The read-only provider flag is defined as `isReadOnlyProvider` but
is not being checked in the `handlePolicySubmit` function to prevent policy
submissions. Add `isReadOnlyProvider` to the early-return condition in
`handlePolicySubmit` to guard against submissions when the provider is in
read-only mode, ensuring that policy changes cannot be submitted for read-only
providers.
In
`@portals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderOverview.tsx`:
- Around line 477-478: The isReadOnlyProvider flag is defined but not enforced
in the save flow, allowing users to attempt saving even when the provider is
read-only. Add an early return check at the beginning of the handleSaveChanges
function to immediately return if isReadOnlyProvider is true, preventing any
save operation from proceeding. Additionally, update the footer action buttons
(Save and Cancel buttons around lines 1459-1473) to disable them when
isReadOnlyProvider is true, ensuring the UI consistently prevents read-only
users from interacting with save functionality throughout the page.
In
`@portals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderOverviewTab.tsx`:
- Line 162: The isReadOnlyProvider variable defined at line 162 is not being
applied to enforce read-only restrictions for API key operations. Update the
DisabledActionTooltip components at the delete guard location (around line 605)
and the generate button wrapper (lines 825-834) to use the isReadOnlyProvider
flag instead of the hardcoded disabled={false} value. Replace disabled={false}
with disabled={isReadOnlyProvider} in both locations to properly prevent API key
operations when the provider is in read-only mode.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ed03d390-bc54-4979-9010-3065921e00cf
📒 Files selected for processing (26)
portals/ai-workspace/src/pages/appShell/appShellPages/externalServers/EditExternalServer.tsxportals/ai-workspace/src/pages/appShell/appShellPages/externalServers/ExternalServersDeploy.tsxportals/ai-workspace/src/pages/appShell/appShellPages/externalServers/ExternalServersOverview.tsxportals/ai-workspace/src/pages/appShell/appShellPages/externalServers/PolicyMapper.tsxportals/ai-workspace/src/pages/appShell/appShellPages/proxies/EditLLMProxy.tsxportals/ai-workspace/src/pages/appShell/appShellPages/proxies/LLMProxyDefinitionTab.tsxportals/ai-workspace/src/pages/appShell/appShellPages/proxies/LLMProxyDeploy.tsxportals/ai-workspace/src/pages/appShell/appShellPages/proxies/LLMProxyDeploymentsCard.tsxportals/ai-workspace/src/pages/appShell/appShellPages/proxies/LLMProxyGuardrailsTab.tsxportals/ai-workspace/src/pages/appShell/appShellPages/proxies/LLMProxyOverview.tsxportals/ai-workspace/src/pages/appShell/appShellPages/proxies/LLMProxyOverviewTab.tsxportals/ai-workspace/src/pages/appShell/appShellPages/proxies/LLMProxyProviderTab.tsxportals/ai-workspace/src/pages/appShell/appShellPages/proxies/LLMProxySecurityTab.tsxportals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/EditServiceProvider.tsxportals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderConnectionTab.tsxportals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderDeploy.tsxportals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderDeploymentsCard.tsxportals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderGuardrailsTab.tsxportals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderModelsTab.tsxportals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderOverview.tsxportals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderOverviewTab.tsxportals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderRateLimitingTab.tsxportals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderResourcesTab.tsxportals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderSecurityTab.tsxportals/ai-workspace/src/utils/readOnlyArtifacts.tsxportals/ai-workspace/src/utils/types.ts
| {server?.readOnly ? ( | ||
| <Alert severity="info"> | ||
| This MCP proxy was created from a gateway. Deployment actions are | ||
| unavailable in AI Workspace. | ||
| </Alert> | ||
| ) : ( | ||
| <GatewayDeployMainSection showConfigureOption={false} /> | ||
| )} |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Gate deployment UI until server read-only metadata is resolved.
At Line 103, server?.readOnly treats null as editable, so deployment actions can appear before fetch completion (or after fetch failure). This should stay blocked until the server metadata is resolved.
Proposed fix
const [server, setServer] = useState<MCPServer | null>(null);
+const [isServerResolved, setIsServerResolved] = useState(false);
useEffect(() => {
if (!serverId || !organizationId) return;
let cancelled = false;
+ setIsServerResolved(false);
mcpProxiesApis
.getMCPServer(serverId, organizationId, apimBaseUrl)
.then((res) => { if (!cancelled) setServer(res); })
- .catch(() => {});
+ .catch(() => { if (!cancelled) setServer(null); })
+ .finally(() => { if (!cancelled) setIsServerResolved(true); });
return () => { cancelled = true; };
}, [serverId, organizationId, apimBaseUrl]);
- {server?.readOnly ? (
+ {!isServerResolved ? null : server?.readOnly ? (
<Alert severity="info">
This MCP proxy was created from a gateway. Deployment actions are
unavailable in AI Workspace.
</Alert>
) : (
<GatewayDeployMainSection showConfigureOption={false} />
- )}
+ )}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@portals/ai-workspace/src/pages/appShell/appShellPages/externalServers/ExternalServersDeploy.tsx`
around lines 103 - 110, The conditional at line 103 in the ExternalServersDeploy
component currently checks only `server?.readOnly`, which treats null/undefined
as falsey and shows the GatewayDeployMainSection before server metadata is
resolved. Gate the deployment UI until the server metadata is fully resolved by
adding an additional check to verify that the server data has been fetched
(check if server exists and is loaded, not just the readOnly property) before
rendering either the Alert or GatewayDeployMainSection component.
| function LLMProxyDeployContent() { | ||
| const { proxyId } = useParams<{ proxyId: string }>(); | ||
| const navigate = useNavigate(); | ||
| const { proxy } = useProxy(); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Block deploy actions until proxy state is loaded.
Line 70 can render GatewayDeployMainSection while proxy data is still loading (proxy is null), which briefly bypasses read-only gating. Read isLoading/error from useProxy() and gate render first.
💡 Suggested fix
function LLMProxyDeployContent() {
const { proxyId } = useParams<{ proxyId: string }>();
const navigate = useNavigate();
- const { proxy } = useProxy();
+ const { proxy, isLoading, error } = useProxy();
+
+ if (isLoading) {
+ return (
+ <PageContent fullWidth>
+ <Typography variant="body2">Loading proxy...</Typography>
+ </PageContent>
+ );
+ }
+
+ if (error) {
+ return (
+ <PageContent fullWidth>
+ <Alert severity="error">{error.message}</Alert>
+ </PageContent>
+ );
+ }
if (!proxyId) {
return (
<PageContent>Also applies to: 70-77
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@portals/ai-workspace/src/pages/appShell/appShellPages/proxies/LLMProxyDeploy.tsx`
at line 31, Update the destructuring from the useProxy hook to also extract
isLoading and error properties (in addition to the existing proxy variable).
Then add a loading/error state check before rendering GatewayDeployMainSection
around lines 70-77 to prevent rendering the section while proxy data is still
being fetched or if an error occurs, ensuring the read-only gating is properly
enforced during the loading phase.
|
|
||
| const apiKeyLocation = provider?.security?.apiKey?.in ?? 'header'; | ||
| const apiKeyName = provider?.security?.apiKey?.key ?? 'X-API-Key'; | ||
| const isReadOnlyProvider = Boolean(provider?.readOnly); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Enforce read-only gating for API key actions in this card.
Line 129 computes isReadOnlyProvider, but Line 464 hardcodes DisabledActionTooltip to disabled={false} and Line 469 only disables by gateway availability. This leaves API key create/delete actions active for read-only providers.
Proposed fix
@@
- const handleGenerateAPIKey = async () => {
- if (!currentOrganization?.uuid || !provider?.id) {
+ const handleGenerateAPIKey = async () => {
+ if (isReadOnlyProvider || !currentOrganization?.uuid || !provider?.id) {
return;
}
@@
- const handleDeleteApiKey = async () => {
- if (!deleteTargetKeyName) {
+ const handleDeleteApiKey = async () => {
+ if (isReadOnlyProvider || !deleteTargetKeyName) {
return;
}
@@
- <DisabledActionTooltip disabled={false}>
+ <DisabledActionTooltip
+ disabled={isReadOnlyProvider}
+ title={GATEWAY_MANAGED_ARTIFACT_TOOLTIP}
+ >
<Button
variant="contained"
size="medium"
onClick={handleOpenApiKeyModal}
- disabled={gateways.length === 0}
+ disabled={isReadOnlyProvider || gateways.length === 0}
>
Generate API Key
</Button>
</DisabledActionTooltip>
@@
- disabled={!key.name || isDeletingKey}
+ disabled={
+ isReadOnlyProvider || !key.name || isDeletingKey
+ }Also applies to: 464-473
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@portals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderDeploymentsCard.tsx`
at line 129, The isReadOnlyProvider boolean computed on line 129 is not being
used to gate API key actions in the card. Update the disabled prop logic for the
DisabledActionTooltip component and related action handlers in the range of
lines 464-473 to include isReadOnlyProvider in the disabled condition alongside
the existing gateway availability check. This ensures that when a provider is
read-only, the API key create and delete actions are properly disabled
regardless of gateway availability.
| export default function ServiceProviderGuardrailsTab() { | ||
| const { provider, isLoading, error, updateProvider, isDraftMode } = | ||
| useLLMProvider(); | ||
| const isReadOnlyProvider = Boolean(provider?.readOnly); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Guard the guardrail submit mutation in read-only mode.
The read-only flag is introduced, but handlePolicySubmit (Line 409) can still proceed without checking it. Add isReadOnlyProvider to that early-return condition.
Suggested fix
const handlePolicySubmit = async (params: ParameterValues) => {
- if (!provider || !selectedGuardrailPolicy || isLoading || error) return;
+ if (
+ !provider ||
+ !selectedGuardrailPolicy ||
+ isLoading ||
+ error ||
+ isReadOnlyProvider
+ ) {
+ return;
+ }As per path instructions, "Provide concise, actionable feedback focused on correctness and best practices."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@portals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderGuardrailsTab.tsx`
at line 163, The read-only provider flag is defined as `isReadOnlyProvider` but
is not being checked in the `handlePolicySubmit` function to prevent policy
submissions. Add `isReadOnlyProvider` to the early-return condition in
`handlePolicySubmit` to guard against submissions when the provider is in
read-only mode, ensuring that policy changes cannot be submitted for read-only
providers.
Source: Path instructions
| const isReadOnlyProvider = Boolean(provider?.readOnly); | ||
| const createProxyTooltip = isProxyQuotaReached ? proxyQuotaTooltip : ''; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Add read-only enforcement to the save flow.
isReadOnlyProvider is defined, but the save path still allows progression (Line 379 handleSaveChanges and footer actions around Lines 1459-1473). Add an early return in handleSaveChanges and disable Save/Cancel when read-only to keep behavior consistent with the rest of the page.
Suggested fix
const handleSaveChanges = async () => {
- if (!provider || isSavingChanges) return;
+ if (!provider || isSavingChanges || isReadOnlyProvider) return; <Button
variant="outlined"
color="secondary"
- disabled={!hasUnsavedChanges || isSavingChanges}
+ disabled={isReadOnlyProvider || !hasUnsavedChanges || isSavingChanges}
onClick={handleCancelChanges}
>
Cancel
</Button>
<Button
variant="contained"
- disabled={!hasUnsavedChanges || isSavingChanges}
+ disabled={isReadOnlyProvider || !hasUnsavedChanges || isSavingChanges}
onClick={() => void handleSaveChanges()}
>
Save
</Button>As per path instructions, "Provide concise, actionable feedback focused on correctness and best practices."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@portals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderOverview.tsx`
around lines 477 - 478, The isReadOnlyProvider flag is defined but not enforced
in the save flow, allowing users to attempt saving even when the provider is
read-only. Add an early return check at the beginning of the handleSaveChanges
function to immediately return if isReadOnlyProvider is true, preventing any
save operation from proceeding. Additionally, update the footer action buttons
(Save and Cancel buttons around lines 1459-1473) to disable them when
isReadOnlyProvider is true, ensuring the UI consistently prevents read-only
users from interacting with save functionality throughout the page.
Source: Path instructions
| const apiKeyLocation = provider?.security?.apiKey?.in ?? 'header'; | ||
| const apiKeyName = provider?.security?.apiKey?.key ?? 'X-API-Key'; | ||
| const showSnackbar = useAIWorkspaceSnackbar(); | ||
| const isReadOnlyProvider = Boolean(provider?.readOnly); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Apply isReadOnlyProvider to both API key UI disablement and mutation guards.
Line 162 defines read-only state, but Line 605 delete guard and Lines 825-834 generate button wrapper do not enforce it (DisabledActionTooltip is hardcoded to disabled={false}). This allows API key operations in read-only mode.
Proposed fix
@@
- const handleGenerateAPIKey = async () => {
- if (!currentOrganization?.uuid || !provider?.id) {
+ const handleGenerateAPIKey = async () => {
+ if (isReadOnlyProvider || !currentOrganization?.uuid || !provider?.id) {
return;
}
@@
const handleDeleteApiKey = async () => {
if (
+ isReadOnlyProvider ||
!deleteTargetKeyName ||
!provider?.id ||
!currentOrganization?.uuid
@@
- <DisabledActionTooltip disabled={false}>
+ <DisabledActionTooltip
+ disabled={isReadOnlyProvider}
+ title={GATEWAY_MANAGED_ARTIFACT_TOOLTIP}
+ >
<Button
variant="contained"
size="medium"
onClick={handleOpenApiKeyModal}
- disabled={deployedGateways.length === 0}
+ disabled={
+ isReadOnlyProvider || deployedGateways.length === 0
+ }
>
Generate API Key
</Button>
</DisabledActionTooltip>
@@
- disabled={!key.name || isDeletingKey}
+ disabled={
+ isReadOnlyProvider ||
+ !key.name ||
+ isDeletingKey
+ }Also applies to: 605-609, 825-834
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In
`@portals/ai-workspace/src/pages/appShell/appShellPages/serviceProvider/ServiceProviderOverviewTab.tsx`
at line 162, The isReadOnlyProvider variable defined at line 162 is not being
applied to enforce read-only restrictions for API key operations. Update the
DisabledActionTooltip components at the delete guard location (around line 605)
and the generate button wrapper (lines 825-834) to use the isReadOnlyProvider
flag instead of the hardcoded disabled={false} value. Replace disabled={false}
with disabled={isReadOnlyProvider} in both locations to properly prevent API key
operations when the provider is in read-only mode.
This pull request introduces comprehensive support for "read-only" MCP proxy servers that are managed externally (via a gateway) and should not be editable or deployable from the AI Workspace UI. The changes ensure that when a server is marked as read-only, all relevant editing, deployment, and policy management actions are disabled, and informative tooltips or alerts are shown to the user.
Key changes include:
Read-only Server Detection and Enforcement:
readOnlyproperty on servers and propagated this asisReadOnlyServerthroughout the UI components. All editing, deployment, and policy management actions are now conditionally disabled if the server is read-only. [1] [2] [3]UI Feedback and Disabled Actions:
Alertcomponents in the Edit, Overview, and Deploy pages to inform users when a server is read-only and actions are unavailable. [1] [2] [3]DisabledActionTooltipcomponents, providing tooltips that explain why actions are disabled. [1] [2] [3]Form and Button Disabling:
Policy Management Restrictions:
PolicyMappercomponent when in read-only mode, and passed thereadOnlyprop from parent components. [1] [2] [3] [4] [5] [6] [7] [8] [9] [10]Imports and Utility Integration:
DisabledActionTooltipand related constants fromreadOnlyArtifactsutility module across affected files. [1] [2] [3] [4] [5]These updates ensure a clear and consistent user experience when interacting with gateway-managed MCP proxies, preventing unsupported modifications and providing clear communication to users.