Skip to content

feat(dashboard): replace UI with new cozystack-ui build - #2507

Merged
myasnikovdaniil merged 28 commits into
mainfrom
feat/new-ui
May 13, 2026
Merged

feat(dashboard): replace UI with new cozystack-ui build#2507
myasnikovdaniil merged 28 commits into
mainfrom
feat/new-ui

Conversation

@IvanHunters

@IvanHunters IvanHunters commented Apr 28, 2026

Copy link
Copy Markdown
Collaborator

Summary

Replaces the old openapi-ui with the new cozystack-ui build from the cozystack-ui repository.

Key Changes

New UI

Removed Components

  • Removed BFF (Backend-For-Frontend) container - new UI communicates directly with Kubernetes API
  • Removed old openapi-ui and openapi-ui-k8s-bff build targets from Makefile
  • Removed old UI Dockerfiles and patch files

RBAC Updates

  • Added read permissions for cozystack.io/applicationdefinitions to fix 403 errors
  • New UI requires access to applicationdefinitions for marketplace and catalog functionality

Bug Fixes

  • Fixed VNC WebSocket connections to use dynamic URLs instead of hardcoded localhost:8001
  • VNC now works properly in-cluster deployments

Testing

Tested on dev3.infra.aenix.org cluster:

  • ✅ Dashboard loads correctly
  • ✅ Application definitions accessible
  • ✅ VNC connections working
  • ✅ Backup pages functional
  • ✅ All TypeScript errors resolved

Migration Notes

The new UI is a complete rewrite with:

  • Modern React 19 + TypeScript stack
  • Improved backup management pages
  • Better type safety and error handling
  • Direct Kubernetes API communication (no BFF needed)

Replace old openapi-ui with new cozystack-ui that proxies API requests through BFF.

Changes:
- New UI image: 999669/cozystack-ui:latest@sha256:74e39ad4
- BFF container: kept unchanged for K8s API authentication
- New UI includes TypeScript fixes and improved backup pages
- nginx configured to proxy /api and /apis to localhost:64231 (BFF)

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
- Update openapiUI image to amd64 build (sha256:9d8fc5c1...)
- Remove old openapi-ui and openapi-ui-k8s-bff build targets from Makefile
- Remove old UI Dockerfiles and related files
- Add RBAC permissions for cozystack.io/applicationdefinitions to fix 403 errors

The new cozystack-ui requires read access to applicationdefinitions API group
for marketplace and application catalog functionality.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
Update to new image digest with dynamic WebSocket URL fix for VNC connections.
VNC now uses window.location instead of hardcoded localhost:8001.

Image: 999669/cozystack-ui:latest@sha256:ea4e832c2...
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
@coderabbitai

coderabbitai Bot commented Apr 28, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Replaces the OpenAPI UI/nginx/web stack with a single console deployment: Makefile now builds a pinned cozystack-ui image; OpenAPI Dockerfiles and nginx/web manifests removed; Helm templates, Service/ServiceAccount names, and RBAC retargeted/renamed to cozy-dashboard-*; values.yaml now exposes console.image.

Changes

