Skip to main content

CSP Kit Architecture

This document provides a comprehensive overview of the CSP Kit ecosystem architecture, design decisions, and implementation details.

Table of Contents

System Overview

Core Concept

CSP Kit revolutionizes Content Security Policy management by introducing a service-first approach. Instead of manually crafting CSP directives, developers specify the services they use, and CSP Kit automatically generates the appropriate security policies.

Traditional Approach:
Developer → Manual CSP Rules → Security Policy

CSP Kit Approach:
Developer → Service Specifications → Auto-Generated CSP → Security Policy

High-Level Architecture

graph TB
subgraph "Developer Interface"
CLI[CLI Tools]
WEB[Web Interface]
API[Node.js API]
end

subgraph "Core Engine"
GEN[CSP Generator]
VER[Version Manager]
VAL[Validator]
end

subgraph "Data Layer"
SDB[Service Database]
MON[Monitoring Data]
CACHE[Cache Layer]
end

subgraph "Automation"
GHA[GitHub Actions]
BOT[Update Bot]
TEST[Test Suite]
end

subgraph "External Services"
NPM[NPM Registry]
GH[GitHub Repository]
WEB_HOST[Web Hosting]
end

CLI --> GEN
WEB --> GEN
API --> GEN

GEN --> VER
GEN --> VAL
GEN --> SDB

VER --> SDB
VAL --> SDB

GHA --> MON
GHA --> SDB
BOT --> SDB

GEN --> NPM
WEB --> WEB_HOST
SDB --> GH

Package Architecture

Monorepo Structure

CSP Kit follows a data-package separation architecture inspired by browserslist:

csp-kit/
├── packages/
│ ├── generator/ # Core CSP generation library
│ ├── data/ # Service definitions database
│ ├── cli/ # Command-line interface
│ ├── ui/ # Shared UI components
│ ├── eslint-config/ # Shared ESLint configuration
│ └── typescript-config/ # Shared TypeScript configuration
├── apps/
│ ├── web/ # Next.js web interface
│ └── docs/ # Documentation site
└── docs/ # Maintainer documentation

Package Dependencies

graph LR
subgraph "Packages"
CSP[generator]
DATA[data]
CLI[cli]
UI[ui]
end

subgraph "Apps"
WEB[web]
DOCS[docs]
end

CSP --> DATA
CLI --> DATA
WEB --> CSP
WEB --> UI
DOCS --> UI

CSP -.-> NPM[NPM Distribution]
DATA -.-> NPM
CLI -.-> NPM

Core Packages

1. @csp-kit/generator - Core Library

Purpose: CSP generation engine and public API

Key Components:

// Generator - Core CSP generation logic
export function generateCSP(options: CSPOptions): CSPResult;

// Utilities - Helper functions for CSP manipulation
export function generateNonce(): string;
export function mergeCSPDirectives(...directives: CSPDirectives[]): CSPDirectives;

// Re-exports from data package for convenience
export { getService, searchServices, getServiceVersions } from '@csp-kit/data';

Design Principles:

  • Minimal Dependencies: Only essential dependencies
  • Tree Shakeable: Supports tree shaking for bundle optimization
  • Framework Agnostic: Works with any Node.js or browser environment
  • TypeScript First: Full TypeScript support with comprehensive types

2. @csp-kit/data - Service Database

Purpose: Centralized database of service CSP requirements

Key Components:

// Service Definitions
export const services: Record<string, ServiceDefinition>;

// Service Discovery
export function getService(id: string): ServiceDefinition | undefined;
export function searchServices(query: string): ServiceDefinition[];

// Version Management
export function getServiceWithVersion(id: string, version?: string): ServiceWithVersion;
export function getServiceVersions(id: string): string[];
export function getDeprecationWarning(id: string, version: string): string | undefined;

Data Structure:

interface ServiceDefinition {
id: string;
name: string;
category: ServiceCategory;
description: string;
website: string;
officialDocs: string[];
versions: Record<string, ServiceVersion>;
defaultVersion: string;
aliases?: string[];
lastUpdated: string;
monitoring?: ServiceMonitoring;
}

3. @csp-kit/cli - Command Line Interface

Purpose: Automation and service management tools

Key Features:

  • Interactive service addition
  • Automated service updates
  • CSP validation and testing
  • GitHub integration for PR creation

4. Web Interface

Purpose: User-friendly CSP generator with visual interface

Technology Stack:

  • Next.js 15 with App Router
  • React 19 with TypeScript
  • Tailwind CSS v4
  • Shadcn/ui components

Data Flow

CSP Generation Flow

