docs: fix stale references, seed data case bugs, and convert ASCII diagrams to Mermaid

Audit all docs and examples against current codebase state. Fix seed_demo.sql
domain constant casing (IssuerType, TargetType, AgentStatus) that would cause
agent dispatch failures. Fix example docker-compose health endpoints (/health
not /api/v1/health) and env var names (CERTCTL_DATABASE_URL). Update connector
counts, test numbers, and planned→implemented status across docs. Convert 3
ASCII flow diagrams to Mermaid.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Shankar
2026-04-03 16:11:42 -04:00
parent b1178c177c
commit b9e8630cd7
16 changed files with 102 additions and 107 deletions
+7 -3
View File
@@ -90,8 +90,10 @@ flowchart TB
T5["HAProxy\n(combined PEM + reload)"]
T6["Traefik\n(file provider)"]
T7["Caddy\n(admin API / file)"]
T8["Envoy\n(file-based SDS)"]
T9["Postfix/Dovecot\n(file + service reload)"]
T2["F5 BIG-IP\n(proxy agent + iControl REST, planned)"]
T3["IIS\n(agent-local PowerShell, planned)"]
T3["IIS\n(WinRM + local)"]
end
DASH --> API
@@ -119,7 +121,7 @@ The server exposes a REST API under `/api/v1/` and optionally serves the web das
### Agents
Lightweight Go processes that run on or near your infrastructure. Agents generate ECDSA P-256 private keys locally, create CSRs, and submit them to the control plane for signing — private keys never leave agent infrastructure. Agents also handle certificate deployment to target systems (NGINX, Apache httpd, HAProxy fully implemented; F5 BIG-IP, IIS interface only with V2 implementations planned) and report job status. They communicate with the control plane via HTTP and authenticate with API keys.
Lightweight Go processes that run on or near your infrastructure. Agents generate ECDSA P-256 private keys locally, create CSRs, and submit them to the control plane for signing — private keys never leave agent infrastructure. Agents also handle certificate deployment to target systems (NGINX, Apache httpd, HAProxy, Traefik, Caddy, Envoy, Postfix, Dovecot, IIS fully implemented; F5 BIG-IP interface stub only) and report job status. They communicate with the control plane via HTTP and authenticate with API keys.
The agent runs two background loops: a heartbeat (every 60 seconds) to signal it's alive, and a work poll (every 30 seconds) to check for actionable jobs via `GET /api/v1/agents/{id}/work`. Jobs may be `AwaitingCSR` (agent needs to generate key + submit CSR) or `Deployment` (agent needs to deploy a certificate). Private keys are stored in `CERTCTL_KEY_DIR` (default `/var/lib/certctl/keys`) with 0600 permissions.
@@ -521,8 +523,10 @@ flowchart TB
TI --> HP["HAProxy"]
TI --> TF["Traefik"]
TI --> CD["Caddy"]
TI --> EV["Envoy"]
TI --> PO["Postfix/Dovecot"]
TI --> IIS["IIS"]
TI --> F5["F5 BIG-IP (interface only)"]
TI --> IIS["IIS (interface only)"]
end
subgraph "Notifier Connectors"
+2 -2
View File
@@ -125,9 +125,9 @@ Agents also report **metadata** about themselves — their operating system, CPU
### Deployment Targets
Targets are the systems where certificates actually get installed — NGINX web servers, Apache httpd servers, HAProxy load balancers, F5 BIG-IP appliances, Microsoft IIS servers. Each target type has a **connector** that knows how to deploy certificates to that specific system (e.g., writing files and reloading NGINX or Apache config, building a combined PEM for HAProxy).
Targets are the systems where certificates actually get installed — NGINX web servers, Apache httpd servers, HAProxy load balancers, Traefik reverse proxies, Caddy servers, Envoy gateways, Postfix/Dovecot mail servers, Microsoft IIS servers, and network appliances. Each target type has a **connector** that knows how to deploy certificates to that specific system (e.g., writing files and reloading NGINX or Apache config, building a combined PEM for HAProxy).
For targets where an agent runs directly on the machine (NGINX, Apache, HAProxy, IIS), the agent deploys certificates locally — no remote access needed. For network appliances where you can't install an agent (F5 BIG-IP, Palo Alto, etc.), a **proxy agent** in the same network zone picks up the deployment job and calls the appliance's API. The server never initiates outbound connections to any target.
For targets where an agent runs directly on the machine (NGINX, Apache, HAProxy, Traefik, Caddy, Envoy, Postfix, Dovecot, IIS), the agent deploys certificates locally — no remote access needed. For network appliances where you can't install an agent (F5 BIG-IP, Palo Alto, etc.), a **proxy agent** in the same network zone picks up the deployment job and calls the appliance's API. The server never initiates outbound connections to any target.
## The Certificate Lifecycle
+2 -2
View File
@@ -53,8 +53,8 @@ Connectors extend certctl to integrate with external systems for certificate iss
Three types of connectors:
1. **Issuer Connector** — Obtains certificates from CAs (Local CA with sub-CA support, ACME with HTTP-01 + DNS-01 + DNS-PERSIST-01, step-ca, OpenSSL/Custom CA implemented; additional CA integrations planned)
2. **Target Connector** — Deploys certificates to infrastructure (NGINX, Apache httpd, HAProxy, Traefik, Caddy, Envoy, IIS implemented; F5 via proxy agent planned; additional cloud and network targets planned)
1. **Issuer Connector** — Obtains certificates from CAs (Local CA with sub-CA support, ACME with HTTP-01 + DNS-01 + DNS-PERSIST-01, step-ca, OpenSSL/Custom CA, Vault PKI, DigiCert implemented; additional CA integrations planned)
2. **Target Connector** — Deploys certificates to infrastructure (NGINX, Apache httpd, HAProxy, Traefik, Caddy, Envoy, Postfix, Dovecot, IIS implemented; F5 via proxy agent planned; additional cloud and network targets planned)
3. **Notifier Connector** — Sends alerts about certificate events (Email, Webhooks, Slack, Microsoft Teams, PagerDuty, OpsGenie implemented)
All connectors accept JSON configuration at initialization, support config validation, and are registered in the service layer. Issuer connectors run on the control plane; target connectors run on agents. For network appliances where agents can't be installed, a **proxy agent** in the same network zone handles deployment — the server never initiates outbound connections.
+2 -2
View File
@@ -307,8 +307,8 @@ flowchart TD
A --> F["ACME\n(Let's Encrypt)"]
A --> G["step-ca\n(implemented)"]
A --> H["OpenSSL / Custom CA\n(script-based)"]
A --> J["DigiCert API\n(planned)"]
A --> K["Vault PKI\n(planned)"]
A --> J["DigiCert API\n(implemented)"]
A --> K["Vault PKI\n(implemented)"]
A --> L["Entrust / GlobalSign\n(planned)"]
A --> M["Google CAS / EJBCA\n(planned)"]
```
+7 -7
View File
@@ -1286,11 +1286,11 @@ The web dashboard is the primary operational interface for certctl. Built with *
- **Docker Tags** — `:latest`, `:v{version}` (`shankar0123.docker.scarf.sh/certctl-server`, `shankar0123.docker.scarf.sh/certctl-agent`)
### Test Suite
- **Unit Tests** — 625+ test functions across service, handler, middleware, domain layers
- **Unit Tests** — 1,088+ test functions across service, handler, middleware, domain layers
- **Integration Tests** — End-to-end workflows (issuance→renewal→deployment)
- **Negative Tests** — Malformed input, nonexistent resources, error conditions
- **Frontend Tests** — 86 Vitest tests (API client, utilities, stats/metrics, full endpoint coverage)
- **Total Coverage** — 900+ tests (Go + frontend combined)
- **Frontend Tests** — 211 Vitest tests (API client, utilities, stats/metrics, full endpoint coverage)
- **Total Coverage** — 1,554+ tests (Go + frontend combined)
### Licensing
- **License** — Business Source License 1.1 (BSL 1.1)
@@ -1478,10 +1478,10 @@ Each guide includes an evidence summary table mapping specific criteria to certc
| Category | Count |
|----------|-------|
| **API Endpoints** | 95 (under /api/v1/ + /.well-known/est/) |
| **API Endpoints** | 97 (under /api/v1/ + /.well-known/est/) |
| **Dashboard** | Full web GUI |
| **Issuer Connectors** | 4 (Local CA, ACME, step-ca, OpenSSL) |
| **Target Connectors** | 5 (3 impl: NGINX, Apache, HAProxy; 2 stubs: F5, IIS) |
| **Issuer Connectors** | 6 (Local CA, ACME, step-ca, OpenSSL, Vault PKI, DigiCert) |
| **Target Connectors** | 10 (9 impl: NGINX, Apache, HAProxy, Traefik, Caddy, Envoy, IIS, Postfix, Dovecot; 1 stub: F5) |
| **Notifier Channels** | 6 (Email, Webhook, Slack, Teams, PagerDuty, OpsGenie) |
| **Job Types** | 4 (Issuance, Renewal, Deployment, Validation) |
| **Job States** | 7 (Pending, AwaitingCSR, AwaitingApproval, Running, Completed, Failed, Cancelled) |
@@ -1492,6 +1492,6 @@ Each guide includes an evidence summary table mapping specific criteria to certc
| **MCP Tools** | 76 (16 resource domains) |
| **CLI Subcommands** | 10 |
| **Database Tables** | 19 |
| **Test Suite** | 900+ tests (Go backend + frontend) |
| **Test Suite** | 1,554+ tests (Go backend + frontend) |
| **Environment Variables** | 41+ configuration options |
+2 -2
View File
@@ -1600,7 +1600,7 @@ curl -s -w "\nHTTP %{http_code}\n" -X POST -H "$AUTH" -H "$CT" \
---
**Test 7.1.6 — Create IIS target (stub)**
**Test 7.1.6 — Create IIS target**
```bash
curl -s -w "\nHTTP %{http_code}\n" -X POST -H "$AUTH" -H "$CT" \
@@ -5833,7 +5833,7 @@ These must be green before starting manual QA:
| 7.1.3 | Create Apache target | Manual | ☐ | | |
| 7.1.4 | Create HAProxy target | Manual | ☐ | | |
| 7.1.5 | Create F5 BIG-IP target (stub) | Auto | ☑ | 2026-03-30 | |
| 7.1.6 | Create IIS target (stub) | Auto | ☑ | 2026-03-30 | |
| 7.1.6 | Create IIS target | Auto | ☑ | 2026-03-30 | |
| 7.1.7 | Get target verifies type-specific config stored | Manual | ☐ | | |
| 7.1.8 | Update target config | Manual | ☐ | | |
| 7.1.9 | Delete target returns 204 | Auto | ☑ | 2026-03-30 | |
+12 -10
View File
@@ -13,16 +13,18 @@ This example demonstrates certctl's core use case: **automatically manage TLS ce
## Architecture
```
Your Domain (example.com)
↓ [HTTP-01 validation, port 80]
Let's Encrypt ACME
↓ [CSR submission]
certctl Server (control plane)
↓ [API polling]
certctl Agent (on NGINX server)
↓ [deploy cert+key]
NGINX Reverse Proxy
```mermaid
flowchart TD
A["Your Domain (example.com)"]
B["Let's Encrypt ACME"]
C["certctl Server (control plane)"]
D["certctl Agent (on NGINX server)"]
E["NGINX Reverse Proxy"]
A -->|HTTP-01 validation<br/>port 80| B
B -->|CSR submission| C
C -->|API polling| D
D -->|deploy cert+key| E
```
## Prerequisites
+2 -2
View File
@@ -26,7 +26,7 @@ services:
container_name: certctl-server-acme-nginx
environment:
# Database
DATABASE_URL: postgres://certctl:${DB_PASSWORD:-certctl-dev-password}@postgres:5432/certctl?sslmode=disable
CERTCTL_DATABASE_URL: postgres://certctl:${DB_PASSWORD:-certctl-dev-password}@postgres:5432/certctl?sslmode=disable
# Server settings
CERTCTL_SERVER_PORT: 8443
@@ -61,7 +61,7 @@ services:
networks:
- certctl-network
healthcheck:
test: ['CMD-SHELL', 'curl -sf http://localhost:8443/api/v1/health || exit 1']
test: ['CMD-SHELL', 'curl -sf http://localhost:8443/health || exit 1']
interval: 10s
timeout: 5s
retries: 3
@@ -50,7 +50,7 @@ services:
container_name: certctl-server-dns01
environment:
# Database
DATABASE_URL: postgres://certctl:${DB_PASSWORD:-certctl-dev-password}@postgres:5432/certctl?sslmode=disable
CERTCTL_DATABASE_URL: postgres://certctl:${DB_PASSWORD:-certctl-dev-password}@postgres:5432/certctl?sslmode=disable
# Server settings
CERTCTL_SERVER_PORT: 8443
@@ -113,7 +113,7 @@ services:
- certctl-network
healthcheck:
test: ['CMD-SHELL', 'curl -sf http://localhost:8443/api/v1/health || exit 1']
test: ['CMD-SHELL', 'curl -sf http://localhost:8443/health || exit 1']
interval: 10s
timeout: 5s
retries: 3
+2 -2
View File
@@ -27,7 +27,7 @@ services:
container_name: certctl-server-multi-issuer
environment:
# Database
DATABASE_URL: postgres://certctl:${DB_PASSWORD:-certctl-dev-password}@postgres:5432/certctl?sslmode=disable
CERTCTL_DATABASE_URL: postgres://certctl:${DB_PASSWORD:-certctl-dev-password}@postgres:5432/certctl?sslmode=disable
# Server settings
CERTCTL_SERVER_PORT: 8443
@@ -64,7 +64,7 @@ services:
networks:
- certctl-network
healthcheck:
test: ['CMD-SHELL', 'curl -sf http://localhost:8443/api/v1/health || exit 1']
test: ['CMD-SHELL', 'curl -sf http://localhost:8443/health || exit 1']
interval: 10s
timeout: 5s
retries: 3
+24 -22
View File
@@ -13,27 +13,29 @@ With certctl, both issuer types are configured and available. You assign each ce
## Architecture
```
┌─────────────────────────────────────────────────────────────────┐
certctl Server (Control Plane)
│ - Let's Encrypt ACME issuer (HTTP-01 challenges)
│ - Local CA issuer (self-signed or sub-CA mode)
│ - PostgreSQL database (cert inventory, audit, jobs)
└─────────────────────────────────────────────────────────────────┘
│ API polling
┌─────────────────────────────────────────────────────────────────┐
│ certctl Agent │
│ - Discovers existing certs in /etc/nginx/ssl and /etc/app/ssl │
│ - Polls server for renewal/issuance/deployment jobs │
│ - Generates keys locally (agent-side crypto) │
│ - Deploys certs to NGINX and app service directories │
└─────────────────────────────────────────────────────────────────┘
│ │
▼ ▼
NGINX (public TLS) App Services (internal TLS)
(Let's Encrypt certs) (Local CA certs)
```mermaid
flowchart TD
subgraph Server ["certctl Server (Control Plane)"]
A["Let's Encrypt ACME issuer<br/>(HTTP-01 challenges)"]
B["Local CA issuer<br/>(self-signed or sub-CA mode)"]
C["PostgreSQL database<br/>(cert inventory, audit, jobs)"]
end
subgraph Agent ["certctl Agent"]
D["Discovers existing certs<br/>(/etc/nginx/ssl, /etc/app/ssl)"]
E["Polls server for<br/>renewal/issuance/deployment jobs"]
F["Generates keys locally<br/>(agent-side crypto)"]
G["Deploys certs to NGINX<br/>and app service directories"]
end
subgraph Targets ["Target Services"]
H["NGINX (public TLS)<br/>(Let's Encrypt certs)"]
I["App Services (internal TLS)<br/>(Local CA certs)"]
end
Server -->|API polling| Agent
Agent -->|Deploy| H
Agent -->|Deploy| I
```
## Prerequisites
@@ -212,7 +214,7 @@ Each agent independently manages its local cert inventory and deployments. The s
- For ACME, ensure ports 80/443 are open and your domain resolves
### Agent can't reach server
- Check network: `docker compose exec certctl-agent curl http://certctl-server:8443/api/v1/health`
- Check network: `docker compose exec certctl-agent curl http://certctl-server:8443/health`
- Verify `CERTCTL_SERVER_URL` environment variable
### No issuers showing up
@@ -26,7 +26,7 @@ services:
container_name: certctl-server-private-ca
environment:
# Database
DATABASE_URL: postgres://certctl:${DB_PASSWORD:-certctl-dev-password}@postgres:5432/certctl?sslmode=disable
CERTCTL_DATABASE_URL: postgres://certctl:${DB_PASSWORD:-certctl-dev-password}@postgres:5432/certctl?sslmode=disable
# Server settings
CERTCTL_SERVER_PORT: 8443
@@ -77,7 +77,7 @@ services:
networks:
- certctl-network
healthcheck:
test: ['CMD-SHELL', 'curl -sf http://localhost:8443/api/v1/health || exit 1']
test: ['CMD-SHELL', 'curl -sf http://localhost:8443/health || exit 1']
interval: 10s
timeout: 5s
retries: 3
@@ -17,29 +17,16 @@ This example demonstrates certctl managing certificates for **internal services
## Architecture
```
┌──────────────────┐
certctl-server(Local CA issuer)
│ (control │
│ plane) │
└────────┬─────────┘
REST API (job polling)
┌────────▼──────────┐
│ certctl-agent │ (certificate deployer)
└────────┬──────────┘
│ Write cert/key files
┌────────▼──────────────────────┐
│ Traefik │
│ (watches cert directory) │
└────────────────────────────────┘
│ TLS handshakes
[Internal Services]
```mermaid
flowchart TD
A["certctl-server<br/>(control plane)<br/>(Local CA issuer)"]
B["certctl-agent<br/>(certificate deployer)"]
C["Traefik<br/>(watches cert directory)"]
D["[Internal Services]"]
A -->|REST API<br/>job polling| B
B -->|Write cert/key files| C
C -->|TLS handshakes| D
```
## Quick Start (Self-Signed CA)
+2 -2
View File
@@ -81,7 +81,7 @@ services:
container_name: certctl-server-stepca-haproxy
environment:
# Database
DATABASE_URL: postgres://certctl:${DB_PASSWORD:-certctl-dev-password}@postgres:5432/certctl?sslmode=disable
CERTCTL_DATABASE_URL: postgres://certctl:${DB_PASSWORD:-certctl-dev-password}@postgres:5432/certctl?sslmode=disable
# Server settings
CERTCTL_SERVER_PORT: 8443
@@ -119,7 +119,7 @@ services:
networks:
- certctl-network
healthcheck:
test: ['CMD-SHELL', 'curl -sf http://localhost:8443/api/v1/health || exit 1']
test: ['CMD-SHELL', 'curl -sf http://localhost:8443/health || exit 1']
interval: 10s
timeout: 5s
retries: 3
+1 -1
View File
@@ -315,7 +315,7 @@ Common issues:
Verify network:
```bash
docker compose exec certctl-agent curl http://certctl-server:8443/api/v1/health
docker compose exec certctl-agent curl http://certctl-server:8443/health
```
### HAProxy config validation fails
+23 -23
View File
@@ -39,11 +39,11 @@ ON CONFLICT (id) DO NOTHING;
-- 3. Issuers
-- ============================================================
INSERT INTO issuers (id, name, type, config, enabled, created_at, updated_at) VALUES
('iss-local', 'Local Dev CA', 'local', '{"ca_common_name": "CertCtl Demo CA", "validity_days": 90}', true, NOW() - INTERVAL '180 days', NOW() - INTERVAL '180 days'),
('iss-acme-le', 'Let''s Encrypt Staging', 'acme', '{"directory_url": "https://acme-staging-v02.api.letsencrypt.org/directory", "email": "admin@example.com", "challenge_type": "http-01"}', true, NOW() - INTERVAL '150 days', NOW() - INTERVAL '150 days'),
('iss-stepca', 'step-ca Internal', 'stepca', '{"ca_url": "https://ca.internal:9000", "provisioner_name": "certctl", "validity_days": 90}', true, NOW() - INTERVAL '120 days', NOW() - INTERVAL '120 days'),
('iss-acme-zs', 'ZeroSSL (EAB)', 'acme', '{"directory_url": "https://acme.zerossl.com/v2/DV90", "email": "admin@example.com", "challenge_type": "http-01"}', true, NOW() - INTERVAL '60 days', NOW() - INTERVAL '60 days'),
('iss-openssl', 'Custom OpenSSL CA', 'openssl', '{"sign_script": "/opt/ca/sign.sh", "timeout_seconds": 30}', false, NOW() - INTERVAL '30 days', NOW() - INTERVAL '30 days'),
('iss-local', 'Local Dev CA', 'GenericCA', '{"ca_common_name": "CertCtl Demo CA", "validity_days": 90}', true, NOW() - INTERVAL '180 days', NOW() - INTERVAL '180 days'),
('iss-acme-le', 'Let''s Encrypt Staging', 'ACME', '{"directory_url": "https://acme-staging-v02.api.letsencrypt.org/directory", "email": "admin@example.com", "challenge_type": "http-01"}', true, NOW() - INTERVAL '150 days', NOW() - INTERVAL '150 days'),
('iss-stepca', 'step-ca Internal', 'StepCA', '{"ca_url": "https://ca.internal:9000", "provisioner_name": "certctl", "validity_days": 90}', true, NOW() - INTERVAL '120 days', NOW() - INTERVAL '120 days'),
('iss-acme-zs', 'ZeroSSL (EAB)', 'ACME', '{"directory_url": "https://acme.zerossl.com/v2/DV90", "email": "admin@example.com", "challenge_type": "http-01"}', true, NOW() - INTERVAL '60 days', NOW() - INTERVAL '60 days'),
('iss-openssl', 'Custom OpenSSL CA', 'OpenSSL', '{"sign_script": "/opt/ca/sign.sh", "timeout_seconds": 30}', false, NOW() - INTERVAL '30 days', NOW() - INTERVAL '30 days'),
('iss-vault', 'HashiCorp Vault PKI', 'VaultPKI', '{"addr": "https://vault.internal:8200", "mount": "pki", "role": "web-certs", "ttl": "8760h"}', true, NOW() - INTERVAL '20 days', NOW() - INTERVAL '20 days'),
('iss-digicert', 'DigiCert CertCentral', 'DigiCert', '{"base_url": "https://www.digicert.com/services/v2", "product_type": "ssl_basic"}', true, NOW() - INTERVAL '15 days', NOW() - INTERVAL '15 days')
ON CONFLICT (id) DO NOTHING;
@@ -52,33 +52,33 @@ ON CONFLICT (id) DO NOTHING;
-- 4. Agents (8 agents across multiple platforms)
-- ============================================================
INSERT INTO agents (id, name, hostname, status, last_heartbeat_at, registered_at, api_key_hash, os, architecture, ip_address, version) VALUES
('ag-web-prod', 'web-prod-agent', 'web-prod-01.internal', 'online', NOW() - INTERVAL '30 seconds', NOW() - INTERVAL '120 days', 'demo_hash_1', 'linux', 'amd64', '10.0.1.10', '2.0.14'),
('ag-web-staging', 'web-staging-agent', 'web-stg-01.internal', 'online', NOW() - INTERVAL '45 seconds', NOW() - INTERVAL '90 days', 'demo_hash_2', 'linux', 'amd64', '10.0.2.20', '2.0.14'),
('ag-lb-prod', 'lb-prod-agent', 'lb-prod-01.internal', 'online', NOW() - INTERVAL '15 seconds', NOW() - INTERVAL '150 days', 'demo_hash_3', 'linux', 'amd64', '10.0.1.50', '2.0.14'),
('ag-iis-prod', 'iis-prod-agent', 'iis-prod-01.internal', 'offline', NOW() - INTERVAL '3 hours', NOW() - INTERVAL '60 days', 'demo_hash_4', 'windows', 'amd64', '10.0.3.15', '2.0.12'),
('ag-data-prod', 'data-prod-agent', 'data-prod-01.internal', 'online', NOW() - INTERVAL '20 seconds', NOW() - INTERVAL '90 days', 'demo_hash_5', 'linux', 'arm64', '10.0.4.30', '2.0.14'),
('ag-edge-01', 'edge-eu-agent', 'edge-eu-01.internal', 'online', NOW() - INTERVAL '50 seconds', NOW() - INTERVAL '45 days', 'demo_hash_6', 'linux', 'arm64', '10.0.5.10', '2.0.14'),
('ag-k8s-prod', 'k8s-prod-agent', 'k8s-node-01.internal', 'online', NOW() - INTERVAL '10 seconds', NOW() - INTERVAL '30 days', 'demo_hash_7', 'linux', 'amd64', '10.0.6.10', '2.0.14'),
('ag-mac-dev', 'mac-dev-agent', 'dev-mac-01.internal', 'online', NOW() - INTERVAL '60 seconds', NOW() - INTERVAL '15 days', 'demo_hash_8', 'darwin', 'arm64', '10.0.7.5', '2.0.14')
('ag-web-prod', 'web-prod-agent', 'web-prod-01.internal', 'Online', NOW() - INTERVAL '30 seconds', NOW() - INTERVAL '120 days', 'demo_hash_1', 'linux', 'amd64', '10.0.1.10', '2.0.14'),
('ag-web-staging', 'web-staging-agent', 'web-stg-01.internal', 'Online', NOW() - INTERVAL '45 seconds', NOW() - INTERVAL '90 days', 'demo_hash_2', 'linux', 'amd64', '10.0.2.20', '2.0.14'),
('ag-lb-prod', 'lb-prod-agent', 'lb-prod-01.internal', 'Online', NOW() - INTERVAL '15 seconds', NOW() - INTERVAL '150 days', 'demo_hash_3', 'linux', 'amd64', '10.0.1.50', '2.0.14'),
('ag-iis-prod', 'iis-prod-agent', 'iis-prod-01.internal', 'Offline', NOW() - INTERVAL '3 hours', NOW() - INTERVAL '60 days', 'demo_hash_4', 'windows', 'amd64', '10.0.3.15', '2.0.12'),
('ag-data-prod', 'data-prod-agent', 'data-prod-01.internal', 'Online', NOW() - INTERVAL '20 seconds', NOW() - INTERVAL '90 days', 'demo_hash_5', 'linux', 'arm64', '10.0.4.30', '2.0.14'),
('ag-edge-01', 'edge-eu-agent', 'edge-eu-01.internal', 'Online', NOW() - INTERVAL '50 seconds', NOW() - INTERVAL '45 days', 'demo_hash_6', 'linux', 'arm64', '10.0.5.10', '2.0.14'),
('ag-k8s-prod', 'k8s-prod-agent', 'k8s-node-01.internal', 'Online', NOW() - INTERVAL '10 seconds', NOW() - INTERVAL '30 days', 'demo_hash_7', 'linux', 'amd64', '10.0.6.10', '2.0.14'),
('ag-mac-dev', 'mac-dev-agent', 'dev-mac-01.internal', 'Online', NOW() - INTERVAL '60 seconds', NOW() - INTERVAL '15 days', 'demo_hash_8', 'darwin', 'arm64', '10.0.7.5', '2.0.14')
ON CONFLICT (id) DO NOTHING;
-- Sentinel agent for network-discovered certificates
INSERT INTO agents (id, name, hostname, status, last_heartbeat_at, registered_at, api_key_hash, os, architecture, ip_address, version) VALUES
('server-scanner', 'Network Scanner (Server-Side)', 'certctl-server', 'online', NOW(), NOW() - INTERVAL '90 days', 'sentinel_no_auth', 'linux', 'amd64', '127.0.0.1', '2.0.14')
('server-scanner', 'Network Scanner (Server-Side)', 'certctl-server', 'Online', NOW(), NOW() - INTERVAL '90 days', 'sentinel_no_auth', 'linux', 'amd64', '127.0.0.1', '2.0.14')
ON CONFLICT (id) DO NOTHING;
-- ============================================================
-- 5. Deployment Targets (8 targets across multiple connector types)
-- ============================================================
INSERT INTO deployment_targets (id, name, type, agent_id, config, enabled, created_at, updated_at) VALUES
('tgt-nginx-prod', 'NGINX Production', 'nginx', 'ag-web-prod', '{"cert_path": "/etc/nginx/ssl/cert.pem", "key_path": "/etc/nginx/ssl/key.pem", "reload_command": "nginx -s reload"}', true, NOW() - INTERVAL '120 days', NOW()),
('tgt-nginx-staging', 'NGINX Staging', 'nginx', 'ag-web-staging', '{"cert_path": "/etc/nginx/ssl/cert.pem", "key_path": "/etc/nginx/ssl/key.pem", "reload_command": "nginx -s reload"}', true, NOW() - INTERVAL '90 days', NOW()),
('tgt-haproxy-prod', 'HAProxy Production', 'haproxy', 'ag-lb-prod', '{"combined_pem_path": "/etc/haproxy/ssl/site.pem", "reload_command": "systemctl reload haproxy"}', true, NOW() - INTERVAL '150 days', NOW()),
('tgt-apache-prod', 'Apache Production', 'apache', 'ag-web-prod', '{"cert_path": "/etc/httpd/ssl/cert.pem", "key_path": "/etc/httpd/ssl/key.pem", "chain_path": "/etc/httpd/ssl/chain.pem", "reload_command": "apachectl graceful"}', true, NOW() - INTERVAL '100 days', NOW()),
('tgt-iis-prod', 'IIS Production', 'iis', 'ag-iis-prod', '{"site_name": "Default Web Site", "binding_info": "*:443:"}', true, NOW() - INTERVAL '60 days', NOW()),
('tgt-traefik-prod', 'Traefik Production', 'traefik', 'ag-k8s-prod', '{"watch_dir": "/etc/traefik/dynamic/certs"}', true, NOW() - INTERVAL '30 days', NOW()),
('tgt-caddy-prod', 'Caddy Production', 'caddy', 'ag-edge-01', '{"mode": "api", "admin_url": "http://localhost:2019"}', true, NOW() - INTERVAL '45 days', NOW()),
('tgt-nginx-data', 'NGINX Data Services', 'nginx', 'ag-data-prod', '{"cert_path": "/etc/nginx/ssl/cert.pem", "key_path": "/etc/nginx/ssl/key.pem", "reload_command": "nginx -s reload"}', true, NOW() - INTERVAL '90 days', NOW())
('tgt-nginx-prod', 'NGINX Production', 'NGINX', 'ag-web-prod', '{"cert_path": "/etc/nginx/ssl/cert.pem", "key_path": "/etc/nginx/ssl/key.pem", "reload_command": "nginx -s reload"}', true, NOW() - INTERVAL '120 days', NOW()),
('tgt-nginx-staging', 'NGINX Staging', 'NGINX', 'ag-web-staging', '{"cert_path": "/etc/nginx/ssl/cert.pem", "key_path": "/etc/nginx/ssl/key.pem", "reload_command": "nginx -s reload"}', true, NOW() - INTERVAL '90 days', NOW()),
('tgt-haproxy-prod', 'HAProxy Production', 'HAProxy', 'ag-lb-prod', '{"combined_pem_path": "/etc/haproxy/ssl/site.pem", "reload_command": "systemctl reload haproxy"}', true, NOW() - INTERVAL '150 days', NOW()),
('tgt-apache-prod', 'Apache Production', 'Apache', 'ag-web-prod', '{"cert_path": "/etc/httpd/ssl/cert.pem", "key_path": "/etc/httpd/ssl/key.pem", "chain_path": "/etc/httpd/ssl/chain.pem", "reload_command": "apachectl graceful"}', true, NOW() - INTERVAL '100 days', NOW()),
('tgt-iis-prod', 'IIS Production', 'IIS', 'ag-iis-prod', '{"site_name": "Default Web Site", "binding_info": "*:443:"}', true, NOW() - INTERVAL '60 days', NOW()),
('tgt-traefik-prod', 'Traefik Production', 'Traefik', 'ag-k8s-prod', '{"watch_dir": "/etc/traefik/dynamic/certs"}', true, NOW() - INTERVAL '30 days', NOW()),
('tgt-caddy-prod', 'Caddy Production', 'Caddy', 'ag-edge-01', '{"mode": "api", "admin_url": "http://localhost:2019"}', true, NOW() - INTERVAL '45 days', NOW()),
('tgt-nginx-data', 'NGINX Data Services', 'NGINX', 'ag-data-prod', '{"cert_path": "/etc/nginx/ssl/cert.pem", "key_path": "/etc/nginx/ssl/key.pem", "reload_command": "nginx -s reload"}', true, NOW() - INTERVAL '90 days', NOW())
ON CONFLICT (id) DO NOTHING;
-- ============================================================
@@ -128,7 +128,7 @@ INSERT INTO certificate_profiles (id, name, description, allowed_key_algorithms,
ON CONFLICT (id) DO NOTHING;
-- ============================================================
-- 7. Managed Certificates (35 certs across multiple issuers and environments)
-- 7. Managed Certificates (32 certs across multiple issuers and environments)
-- ============================================================
INSERT INTO managed_certificates (id, name, common_name, sans, environment, owner_id, team_id, issuer_id, renewal_policy_id, status, expires_at, tags, last_renewal_at, last_deployment_at, created_at, updated_at) VALUES
-- ---- Active, healthy production certs (Local CA) ----