Cohort / File(s) Summary
Build system & CI
packages/system/dashboard/.gitignore, packages/system/dashboard/Makefile
Adds .tmp-cozystack-ui to .gitignore. Makefile: removes OpenAPI image/update targets; adds CONSOLE_REPO/CONSOLE_REF and image-console target that clones the console repo, builds/pushes cozystack-ui, records build metadata, updates values.yaml, and cleans temp files.
Removed OpenAPI images
packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile, packages/system/dashboard/images/openapi-ui/Dockerfile
Deletes multi-stage Dockerfiles for openapi-ui and openapi-ui k8s-bff.
OpenAPI toolkit patches (reverted/removed)
packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/*
Removes previously applied toolkit patches (flatmap-unresolved-placeholder.diff, formlistinput-allow-empty.diff, secret-copy-preserve-newlines.diff, tenantmodules.diff), reverting those UI toolkit modifications.
Console service & templates (modified)
packages/system/dashboard/templates/console-sa.yaml, packages/system/dashboard/templates/console-svc.yaml, packages/system/dashboard/templates/console.yaml, packages/system/dashboard/templates/configmap.yaml, packages/system/dashboard/values.yaml
Renames ServiceAccount/Service/Deployment to cozy-dashboard-console/cozy-dashboard; updates selectors/labels; removes nginx config volume and embedded nginx config; consolidates branding into data.config.json (cozy-dashboard-console-config); exposes Values.console.image; adds /healthcheck startupProbe on port 8080.
Removed nginx & web resources
packages/system/dashboard/templates/nginx-config.yaml, packages/system/dashboard/templates/web.yaml, packages/system/dashboard/templates/web-sa.yaml, packages/system/dashboard/templates/web-svc.yaml
Deletes legacy nginx ConfigMap and the incloud-web Deployment, Service, and ServiceAccount templates.
RBAC / bindings / flow control updates
packages/system/dashboard/templates/clusterrolebinding-cluster-view.yaml, packages/system/dashboard/templates/clusterrolebinding-web-user-edit.yaml, packages/system/dashboard/templates/rbac.yaml, packages/system/dashboard/templates/flowschema.yaml, packages/system/dashboard/templates/gatekeeper.yaml, packages/system/dashboard/templates/console-rbac.yaml
Updates ClusterRoleBinding names/subjects to cozy-dashboard-console and release namespace; adds cozystack.io applicationdefinitions read rules to cozystack-dashboard-readonly; updates FlowSchema subject and gatekeeper upstream targets; adds Role/RoleBinding to expose cozy-dashboard-console-config to authenticated users.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer/CI
  participant Git as Git (CONSOLE_REPO)
  participant Builder as Builder (make)
  participant Registry as Image Registry
  participant Values as Helm values.yaml
  participant K8s as Kubernetes (helm)

  Dev->>Builder: run `make image` (image-console)
  Builder->>Git: git clone CONSOLE_REPO@CONSOLE_REF
  Builder->>Builder: build image from Containerfile (cozystack-ui)
  Builder->>Registry: push image & obtain digest
  Builder->>Values: write image digest to `Values.console.image`
  Dev->>K8s: helm upgrade/install using updated values
  K8s->>K8s: deploy `cozy-dashboard-console` Deployment with new image
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I cloned a repo beneath the moonlight,
I baked a console, tidy and bright.
Nginx hopped off and labels rearranged,
Digests recorded, old stacks exchanged.
Small paws, big deploy — the dashboard’s right!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: replacing the old openapi-ui with a new cozystack-ui build, which aligns with the substantial refactoring of dashboard UI components, Makefile targets, and Kubernetes manifests.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/new-ui

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added area/dashboard Issues or PRs related to the dashboard / UI kind/feature Categorizes issue or PR as related to a new feature labels Apr 28, 2026
myasnikovdaniil added a commit that referenced this pull request Apr 28, 2026
The cozy-installer chart declares Namespace cozy-system itself (with
helm.sh/resource-policy: keep). Combining that with --create-namespace
makes Helm v3 pre-create the namespace via plain kubectl-create (without
helm annotations); the subsequent chart apply then fails with
'namespaces cozy-system already exists'.

The 3x retry on Install Cozystack was hiding this. First attempt failed,
second saw 'release exists' and treated it as upgrade. Reproducible
across PRs (PR #2507 E2E hit the same first-attempt failure today and
recovered on retry). Surfaced cleanly after dropping the retry on this
step.

Drop --create-namespace; let the chart manage its own namespace.

Signed-off-by: Myasnikov Daniil <myasnikovdaniil2001@gmail.com>
IvanHunters and others added 8 commits April 28, 2026 23:35
- Add RBAC permissions for VNC console access to virtual machines
- Update cozystack-ui image to latest version with VNC fixes

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
Remove old openapi-ui implementation and adopt new React-based console:

**Removed:**
- images/openapi-ui/ - old PRO-Robotech based UI
- images/openapi-ui-k8s-bff/ - unused backend-for-frontend
- templates/nginx.yaml - separate nginx proxy (replaced by built-in nginx)
- templates/configmap.yaml - old UI configuration

**Changes:**
- Rename web → console throughout all manifests
- Rename incloud-web-* → cozy-dashboard-* for all resources
- Remove all environment variables (new UI requires no configuration)
- Update gatekeeper upstream to point directly to console service
- Simplify Makefile (only token-proxy image build remains)
- Update values.yaml: openapiUI → console

**Architecture changes:**
Before: gatekeeper → nginx → web (openapi-ui)
After: gatekeeper → console (React SPA with built-in nginx)

The new console includes nginx that proxies /api and /apis to K8s API,
eliminating the need for a separate nginx deployment. Authentication
flow remains unchanged - gatekeeper adds Authorization header which
is passed through to K8s API.

Breaking change: Resource names changed from incloud-web-* to
cozy-dashboard-*. Existing deployments will need migration.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
Add Makefile target to build console image from external repository:
- Clone cozystack-ui repository (configurable via CONSOLE_REPO/CONSOLE_REF)
- Build multi-arch image (amd64, arm64)
- Push to registry and update values.yaml with digest
- Clean up temporary directory after build

This enables automated console image builds as part of the dashboard
release process, similar to how token-proxy is built.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
- Add --file flag to specify Containerfile path in docker buildx
- Build console image from cozystack-ui feat/ui-overhaul branch
- Update console image with VNC fix (includes /k8s proxy location)

New console image includes nginx /k8s location for VNC WebSocket
routing to KubeVirt VMI subresources.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
- Pin CONSOLE_REF to a specific commit hash for reproducible builds
- Fix git clone to support fetching by commit hash (not branch)
- Pass COZYSTACK_VERSION as build arg for version display in UI

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
- Rename ClusterRoleBinding and update ServiceAccount references
- Update FlowSchema to use new cozy-dashboard-console service account
- Add core.cozystack.io permissions for tenant resources

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
Containerfile expects ARG APP_VERSION, not COZYSTACK_VERSION

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
@IvanHunters
IvanHunters marked this pull request as ready for review April 29, 2026 20:53
@dosubot dosubot Bot added the size/L This PR changes 100-499 lines, ignoring generated files label Apr 29, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant upgrade to the dashboard UI by integrating a new cozystack-ui build. This change streamlines the application's architecture by eliminating the need for a Backend-For-Frontend (BFF) service, as the new UI communicates directly with the Kubernetes API. It also includes essential RBAC updates to support new features like marketplace access and functional VNC connections, ensuring a more modern and robust user experience.

Highlights

  • UI Replacement: The old openapi-ui has been completely replaced with a new cozystack-ui build, featuring a modern React 19 + TypeScript stack.
  • Architectural Simplification: The Backend-For-Frontend (BFF) container has been removed, as the new UI communicates directly with the Kubernetes API, streamlining the application's architecture.
  • RBAC Enhancements: New read permissions were added for cozystack.io/applicationdefinitions and Kubevirt resources to support marketplace functionality and VNC connections.
  • VNC Functionality Fix: VNC WebSocket connections were updated to use dynamic URLs instead of hardcoded localhost:8001, resolving VNC issues in in-cluster deployments.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Ignored Files
  • Ignored by pattern: **/*.diff (4)
    • packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/flatmap-unresolved-placeholder.diff
    • packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/formlistinput-allow-empty.diff
    • packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/secret-copy-preserve-newlines.diff
    • packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/tenantmodules.diff
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment Gemini (@gemini-code-assist) Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on Gemini (@gemini-code-assist) comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Default docker driver does not support multi-platform builds.
All other packages in make build use linux/amd64 only.

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request refactors the dashboard by replacing the legacy openapi-ui components with a new unified cozystack-ui console. The changes involve significant updates to the Makefile for image building, consolidation of Kubernetes manifests, and removal of obsolete Nginx configurations. Review feedback identifies high-severity security risks where sensitive resources like tenant secrets and VM VNC consoles are exposed to all authenticated users via broad RBAC permissions. Furthermore, the update violates style guidelines by using a personal image registry and manually defining image digests in the values file.