sequenceDiagram
participant User
participant API as CSP Kit API
participant Data as Service Database
participant Generator as CSP Generator
participant Validator as Validator

User->>API: generateCSP(['google-analytics', 'stripe'])
API->>Data: getService('google-analytics')
Data-->>API: ServiceDefinition
API->>Data: getService('stripe')
Data-->>API: ServiceDefinition

API->>Generator: Process service definitions
Generator->>Generator: Merge CSP directives
Generator->>Generator: Apply custom rules
Generator->>Generator: Add nonce (if requested)

Generator->>Validator: Validate final CSP
Validator-->>Generator: Validation results

Generator-->>API: CSPResult with warnings
API-->>User: Complete CSP header

Service Update Flow

sequenceDiagram
participant Monitor as GitHub Actions
participant Service as External Service
participant CLI as CSP Kit CLI
participant Repo as GitHub Repository
participant Community as Community

Monitor->>Service: Check CSP requirements
Service-->>Monitor: Current CSP rules

alt Changes Detected
Monitor->>Repo: Create issue for changes
Community->>CLI: Use CLI to update service
CLI->>Repo: Create PR with updates
Community->>Repo: Review and merge PR
else No Changes
Monitor->>Repo: Update lastChecked timestamp
end

Design Patterns

1. Data-Package Separation

Problem: Service CSP requirements change frequently, but the core library logic is stable.

Solution: Separate service data from library code, allowing independent updates.

Benefits:

  • Service updates don't require library releases
  • Community can contribute service definitions easily
  • Data updates are faster and safer

2. Version-Aware Service Definitions

Problem: Services evolve their CSP requirements over time.

Solution: Store multiple versions of CSP requirements per service.

{
"versions": {
"1.0.0": { csp: { /* old rules */ }, validFrom: "2023-01-01" },
"2.0.0": { csp: { /* new rules */ }, validFrom: "2024-01-01", breaking: true }
},
"defaultVersion": "2.0.0"
}

Benefits:

  • Backward compatibility support
  • Gradual migration paths
  • Clear deprecation timeline

3. Service-First API Design

Problem: Traditional CSP configuration is complex and error-prone.

Solution: Abstract CSP complexity behind service identifiers.

// Before: Manual CSP configuration
const csp = "script-src 'self' https://js.stripe.com https://www.google-analytics.com";

// After: Service-based configuration
const result = generateCSP(['stripe', 'google-analytics']);

4. Plugin Architecture

Problem: Different environments need different CSP generation features.

Solution: Modular design with optional features.

// Core generation
import { generateCSP } from '@csp-kit/generator';

// Optional utilities
import { generateNonce, validateDirectives } from '@csp-kit/generator/utils';

// Framework integrations (future)
import { nextjsPlugin } from '@csp-kit/generator/plugins/nextjs';

5. Community-Driven Updates

Problem: Maintaining service definitions at scale requires community involvement.

Solution: Automated workflows and easy contribution tools.

Components:

  • GitHub Actions for monitoring
  • CLI tools for easy contributions
  • Issue templates for structured requests
  • Automated validation and testing

Technology Stack

Core Technologies

ComponentTechnologyJustification
LanguageTypeScriptType safety, developer experience
Build SystemTurborepo + tsupMonorepo optimization, fast builds
Package ManagerpnpmEfficient workspace management
TestingVitestFast, modern testing framework
LintingESLint + PrettierCode quality and consistency

Runtime Dependencies

// Minimal runtime dependencies for @csp-kit/generator
{
"dependencies": {
"@csp-kit/data": "workspace:*"
}
}

// CLI dependencies for automation
{
"dependencies": {
"commander": "^12.0.0", // CLI framework
"inquirer": "^12.0.0", // Interactive prompts
"chalk": "^5.3.0", // Terminal colors
"got": "^14.0.0", // HTTP client
"cheerio": "^1.0.0" // HTML parsing for service analysis
}
}

Development Dependencies

  • TypeScript: 5.8.2 (latest stable)
  • Node.js: >=18 (LTS support)
  • ESLint: 9.x (latest)
  • Prettier: 3.x
  • Vitest: 2.x

Performance Considerations

Bundle Size Optimization

Tree Shaking Support:

// Only import what you need
import { generateCSP } from '@csp-kit/generator';
// vs
import { generateCSP, generateNonce, validateDirectives } from '@csp-kit/generator';

Data Package Separation:

  • Service data is separate from core logic
  • Data updates don't affect bundle size
  • Optional data subsets for specific use cases

Build Optimization:

// Multiple output formats
{
"main": "./dist/index.js", // CommonJS
"module": "./dist/index.mjs", // ES Modules
"types": "./dist/index.d.ts" // TypeScript definitions
}

