Skip to content

Conversation

@nfebe
Copy link
Contributor

@nfebe nfebe commented Jan 26, 2026

Add frontend support for multi-user authentication with RBAC:

  • UsersView: User management with deployment assignment panel
  • APIKeysView: API key creation, listing, and revocation
  • LoginView: Toggle between username/password and API key login
  • DashboardLayout: User info display, role-based nav items

Updated stores and services:

  • auth store: currentUser, permissions, hasPermission()
  • users store: User and API key state management
  • api service: usersApi, apiKeysApi, deploymentUsersApi

Types added for User, APIKey, UserDeploymentAccess, Permission.

Add frontend support for multi-user authentication with RBAC:

- UsersView: User management with deployment assignment panel
- APIKeysView: API key creation, listing, and revocation
- LoginView: Toggle between username/password and API key login
- DashboardLayout: User info display, role-based nav items

Updated stores and services:
- auth store: currentUser, permissions, hasPermission()
- users store: User and API key state management
- api service: usersApi, apiKeysApi, deploymentUsersApi

Types added for User, APIKey, UserDeploymentAccess, Permission.

Signed-off-by: nfebe <fenn25.fn@gmail.com>
@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Jan 26, 2026

Deploying flatrun-ui with  Cloudflare Pages  Cloudflare Pages

Latest commit: 0bca360
Status: ✅  Deploy successful!
Preview URL: https://ede40ecf.flatrun-ui.pages.dev
Branch Preview URL: https://feat-api-key-rbac.flatrun-ui.pages.dev

View logs

@openhands-ai
Copy link

openhands-ai bot commented Jan 26, 2026

Looks like there are a few issues preventing this PR from being merged!

  • GitHub Actions are failing:
    • CI

If you'd like me to help, just leave a comment, like

@OpenHands please fix the failing actions on PR #41 at branch `feat/api-key-rbac`

Feel free to include any additional details that might help me get this PR into a better state.

You can manage your notification settings

@sourceant
Copy link

sourceant bot commented Jan 26, 2026

Code Review Summary

This pull request introduces a comprehensive role-based access control (RBAC) system, enhancing the application's security and user management capabilities. Key changes include a new useAuthStore for centralized authentication and authorization logic, explicit permission definitions for routes and UI elements, and dedicated views for managing users and API keys. The new PermissionPicker component facilitates granular permission configuration. A minor bug in the useStatsStore related to data fetching was also corrected. The implementation is robust and follows best practices for a secure and maintainable application.

🚀 Key Improvements

  • Centralized Authentication & Authorization: The useAuthStore now provides a single source of truth for user authentication state, roles, and permissions, including deployment-specific access.
  • Granular UI Access Control: v-if directives with authStore.hasPermission are extensively used to show/hide UI elements (navigation items, action buttons) based on user roles and permissions.
  • Route-Level Security: New meta.permission fields in src/router/index.ts ensure that unauthorized users cannot access protected routes.
  • User and API Key Management: New views in src/views/UsersView.vue and src/views/APIKeysView.vue provide full CRUD operations for managing users and API keys, supporting custom permissions and roles.
  • Reusable Permission Picker: The src/components/PermissionPicker.vue component allows for easy and consistent permission selection and display across the application.

💡 Minor Suggestions

  • Consider moving the permissionGroups array in src/components/PermissionPicker.vue to a shared utility or global store if it needs to be dynamic or reused across more components, though current implementation is acceptable.
  • While authStore.currentUser effectively guards the user info block in src/layouts/DashboardLayout.vue, explicitly using v-if="authStore.isAuthenticated" could offer clearer intent if there were scenarios where currentUser might be null while isAuthenticated is true, though this is a minor stylistic point.
  • Add input validation to the newDeployment.name field in src/views/UsersView.vue to ensure that only valid deployment names can be added to user access controls. This would enhance robustness and user experience.

Copy link

@sourceant sourceant bot left a comment

Choose a reason for hiding this comment

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

Review complete. See the overview comment for a summary.

Add resource-specific permission gates to router, sidebar, and
all view components for containers, images, volumes, databases,
infrastructure, scheduler, system, dns, registries, templates,
and traffic.

Add PermissionPicker component for editing user and API key
permissions. Rework UsersView with tabbed dialog (Profile,
Permissions, Deployments) and table columns showing permission
and deployment status.

Read deployment stats from authenticated /stats endpoint instead
of public /health to reflect per-user filtered counts.

Add PermissionPicker component tests and permission denial tests
for DeploymentsView, DeploymentDetailView, CronJobsView, and
SettingsView to verify write/delete buttons are hidden when the
user lacks the required permissions.

Signed-off-by: nfebe <fenn25.fn@gmail.com>
@sourceant
Copy link

sourceant bot commented Jan 28, 2026

🔍 Code Review

💡 1. **src/stores/auth.ts** (Lines 53-65) - BUG

The original implementation of fetchAll in useStatsStore incorrectly tried to access healthRes.data.stats (which didn't exist) instead of calling healthApi.stats() separately to get detailed statistics. This led to deployments.total, containers.total, etc. potentially being zero or undefined. The fix correctly separates these API calls.

Suggested Code:

      const statsRes = await healthApi.stats();
      if (statsRes.data) {
        const data = statsRes.data;
        if (data.deployments) {
          deployments.total = data.deployments.total_deployments || 0;
          deployments.running = data.deployments.running || 0;
          deployments.stopped = data.deployments.stopped || 0;
          deployments.error = data.deployments.error || 0;
        }
        containers.total = data.containers?.total || 0;
        containers.running = data.containers?.running || 0;
        containers.stopped = data.containers?.stopped || 0;
        docker.images = data.images?.total || 0;
        docker.volumes = data.volumes?.total || 0;
        docker.networks = data.networks?.total || 0;
        docker.ports = data.ports?.total || 0;

Current Code:

      if (healthRes.data.stats) {
        deployments.total = healthRes.data.stats.total_deployments || 0;
        deployments.running = healthRes.data.stats.running || 0;
        deployments.stopped = healthRes.data.stats.stopped || 0;
        deployments.error = healthRes.data.stats.error || 0;
      }

      const statsRes = await healthApi.stats();
      if (statsRes.data) {
        containers.total = statsRes.data.containers?.total || 0;
        containers.running = statsRes.data.containers?.running || 0;
        containers.stopped = statsRes.data.containers?.stopped || 0;
        docker.images = statsRes.data.images?.total || 0;
        docker.volumes = statsRes.data.volumes?.total || 0;
        docker.networks = statsRes.data.networks?.total || 0;
        docker.ports = statsRes.data.ports?.total || 0;

Verdict: APPROVE

Posted as a comment because posting a review failed.

@nfebe nfebe merged commit d7b13cb into main Jan 28, 2026
5 checks passed
@nfebe nfebe deleted the feat/api-key-rbac branch January 28, 2026 21:43
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.

2 participants