Comment on lines +15 to +24
- apiGroups:
- core.cozystack.io
resources:
- tenantmodules
- tenantnamespaces
- tenantsecrets
verbs:
- get
- list
- watch

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-high high

Granting get, list, and watch permissions on tenantsecrets to all authenticated users (system:authenticated) is a significant security risk. In a multi-tenant PaaS, this allows any user with cluster access to discover and potentially inspect resources belonging to other tenants. These permissions should be restricted to administrative users or handled via more granular role bindings that respect tenant boundaries.

References
  1. Avoid overly broad RBAC permissions that expose sensitive resources like secrets to all authenticated users.

Comment on lines +57 to +62
- apiGroups:
- subresources.kubevirt.io
resources:
- virtualmachineinstances/vnc
verbs:
- get

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

security-high high

Granting virtualmachineinstances/vnc access to system:authenticated allows any authenticated user in the cluster to potentially connect to the VNC console of any virtual machine. This permission should be restricted to the owners of the respective VMs or specific namespaces to prevent unauthorized access to VM consoles.

Comment thread packages/system/dashboard/values.yaml Outdated
openapiUIK8sBff:
image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v1.3.0@sha256:1b3ea6d4c7dbbe6a8def3b2807fffdfab2ac4afc39d7a846e57dd491fa168f92
console:
image: 999669/cozystack-ui:latest@sha256:c5b0dcfa241603763150188150d56ab58fba1ea820bfdac92c601199057bf9a2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The image registry 999669 appears to be a personal account. Please use the official project registry (e.g., ghcr.io/cozystack/cozystack/cozystack-ui). Additionally, per the repository style guide (line 31), image digest values in values.yaml should be set by CI rather than manually updated in the pull request.

References
  1. Image digest values in values.yaml should be set by CI, not by humans. (link)

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/system/dashboard/Makefile (1)

12-32: Consider splitting image-console into smaller helper targets.

