Skip to content

feat: add operating model workspace and tenant caller guards#47

Merged
chitcommit merged 1 commit intomainfrom
feat/operating-model-tenant-access
Mar 13, 2026
Merged

feat: add operating model workspace and tenant caller guards#47
chitcommit merged 1 commit intomainfrom
feat/operating-model-tenant-access

Conversation

@chitcommit
Copy link
Contributor

@chitcommit chitcommit commented Mar 13, 2026

Summary

  • add the role-aware operating model workspace, preferences hook, and scenario/agent helpers for dashboard and settings
  • harden tenant access by resolving caller context and membership in both the Hono middleware path and the shipped Express runtime
  • add focused coverage for operating-model helpers, caller middleware, tenant membership checks, and tenant route shaping

Validation

  • pnpm -s tsc --noEmit
  • pnpm -s vitest run server/tests/express-context.test.ts server/tests/middleware-caller.test.ts server/tests/middleware-tenant.test.ts server/tests/routes-tenants.test.ts client/src/tests/operating-model.test.ts
  • pnpm -s build

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced role-based operating model with configurable agents and automation scenarios
    • Redesigned dashboard with improved layout showing role-specific insights and agent status cards
    • Redesigned settings page with simplified controls for leader configuration and scenario management
    • Added preference controls for digest frequency, task automation, and approval handling
  • Bug Fixes

    • Corrected authentication context computation to eliminate duplicate processing
  • Tests

    • Expanded test coverage for operating model and user preferences
    • Added comprehensive tests for authentication and tenant access permissions

Copilot AI review requested due to automatic review settings March 13, 2026 22:51
@chitcommit chitcommit enabled auto-merge (squash) March 13, 2026 22:51
@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 13, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 76e581ed-90c6-4bf1-851a-3634bd36cf35

📥 Commits

Reviewing files that changed from the base of the PR and between 0ade4b7 and 2d1c42d.

📒 Files selected for processing (18)
  • client/src/App.tsx
  • client/src/__tests__/operating-model.test.ts
  • client/src/contexts/RoleContext.tsx
  • client/src/hooks/use-operating-preferences.ts
  • client/src/lib/operating-model.ts
  • client/src/pages/Dashboard.tsx
  • client/src/pages/Settings.tsx
  • server/__tests__/express-context.test.ts
  • server/__tests__/middleware-caller.test.ts
  • server/__tests__/middleware-tenant.test.ts
  • server/__tests__/routes-tenants.test.ts
  • server/app.ts
  • server/lib/chargeAutomation.ts
  • server/middleware/caller.ts
  • server/middleware/express-context.ts
  • server/middleware/tenant.ts
  • server/routes.ts
  • server/routes/tenants.ts

📝 Walkthrough

Walkthrough

This 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

Cohort / File(s) Summary
Operating Model Core
client/src/lib/operating-model.ts
Introduces domain model with types (UserRole, AutomationMode, DigestCadence), interfaces (RoleConfig, AccountableAgent, ScenarioDefinition, OperatingPreferences, SimpleTask, SimpleWorkflow, VerificationCheck, FocusItem, AgentCard), constants (ROLE_CONFIGS, ACCOUNTABLE_AGENTS, SCENARIOS, DEFAULT_OPERATING_PREFERENCES), and utility functions (getRoleConfig, getScenario, getEnabledAgentCards, buildFocusQueue) for managing roles, agents, scenarios, and UI card/focus-queue generation.
Client State Management
client/src/hooks/use-operating-preferences.ts, client/src/contexts/RoleContext.tsx
New useOperatingPreferences hook loads/persists preferences from localStorage with methods to update, toggle agents, and reset. RoleContext refactored to re-export types and use ROLE_CONFIGS from operating-model instead of local definitions, centralizing role data.
Client Pages
client/src/pages/Dashboard.tsx, client/src/pages/Settings.tsx
Dashboard extensively refactored to introduce role-aware header, agent cards, focus queue, scenario insights, and consolidated reporting; adds data fetching for preferences, tasks, workflows, and integrations. Settings redesigned with sectioned UI for leader model, scenario pack, accountable agents, and automation policy; added draft state with save/reset flows.
Client Configuration & Tests
client/src/App.tsx, client/src/__tests__/operating-model.test.ts
App.tsx optimized by computing authContextValue earlier with useMemo to eliminate duplication. New test file validates buildFocusQueue prioritization and getEnabledAgentCards sentinel logic.
Server Middleware
server/middleware/caller.ts, server/middleware/express-context.ts, server/middleware/tenant.ts
New caller middleware extracts and validates user identity from headers/query. New express-context module provides caller and tenant context factories with storage-backed user/tenant validation. Tenant middleware extended with optional membership gate for multi-tenant access control.
Server Routes & Core
server/routes/tenants.ts, server/routes.ts, server/app.ts
Tenant routes refactored to fetch user memberships and augment tenant responses with member roles. app.ts recomposed middleware stack to include callerContext in auth+context group. routes.ts updated to use new middleware constructors for caller context and tenant access resolution.
Server Tests
server/__tests__/middleware-caller.test.ts, server/__tests__/middleware-tenant.test.ts, server/__tests__/express-context.test.ts, server/__tests__/routes-tenants.test.ts
Comprehensive unit tests added for caller middleware (user extraction, fallback resolution, error handling), express context factories (caller/tenant resolution, membership validation, HTTP error responses), and tenant routes (membership listing, access control).
Server Utilities
server/lib/chargeAutomation.ts
ChargeDetails interface extended with optional subscriptionId field for recurring charge tracking.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 New models bloom in structured rows,
Roles, agents, preferences—the system grows,
Middleware guards each tenant gate,
While dashboards dance with focus state,
From localStorage to cards so bright,
Automation orchestrates the light! 🌿

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/operating-model-tenant-access
📝 Coding Plan
  • Generate coding plan for human review comments

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.

