Project 36: Enterprise Config - Team-Wide Standards
Project 36: Enterprise Config - Team-Wide Standards
Comprehensive Learning Guide Build policy-based configuration systems that enforce coding standards, security policies, and compliance requirements across Claude Code installations
Table of Contents
- Learning Objectives
- Deep Theoretical Foundation
- Complete Project Specification
- Real World Outcome
- Solution Architecture
- Phased Implementation Guide
- Testing Strategy
- Common Pitfalls & Debugging
- Extensions & Challenges
- Resources
- Self-Assessment Checklist
Learning Objectives
By completing this project, you will master:
-
Enterprise Configuration Architecture: Understand how to layer policies over user configurations while maintaining usability and allowing appropriate exceptions.
-
Policy-as-Code Patterns: Learn to express organizational policies as machine-readable, versionable, and testable code using patterns from Open Policy Agent (OPA).
-
Configuration Distribution: Implement mechanisms to distribute policies to developer machines via MDM, git, APIs, or custom sync services.
-
Audit Logging: Build comprehensive audit trails that capture Claude Code actions for compliance reporting (SOC 2, HIPAA, etc.).
-
Exception Management: Design systems that allow controlled policy bypasses for legitimate use cases while maintaining security.
-
Developer Experience: Balance security requirements with developer productivity to avoid frustrating users while maintaining guardrails.
Deep Theoretical Foundation
Enterprise Configuration Hierarchy
Enterprise configuration adds a governance layer on top of Claude Code’s existing configuration system:
Enterprise Configuration Precedence:
====================================
ENTERPRISE POLICY (Highest - Cannot Override)
|
v
+-----------------------------------------------+
| Organization-Wide Rules |
| - Approved MCP servers only |
| - No external API access |
| - Mandatory audit logging |
| - Required skills (code-review) |
+-----------------------------------------------+
|
v
PROJECT CONFIG (Team/Repository Level)
|
v
+-----------------------------------------------+
| Project-Specific Settings |
| - CLAUDE.md instructions |
| - Project hooks and skills |
| - (Constrained by enterprise policy) |
+-----------------------------------------------+
|
v
USER CONFIG (Individual Developer)
|
v
+-----------------------------------------------+
| Personal Preferences |
| - Output style preferences |
| - Personal hooks |
| - (Constrained by enterprise + project) |
+-----------------------------------------------+
|
v
DEFAULTS (Built-in Fallbacks)
Configuration Merge Strategy:
============================
For each setting:
1. Check if enterprise policy LOCKS the value -> Use policy value
2. Check if enterprise policy RESTRICTS options -> Validate against policy
3. Check if project config sets value -> Use project value
4. Check if user config sets value -> Use user value
5. Use default value
Example:
--------
Enterprise Policy: mcpServers RESTRICTED to ["github", "jira", "internal-docs"]
Project Config: mcpServers = ["github", "internal-docs"]
User Config: mcpServers = ["github", "slack"] // slack not approved!
Result: mcpServers = ["github", "internal-docs"]
(User's "slack" rejected - not in enterprise allowlist)
(User notified of policy violation)
Reference: “Enterprise Integration Patterns” by Hohpe & Woolf, Chapter 7 discusses configuration distribution patterns.
Policy-as-Code Concepts
Expressing policies as code enables version control, testing, and automated enforcement:
Policy Components:
=================
1. POLICY DEFINITION
- What is being controlled?
- What are the allowed values/actions?
- What happens on violation?
2. POLICY EVALUATION
- When is the policy checked?
- What context is available?
- How is the decision made?
3. POLICY ENFORCEMENT
- Block action? Allow with warning?
- Audit log only?
- Require approval?
Policy Types:
=============
ALLOWLIST (Whitelist)
---------------------
Only explicitly permitted items are allowed.
policy:
name: approved-mcp-servers
type: allowlist
target: mcpServers
values: [github, jira, internal-docs]
Evaluation: mcpServer IN allowlist? -> ALLOW : DENY
DENYLIST (Blacklist)
--------------------
Everything allowed except explicitly denied items.
policy:
name: blocked-tools
type: denylist
target: tools
values: [Bash, Write] # Block dangerous tools
Evaluation: tool IN denylist? -> DENY : ALLOW
PATTERN MATCH
-------------
Content matching regular expressions.
policy:
name: no-secrets-in-config
type: pattern-deny
target: claudeMd
pattern: "(sk-|api[-_]?key|password|secret)"
Evaluation: content MATCHES pattern? -> DENY : ALLOW
REQUIRE
-------
Certain items must be present.
policy:
name: require-code-review
type: require
target: skills
values: [code-review]
Evaluation: required SUBSET OF current? -> ALLOW : WARN
LIMIT
-----
Numeric constraints.
policy:
name: max-tokens-per-session
type: limit
target: sessionTokens
max: 100000
Evaluation: value <= max? -> ALLOW : DENY
Reference: Open Policy Agent (OPA) documentation at openpolicyagent.org
Audit Logging for Compliance
Enterprise environments require detailed audit trails for compliance frameworks:
Audit Log Architecture:
======================
+-------------------+ +-------------------+ +-------------------+
| Claude Code | | Local Log | | Central Audit |
| Instance | | Buffer | | Service |
|-------------------| |-------------------| |-------------------|
| Events: |---->| Batch collection |---->| Storage: |
| - Tool executions | | Encryption | | - S3/GCS |
| - File changes | | Retry queue | | - SIEM |
| - MCP calls | | | | - Splunk |
+-------------------+ +-------------------+ +-------------------+
Audit Event Schema:
==================
{
"version": "1.0",
"timestamp": "2024-12-22T14:30:00.000Z",
"eventId": "evt_a1b2c3d4e5f6",
// Identity
"user": {
"id": "user_123",
"email": "developer@company.com",
"department": "engineering"
},
// Machine
"machine": {
"id": "machine_abc123",
"hostname": "developer-laptop",
"os": "macOS 14.0"
},
// Session
"session": {
"id": "sess_xyz789",
"startTime": "2024-12-22T14:00:00.000Z",
"projectPath": "/Users/dev/project"
},
// Action
"action": {
"type": "tool_execution",
"tool": "Write",
"params": {
"path": "/src/config.py",
"contentHash": "sha256:abc123..." // Don't log actual content
},
"result": "success",
"duration": 234
},
// Policy
"policyCheck": {
"policies": ["file-access", "approved-paths"],
"result": "passed",
"violations": []
},
// Context
"context": {
"prompt": "[REDACTED]", // May contain sensitive info
"tokenCount": 1500
}
}
Compliance Mappings:
===================
SOC 2 Requirements:
-------------------
- CC6.1: Logical access controls -> Policy enforcement logs
- CC7.2: System change monitoring -> Tool execution logs
- CC8.1: Change management -> File modification tracking
HIPAA Requirements:
-------------------
- Access controls -> User identity in all logs
- Audit controls -> Comprehensive action logging
- Integrity controls -> Hash verification
GDPR Considerations:
-------------------
- Minimize PII in logs
- Support data subject requests
- Define retention periods
Reference: “Security Engineering” by Ross Anderson, Chapter 6 covers audit and monitoring systems.
Exception Management
Not all policy violations should be blocked. A good system allows controlled exceptions:
Exception Hierarchy:
===================
PERMANENT EXCEPTIONS
--------------------
Granted to specific teams/users indefinitely.
exceptions:
- team: security-team
exempt_from: [approved-mcp-servers]
reason: Security testing requires arbitrary access
approved_by: CISO
expires: null # Permanent
TEMPORARY EXCEPTIONS
--------------------
Time-limited bypasses for specific needs.
exceptions:
- user: alice@company.com
exempt_from: [file-access-restrictions]
reason: Emergency production fix
approved_by: manager@company.com
expires: 2024-12-23T00:00:00Z # 24-hour window
PROJECT EXCEPTIONS
------------------
Exceptions scoped to specific repositories.
exceptions:
- project: legacy-system
exempt_from: [typescript-required]
reason: Legacy JavaScript codebase
approved_by: tech-lead@company.com
Exception Workflow:
==================
Developer Admin Portal Policy System
--------- ----------- -------------
Encounters
violation
|
v
Request ------> Review request
exception |
v
Approve/Deny
|
<------ If approved:
Notified Update policy
with exception
|
v
Retry action ------> Re-evaluate
(exception applies)
|
<------ v
Action Action allowed
succeeds + audit logged
Complete Project Specification
Functional Requirements
Core Features (Must Have):
| Feature | Description | Priority |
|---|---|---|
| Policy definition | YAML/JSON policy format | P0 |
| Policy enforcement | Block/allow based on policies | P0 |
| Configuration distribution | Deliver policies to machines | P0 |
| Audit logging | Log all actions with policy results | P0 |
| Exception management | Allow controlled policy bypasses | P0 |
| Policy testing | Test policies before deployment | P1 |
| Admin dashboard | View violations and manage exceptions | P1 |
| Compliance reports | Generate SOC 2/HIPAA reports | P2 |
| Policy versioning | Track and rollback policy changes | P2 |
Policy Definition Format:
# enterprise-policy.yaml
version: "1.0"
organization: "Acme Corporation"
effective_date: "2024-12-01"
last_updated: "2024-12-20"
# Policy definitions
policies:
# Restrict MCP servers to approved list
- name: approved-mcp-servers
description: Only allow approved MCP servers
type: allowlist
target: mcpServers
values:
- github-mcp
- jira-mcp
- internal-docs-mcp
severity: error
message: "MCP server '{{value}}' is not on the approved list"
# Prevent secrets in CLAUDE.md
- name: no-secrets-in-claude-md
description: Prevent API keys and secrets in configuration
type: pattern-deny
target: claudeMd
pattern: "(sk-[a-zA-Z0-9]{32,}|api[-_]?key\\s*[=:]|password\\s*[=:])"
severity: error
message: "Potential secret detected in CLAUDE.md"
# Require code review skill
- name: require-code-review
description: All projects must have code review capability
type: require
target: skills
values:
- code-review
severity: warning
message: "Consider adding the code-review skill"
# Limit token usage
- name: max-session-tokens
description: Limit tokens per session for cost control
type: limit
target: sessionTokens
max: 100000
severity: warning
message: "Approaching token limit ({{current}}/{{max}})"
# Audit configuration
audit:
enabled: true
destination: https://audit.acme.com/claude-logs
batch_size: 100
flush_interval: 60 # seconds
include_events:
- tool_execution
- file_modification
- mcp_call
- policy_violation
- session_start
- session_end
exclude_patterns:
- path: "*.log"
- path: "node_modules/*"
# Exception definitions
exceptions:
- team: security-team
exempt_from:
- approved-mcp-servers
reason: Security testing requires arbitrary MCP access
approved_by: ciso@acme.com
- user: alice@acme.com
exempt_from:
- max-session-tokens
reason: Large codebase migration project
expires: "2024-12-31"
approved_by: manager@acme.com
Real World Outcome
You’ll have an enterprise policy system:
Policy Enforcement in Action:
$ claude
Enterprise Policy Active: Acme Corporation
Policies: 4 active, 1 exception applied (security-team)
You: Can you install this MCP server from npm: random-utils-mcp?
Claude: I'd like to help, but I can't install that MCP server.
+----------------------------------------------------------------+
| POLICY VIOLATION |
+----------------------------------------------------------------+
| Policy: approved-mcp-servers |
| Severity: ERROR |
| |
| The MCP server "random-utils-mcp" is not on the approved list. |
| |
| Approved servers: |
| - github-mcp |
| - jira-mcp |
| - internal-docs-mcp |
| |
| To request an exception: |
| 1. Visit https://admin.acme.com/claude/exceptions |
| 2. Submit request with business justification |
| 3. Wait for security team approval |
+----------------------------------------------------------------+
You: Can you write to /etc/hosts?
Claude: I cannot write to that location.
+----------------------------------------------------------------+
| POLICY VIOLATION |
+----------------------------------------------------------------+
| Policy: approved-paths |
| Severity: ERROR |
| |
| Writing to system paths is not permitted. |
| Allowed paths: ~/*, /tmp/claude-* |
+----------------------------------------------------------------+
You: Let's review the authentication code instead.
Claude: I'll review the authentication code for you.
[Reviews code normally]
+----------------------------------------------------------------+
| ACTION LOGGED |
+----------------------------------------------------------------+
| Event: tool_execution (Read) |
| Target: src/auth/login.ts |
| Policy check: PASSED |
| Audit ID: evt_abc123 |
+----------------------------------------------------------------+
Admin Dashboard View:
+------------------------------------------------------------------+
| CLAUDE CODE ENTERPRISE DASHBOARD |
+------------------------------------------------------------------+
| |
| OVERVIEW (Last 24 Hours) |
| ========================= |
| Active Users: 127 |
| Total Sessions: 342 |
| Policy Violations: 23 |
| Exceptions Used: 8 |
| |
| VIOLATION BREAKDOWN |
| ==================== |
| approved-mcp-servers |######## | 12 (52%) |
| no-secrets-in-config |##### | 6 (26%) |
| max-session-tokens |### | 4 (17%) |
| require-code-review |# | 1 (4%) |
| |
| RECENT VIOLATIONS |
| ================= |
| 14:32 | bob@acme.com | approved-mcp-servers | random-mcp |
| 14:28 | alice@acme.com | no-secrets-in-config | API key found |
| 14:15 | carol@acme.com | approved-mcp-servers | custom-mcp |
| |
| PENDING EXCEPTION REQUESTS (3) |
| ============================== |
| [View] | bob@acme.com | random-mcp | Business justification... |
| [View] | dev-team | new-tool | Required for project X... |
| |
+------------------------------------------------------------------+
Solution Architecture
System Architecture Diagram
+------------------------------------------------------------------+
| ENTERPRISE CONFIG SYSTEM |
+------------------------------------------------------------------+
| |
| +--------------------+ |
| | POLICY SERVER | |
| |--------------------| |
| | - Policy storage | |
| | - Version control | |
| | - Distribution API | |
| +--------+-----------+ |
| | |
| | Policy sync |
| v |
| +--------------------+ +-------------------+ |
| | LOCAL AGENT | | CLAUDE CODE | |
| |--------------------| |-------------------| |
| | - Policy cache |<--->| - Hook system | |
| | - Offline support | | - Event emitter | |
| | - Update checker | | - Action executor | |
| +--------+-----------+ +--------+----------+ |
| | | |
| v v |
| +--------------------+ +-------------------+ |
| | POLICY ENGINE | | AUDIT COLLECTOR | |
| |--------------------| |-------------------| |
| | - Evaluation logic | | - Event buffering | |
| | - Exception check | | - Encryption | |
| | - Decision cache | | - Batch upload | |
| +--------+-----------+ +--------+----------+ |
| | | |
| v v |
| +--------------------+ +-------------------+ |
| | ENFORCEMENT HOOKS | | AUDIT SERVICE | |
| |--------------------| |-------------------| |
| | - PreToolUse | | - Log storage | |
| | - PostToolUse | | - Query API | |
| | - Config validate | | - Reports | |
| +--------------------+ +-------------------+ |
| |
+------------------------------------------------------------------+
Policy Enforcement Flow
Action Request Flow:
===================
User Request Policy Check Execution
============ ============ =========
"Write to file"
|
v
+-------------+
| PreToolUse |
| Hook |
+------+------+
|
v
+-------------+ +-------------+
| Load Active |---->| Policy |
| Policies | | Definitions |
+------+------+ +-------------+
|
v
+-------------+ +-------------+
| Check |---->| Exception |
| Exceptions | | Database |
+------+------+ +-------------+
|
v
+-------------+
| Evaluate |
| Policies |
+------+------+
|
+------------+-----------+
| | |
v v v
ALLOWED WARNING BLOCKED
| | |
v v v
Execute Execute Return
action + warn error
| | |
+------------+-----------+
|
v
+-------------+
| Audit Log |
| Event |
+-------------+
|
v
+-------------+
| Upload to |
| Central |
+-------------+
Module Breakdown
src/
+-- index.ts # Main entry point
|
+-- policy/
| +-- loader.ts # Load policies from sources
| +-- parser.ts # Parse YAML/JSON policies
| +-- validator.ts # Validate policy syntax
| +-- types.ts # Policy type definitions
|
+-- engine/
| +-- evaluator.ts # Policy evaluation logic
| +-- matcher.ts # Pattern matching
| +-- decision.ts # Decision making
| +-- cache.ts # Decision caching
|
+-- exceptions/
| +-- manager.ts # Exception CRUD
| +-- checker.ts # Check if exception applies
| +-- types.ts # Exception types
|
+-- enforcement/
| +-- hooks/
| | +-- pre-tool.ts # PreToolUse policy hook
| | +-- post-tool.ts # PostToolUse audit hook
| | +-- config-validate.ts # Config validation hook
| +-- blocker.ts # Action blocking logic
| +-- warner.ts # Warning generation
|
+-- audit/
| +-- collector.ts # Event collection
| +-- buffer.ts # Batch buffering
| +-- uploader.ts # Send to audit service
| +-- schema.ts # Event schema
|
+-- sync/
| +-- client.ts # Policy server client
| +-- cache.ts # Local policy cache
| +-- updater.ts # Check for updates
|
+-- admin/
| +-- server.ts # Admin API server
| +-- dashboard.ts # Dashboard routes
| +-- reports.ts # Report generation
|
+-- types/
+-- policy.ts # Policy types
+-- event.ts # Audit event types
+-- config.ts # Configuration types
Phased Implementation Guide
Phase 1: Policy Engine Core (Day 1-3)
Goal: Build policy parser and evaluator.
Milestone: Policies load from YAML and evaluate against test inputs.
Tasks:
- Project Setup
mkdir enterprise-config && cd enterprise-config npm init -y npm install yaml commander chalk winston npm install -D typescript @types/node vitest npx tsc --init - Define Policy Types (
src/types/policy.ts)export type PolicyType = | 'allowlist' | 'denylist' | 'pattern-deny' | 'require' | 'limit'; export type PolicySeverity = 'error' | 'warning' | 'info'; export interface Policy { name: string; description: string; type: PolicyType; target: string; values?: string[]; pattern?: string; max?: number; severity: PolicySeverity; message: string; } export interface PolicyResult { policy: string; passed: boolean; severity: PolicySeverity; message?: string; value?: unknown; } - Create Policy Parser (
src/policy/parser.ts)import { parse } from 'yaml'; import { readFileSync } from 'fs'; import { Policy } from '../types/policy'; export interface EnterprisePolicy { version: string; organization: string; policies: Policy[]; audit: AuditConfig; exceptions: Exception[]; } export function parsePolicy(path: string): EnterprisePolicy { const content = readFileSync(path, 'utf-8'); const parsed = parse(content); validatePolicy(parsed); return parsed as EnterprisePolicy; } function validatePolicy(policy: unknown): void { // Validate required fields // Validate policy types // Validate patterns compile } - Create Policy Evaluator (
src/engine/evaluator.ts)import { Policy, PolicyResult } from '../types/policy'; export function evaluatePolicy( policy: Policy, context: EvaluationContext ): PolicyResult { switch (policy.type) { case 'allowlist': return evaluateAllowlist(policy, context); case 'denylist': return evaluateDenylist(policy, context); case 'pattern-deny': return evaluatePatternDeny(policy, context); case 'require': return evaluateRequire(policy, context); case 'limit': return evaluateLimit(policy, context); default: throw new Error(`Unknown policy type: ${policy.type}`); } } function evaluateAllowlist(policy: Policy, context: EvaluationContext): PolicyResult { const value = context.getValue(policy.target); const allowed = policy.values || []; if (Array.isArray(value)) { const violations = value.filter(v => !allowed.includes(v)); return { policy: policy.name, passed: violations.length === 0, severity: policy.severity, message: violations.length > 0 ? policy.message.replace('{{value}}', violations.join(', ')) : undefined, value: violations }; } const passed = allowed.includes(value as string); return { policy: policy.name, passed, severity: policy.severity, message: passed ? undefined : policy.message.replace('{{value}}', String(value)), value }; } - Test Evaluator
npx tsx src/test-evaluator.ts
Success Criteria: Policies correctly evaluate against test inputs.
Phase 2: Enforcement Hooks (Day 4-5)
Goal: Integrate policy engine with Claude Code hooks.
Milestone: PreToolUse hook blocks policy violations.
Tasks:
-
Create Enforcement Hook (
src/enforcement/hooks/pre-tool.ts) ```typescript import { evaluatePolicy } from ‘../../engine/evaluator’; import { loadPolicies } from ‘../../policy/loader’; import { checkExceptions } from ‘../../exceptions/checker’;export interface HookEvent { type: ‘PreToolUse’; tool: string; params: Record<string, unknown>; session: SessionContext; }
export interface HookResult { decision: ‘continue’ | ‘block’; reason?: string; }
export async function preToolUseHook(event: HookEvent): Promise
{ const policies = await loadPolicies(); const context = buildContext(event); for (const policy of policies) { // Check if user has exception if (await checkExceptions(event.session.user, policy.name)) { continue; }
const result = evaluatePolicy(policy, context); if (!result.passed && result.severity === 'error') { return { decision: 'block', reason: formatViolation(result) }; } }return { decision: ‘continue’ }; }
function formatViolation(result: PolicyResult): string { return ` Policy Violation: ${result.policy} Severity: ${result.severity.toUpperCase()}
${result.message}
To request an exception, visit: https://admin.company.com/exceptions `.trim(); }
2. **Create Exception Checker** (`src/exceptions/checker.ts`)
```typescript
export interface Exception {
user?: string;
team?: string;
project?: string;
exempt_from: string[];
reason: string;
expires?: string;
approved_by: string;
}
export async function checkExceptions(
user: UserContext,
policyName: string
): Promise<boolean> {
const exceptions = await loadExceptions();
for (const exception of exceptions) {
// Check if exception applies to this user
if (exception.user && exception.user !== user.email) continue;
if (exception.team && !user.teams.includes(exception.team)) continue;
// Check if exception covers this policy
if (!exception.exempt_from.includes(policyName)) continue;
// Check if exception is expired
if (exception.expires && new Date(exception.expires) < new Date()) continue;
return true;
}
return false;
}
- Register Hook with Claude Code
// package.json { "claude": { "hooks": ["./dist/enforcement/hooks/pre-tool.js"] } } - Test Hook Integration
- Create test policy blocking specific tool
- Verify hook blocks the action
- Verify exception bypasses block
Success Criteria: Policy violations blocked by hook.
Phase 3: Audit Logging (Day 6-7)
Goal: Capture and upload audit events.
Milestone: All actions logged with policy check results.
Tasks:
- Create Audit Collector (
src/audit/collector.ts)import { v4 as uuid } from 'uuid'; export interface AuditEvent { eventId: string; timestamp: string; user: UserInfo; machine: MachineInfo; session: SessionInfo; action: ActionInfo; policyCheck: PolicyCheckInfo; } class AuditCollector { private buffer: AuditEvent[] = []; private flushInterval: NodeJS.Timer; constructor(private config: AuditConfig) { this.flushInterval = setInterval( () => this.flush(), config.flush_interval * 1000 ); } collect(event: Partial<AuditEvent>): void { const fullEvent: AuditEvent = { eventId: uuid(), timestamp: new Date().toISOString(), ...this.getContextInfo(), ...event }; this.buffer.push(fullEvent); if (this.buffer.length >= this.config.batch_size) { this.flush(); } } private async flush(): Promise<void> { if (this.buffer.length === 0) return; const batch = [...this.buffer]; this.buffer = []; try { await this.upload(batch); } catch (error) { // Re-add to buffer for retry this.buffer.unshift(...batch); console.error('Audit upload failed:', error); } } private async upload(events: AuditEvent[]): Promise<void> { const encrypted = this.encrypt(events); await fetch(this.config.destination, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(encrypted) }); } } - Create PostToolUse Hook (
src/enforcement/hooks/post-tool.ts)import { auditCollector } from '../../audit/collector'; export async function postToolUseHook(event: HookEvent): Promise<void> { auditCollector.collect({ action: { type: 'tool_execution', tool: event.tool, params: redactSensitive(event.params), result: event.result.status, duration: event.result.duration }, policyCheck: { policies: event.policiesChecked, result: event.policyResult, violations: event.violations } }); } function redactSensitive(params: Record<string, unknown>): Record<string, unknown> { // Redact file contents, keep paths // Hash sensitive values // Remove PII } - Implement Audit Service (optional)
- Simple HTTP server to receive logs
- Store in PostgreSQL or S3
- Basic query API
Success Criteria: Actions logged and queryable.
Phase 4: Admin Dashboard (Day 8-10)
Goal: Build web interface for policy management.
Milestone: Dashboard shows violations and manages exceptions.
Tasks:
- Create Admin API (
src/admin/server.ts)import express from 'express'; const app = express(); // Get dashboard stats app.get('/api/stats', async (req, res) => { const stats = await getStats(); res.json(stats); }); // List violations app.get('/api/violations', async (req, res) => { const violations = await getViolations(req.query); res.json(violations); }); // List exception requests app.get('/api/exceptions/requests', async (req, res) => { const requests = await getExceptionRequests(); res.json(requests); }); // Approve exception app.post('/api/exceptions/:id/approve', async (req, res) => { await approveException(req.params.id, req.body.approvedBy); res.json({ success: true }); }); // Generate compliance report app.get('/api/reports/:type', async (req, res) => { const report = await generateReport(req.params.type); res.json(report); }); - Create Dashboard UI
- Use React or simple HTML/JS
- Show violation counts and trends
- List recent violations
- Manage exception requests
- Create Report Generator (
src/admin/reports.ts)export async function generateSOC2Report(startDate: Date, endDate: Date) { const events = await queryAuditLogs(startDate, endDate); return { period: { startDate, endDate }, accessControls: { totalLogins: events.filter(e => e.action.type === 'session_start').length, uniqueUsers: new Set(events.map(e => e.user.id)).size, policyViolations: events.filter(e => !e.policyCheck.result).length }, changeMonitoring: { filesModified: events.filter(e => e.action.tool === 'Write').length, toolExecutions: events.filter(e => e.action.type === 'tool_execution').length }, // ... more SOC 2 mappings }; }
Success Criteria: Dashboard shows real-time policy status.
Phase 5: Distribution and Polish (Day 11-14)
Goal: Distribute policies to machines and polish UX.
Milestone: Production-ready enterprise config system.
Tasks:
- Create Policy Sync Client (
src/sync/client.ts)export class PolicySyncClient { private cacheDir: string; constructor(private serverUrl: string) { this.cacheDir = path.join(os.homedir(), '.claude-enterprise'); } async sync(): Promise<void> { try { const policies = await this.fetchPolicies(); await this.saveToCache(policies); } catch (error) { console.warn('Policy sync failed, using cached policies'); } } async getPolicies(): Promise<EnterprisePolicy> { // Try cache first for offline support const cached = await this.loadFromCache(); // Background sync this.sync().catch(() => {}); return cached; } } - Create MDM Integration Guide
- macOS: Profile for config deployment
- Windows: Group Policy template
- Linux: systemd service
- Developer Experience Polish
- Clear violation messages
- Exception request workflow
- Documentation for common scenarios
- Testing
- Unit tests for all policies
- Integration tests for hooks
- Load testing for audit system
Success Criteria: System ready for team deployment.
Testing Strategy
Unit Tests: Policy Evaluation
// tests/engine/evaluator.test.ts
import { describe, it, expect } from 'vitest';
import { evaluatePolicy } from '../../src/engine/evaluator';
describe('policy evaluation', () => {
describe('allowlist', () => {
const policy = {
name: 'approved-mcp',
type: 'allowlist' as const,
target: 'mcpServers',
values: ['github', 'jira'],
severity: 'error' as const,
message: 'MCP {{value}} not approved'
};
it('allows approved values', () => {
const context = { getValue: () => ['github'] };
const result = evaluatePolicy(policy, context);
expect(result.passed).toBe(true);
});
it('blocks unapproved values', () => {
const context = { getValue: () => ['slack'] };
const result = evaluatePolicy(policy, context);
expect(result.passed).toBe(false);
expect(result.message).toContain('slack');
});
it('identifies multiple violations', () => {
const context = { getValue: () => ['github', 'slack', 'notion'] };
const result = evaluatePolicy(policy, context);
expect(result.passed).toBe(false);
expect(result.value).toEqual(['slack', 'notion']);
});
});
describe('pattern-deny', () => {
const policy = {
name: 'no-secrets',
type: 'pattern-deny' as const,
target: 'claudeMd',
pattern: 'sk-[a-zA-Z0-9]{20,}',
severity: 'error' as const,
message: 'Secret detected in config'
};
it('passes when no secrets', () => {
const context = { getValue: () => 'Normal configuration content' };
const result = evaluatePolicy(policy, context);
expect(result.passed).toBe(true);
});
it('blocks when secret found', () => {
const context = { getValue: () => 'API key: sk-abcdefghij1234567890' };
const result = evaluatePolicy(policy, context);
expect(result.passed).toBe(false);
});
});
});
Integration Tests: Hooks
// tests/enforcement/hooks.test.ts
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { preToolUseHook } from '../../src/enforcement/hooks/pre-tool';
describe('preToolUseHook', () => {
beforeEach(() => {
vi.resetModules();
});
it('blocks policy violation', async () => {
vi.mock('../../src/policy/loader', () => ({
loadPolicies: () => [{
name: 'block-bash',
type: 'denylist',
target: 'tool',
values: ['Bash'],
severity: 'error',
message: 'Bash tool blocked'
}]
}));
const event = {
type: 'PreToolUse',
tool: 'Bash',
params: { command: 'rm -rf /' },
session: { user: { email: 'user@company.com' } }
};
const result = await preToolUseHook(event);
expect(result.decision).toBe('block');
expect(result.reason).toContain('block-bash');
});
it('allows with valid exception', async () => {
vi.mock('../../src/exceptions/checker', () => ({
checkExceptions: () => Promise.resolve(true)
}));
const event = {
type: 'PreToolUse',
tool: 'Bash',
params: { command: 'ls' },
session: { user: { email: 'admin@company.com' } }
};
const result = await preToolUseHook(event);
expect(result.decision).toBe('continue');
});
});
Common Pitfalls & Debugging
Pitfall 1: Too Restrictive Policies
Symptom: Developers constantly hitting policy violations.
Bad:
policies:
- name: no-file-writes
type: denylist
target: tool
values: [Write]
severity: error
Good:
policies:
- name: restricted-paths
type: pattern-deny
target: writePath
pattern: "^/(etc|var|usr|bin|sbin)"
severity: error
message: "System paths are protected"
Pitfall 2: Policy Server Single Point of Failure
Symptom: Claude Code unusable when policy server is down.
Bad:
// Blocks if server unreachable
const policies = await fetchPolicies();
Good:
// Graceful fallback
async function getPolicies() {
try {
const fresh = await fetchPolicies();
await saveToCache(fresh);
return fresh;
} catch (error) {
console.warn('Using cached policies');
return loadFromCache();
}
}
Pitfall 3: Insufficient Audit Context
Symptom: Can’t investigate incidents due to missing data.
Bad:
auditLog({
action: 'file_write',
user: userId
});
Good:
auditLog({
eventId: uuid(),
timestamp: new Date().toISOString(),
user: {
id: userId,
email: userEmail,
team: userTeam
},
machine: {
id: machineId,
hostname: os.hostname()
},
session: {
id: sessionId,
project: projectPath
},
action: {
type: 'tool_execution',
tool: 'Write',
target: filePath,
contentHash: hash(content),
result: 'success'
},
policyCheck: {
policies: checkedPolicies,
result: 'passed'
}
});
Pitfall 4: No Exception Expiration
Symptom: Temporary exceptions become permanent.
Bad:
exceptions:
- user: alice@company.com
exempt_from: [all-policies]
reason: Emergency access
# No expiration!
Good:
exceptions:
- user: alice@company.com
exempt_from: [file-access-restrictions]
reason: Emergency production fix - INCIDENT-123
expires: "2024-12-23T00:00:00Z"
approved_by: manager@company.com
reviewed_at: "2024-12-22T14:30:00Z"
The Interview Questions They’ll Ask
Prepare to answer these:
- “How would you roll out a policy change to 1000 developers?”
- Staged rollout (10% -> 50% -> 100%)
- Warning-only period before enforcement
- Clear communication and documentation
- Exception request process ready
- Rollback plan if issues
- “What’s your strategy for handling emergency policy bypasses?”
- On-call admin approval workflow
- Time-limited emergency exceptions
- Automatic expiration with review
- Full audit trail
- Post-incident review process
- “How do you ensure audit logs can’t be tampered with?”
- Cryptographic signing of events
- Immutable storage (write-once)
- Separate audit infrastructure
- Independent verification
- Chain of custody
- “How do you test policies before deploying to production?”
- Policy unit tests
- Staging environment
- Dry-run mode
- Shadow evaluation (log-only)
- Canary deployment
- “What’s the performance impact of policy checking?”
- Local policy caching
- Decision caching
- Async audit logging
- Batch processing
- Lazy evaluation
Hints in Layers
Hint 1: Start with Hooks Use PreToolUse hooks to implement policy checking before actions. This is the enforcement point.
Hint 2: Policy Evaluation Build a policy engine that evaluates rules against proposed actions. Keep it fast and testable.
Hint 3: Central Distribution Host policies in a central location (git repo, S3, API) that clients fetch and cache locally.
Hint 4: Graceful Degradation If the policy server is unreachable, fail open with logging, not fail closed. But log everything.
Books That Will Help
| Topic | Book | Chapter |
|---|---|---|
| Enterprise patterns | “Enterprise Integration Patterns” by Hohpe & Woolf | Ch. 7: Messaging |
| Policy design | “Security Engineering” by Ross Anderson | Ch. 6: Access Control |
| Compliance | “The DevOps Handbook” by Kim et al. | Ch. 22-23: Security & Compliance |
| Distributed config | “Designing Data-Intensive Applications” by Kleppmann | Ch. 9: Consistency |
| Audit logging | “Logging and Log Management” by Chuvakin | Full book |
Extensions & Challenges
Extension 1: Policy as Rego (OPA)
Use Open Policy Agent’s Rego language for complex policies:
package claude.enterprise
default allow = false
allow {
input.tool == "Read"
allowed_path(input.params.path)
}
allowed_path(path) {
startswith(path, "/home/")
}
allowed_path(path) {
startswith(path, "/tmp/")
}
Extension 2: Real-Time Dashboard
Use WebSocket for live updates:
io.on('connection', (socket) => {
auditStream.on('event', (event) => {
socket.emit('audit_event', event);
});
});
Extension 3: ML-Based Anomaly Detection
Flag unusual patterns:
async function detectAnomaly(event: AuditEvent): Promise<boolean> {
const userBaseline = await getUserBaseline(event.user.id);
const score = calculateAnomalyScore(event, userBaseline);
return score > threshold;
}
Self-Assessment Checklist
Conceptual Understanding
- Can you explain enterprise configuration precedence?
- Can you describe different policy types and when to use each?
- Can you explain audit logging requirements for SOC 2?
- Can you list exception management best practices?
- Can you explain graceful degradation patterns?
Implementation Skills
- Can you parse and validate YAML policies?
- Can you implement policy evaluation for different types?
- Can you create enforcement hooks for Claude Code?
- Can you design an audit event schema?
- Can you build a policy distribution system?
Code Quality
- Is your policy engine testable?
- Are exceptions properly time-limited?
- Is audit logging reliable?
- Does the system fail gracefully?
- Can policies be updated without restarts?
The Core Question You’ve Answered
“How do you enable Claude Code across an organization while maintaining security and compliance?”
Enterprises need guardrails. This project shows how to provide them without destroying the developer experience.
By building this system, you have mastered:
- Policy-as-Code: Expressing organizational rules as testable, versionable code
- Enterprise Distribution: Delivering configuration across many machines
- Audit & Compliance: Building trails that satisfy auditors
- Exception Management: Allowing flexibility while maintaining control
You can now deploy Claude Code safely across your entire organization.
Project Guide Version 1.0 - December 2025