The target is doing clone/build/update/cleanup in one block; breaking it up will satisfy checkmake and make failures easier to isolate.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/system/dashboard/Makefile` around lines 12 - 32, The single large
image-console target should be split into smaller phony helper targets to
isolate clone, build, update-values, and cleanup steps; create targets like
clone-console (runs git clone/fetch/checkout using CONSOLE_REPO and CONSOLE_REF
into .tmp-cozystack-ui), build-console (invokes docker buildx with BUILDER,
REGISTRY, TAG, COZYSTACK_VERSION, PUSH, LOAD and writes images/console.json),
update-values-console (reads images/console.json to set IMAGE and updates
values.yaml), and clean-console (removes .tmp-cozystack-ui and
images/console.json), then make image-console depend on them in order so
failures are isolated and checkmake passes; also declare .PHONY for these helper
targets and preserve the same unique filenames (.tmp-cozystack-ui,
images/console.json, values.yaml) and build args to avoid changing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/system/dashboard/Makefile`:
- Line 7: Add a .PHONY declaration for the Makefile targets to ensure they
always run: declare image and its subtargets (image-console and
image-token-proxy) as phony targets so a file or directory named "image" won't
short-circuit execution; update the Makefile to include a .PHONY line listing
image, image-console, and image-token-proxy.

In `@packages/system/dashboard/templates/rbac.yaml`:
- Around line 15-24: The ClusterRole cozystack-dashboard-readonly currently
grants get/list/watch on tenantsecrets and is bound to system:authenticated,
which is overly broad; remove tenantsecrets from the ClusterRole (or remove the
ClusterRole binding to system:authenticated) and instead create a
namespace-scoped Role that grants get/list/watch on tenantsecrets and bind that
Role to the dashboard ServiceAccount (the same SA used by the dashboard
controller in internal/controller/dashboard/factory.go), or alternatively
restrict the existing binding to only that ServiceAccount rather than
system:authenticated.

---

Nitpick comments:
In `@packages/system/dashboard/Makefile`:
- Around line 12-32: The single large image-console target should be split into
smaller phony helper targets to isolate clone, build, update-values, and cleanup
steps; create targets like clone-console (runs git clone/fetch/checkout using
CONSOLE_REPO and CONSOLE_REF into .tmp-cozystack-ui), build-console (invokes
docker buildx with BUILDER, REGISTRY, TAG, COZYSTACK_VERSION, PUSH, LOAD and
writes images/console.json), update-values-console (reads images/console.json to
set IMAGE and updates values.yaml), and clean-console (removes .tmp-cozystack-ui
and images/console.json), then make image-console depend on them in order so
failures are isolated and checkmake passes; also declare .PHONY for these helper
targets and preserve the same unique filenames (.tmp-cozystack-ui,
images/console.json, values.yaml) and build args to avoid changing behavior.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a752d515-a3cc-4e1b-b0e9-5a3212fa66ce

📥 Commits

Reviewing files that changed from the base of the PR and between f1e5641 and e8fbd4e.

📒 Files selected for processing (21)
  • packages/system/dashboard/.gitignore
  • packages/system/dashboard/Makefile
  • packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile
  • packages/system/dashboard/images/openapi-ui/Dockerfile
  • packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/flatmap-unresolved-placeholder.diff
  • packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/formlistinput-allow-empty.diff
  • packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/secret-copy-preserve-newlines.diff
  • packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/tenantmodules.diff
  • packages/system/dashboard/templates/clusterrolebinding-cluster-view.yaml
  • packages/system/dashboard/templates/configmap.yaml
  • packages/system/dashboard/templates/console-sa.yaml
  • packages/system/dashboard/templates/console-svc.yaml
  • packages/system/dashboard/templates/console.yaml
  • packages/system/dashboard/templates/flowschema.yaml
  • packages/system/dashboard/templates/gatekeeper.yaml
  • packages/system/dashboard/templates/nginx-config.yaml
  • packages/system/dashboard/templates/rbac.yaml
  • packages/system/dashboard/templates/web-sa.yaml
  • packages/system/dashboard/templates/web-svc.yaml
  • packages/system/dashboard/templates/web.yaml
  • packages/system/dashboard/values.yaml
💤 Files with no reviewable changes (11)
  • packages/system/dashboard/images/openapi-ui-k8s-bff/Dockerfile
  • packages/system/dashboard/templates/web-sa.yaml
  • packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/flatmap-unresolved-placeholder.diff
  • packages/system/dashboard/templates/web-svc.yaml
  • packages/system/dashboard/templates/nginx-config.yaml
  • packages/system/dashboard/images/openapi-ui/Dockerfile
  • packages/system/dashboard/templates/web.yaml
  • packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/secret-copy-preserve-newlines.diff
  • packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/formlistinput-allow-empty.diff
  • packages/system/dashboard/templates/configmap.yaml
  • packages/system/dashboard/images/openapi-ui/openapi-k8s-toolkit/patches/tenantmodules.diff

