Contigov — Architecture Overview

This document describes the technical architecture of the Contigov platform: how components are structured, how they communicate, what each component is responsible for, and how data flows through the system.

Table of Contents

  1. High-Level Summary
  2. Architecture Diagram
  3. Central Server
  4. Agent (Endpoint Binary)
  5. Server ↔ Agent Communication
  6. Database
  7. Authentication & Security
  8. Policy Enforcement Flow
  9. Vulnerability Scanning Flow
  10. External Integrations
  11. Scalability & Performance
  12. Full Technology Stack

1. High-Level Summary

Contigov is a hub-and-spoke governance platform. A single central server acts as the control plane — storing policy, receiving telemetry, and delivering actions. Lightweight agents run natively on every managed endpoint and carry out enforcement locally, even if the server is temporarily unreachable.

The platform is designed around three core principles:

  • Agent autonomy — policy is cached on the agent. Enforcement continues during network interruptions without degrading to an open state.
  • Zero persistent open ports on endpoints — agents initiate all outbound connections to the server. No inbound firewall rules are needed on managed machines.
  • Single deployable unit — the entire server (web UI, REST API, database, TLS, metrics) ships as one Docker image with no external dependencies (no Redis, no Postgres, no message broker required).

2. Architecture Diagram

┌─────────────────────────────────────────────────────────────────────┐
│ External Access │
│ Browser / Admin UI AI Assistants (MCP) │
│ Prometheus Scraper Webhooks (Teams/Slack) │
└───────────────┬────────────────────────────┬────────────────────────┘
│ HTTPS (443) │ HTTPS
▼ ▼
┌─────────────────────────────────────────────────────────────────────┐
│ Optional: AWS ALB / nginx / Cloudflare │
│ (TLS termination layer) │
└───────────────────────────────┬─────────────────────────────────────┘
│ HTTP (proxy mode) or HTTPS (direct)
▼
┌─────────────────────────────────────────────────────────────────────┐
│ CONTIGOV SERVER │
│ (Docker container, Node.js 20) │
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌──────────────┐ ┌──────────┐ │
│ │ Web UI │ │ REST API │ │ MCP Server │ │ /metrics │ │
│ │ (SPA) │ │ /api/* │ │ /mcp │ │ Prometheus│ │
│ └─────────────┘ └──────┬──────┘ └──────────────┘ └──────────┘ │
│ │ │
│ ┌────────────────────────▼────────────────────────────────────┐ │
│ │ Business Logic Layer │ │
│ │ Policy Engine · Audit Logger · Webhook Engine │ │
│ │ Write Buffer · Notification Rules · AI Detection │ │
│ └────────────────────────┬────────────────────────────────────┘ │
│ │ │
│ ┌────────────────────────▼────────────────────────────────────┐ │
│ │ SQLite Database (WAL mode) │ │
│ │ AES-256-GCM encrypted at rest │ │
│ └─────────────────────────────────────────────────────────────┘ │
└───────────┬───────────────────────────────────────────────────┬─────┘
│ HTTPS (agent reports every 30s) │
│ Agent authenticates with Bearer API Key │
┌─────────▼──────────┐ ┌───────────────────┐ ┌────────────▼──────┐
│ AGENT │ │ AGENT │ │ AGENT │
│ Windows │ │ macOS │ │ Linux │
│ (Go binary) │ │ (Go binary) │ │ (Go binary) │
│ │ │ │ │ │
│ • Container report │ │ • Container report│ │ • Container report│
│ • Hosts enforcement │ │ • Hosts enforcement │ • Hosts enforcement│
│ • Pull interception │ │ • Pull interception │ • Pull interception│
│ • Trivy scanning │ │ • Trivy scanning │ │ • Trivy scanning │
│ • Desktop notify │ │ • Desktop notify │ │ • Desktop notify │
└─────────────────────┘ └───────────────────┘ └───────────────────┘

3. Central Server

The server is a Node.js 20 / Express application packaged as a single Docker image. It is responsible for:

Responsibility Description
Web UI Single-page application served as static files. Dashboard, policy management, audit logs, settings, AI Index, and integrations — all running in the browser with no separate frontend server.
REST API All data operations — device registration, container reporting, policy reads and writes, vulnerability results, audit log writes, user management — served under /api/*.
Policy engine Stores blocked images, blocked registries, and per-endpoint overrides. Serves the current policy to agents on every report cycle response.
Write buffer Agent reports are queued in memory and flushed to SQLite every 2 seconds in a single batch transaction. This prevents per-report disk writes and allows the server to sustain high-frequency reporting from large fleets.
Hot caches API key, blocked images, repo policy, notification rules, and session settings are cached in memory. The agent report hot path reads zero rows from the database on a cache hit.
Webhook engine Fires HTTP POST requests to configured endpoints (Teams, Slack, Discord, generic JSON) when governance events occur — blocking enforcement, scan completion, new endpoint, threshold breach.
Audit logger Every governance action is written to the audit_logs table with a timestamp, acting user, correlation ID, and event payload.
AI detection Container image names are compared against a pattern library (LLM runners, ML frameworks, GPU toolkits, MCP servers). Matching containers are flagged in the AI Index view.
MCP server A JSON-RPC 2.0 endpoint at /mcp that allows AI assistants (Cursor, Claude, Copilot) to query endpoints, vulnerabilities, and manage policy via natural language.
Prometheus metrics Exposes standard Node.js process metrics plus custom gauges (active agents, write queue depth, DB size, requests/sec) at /metrics.
TLS Self-signed certificate baked in for zero-config HTTPS. Supports custom certificate mounting or proxy mode (ALB/ACM/nginx) via environment variable.

Internal port layout

Internal port Maps to external Purpose
3443 443 Main HTTPS (or HTTP in proxy mode)
3080 80 HTTP → HTTPS redirect (auto/direct modes only)

4. Agent (Endpoint Binary)

The agent is a statically compiled Go binary — no runtime, no dependencies, no installation wizard. It runs natively on Windows, macOS, and Linux. Its entire job is to observe the local Docker daemon, enforce policy, and report telemetry to the server.

Agent responsibilities

Module What it does How
Reporter Sends a full snapshot of running containers and local images to the server HTTP POST to /api/report every 30 seconds (configurable server-side)
Policy cache Stores the latest policy received from the server in memory Parsed from the JSON response of each report. Used immediately — no disk read needed
Hosts enforcer Redirects blocked Docker registry hostnames to 127.0.0.1 by rewriting the system hosts file Runs on startup and every 60 seconds. Managed block added between # CONTIGOV START / # CONTIGOV END markers — never touches user-defined entries
Container enforcer Stops blocked containers the instant they start Subscribes to the Docker event stream. On a container start event, checks the image name against the block list and calls docker stop -t 0 if matched
Pull interceptor Detects docker pull attempts to blocked registries in real time Listens on 127.0.0.1:443 (TLS SNI inspection). When a pull hits the redirected IP, the agent reads the SNI hostname, logs the event as PULL_ATTEMPT_BLOCKED, sends a desktop notification, and reports to the server
Vulnerability scanner Scans local images for CVEs and sends results to the server Downloads Trivy automatically on first run. Scans each image once on discovery, on image change, or on manual trigger from the dashboard
Override poller Picks up per-endpoint policy exceptions granted by admins Polls /api/agent/overrides every 5 seconds. Exceptions are applied immediately without waiting for the next report cycle
Desktop notifications Displays OS-native alerts on the managed machine Windows Toast notifications (custom AUMID + icon), macOS notification center, Linux libnotify
Remote actions Executes admin-initiated actions (stop container, run scan, send message) Actions are embedded in the report response payload. The agent processes them on the next report cycle
Maintenance mode Temporarily suspends all enforcement for debugging Server sets a maintenance_until timestamp in the report response. Agent immediately clears hosts file blocks and skips enforcement until the time expires

Agent startup sequence

  1. Detect operating system and Docker socket path
  2. Self-elevate to administrator / root (UAC on Windows, sudo on Linux/macOS) if not already elevated
  3. Load configuration from agent-config.json (or environment variables)
  4. Send first report to server — registers the endpoint and receives initial policy
  5. Apply policy: rewrite hosts file, start Docker event listener
  6. Start background loops: report timer, override poller, pull interceptor listener
  7. Download Trivy if not cached; begin scanning local images

Agent binary sizes

Platform Approx. size Notes
Windows amd64 ~12 MB Includes Windows Service manager and Toast notification support
Linux amd64 ~10 MB Statically linked, runs on any glibc-free distro including Alpine
macOS arm64 ~10 MB Signed with ad-hoc signature; requires Gatekeeper quarantine removal
macOS Universal ~20 MB Fat binary containing both Intel and Apple Silicon slices

5. Server ↔ Agent Communication

Protocol

All agent-to-server communication uses HTTPS over port 443 (or the configured server URL). Communication is always agent-initiated — the server never pushes to agents directly. This means:

  • No inbound firewall ports need to be opened on managed machines
  • Agents behind NAT or corporate proxies work without special configuration
  • The server can be on a private network as long as agents can reach its URL

Authentication

Every request from an agent includes:

Authorization: Bearer <API_KEY>

The server validates this against the configured API_KEY environment variable. Requests without a valid key are rejected with HTTP 401. This key is shared across all agents in the fleet and is configured in agent-config.json.

Report cycle

Every report cycle the agent:

  1. Sends POST /api/report with a JSON payload containing running containers, local images, agent version, OS, and hostname
  2. Receives a JSON response containing the current policy (blocked images, blocked registries, overrides), any pending remote actions, the next report interval, and maintenance mode status
  3. Applies any changes immediately (hosts file sync, container enforcement, action execution)

Report payload (simplified)

{
“hostname”: “WORKSTATION-01”,
“os”: “windows”,
“agent_version”: “1.0.42”,
“containers”: [
{ “id”: “abc123”, “name”: “nginx”, “image”: “nginx:1.25”, “status”: “running” }
],
“images”: [
{ “id”: “sha256:…”, “tags”: [“nginx:1.25”], “size”: 142000000 }
]
}

Response payload (simplified)

{
“blocked_images”: [“nginx:1.19”, “python:2.7”],
“blocked_hosts”: [“docker.io”, “gcr.io”],
“overrides”: [],
“actions”: [],
“report_interval_seconds”: 30,
“maintenance_paused”: false,
“maintenance_until”: null
}

Additional agent endpoints

Endpoint Method Purpose Polling interval
/api/report POST Container telemetry + policy fetch 30 s (server-controlled)
/api/agent/overrides GET Per-endpoint policy exceptions 5 s
/api/repos/blocked-hosts GET Current hosts file block list 60 s (hosts sync cycle)
/api/scans POST Upload Trivy scan results On scan completion
/api/audit POST Report enforcement events (pull blocked, container stopped) On event

6. Database

Contigov uses SQLite as its embedded database. This is a deliberate design choice — SQLite eliminates the need for a separate database server, making the platform genuinely single-binary deployable with no external dependencies.

Configuration

  • WAL mode (Write-Ahead Logging) — readers never block writers. Write throughput is 5–10× higher than SQLite’s default journal mode. Critical for handling concurrent agent reports.
  • AES-256-GCM encryption at rest — the entire database file is encrypted using the DB_ENCRYPTION_KEY environment variable. The key never leaves the server process.
  • 9 indexes — covering all hot-path queries (device lookups, audit log searches, container history). Full table scans are eliminated on all common access patterns.
  • In-memory write buffer — agent reports are batched in memory and flushed every 2 seconds in a single transaction, reducing write amplification under high agent load.
  • DB-ready guard — the server does not begin accepting API traffic until all schema migrations have completed successfully.

Key tables

Table Stores
devices Registered endpoints — hostname, OS, agent version, last seen, maintenance status
containers Container snapshots per device — name, image, status, AI type flag
images Local image inventory per device — tags, size, digest
vulnerabilities Trivy scan results — CVE ID, severity, package, fix version, per image
audit_logs All governance events — action type, user, device, timestamp, correlation ID
users Local accounts — username, bcrypt hash, role, MFA secret, SSO sub
revoked_tokens JWT JTIs revoked at logout — replayed into memory on startup
settings Key/value store for all configurable server parameters
blocked_images Global image block list
blocked_repos Registry-level block and allow list (denylist/whitelist mode)
policy_overrides Per-endpoint exceptions to global policy
webhooks Configured webhook destinations and subscribed events
integrations OX Security and MCP server configuration
sso_config OIDC/SSO provider settings — client ID, discovery URL, group mappings

Storage estimates

Fleet size Estimated DB size after 90 days
10 agents ~50 MB
100 agents ~500 MB
500 agents ~2–3 GB
1,000 agents ~5 GB

The Monitoring page displays live DB size and audit log row count with threshold warnings at 1 GB, 5 GB, and 10 GB.

7. Authentication & Security

User authentication flow

  1. User submits username and password to POST /api/auth/login
  2. Server verifies bcrypt hash. If MFA is enabled, returns a short-lived mfa_token instead of a session
  3. User submits TOTP code to POST /api/auth/mfa/verify with the mfa_token
  4. Server issues a signed JWT with a unique jti claim, expiry, and user role. The JWT is set as an httpOnly, Secure, SameSite=Strict cookie — never accessible to JavaScript
  5. All subsequent API requests are authenticated by reading and verifying the cookie. The jti is checked against the in-memory revocation map on every request

SSO / OIDC flow

  1. User clicks “Continue with SSO” on the login page
  2. Server generates a PKCE code verifier + challenge and a random state token, then redirects to the OIDC provider (Entra ID, Okta, Google, Keycloak, etc.)
  3. User authenticates with the provider
  4. Provider redirects to /api/auth/callback with an authorization code
  5. Server exchanges the code for tokens, verifies the ID token signature using the provider’s JWKS, and extracts claims
  6. If allowed_group_id is configured, the user’s group membership is checked. If admin_group_id is configured, matching group members receive the admin role automatically
  7. User account is auto-provisioned on first SSO login. Subsequent logins update the last-seen timestamp
  8. Session cookie is issued identically to local login

Security controls summary

Control Implementation
Session tokens httpOnly + Secure + SameSite=Strict JWT cookies — immune to XSS token theft
Token revocation JTI persisted to DB on logout; replayed into memory on restart — tokens stay invalid permanently
Password hashing bcrypt with cost factor 12
MFA TOTP (RFC 6238) via speakeasy — compatible with Google Authenticator, Authy, 1Password
Database encryption AES-256-GCM — entire SQLite file encrypted at rest using DB_ENCRYPTION_KEY
TLS Self-signed (zero config), custom cert mount, or ALB/ACM proxy mode
HSTS Enforced via helmet — browsers lock to HTTPS after first visit
Content Security Policy script-src ‘self’ — no inline scripts, no eval — prevents XSS script execution
Rate limiting — login 10 attempts per 15 minutes per IP
Rate limiting — MFA 10 attempts per 10 minutes per IP
Rate limiting — agent reports Configurable per-IP limit to prevent DB flooding from a leaked API key
Agent authentication Static Bearer token (API_KEY) — all agent endpoints reject requests without a valid key
CORS Configurable allowed origins — defaults to same-origin only
Correlation IDs Every HTTP request gets a UUID stored in AsyncLocalStorage — appears in every log line produced by that request

8. Policy Enforcement Flow

This diagram shows what happens from the moment an admin blocks an image to the moment a container is stopped on a managed endpoint.

Admin blocks image “nginx:1.19” in the web UI
│
▼
POST /api/blocked-images (server)
→ Writes to blocked_images table
→ Invalidates in-memory policy cache
│
▼ (next agent report cycle — up to 30 seconds)
Agent sends POST /api/report
← Server responds with updated blocked_images list
│
▼
Agent updates in-memory policy cache
│
┌─────┴──────────────────────────────────┐
│ │
▼ ▼
Docker event listener Hosts file enforcer
detects “container start” runs on next 60s tick
for a container running nginx:1.19 │
│ ▼
▼ Adds docker.io → 127.0.0.1
Agent calls docker stop -t 0 to /etc/hosts
│ │
▼ ▼
Container is stopped immediately Future “docker pull nginx:1.19”
│ fails immediately at DNS level
▼
Agent sends POST /api/audit
event: ENFORCEMENT_TRIGGERED
│
▼
Server fires webhook (if configured):
Teams / Slack / Discord notification

Agent sends OS desktop notification
to the endpoint user

Hosts file management

The agent writes a clearly marked block to the system hosts file:

# CONTIGOV START — do not edit this block manually
127.0.0.1 registry-1.docker.io
127.0.0.1 auth.docker.io
127.0.0.1 index.docker.io
# CONTIGOV END

Only entries between the markers are managed by Contigov. All other hosts file entries are left untouched. When maintenance mode is active or a policy override is granted, the block is removed immediately and restored after the exception expires.

9. Vulnerability Scanning Flow

Agent discovers a new image (or image changes)
│
▼
Is Trivy binary present and up to date?
No → Download Trivy from GitHub releases (one-time)
Yes → Proceed
│
▼
Run: trivy image –format json <image>
│
▼
Parse JSON output → extract CVE list
(CVE ID, severity, package, version, fix version)
│
▼
POST /api/scans → Server stores results in vulnerabilities table
│
▼
Web UI displays CVE breakdown per image:
CRITICAL · HIGH · MEDIUM · LOW · UNKNOWN
(with one-click CSV export per image or fleet-wide)
│
▼
If any CRITICAL CVEs found:
→ Notification rule “critical_cve” fires (if enabled)
→ Webhook fires with event type “scan.critical”
→ Admin sees alert badge on the endpoint card

Scan triggers

Trigger When
First discovery Any time an image is seen by the agent for the first time
Image change Image digest changes (e.g. after a docker pull of the same tag)
Manual trigger Admin clicks “Scan” on an endpoint card or in the endpoint details drawer
Scheduled (future) Configurable rescan interval — planned for a future release

10. External Integrations

Webhooks

The server’s built-in webhook engine delivers real-time event notifications to external systems. No plugin or third-party service is required.

Platform Format
Microsoft Teams Legacy MessageCard (adaptive cards planned)
Slack Block Kit with colour-coded attachments
Discord Embed with colour coding
Generic JSON Raw event payload — Zapier, Make, n8n, PagerDuty, custom APIs

OX Security

When the OX Security integration is enabled, container vulnerability scan results are pushed to OX Security’s ASPM platform automatically after each Trivy scan completes. Configure the API key and API URL under Settings → Integrations → OX Security.

MCP Server (AI Assistants)

Contigov exposes a Model Context Protocol (MCP) endpoint at /mcp. Any MCP-compatible AI assistant (Cursor IDE, Claude Desktop, GitHub Copilot) can connect and use natural language to query the fleet, check vulnerabilities, and manage policy.

MCP Tool What it does
list_endpoints List all managed endpoints and their status
get_endpoint Full details of one endpoint including containers and images
get_policy Current block list and blocked registries
block_image Add an image to the block list
unblock_image Remove an image from the block list
get_vulnerabilities CVE scan results for a specific image
get_audit_log Recent governance audit log entries
get_ai_index All endpoints running AI/LLM/MCP containers

Prometheus

Standard Prometheus metrics are available at /metrics. Authentication is required — either an admin session JWT or a static METRICS_TOKEN configured via environment variable for scrape jobs.

# prometheus.yml
scrape_configs:
– job_name: contigov
scheme: https
bearer_token: <METRICS_TOKEN>
static_configs:
– targets: [“your-contigov-domain.com”]

11. Scalability & Performance

Capacity targets

Metric Value
Maximum simultaneous agents 1,000
Recommended max fleet size (SQLite) 1,000 agents
Report throughput at 30s interval ~33 reports/second
Write buffer flush interval 2 seconds
Minimum server RAM 1 GB (2 GB recommended)
SQLite WAL write throughput 5–10× vs default journal mode

Tuning the report interval

Fleet size Recommended report interval
Under 100 agents 10–30 seconds
100–500 agents 30–60 seconds
500–1,000 agents 60–120 seconds
Over 1,000 agents Migrate to a PostgreSQL-backed deployment

The report interval is set globally from the Dashboard (Settings → General) and pushed to all agents automatically on their next report cycle — no agent restart or re-deployment required.

Multi-instance / HA limitations

The current architecture is single-server. SQLite, in-memory rate limiters, in-memory token revocation maps, and in-memory write buffers do not coordinate across multiple instances. For high-availability or multi-region deployments, a PostgreSQL-backed version with Redis for shared state is required.

12. Full Technology Stack

Layer Technology Purpose
Server runtime Node.js 20 + Express HTTP server, REST API, middleware pipeline
Database SQLite (WAL, AES-256-GCM encrypted) All persistent state — zero external DB dependency
Authentication jsonwebtoken, bcryptjs, speakeasy, uuid JWT sessions, password hashing, TOTP MFA, token IDs
Security middleware helmet, express-rate-limit, cors CSP, HSTS, X-Frame-Options, brute-force protection, CORS
SSO / OIDC Built-in (Node.js crypto + fetch) Authorization Code + PKCE flow, JWKS verification — no Passport.js dependency
Observability prom-client, AsyncLocalStorage Prometheus metrics, structured JSON logging with correlation IDs
Frontend Vanilla HTML / CSS / JavaScript No framework — single HTML file + app.js + style.css
TLS Node.js https module, openssl Self-signed cert baked in; custom cert via volume mount; proxy mode for ALB/ACM
Container runtime Docker 20.10+ Server container host; agent monitors Docker/Podman on endpoints
Agent language Go 1.21+ Statically compiled — no runtime required on endpoints
Vulnerability scanner Trivy (Aqua Security) Auto-downloaded by agent; CVE scanning for container images
Windows integration golang.org/x/sys/windows, Windows SCM UAC self-elevation, Windows Service install, Toast notifications
macOS integration osascript, launchd Desktop notifications, daemon service management
Linux integration libnotify / notify-send Desktop notifications on Linux desktops
CI/CD GitHub Actions Multi-stage Docker build, Go cross-compilation, ECR push, OIDC keyless auth
Image registry Amazon ECR Production image storage with scan-on-push enabled