feat: add operating model workspace and tenant caller guards#47
feat: add operating model workspace and tenant caller guards#47chitcommit merged 1 commit intomainfrom
Conversation
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (18)
📝 WalkthroughWalkthroughThis pull request introduces a comprehensive operating model and preferences system. It defines domain types for roles, agents, and scenarios in a new client library module, adds a preferences hook for state management, refactors Dashboard and Settings pages to use role-aware rendering and preferences, and implements new server middleware for caller context and tenant access validation with supporting tests. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
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 |
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ❌ Deployment failed View logs |
chittyfinance | 2d1c42d | Mar 13 2026, 10:52 PM |
PR Review: feat: add operating model workspace and tenant caller guardsOverall this is a well-structured PR with good test coverage for the new middleware. The operating model design is clean and the tenant caller guard is a meaningful security improvement. Below are findings by category. Security[Medium]
c.req.query('userId') ?? ''Query parameters appear in server access logs, CDN logs, and browser history. User/session IDs should stay in headers only. Recommend removing the [Medium] Tenant access bypass when
if (contextReq.userId && storage.getUserTenants) {
// membership check
}
contextReq.tenantId = tenantId; // always executedIf if (!contextReq.userId) {
return res.status(401).json({ error: 'unauthenticated' });
}[Low] Wrong HTTP status for missing authentication
Bugs[Medium] Transaction query key loses tenant scoping
// Before (tenant-scoped)
queryKey: ['/api/transactions', tenantId, { limit: 6 }]
// After (unscoped)
queryKey: ['/api/transactions?limit=6']React Query caches by key. Switching tenants will show stale transactions from the previously selected tenant until a refetch. Either restore [Low] Hardcoded leader name in default preferences
export const DEFAULT_OPERATING_PREFERENCES: OperatingPreferences = {
leaderName: 'NB', // ← hardcodedThis should be [Low]
<span className="text-[10px] ... font-mono">human-led</span>The label is hardcoded to Performance[Minor] Double DB queries in tenant detail route
[Minor] No per-request caching for
Code Quality[Minor] Stale agent IDs accumulate in
enabledAgentIds: parsed.enabledAgentIds?.length
? parsed.enabledAgentIds
: DEFAULT_OPERATING_PREFERENCES.enabledAgentIds,If the agent catalog changes (agent removed or renamed), old IDs persist in user preferences indefinitely and [Minor] Workflows query and focus queue are decoupled
const { data: workflows = [] } = useQuery<SimpleWorkflow[]>({
queryKey: ['/api/workflows'],
enabled: !!tenantId, // ← only fetches in system mode
});
[Minor] The queue always prioritizes checks → approvals → tasks → delegation. With 3 checks + 2 approvals + 1 delegation sentinel = 6 items, urgent tasks are always cut. A brief comment explaining the intentional priority order would help future maintainers. Positives
Bottom line: The tenant guard hardening is the right call and the implementation is mostly solid. Address the tenant access bypass in |
There was a problem hiding this comment.
Pull request overview
Adds a role-aware “operating model” workspace experience in the client (dashboard + settings) and hardens caller/tenant context resolution across both the Hono (worker) path and the Express runtime, with targeted test coverage.
Changes:
- Introduces operating-model primitives (roles, scenarios, agents, queues) plus a localStorage-backed preferences hook, and rewires Dashboard/Settings to use them.
- Adds caller context + tenant access resolution middleware for both Hono and Express, and shapes
/tenantsresponses to include membership role. - Adds focused tests for the new operating-model helpers and middleware behavior.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| server/routes/tenants.ts | Returns tenants with flattened membership role; adds membership gate on single-tenant fetch. |
| server/routes.ts | Replaces Express “shims” with real caller/tenant resolvers; shapes tenant routes with role. |
| server/middleware/tenant.ts | Adds tenant membership enforcement (via getUserTenants) to Hono tenant middleware. |
| server/middleware/express-context.ts | New Express middleware for caller resolution + tenant membership enforcement. |
| server/middleware/caller.ts | New Hono middleware to resolve caller identity from headers/query. |
| server/app.ts | Reworks protected middleware stack to include caller context; mounts /api/tenants without tenant middleware. |
| server/lib/chargeAutomation.ts | Extends ChargeDetails with optional subscriptionId. |
| server/tests/routes-tenants.test.ts | Covers tenant list/detail shaping and membership gating. |
| server/tests/middleware-tenant.test.ts | Adds tests for allow/deny behavior based on tenant membership. |
| server/tests/middleware-caller.test.ts | Covers callerContext header/query resolution and 400/404 cases. |
| server/tests/express-context.test.ts | Covers Express caller resolution + tenant membership gating behavior. |
| client/src/lib/operating-model.ts | New role/scenario/agent definitions + helper functions (queue/cards). |
| client/src/hooks/use-operating-preferences.ts | New hook for persisting operating preferences in localStorage. |
| client/src/contexts/RoleContext.tsx | Consolidates role definitions into operating-model library. |
| client/src/pages/Settings.tsx | Replaces legacy settings UI with operating-model workspace controls. |
| client/src/pages/Dashboard.tsx | Rebuilds dashboard to render role queue, agent cards, and operating context. |
| client/src/tests/operating-model.test.ts | Tests focus queue and agent-card state derivation. |
| client/src/App.tsx | Minor refactor: ensures auth context memoization is created before early returns. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (!storage || !userId || typeof storage.getUserTenants !== 'function') { | ||
| c.set('tenantId', tenantId); | ||
| await next(); | ||
| return; | ||
| } | ||
|
|
| if (contextReq.userId && storage.getUserTenants) { | ||
| const memberships = await storage.getUserTenants(String(contextReq.userId)); | ||
| const hasAccess = memberships.some((membership) => membership.tenant.id === tenantId); | ||
|
|
||
| if (!hasAccess) { | ||
| return res.status(403).json({ | ||
| error: 'forbidden', | ||
| message: 'Caller does not have access to tenant', | ||
| }); | ||
| } | ||
| } | ||
|
|
| return c.json({ error: 'user_not_found' }, 404); | ||
| } | ||
|
|
||
| c.set('userId', user.id); |
| const storage = c.get('storage'); | ||
| const userId = c.get('userId'); | ||
| const memberships = await storage.getUserTenants(userId); |
| queryKey: ['/api/transactions?limit=6'], | ||
| }); | ||
| const { data: tasks = [] } = useQuery<SimpleTask[]>({ | ||
| queryKey: ['/api/tasks'], |
| <div className="cf-card animate-slide-up" style={{ animationDelay: '140ms' }}> | ||
| <div className="flex items-center justify-between px-4 py-3 border-b border-[hsl(var(--cf-border-subtle))]"> | ||
| <div className="flex items-center gap-2"> | ||
| <Bot className="w-4 h-4 text-[hsl(var(--cf-cyan))]" /> | ||
| <span className="text-sm font-display font-semibold text-[hsl(var(--cf-text))]">Accountable Agents</span> | ||
| </div> | ||
| <span className="text-[10px] text-[hsl(var(--cf-text-muted))] font-mono">human-led</span> | ||
| </div> |
Summary
Validation
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Tests