Comment on lines +15 to +24
- apiGroups:
- core.cozystack.io
resources:
- tenantmodules
- tenantnamespaces
- tenantsecrets
verbs:
- get
- list
- watch

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether tenantsecrets is broadly exposed and whether it's actually required by dashboard paths.

set -euo pipefail

echo "== RBAC exposure =="
rg -n -C3 --iglob '*rbac*.yaml' 'cozystack-dashboard-readonly|system:authenticated|tenantsecrets'

echo
echo "== CRD definition hints for tenantsecrets =="
rg -n -C4 --iglob '*.{yaml,yml}' 'name:\s*tenantsecrets|tenantsecrets\.core\.cozystack\.io|kind:\s*CustomResourceDefinition'

echo
echo "== Repo usages of tenantsecrets =="
rg -n -C2 --iglob '*.{yaml,yml,go,ts,tsx,js}' '\btenantsecrets\b'

Repository: cozystack/cozystack

Length of output: 50376


🏁 Script executed:

# More targeted searches
echo "=== Looking for tenantsecrets API group definition ==="
rg -n 'tenantsecrets\.core\.cozystack\.io' --max-count=20

echo
echo "=== Search for tenantsecrets in core.cozystack.io context ==="
rg -n -B2 -A2 'core\.cozystack\.io' --iglob '*.yaml' | grep -A5 -B5 tenantsecrets || echo "No context found"

echo
echo "=== Dashboard-specific code references to tenantsecrets ==="
fd -t f --iglob '*dashboard*' . | xargs rg -l 'tenantsecrets' 2>/dev/null || echo "No dashboard files reference tenantsecrets"

echo
echo "=== Check for cozystack-api CRD definitions ==="
fd -t f -path '*/cozystack-api/*' --iglob '*.yaml' | head -20

echo
echo "=== Search for tenantsecrets in cozystack-api or core APIs ==="
rg -n 'tenantsecrets' packages/system/cozystack-api/ 2>/dev/null | head -30 || echo "No tenantsecrets found in cozystack-api"

Repository: cozystack/cozystack

Length of output: 1075


🏁 Script executed:

echo "=== Registry definition for tenantsecrets ==="
cat pkg/registry/core/tenantsecret/rest.go | head -80

echo
echo "=== Dashboard code usage of tenantsecrets ==="
rg -n 'tenantsecrets' internal/controller/dashboard/ -A2 -B2 | head -60

echo
echo "=== APIServer definition of tenantsecrets ==="
rg -n -A5 -B5 'tenantsecrets' pkg/apiserver/apiserver.go | head -80

echo
echo "=== Check cozystack-basics RBAC to see if tenantsecrets pattern exists elsewhere ==="
rg -n -A3 -B3 'tenantsecrets' packages/system/cozystack-basics/templates/clusterroles.yaml

Repository: cozystack/cozystack

Length of output: 5842


Exposing tenantsecrets to all authenticated users weakens least-privilege.

The cozystack-dashboard-readonly ClusterRole grants get, list, and watch on tenantsecrets (line 20), which is bound to system:authenticated (line 75). Since tenantsecrets is a view over Kubernetes Secrets with sensitive data, this grants all authenticated cluster users read access to all tenant secrets cluster-wide.

While the dashboard legitimately uses tenantsecrets (via namespace-scoped API paths in internal/controller/dashboard/factory.go), the ClusterRole permission is broader than necessary. Consider restricting this to a Role bound to the dashboard's ServiceAccount, or limiting via RoleBindings in specific namespaces.

🔧 Suggested minimal hardening
 - apiGroups:
   - core.cozystack.io
   resources:
   - tenantmodules
   - tenantnamespaces
-  - tenantsecrets
   verbs:
   - get
   - list
   - watch

