refactor: architecture cleanup — OIDC dedup, PKCE, K8s hardening
Some checks failed
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m6s
CI / docker (push) Successful in 59s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Failing after 2m59s

- Extract OidcProviderHelper for shared discovery + JWK source construction
- Add SystemRole.normalizeScope() to centralize role normalization
- Merge duplicate claim extraction in OidcTokenExchanger
- Add PKCE (S256) to OIDC authorization flow (frontend + backend)
- Add SecurityContext (runAsNonRoot) to all K8s deployments
- Fix postgres probe to use $POSTGRES_USER instead of hardcoded username
- Remove default credentials from Dockerfile
- Extract sanitize_branch() to shared .gitea/sanitize-branch.sh
- Fix sidebar to use /exchanges/ paths directly, remove legacy redirects
- Centralize basePath computation in router.tsx via config module

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-06 21:57:29 +02:00
parent 07ff576eb6
commit c502a42f17
19 changed files with 191 additions and 169 deletions

View File

@@ -1,9 +1,10 @@
import { createBrowserRouter, Navigate, useParams } from 'react-router';
import { createBrowserRouter, Navigate } from 'react-router';
import { ProtectedRoute } from './auth/ProtectedRoute';
import { RequireAdmin } from './auth/RequireAdmin';
import { LoginPage } from './auth/LoginPage';
import { OidcCallback } from './auth/OidcCallback';
import { LayoutShell } from './components/LayoutShell';
import { config } from './config';
import { lazy, Suspense } from 'react';
import { Spinner } from '@cameleer/design-system';
@@ -28,21 +29,7 @@ function SuspenseWrapper({ children }: { children: React.ReactNode }) {
);
}
/** Redirect legacy /apps/:appId/:routeId paths to /exchanges/:appId/:routeId */
function LegacyAppRedirect() {
const { appId, routeId } = useParams<{ appId: string; routeId?: string }>();
const path = routeId ? `/exchanges/${appId}/${routeId}` : `/exchanges/${appId}`;
return <Navigate to={path} replace />;
}
/** Redirect legacy /agents/:appId/:instanceId paths to /runtime/:appId/:instanceId */
function LegacyAgentRedirect() {
const { appId, instanceId } = useParams<{ appId: string; instanceId?: string }>();
const path = instanceId ? `/runtime/${appId}/${instanceId}` : `/runtime/${appId}`;
return <Navigate to={path} replace />;
}
const basename = document.querySelector('base')?.getAttribute('href')?.replace(/\/$/, '') || '';
const basename = config.basePath.replace(/\/$/, '') || undefined;
export const router = createBrowserRouter([
{ path: '/login', element: <LoginPage /> },
@@ -81,14 +68,6 @@ export const router = createBrowserRouter([
{ path: 'config', element: <SuspenseWrapper><AppConfigPage /></SuspenseWrapper> },
{ path: 'config/:appId', element: <SuspenseWrapper><AppConfigPage /></SuspenseWrapper> },
// Legacy redirects — Sidebar uses hardcoded /apps/... and /agents/... paths
{ path: 'apps', element: <Navigate to="/exchanges" replace /> },
{ path: 'apps/:appId', element: <LegacyAppRedirect /> },
{ path: 'apps/:appId/:routeId', element: <LegacyAppRedirect /> },
{ path: 'agents', element: <Navigate to="/runtime" replace /> },
{ path: 'agents/:appId', element: <LegacyAgentRedirect /> },
{ path: 'agents/:appId/:instanceId', element: <LegacyAgentRedirect /> },
// Admin (ADMIN role required)
{
element: <RequireAdmin />,
@@ -110,4 +89,4 @@ export const router = createBrowserRouter([
},
],
},
], { basename: basename || undefined });
], { basename });