Skip to content

Comments

feat: add read-only mode for GitOps deployments#1349

Closed
opspawn wants to merge 3 commits intokagent-dev:mainfrom
opspawn:feat/read-only-mode
Closed

feat: add read-only mode for GitOps deployments#1349
opspawn wants to merge 3 commits intokagent-dev:mainfrom
opspawn:feat/read-only-mode

Conversation

@opspawn
Copy link
Contributor

@opspawn opspawn commented Feb 20, 2026

Summary

Implements read-only mode for kagent (#1344), enabling GitOps-compatible deployments where resources are managed declaratively and the UI serves as a view-only dashboard.

Backend (Go)

  • ReadOnlyAuthorizer in go/internal/httpserver/auth/authz.go — implements the Authorizer interface, allows VerbGet and rejects create/update/delete with a clear error message
  • Wired via KAGENT_READ_ONLY=true environment variable in go/cmd/controller/main.go
  • 4 unit tests covering allow-get, reject-mutations, error messages, and noop baseline

Frontend (Next.js)

  • ReadOnlyProvider context + useReadOnly() hook wired via NEXT_PUBLIC_READ_ONLY=true
  • Header: Hides the "Create" dropdown (desktop + mobile) when read-only
  • Agent cards: Hides edit/delete overlay buttons
  • Models page: Hides "New Model" button + per-row edit/delete buttons; shows GitOps message in empty state
  • MCP Servers page: Hides "Add MCP Server" + per-server delete; shows GitOps message in empty state
  • Chat sidebar: Hides session delete option
  • Route guards: /agents/new and /models/new redirect to / when read-only
  • Onboarding: Wizard is skipped in read-only mode
  • Empty states: Show "Resources are managed via GitOps" instead of create CTAs

How to test

Backend:

cd go && go test ./internal/httpserver/auth/ -v -run "TestReadOnly|TestNoop"

Frontend (read-only mode):

NEXT_PUBLIC_READ_ONLY=true npm run dev

Then verify:

  • No "Create" menu in header
  • No edit/delete buttons on agents, models, servers
  • /agents/new and /models/new redirect to /
  • Empty states show "Resources are managed via GitOps"
  • Onboarding wizard does not appear

Frontend (normal mode):

npm run dev

Verify all create/edit/delete functionality works as before.

Closes #1344

Copilot AI review requested due to automatic review settings February 20, 2026 21:13
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds an application-wide “read-only / GitOps mode” that blocks write operations in the backend authorizer and hides/guards write-capable UI paths and controls in the Next.js frontend.

Changes:

  • Backend: introduce ReadOnlyAuthorizer and wire it via KAGENT_READ_ONLY=true, with unit tests.
  • Frontend: add ReadOnlyProvider (NEXT_PUBLIC_READ_ONLY=true) and conditionally hide create/edit/delete controls across pages/components.
  • Frontend: add route guards for create/edit pages and skip onboarding in read-only mode.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
ui/src/components/sidebars/ChatItem.tsx Hides chat session deletion UI when read-only.
ui/src/components/ReadOnlyProvider.tsx Adds read-only React context + hook sourced from NEXT_PUBLIC_READ_ONLY.
ui/src/components/Header.tsx Hides “Create” menus when read-only (desktop + mobile).
ui/src/components/AppInitializer.tsx Skips onboarding wizard in read-only mode.
ui/src/components/AgentList.tsx Replaces empty-state create CTA with GitOps messaging when read-only.
ui/src/components/AgentCard.tsx Hides edit/delete overlay actions when read-only.
ui/src/app/servers/page.tsx Hides add/remove MCP server UI and updates empty state for read-only.
ui/src/app/models/page.tsx Hides model create/edit/delete UI and shows GitOps messaging when read-only.
ui/src/app/models/new/page.tsx Adds read-only guard redirect for model create/edit page.
ui/src/app/layout.tsx Wires ReadOnlyProvider at the app root.
ui/src/app/agents/new/page.tsx Adds read-only guard redirect for agent create/edit page.
go/internal/httpserver/auth/authz_test.go Adds tests for NoopAuthorizer and new ReadOnlyAuthorizer.
go/internal/httpserver/auth/authz.go Implements ReadOnlyAuthorizer (allow GET only).
go/cmd/controller/main.go Selects ReadOnlyAuthorizer when KAGENT_READ_ONLY=true.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 742 to 751
const readOnly = useReadOnly();
// Determine if in edit mode
const searchParams = useSearchParams();
const isEditMode = searchParams.get("edit") === "true";
const agentName = searchParams.get("name");
const agentNamespace = searchParams.get("namespace");

if (readOnly) {
redirect("/");
}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

redirect() from next/navigation is a server-only API; this page is marked "use client", so calling redirect("/") during render will fail at build/runtime. Use useRouter().replace("/") (typically inside a useEffect) and render null/a small placeholder while navigating, or refactor the guard into a server component wrapper where redirect() is supported.

Copilot uses AI. Check for mistakes.
Comment on lines 762 to 767
export default function ModelPage() {
const readOnly = useReadOnly();

if (readOnly) {
redirect("/");
}
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

redirect() is not supported in Client Components ("use client"). This guard will throw rather than navigating. Prefer a client-side redirect via useRouter().replace("/") in an effect (and return null while it runs), or move the read-only check to a server component where redirect() can be used.

Copilot uses AI. Check for mistakes.
</Link>
</DropdownMenuItem>
<DropdownMenuItem asChild onClick={handleMobileLinkClick}>
<Link href="/servers/new" className="gap-2 cursor-pointer w-full">
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

The mobile "New MCP Server" link points to /servers/new, but there is no ui/src/app/servers/new route in the app (only /servers). This will 404 on mobile. Update the link to the existing /servers page (or add the missing route) to keep mobile/desktop behavior consistent.

Suggested change
<Link href="/servers/new" className="gap-2 cursor-pointer w-full">
<Link href="/servers" className="gap-2 cursor-pointer w-full">

Copilot uses AI. Check for mistakes.
@opspawn
Copy link
Contributor Author

opspawn commented Feb 20, 2026

All 20 CI checks are passing. This PR directly addresses the feature request in #1344. Ready for review whenever you have a chance!

@fl-sean03
Copy link

CI is green (18/20, remaining 2 still running). This implements read-only mode for GitOps deployments (addresses #1344). All Copilot review feedback has been addressed. Ready for maintainer review when available.

Add read-only mode to both the Go backend and Next.js frontend, allowing
kagent to be deployed in GitOps environments where resources are managed
declaratively.

Backend:
- Add ReadOnlyAuthorizer that allows VerbGet but rejects create/update/delete
- Wire via KAGENT_READ_ONLY=true environment variable
- Add comprehensive tests for the new authorizer

Frontend:
- Add ReadOnlyProvider context with useReadOnly() hook
- Hide Create dropdown in Header navigation
- Hide Edit/Delete overlays on agent cards and model rows
- Hide chat session delete option
- Hide Add/Remove buttons on MCP servers page
- Add route guards redirecting /agents/new and /models/new to /
- Skip onboarding wizard in read-only mode
- Show 'Resources are managed via GitOps' in empty states
- Wire via NEXT_PUBLIC_READ_ONLY=true environment variable

Closes kagent-dev#1344

Signed-off-by: opspawn <opspawn@users.noreply.github.com>
- Replace server-only redirect() with client-side useRouter().replace()
  in agents/new and models/new pages (both marked "use client")
- Fix mobile "New MCP Server" link to point to /servers instead of
  non-existent /servers/new route

Signed-off-by: opspawn <opspawn@users.noreply.github.com>
Signed-off-by: opspawn <opspawn@users.noreply.github.com>
@opspawn opspawn force-pushed the feat/read-only-mode branch from 957c410 to 5b388f0 Compare February 21, 2026 00:21
@opspawn
Copy link
Contributor Author

opspawn commented Feb 21, 2026

Closing in favor of #1346 by frank-bee which implements the same read-only mode for GitOps-managed deployments. Our implementation was parallel but theirs is further along.

@opspawn
Copy link
Contributor Author

opspawn commented Feb 21, 2026

Closing in favor of #1346 by frank-bee which covers the same GitOps read-only mode functionality.

@opspawn opspawn closed this Feb 21, 2026
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.

[FEATURE] Read-only mode for GitOps-managed deployments

2 participants