Alternatively, if the dashboard must access tenantsecrets, create a separate Role (not ClusterRole) bound to the dashboard ServiceAccount.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/system/dashboard/templates/rbac.yaml` around lines 15 - 24, The
ClusterRole cozystack-dashboard-readonly currently grants get/list/watch on
tenantsecrets and is bound to system:authenticated, which is overly broad;
remove tenantsecrets from the ClusterRole (or remove the ClusterRole binding to
system:authenticated) and instead create a namespace-scoped Role that grants
get/list/watch on tenantsecrets and bind that Role to the dashboard
ServiceAccount (the same SA used by the dashboard controller in
internal/controller/dashboard/factory.go), or alternatively restrict the
existing binding to only that ServiceAccount rather than system:authenticated.

@lexfrei Aleksei Sviridkin (lexfrei) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

NOT LGTM — B4 and the legacy /openapi-ui redirect were both fixed in the previous round; the only remaining blocker is B2 (personal Docker Hub registry image in values.yaml). The latest commit 6fe9dcc reshapes the Makefile clone step (git clone with branch instead of fetch + raw-SHA checkout) but doesn't touch values.yaml.

Business context: Replace the old openapi-ui + BFF dashboard architecture with the new cozystack-ui console that talks to the Kubernetes API directly.

Resolved earlier rounds

  • B1 (cross-tenant RBAC escalation) — fixed in caaf4f9.
  • B3 (branding) — fixed in fd25969/d2dd687a/89b54349 via runtime config.json + adoption hook.
  • B4 (Makefile values.yaml write race) — fixed in ec0e6d6 with .NOTPARALLEL: image.
  • A1 (stale incloud-web-web-user-edit name) — renamed.
  • Non-blocking #1 (/openapi-ui redirect) — fixed in 8c80c4d with nginx server-snippet.

Blocker still open

B2: chart default image still points at a personal Docker Hub account

File: packages/system/dashboard/values.yaml:2
Issue: console.image: 999669/cozystack-ui:latest@sha256:c5b0dcfa... is unchanged across every iteration of this PR. The 6fe9dcc build-helper refactor doesn't touch values.yaml.
Evidence: The Makefile target image-console (Makefile:32-33) writes $(REGISTRY)/cozystack-ui:...@sha256:<digest> into values.yaml after every official build; $(REGISTRY) resolves to ghcr.io/cozystack/cozystack for releases. The current 999669/... value is a manual one-off-build artifact carried across rounds.
Fix: Run make image-console against the official registry (make image-console PUSH=true REGISTRY=ghcr.io/cozystack/cozystack) and commit the regenerated values.yaml — single mechanical step.

- apiGroups:
- subresources.kubevirt.io
resources:
- virtualmachineinstances/vnc

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is the most egregious half of B1: granting get on virtualmachineinstances/vnc cluster-wide to system:authenticated lets any tenant SA open an interactive VNC console to any VM in any other tenant's namespace. See B1 in the body — the entire system:authenticated block needs scoping back to truly cluster-scoped resources.

resources:
- tenantmodules
- tenantnamespaces
- tenantsecrets

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

B1 (body): tenantsecrets cluster-wide to system:authenticated lets any tenant read every other tenant's secrets via the TenantSecret API. Tenant-scoped resources must not be granted through the cluster-wide binding.

Comment thread packages/system/dashboard/values.yaml Outdated
openapiUIK8sBff:
image: ghcr.io/cozystack/cozystack/openapi-ui-k8s-bff:v1.3.0@sha256:1b3ea6d4c7dbbe6a8def3b2807fffdfab2ac4afc39d7a846e57dd491fa168f92
console:
image: 999669/cozystack-ui:latest@sha256:c5b0dcfa241603763150188150d56ab58fba1ea820bfdac92c601199057bf9a2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

B2 (body): personal-account image. The Makefile's image-console target writes $(REGISTRY)/cozystack-ui to this field on every build — please re-run with REGISTRY=ghcr.io/cozystack/cozystack and commit the regenerated values.yaml.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The 999669/... digest is a development snapshot built locally. The image-console Makefile target automatically overwrites values.yaml with $(REGISTRY)/cozystack-ui:<tag>@<digest> on every build — the release CI run with REGISTRY=ghcr.io/cozystack/cozystack will replace this value before publishing the chart. We attempted to rebuild and push with the official registry but don't have write:packages permissions for the cozystack organization. The build itself completed successfully; the push requires release CI credentials.

… naming

Remove namespace-scoped resources (tenantsecrets, tenantnamespaces,
tenantmodules, virtualmachineinstances, virtualmachineinstances/vnc) from
the cozystack-dashboard-readonly ClusterRole bound to system:authenticated.
These resources must be accessed via per-namespace RoleBindings created by
the tenant operator, not through a cluster-wide grant to all authenticated
users.

Only truly cluster-scoped, public-by-design resources remain in the
ClusterRole: applicationdefinitions, storageclasses, backupclasses,
and dashboard.cozystack.io customization resources.

Also rename the leftover incloud-web-web-user-edit ClusterRoleBinding to
cozystack-dashboard-cluster-admin to match the new naming convention, and
declare Makefile targets as .PHONY.

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/system/dashboard/Makefile (1)

16-18: Consider replacing full clone with a minimal fetch path.

Current flow starts with git clone --no-checkout, which is heavier than needed for a single pinned ref build.

⚙️ Suggested lightweight checkout flow
-	git clone --no-checkout $(CONSOLE_REPO) .tmp-cozystack-ui
-	git -C .tmp-cozystack-ui fetch --depth 1 origin $(CONSOLE_REF)
+	git init .tmp-cozystack-ui
+	git -C .tmp-cozystack-ui remote add origin $(CONSOLE_REPO)
+	git -C .tmp-cozystack-ui fetch --depth 1 origin $(CONSOLE_REF)
 	git -C .tmp-cozystack-ui checkout FETCH_HEAD
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/system/dashboard/Makefile` around lines 16 - 18, Replace the heavy
"git clone --no-checkout $(CONSOLE_REPO) .tmp-cozystack-ui" flow with a minimal,
shallow fetch and detached checkout: create an empty repo in .tmp-cozystack-ui
(git init), add the remote pointing to $(CONSOLE_REPO), fetch only the single
ref with depth 1 (git fetch --depth 1 origin $(CONSOLE_REF)), then checkout the
fetched ref in detached mode (checkout --detach FETCH_HEAD); update the existing
lines that run "git -C .tmp-cozystack-ui fetch --depth 1 origin $(CONSOLE_REF)"
and "git -C .tmp-cozystack-ui checkout FETCH_HEAD" to match this sequence and
remove the initial full clone invocation to avoid unnecessary data transfer and
refs.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/system/dashboard/Makefile`:
- Line 9: The two image subtargets (image-console and image-token-proxy) both
mutate values.yaml and can race when make -j runs prerequisites in parallel;
change the image target so it runs the two steps serially in one recipe instead
of as separate parallel prerequisites—e.g., replace the current prerequisite
list on the image target with a single recipe that invokes the subtargets
sequentially (call make image-console && make image-token-proxy or perform the
two edits in order inside one shell block) so modifications to values.yaml
cannot run concurrently.

---

Nitpick comments:
In `@packages/system/dashboard/Makefile`:
- Around line 16-18: Replace the heavy "git clone --no-checkout $(CONSOLE_REPO)
.tmp-cozystack-ui" flow with a minimal, shallow fetch and detached checkout:
create an empty repo in .tmp-cozystack-ui (git init), add the remote pointing to
$(CONSOLE_REPO), fetch only the single ref with depth 1 (git fetch --depth 1
origin $(CONSOLE_REF)), then checkout the fetched ref in detached mode (checkout
--detach FETCH_HEAD); update the existing lines that run "git -C
.tmp-cozystack-ui fetch --depth 1 origin $(CONSOLE_REF)" and "git -C
.tmp-cozystack-ui checkout FETCH_HEAD" to match this sequence and remove the
initial full clone invocation to avoid unnecessary data transfer and refs.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3e688f62-4f5f-463d-9f86-98a810213c01

📥 Commits

Reviewing files that changed from the base of the PR and between e8fbd4e and caaf4f9.

📒 Files selected for processing (3)
  • packages/system/dashboard/Makefile
  • packages/system/dashboard/templates/clusterrolebinding-web-user-edit.yaml
  • packages/system/dashboard/templates/rbac.yaml
✅ Files skipped from review due to trivial changes (1)
  • packages/system/dashboard/templates/clusterrolebinding-web-user-edit.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/system/dashboard/templates/rbac.yaml

Comment thread packages/system/dashboard/Makefile

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/system/dashboard/templates/configmap.yaml`:
- Line 7: The ConfigMap is rendering config.json as a YAML object because
`config.json: {{ $branding | toJson }}` emits raw JSON; change the template so
the value is emitted as a YAML string by piping the JSON through the Helm/Go
template quote filter (apply toJson | quote) for the `config.json` key (template
variable `$branding`) so Kubernetes ConfigMap.data receives a string.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c04f93a9-fb6e-4898-989f-5e7866048453