@cloudflare-workers-and-pages
Copy link

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
chittyfinance 2d1c42d Mar 13 2026, 10:52 PM

@chitcommit chitcommit merged commit 71f9dd7 into main Mar 13, 2026
8 of 10 checks passed
@chitcommit chitcommit deleted the feat/operating-model-tenant-access branch March 13, 2026 22:53
@claude
Copy link

claude bot commented Mar 13, 2026

PR Review: feat: add operating model workspace and tenant caller guards

Overall 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] userId leaks via query parameter in logs

server/middleware/caller.ts:8 and server/middleware/express-context.ts:17:

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 userId query param fallback and documenting header-only auth.

[Medium] Tenant access bypass when userId is not set

server/middleware/express-context.ts:60-68:

if (contextReq.userId && storage.getUserTenants) {
  // membership check
}
contextReq.tenantId = tenantId; // always executed

If createCallerContext is misconfigured, not applied, or fails silently before this middleware, userId will be undefined and this guard is skipped entirely — any caller can access any tenant. Consider returning a 401 instead of proceeding when userId is absent:

if (!contextReq.userId) {
  return res.status(401).json({ error: 'unauthenticated' });
}

[Low] Wrong HTTP status for missing authentication

server/middleware/caller.ts:11: returning 400 for a missing user ID header. HTTP 401 Unauthorized is more semantically correct when the caller hasn't identified themselves. The Express version returns the same 400 for the session-fallback failure path.


Bugs

[Medium] Transaction query key loses tenant scoping

client/src/pages/Dashboard.tsx:

// 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 tenantId to the key, or conditionally enable the query on !!tenantId.

[Low] Hardcoded leader name in default preferences

client/src/lib/operating-model.ts:230:

export const DEFAULT_OPERATING_PREFERENCES: OperatingPreferences = {
  leaderName: 'NB',  // ← hardcoded

This should be '' or derived from the authenticated user's name at initialization time.

[Low] AgentGrid ignores preferences.automationMode

client/src/pages/Dashboard.tsx:

<span className="text-[10px] ... font-mono">human-led</span>

The label is hardcoded to "human-led" regardless of preferences.automationMode ('balanced' | 'delegated'). Should read preferences.automationMode here.


Performance

[Minor] Double DB queries in tenant detail route

server/routes/tenants.tsGET /api/tenants/:id calls getUserTenants and then getTenant separately. If membership.tenant already contains a full representation, the second query is redundant. If it's a stub, that's fine but worth a comment explaining why both are needed.

[Minor] No per-request caching for getUserTenants

tenantMiddleware calls getUserTenants on every request and GET /api/tenants/:id also calls it. In a single request that hits both middlewares, this could be two separate DB round-trips for the same data. Consider storing the result in the Hono context during callerContext or adding a lightweight request-scoped memoization.


Code Quality

[Minor] Stale agent IDs accumulate in localStorage

client/src/hooks/use-operating-preferences.ts:18-22:

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 getEnabledAgentCards will silently filter them out. Consider intersecting with ACCOUNTABLE_AGENTS.map(a => a.id) on load to prune orphaned entries.

[Minor] Workflows query and focus queue are decoupled

client/src/pages/Dashboard.tsx:

const { data: workflows = [] } = useQuery<SimpleWorkflow[]>({
  queryKey: ['/api/workflows'],
  enabled: !!tenantId,  // ← only fetches in system mode
});

buildFocusQueue always uses workflows, but in standalone mode this is always []. The approvals lane and delegation-check logic will never trigger, silently degrading the queue. Either document this as expected standalone behavior, or add a workflows source for standalone mode.

[Minor] buildFocusQueue ordering bias is implicit

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

  • The App.tsx fix moving useMemo before the early return is a correct Rules of Hooks fix.
  • callerContext Hono middleware is clean and well-tested.
  • The createCallerContext / createTenantAccessResolver factory pattern for Express is a good abstraction that makes the legacy path testable.
  • Test coverage across both the Hono and Express paths (in-memory + real-network) is solid.
  • Separating /api/tenants from protectedRoute (which includes tenantMiddleware) is architecturally correct — tenant listing shouldn't require a tenant to already be selected.
  • The operating-model module is nicely self-contained and the tests cover the key scenarios well.

Bottom line: The tenant guard hardening is the right call and the implementation is mostly solid. Address the tenant access bypass in express-context.ts and the transaction query key regression before merging. The rest are improvements but not blockers.

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 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 /tenants responses 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.

Comment on lines +17 to +22
if (!storage || !userId || typeof storage.getUserTenants !== 'function') {
c.set('tenantId', tenantId);
await next();
return;
}

Comment on lines +67 to +78
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);
Comment on lines 8 to +10
const storage = c.get('storage');
const userId = c.get('userId');
const memberships = await storage.getUserTenants(userId);
Comment on lines +341 to +344
queryKey: ['/api/transactions?limit=6'],
});
const { data: tasks = [] } = useQuery<SimpleTask[]>({
queryKey: ['/api/tasks'],
Comment on lines +131 to +138
<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>
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