Runtime Performance

Caching Strategy:

// Service lookup caching
const serviceCache = new Map<string, ServiceDefinition>();

export function getService(id: string): ServiceDefinition | undefined {
if (serviceCache.has(id)) {
return serviceCache.get(id);
}

const service = lookupService(id);
if (service) {
serviceCache.set(id, service);
}

return service;
}

Lazy Loading:

// Service data is loaded on-demand
let servicesData: ServiceRegistry | null = null;

function getServicesData(): ServiceRegistry {
if (!servicesData) {
servicesData = require('./services.json');
}
return servicesData;
}

Memory Management

Efficient Data Structures:

  • Use Maps for frequent lookups
  • Store only essential data in memory
  • Implement garbage collection for caches

Streaming for Large Operations:

// Process large service updates in chunks
async function validateAllServices(): Promise<ValidationResult[]> {
const results: ValidationResult[] = [];

for await (const serviceChunk of getServiceChunks()) {
const chunkResults = await validateServiceChunk(serviceChunk);
results.push(...chunkResults);
}

return results;
}

Security Architecture

Input Validation

Service Identifier Validation:

function validateServiceIdentifier(id: string): boolean {
// Only allow alphanumeric characters, hyphens, and version specifiers
return /^[a-z0-9-]+(@[a-z0-9.-]+)?$/i.test(id);
}

CSP Directive Validation:

function validateCSPDirective(directive: string, sources: string[]): string[] {
const errors: string[] = [];

// Validate directive name
if (!VALID_DIRECTIVES.includes(directive)) {
errors.push(`Invalid directive: ${directive}`);
}

// Validate sources
for (const source of sources) {
if (!isValidCSPSource(source)) {
errors.push(`Invalid source: ${source}`);
}
}

return errors;
}

Data Integrity

Service Definition Schema Validation:

import Ajv from 'ajv';

const ajv = new Ajv();
const validateService = ajv.compile(serviceDefinitionSchema);

export function validateServiceDefinition(data: unknown): string[] {
const valid = validateService(data);

if (!valid) {
return validateService.errors?.map(err => err.message) || [];
}

return [];
}

Cryptographic Hashing:

// Ensure service data integrity
function calculateServiceHash(service: ServiceDefinition): string {
const content = JSON.stringify(service, Object.keys(service).sort());
return crypto.createHash('sha256').update(content).digest('hex');
}

Supply Chain Security

Dependency Management:

  • Regular security audits with pnpm audit
  • Automated dependency updates with Dependabot
  • Lockfile verification in CI/CD

Build Security:

  • Signed releases with GPG
  • Reproducible builds
  • Build artifact verification

CSP Security Best Practices

Conservative Defaults:

const DEFAULT_CSP_OPTIONS = {
includeSelf: true, // Always include 'self'
unsafeInline: false, // Never allow unsafe-inline by default
unsafeEval: false, // Never allow unsafe-eval by default
strictDynamic: false, // Conservative approach to strict-dynamic
};

Nonce Generation:

import crypto from 'crypto';

export function generateNonce(length: number = 16): string {
return crypto.randomBytes(length).toString('base64');
}

Warning System:

export function validateDirectives(directives: CSPDirectives): string[] {
const warnings: string[] = [];

// Warn about unsafe directives
if (directives['script-src']?.includes("'unsafe-inline'")) {
warnings.push("'unsafe-inline' in script-src reduces security");
}

if (directives['script-src']?.includes("'unsafe-eval'")) {
warnings.push("'unsafe-eval' in script-src is dangerous");
}

return warnings;
}

Future Architecture Considerations

Scaling Considerations

  1. Service Database Growth:

    • Implement service data partitioning
    • Add service categorization and filtering
    • Consider database backend for large-scale deployments
  2. API Rate Limiting:

    • Implement rate limiting for public APIs
    • Add caching layers for high-traffic scenarios
    • Consider CDN distribution for service data
  3. Multi-Region Support:

    • Distribute service checking across regions
    • Implement regional service variations
    • Add latency-based routing

Extension Points

  1. Plugin System:

    interface CSPPlugin {
    name: string;
    transform(directives: CSPDirectives): CSPDirectives;
    validate?(result: CSPResult): string[];
    }
  2. Custom Service Resolvers:

    interface ServiceResolver {
    resolve(id: string): ServiceDefinition | undefined;
    search(query: string): ServiceDefinition[];
    }
  3. Framework Integrations:

    • Next.js plugin for automatic CSP generation
    • Webpack plugin for build-time CSP
    • Express middleware for runtime CSP

Last Updated: 2024-06-29 Architecture Version: 1.0.0