📥 Commits

Reviewing files that changed from the base of the PR and between caaf4f9 and fd25969.

📒 Files selected for processing (2)
  • packages/system/dashboard/templates/configmap.yaml
  • packages/system/dashboard/templates/console.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/system/dashboard/templates/console.yaml

Comment thread packages/system/dashboard/templates/configmap.yaml Outdated
Add cozy-dashboard-console-config ConfigMap that renders _cluster.branding
values as JSON. The new console SPA fetches this ConfigMap at startup via
the Kubernetes API (/api/v1/namespaces/cozy-dashboard/configmaps/...) and
applies titleText, logoSvg, logoText without requiring nginx volume mounts
or pod restarts.

Add Role/RoleBinding granting system:authenticated read access to the
specific ConfigMap so the browser-side K8s API call succeeds.

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
Includes branding config fetch, backup/VNC fixes, and signoff cleanup.

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
packages/system/dashboard/Makefile (1)

9-9: ⚠️ Potential issue | 🟠 Major

Serialize image subtargets to prevent values.yaml write races.

At Line 9, make -j can execute image-console and image-token-proxy in parallel, but both do in-place edits to values.yaml (Line 33 and Line 49). This can cause nondeterministic/lost updates.

💡 Proposed fix
 .PHONY: image image-console image-token-proxy
+.NOTPARALLEL: image
 
 image: image-console image-token-proxy
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/system/dashboard/Makefile` at line 9, The 'image' target currently
lists 'image-console image-token-proxy' as parallel prerequisites which allows
make -j to run them concurrently and race on editing values.yaml; change the
Makefile so the two subtargets run serially: either make 'image' have a recipe
that invokes "make image-console && make image-token-proxy" or make
'image-token-proxy' depend on 'image-console' (so invoking 'image' runs them in
order), ensuring all edits to values.yaml (performed in the image-console and
image-token-proxy targets) happen sequentially to eliminate write races.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/system/dashboard/Makefile`:
- Line 9: The 'image' target currently lists 'image-console image-token-proxy'
as parallel prerequisites which allows make -j to run them concurrently and race
on editing values.yaml; change the Makefile so the two subtargets run serially:
either make 'image' have a recipe that invokes "make image-console && make
image-token-proxy" or make 'image-token-proxy' depend on 'image-console' (so
invoking 'image' runs them in order), ensuring all edits to values.yaml
(performed in the image-console and image-token-proxy targets) happen
sequentially to eliminate write races.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2f1790ea-c3eb-4c97-b725-252e5b7f4d02

📥 Commits

Reviewing files that changed from the base of the PR and between fd25969 and b091073.

📒 Files selected for processing (3)
  • packages/system/dashboard/Makefile
  • packages/system/dashboard/templates/console-rbac.yaml
  • packages/system/dashboard/templates/console.yaml
✅ Files skipped from review due to trivial changes (1)
  • packages/system/dashboard/templates/console-rbac.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/system/dashboard/templates/console.yaml

IvanHunters and others added 11 commits April 30, 2026 01:10
toJson returns a string that must be quoted in YAML data fields,
otherwise Kubernetes API rejects the manifest as the value is parsed
as an object instead of a string.

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
Add pre-upgrade/pre-install hook that labels and annotates the
branding ConfigMap with Helm ownership metadata, allowing Helm to
adopt resources that were created outside of Helm.

Add checksum/config annotation to console pod template so that
branding changes trigger an automatic rolling restart, matching
the behavior of the previous dashboard chart.

Signed-off-by: IvanHunters <ivan.okhotnikov@aenix.io>
…te race

When make -j is used, image-console and image-token-proxy could run
concurrently and both do in-place edits to values.yaml, causing one
update to be silently lost. Add .NOTPARALLEL to force serial execution.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
After the UI migration bookmarks and external links pointing to
/openapi-ui/... return 404. Add an nginx server-snippet to issue
a 301 redirect to / for those paths.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
Replace git clone --no-checkout with a minimal git init + remote add +
fetch --depth 1 to avoid downloading unnecessary refs. Split the
image-console monolith into clone-console, build-console,
update-values-console, and clean-console for easier failure isolation.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
GitHub does not allow fetching arbitrary commits by SHA without
uploadpack.allowReachableSHA1InWants. Replace the git init + fetch
approach with a simple shallow clone of the main branch.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
…ial registry

- Switch CONSOLE_BRANCH to feat/ui-overhaul (main has broken TS build)
- Update console image to ghcr.io/cozystack/cozystack/cozystack-ui

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
rancher/kubectl:v1.29.10 lacks /bin/sh on Talos clusters,
causing the pre-upgrade hook Job to fail. Switch to
docker.io/clastix/kubectl:v1.32 which is already used
across other dashboard hooks and has /bin/sh available.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
Prevents "already exists" errors on repeated hook runs
by deleting hook resources before creating new ones.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
Switch from non-existent latest digest to the available
feat-ui-overhaul image in the official cozystack registry.

Signed-off-by: IvanHunters <xorokhotnikov@gmail.com>
@dosubot dosubot Bot added size:L and removed size/L This PR changes 100-499 lines, ignoring generated files labels May 2, 2026
@github-actions github-actions Bot added size/XL This PR changes 500-999 lines, ignoring generated files size/L This PR changes 100-499 lines, ignoring generated files and removed size:L labels May 2, 2026
Signed-off-by: myasnikovdaniil <60174387+myasnikovdaniil@users.noreply.github.com>
@github-actions github-actions Bot removed the size/L This PR changes 100-499 lines, ignoring generated files label May 13, 2026
@myasnikovdaniil
myasnikovdaniil enabled auto-merge May 13, 2026 15:35
@myasnikovdaniil
myasnikovdaniil merged commit 680803a into main May 13, 2026
9 checks passed
@myasnikovdaniil
myasnikovdaniil deleted the feat/new-ui branch May 13, 2026 17:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/dashboard Issues or PRs related to the dashboard / UI kind/feature Categorizes issue or PR as related to a new feature size/XL This PR changes 500-999 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants