Add missing V2 concepts (Certificate Profiles, Revocation with CRL/OCSP,
Short-Lived Certificates, CLI, MCP Server, Observability) to concepts guide.
Update quickstart with revocation examples, sorting/filtering, cursor pagination,
sparse fields, stats/metrics, and approval workflows. Align 5-minute demo guide
and advanced demo to full V2 feature set including revocation workflows, bulk ops,
fleet overview, and dashboard charts. Update architecture with MCP server section,
5th scheduler loop, API audit log, and 860+ test count. Add revocation-across-issuers
section to connectors guide.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Mark M20 as complete in V2 roadmap
- Add deployments endpoint to API overview
- Update endpoint count (76 → 77)
- Update test count to 860+
- Document new query params (sort, time-range, cursor, sparse fields)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
M17: Script-based issuer connector delegating sign/revoke/CRL to user-provided
scripts. Compatible with any CA tooling (OpenSSL, cfssl, custom PKI). Configurable
timeout, environment variable passthrough. 14 tests including timeout enforcement.
M16b: certctl-cli wraps all 76 REST API endpoints for terminal workflows. Supports
certs/agents/jobs list/get/renew/revoke/cancel, bulk PEM import with progress
reporting, server health status, table and JSON output formats. Zero external
dependencies (stdlib only). 14 tests with mock HTTP server.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
M19: HTTP middleware records every API call to the immutable audit trail
with method, path, actor, SHA-256 body hash, status, and latency. Best-effort
async recording via goroutine. Health/ready probes excluded.
M16a: Four pluggable notifier connectors — Slack (incoming webhook), Teams
(MessageCard), PagerDuty (Events API v2), OpsGenie (Alert API v2). Each
enabled by config env var. 30 new tests across middleware and connectors.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The reject job handler should accept nil/empty bodies (no reason given)
while still rejecting malformed JSON. Check for io.EOF and http.NoBody
to distinguish missing body from invalid body.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Upgrade from Go 1.22 to 1.25 (minimum for MCP SDK, actively supported).
CI updated to match.
Codebase audit fixes:
- Local CA parseIP() now uses net.ParseIP — IP SANs no longer silently dropped
- Nil pointer guards in agent.go GetWorkWithTargets for target/cert enrichment
- MCP CreateCertificateInput marks owner_id/team_id as required
- NGINX connector uses CombinedOutput() — captures diagnostic output on failure
- Jobs handler validates JSON decode on rejection body — returns 400 on malformed
- CRL/OCSP handlers propagate requestID for error tracing
MCP server tests (26 tests):
- client_test.go: HTTP client coverage (GET/POST/PUT/DELETE, auth, 204, errors, binary)
- tools_test.go: tool registration, pagination, end-to-end flows with mock API
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The MCP Go SDK (modelcontextprotocol/go-sdk) requires Go 1.23+. Previous
commit accidentally bumped to 1.25 via go mod tidy on a newer toolchain.
Pin to 1.23 as the minimum compatible version — closest to our original
1.22 baseline. CI updated to match.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
go.mod was bumped to go 1.25.0 by go mod tidy. CI was still on 1.22,
causing covdata tool errors. Also adds mcp-server binary to CI build step.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Separate standalone binary (cmd/mcp-server/) using official MCP Go SDK
(modelcontextprotocol/go-sdk v1.4.1) with stdio transport. Stateless HTTP
proxy translates MCP tool calls to certctl REST API requests. 76 tools
across 16 resource domains with typed input structs and jsonschema tags
for automatic LLM-friendly schema generation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Generate api/openapi.yaml from handler and domain source code. Covers
all 76 endpoints under /api/v1/ plus /health and /ready (78 total).
Includes full request/response schemas, domain model definitions,
enum types (CertificateStatus, JobType, RevocationReason, etc.),
reusable pagination envelope, error responses, and common parameters.
This spec serves as the contract for the upcoming MCP server (M18a)
and enables Swagger/Redocly interactive documentation immediately.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The error routing only checked for "issuer not found" but not
"certificate not found", causing cert-not-found errors to fall
through to a generic 500. Broadened the check to match any
"not found" error string for both CRL and OCSP handlers.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Service tests: newRevocationTestService() was missing SetIssuerRegistry(),
causing all 8 CRL/OCSP tests to fail with "issuer registry not configured".
Handler tests: CRL tests used /api/v1/issuers/{id}/crl but handler parses
/api/v1/crl/{id}. OCSP tests used query string ?serial=X but handler
expects path param /api/v1/ocsp/{id}/{serial}. Fixed all 9 test URLs.
All issues pre-date CI on v2-dev — introduced during M15b.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- revocation_test.go: certRepo unused in TestGenerateDERCRL_Success,
replaced with blank identifier
- lifecycle_test.go: missing revocationRepo init and setter calls
(SetRevocationRepo, SetNotificationService, SetIssuerRegistry)
that negative_test.go already had
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GenerateDERCRL and GetOCSPResponse don't take a context parameter,
but all 8 test calls passed context.Background() as the first arg.
Pre-existing issue never caught because CI wasn't running on v2-dev.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
GenerateCRL test was passing []issuer.RevokedCertEntry instead of
[]CRLEntry, causing go vet failure. Also fixed OCSPSignRequest
references to use service-layer type for consistency.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pushes to v2-dev were not running CI because the workflow only
triggered on master. Add v2-dev to the push branch list.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bulk certificate operations: multi-select checkboxes on certificates list with
bulk action bar for triggering renewal, revocation (with RFC 5280 reason modal
and progress bar), and owner reassignment across selected certificates.
Deployment status timeline: visual 4-step lifecycle pipeline (Requested → Issued
→ Deploying → Active) on certificate detail page, powered by per-cert job queries
with animated status indicators for active steps and failure states.
Inline policy editor: edit/save/cancel interface on certificate detail page for
changing renewal policy and certificate profile assignments via dropdown selectors
with lazy-loaded policy and profile lists.
Target connector configuration wizard: 3-step modal (Select Type → Configure →
Review) with type-specific configuration fields for NGINX, Apache, HAProxy, F5
BIG-IP, and IIS targets including required field validation.
Audit trail export: CSV and JSON download buttons on audit page with applied
filters preserved in export. Added action filter input for narrower searches.
Short-lived credentials dashboard: new page at /short-lived showing ephemeral
certificates (profile TTL < 1 hour) with live TTL countdown, auto-refresh every
10 seconds, profile lookup, and stats bar (active/expired/profiles).
DataTable enhanced with optional selectable/selectedKeys/onSelectionChange props
for checkbox multi-select with select-all toggle and row highlighting.
Frontend tests expanded from 53 to 79: full API client endpoint coverage for
profiles, owners, teams, agent groups, revocation, approval/rejection, policy
violations, and issuer creation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend:
- Embedded OCSP responder: GET /api/v1/ocsp/{issuer_id}/{serial} returns
signed OCSP responses (good/revoked/unknown) using CA key
- DER-encoded X.509 CRL: GET /api/v1/crl/{issuer_id} returns proper DER CRL
signed by issuing CA with 24h validity window
- Short-lived cert exemption: certs with profile TTL < 1 hour skip CRL/OCSP
(expiry is sufficient revocation for ephemeral workloads)
- Extended issuer connector interface with GenerateCRL and SignOCSPResponse
- Local CA implements full CRL/OCSP signing; ACME and step-ca return
appropriate "use native endpoint" errors
- IssuerConnectorAdapter bridges new methods between layers
Frontend:
- Revoke button on certificate detail page with RFC 5280 reason modal
- Revocation banner with reason display and timestamp
- Revocation status indicators in lifecycle section
- "Revoked" filter option in certificates list
- API client: revokeCertificate() function and Certificate type extensions
Tests: ~31 new tests across connector, service, handler, and adapter layers
Docs: milestones renumbered (M13-M14, M16-M18), M15b marked complete
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Strip explicit V2/V3 version labels from planned features in README,
architecture, connectors, and demo docs. F5/IIS now say "interface only"
and "implementation planned" without version targets. DigiCert and other
future issuers say "planned" without version numbers. Keeps completed
milestones detailed (social proof) while keeping future work abstract.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Trim V2 roadmap to free-tier features only (GUI operations, CLI, notifiers,
Prometheus metrics, OCSP, MCP server, filesystem discovery). Move enterprise
features to V3 with deliberately vague descriptions. Remove specific version
references for F5/IIS implementations and SSE/WebSocket from docs. Add
roadmap.md to gitignore for private strategy tracking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Update test counts (525+ → 600+), table counts (17 → 18), endpoint
counts (68 → 70), add revocation/CRL endpoints to API overview, add
certificate_revocations table to schema docs, update M15 roadmap to
show M15a complete and M15b remaining.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Implements core revocation infrastructure: POST /api/v1/certificates/{id}/revoke
with all 8 RFC 5280 reason codes, JSON-formatted CRL at GET /api/v1/crl, webhook
and email revocation notifications, best-effort issuer notification, and immutable
revocation audit trail. Includes 48 new tests across service, handler, integration,
and domain layers (600+ total). Fixes 3 pre-existing test bugs (team_test error
matching, agent_group delete status code, team handler per_page validation).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The seed_demo.sql referenced nonexistent agent IDs (agent-web-1, agent-api-1,
agent-db-1) in the agent_group_members table, causing a FK constraint violation
on fresh database initialization. Fixed to use the actual agent IDs defined
earlier in the same file (ag-web-prod, ag-web-staging, ag-iis-prod).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sub-CA mode: Local CA loads CA cert+key from disk (CERTCTL_CA_CERT_PATH +
CERTCTL_CA_KEY_PATH) to operate as subordinate CA under enterprise root
(e.g., ADCS). Supports RSA, ECDSA, PKCS#8 keys. Validates IsCA and
KeyUsageCertSign. Falls back to self-signed when paths unset.
DNS-01 challenges: Pluggable DNSSolver interface with script-based hook
implementation. User-provided scripts create/cleanup _acme-challenge TXT
records for any DNS provider. Configurable propagation wait. Enables
wildcard certs and non-HTTP-accessible hosts.
step-ca connector: Smallstep private CA via native /sign API with JWK
provisioner auth. Issuance, renewal, revocation. Registered as iss-stepca.
23 new tests across 3 files. CI test path widened to ./internal/connector/issuer/...
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The ballot passed 25-0-5 among CAs and 4-0-0 among browsers.
Not unanimous due to 5 CA abstentions (Entrust, IdenTrust,
Japan Registry Services, SECOM, TWCA).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Three architectural decisions from user feedback:
1. Pull-only deployment model — server never initiates outbound
connections. Network appliances (F5, Palo Alto, FortiGate, Citrix)
use a proxy agent in the same network zone. Added as design principle
#2 across all docs.
2. IIS dual-mode — agent-local PowerShell (primary/recommended) + proxy
agent WinRM (for agentless targets). Replaces the previous WinRM-only
design. Updated connectors.md, architecture.md, demo-advanced.md.
3. Sub-CA to ADCS — Local CA can load a pre-signed CA cert+key from
disk, so all issued certs chain to the enterprise root. Replaces the
planned standalone ADCS issuer connector. Updated concepts.md,
connectors.md, demo-advanced.md issuer diagram.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
README: lead with CA/Browser Forum Ballot SC-081v3 (47-day certs by 2029)
and certctl's end-to-end automation positioning. Update architecture
diagram and target lists to include Apache/HAProxy. Update roadmap
with new M15 (Revocation Infrastructure), renumbered M16-M18, and
V3.1 cert-manager/IAM Roles Anywhere additions.
concepts.md: rewrite "Why Do Certificates Expire?" with shrinking
lifespan timeline and automation imperative.
quickstart.md: add 47-day framing in intro.
architecture.md: add Apache/HAProxy to system diagram, target connector
diagram, deployment section, and ER diagram (agent metadata columns).
Update planned targets list for V3.1. Fix test count (230+).
connectors.md: fix notifier planned version reference (V2 not V2.1).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Agents now report OS, architecture, IP address, hostname, and version
via heartbeat using runtime.GOOS, runtime.GOARCH, and net.Dial. New
migration adds columns to agents table. Heartbeat handler, service,
and repository updated to accept and persist metadata. GUI shows
OS/Arch in agent list and full system info in agent detail page.
Apache httpd connector: separate cert/chain/key files, apachectl
configtest validation, graceful reload. HAProxy connector: combined
PEM file (cert+chain+key), optional config validation, reload.
Both wired into agent binary's target connector switch.
14 tests for new connectors. All existing tests updated for new
Heartbeat/UpdateHeartbeat signatures. Docs updated across README,
architecture, concepts, and connectors guides.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix demo certificate count: 14 → 15 across README, quickstart,
demo-guide (wildcard cert was added but count never updated)
- Fix negative_test subtest count: 12 → 14 in architecture.md
- Update README roadmap: v1.0.0 released (no longer "tag pending")
- Update status badge: "active development" → "v1.0.0"
- Remove stale POSTGRES_IMPLEMENTATION.md and POSTGRES_PATTERNS.md
(scaffold-era dev notes, not referenced anywhere)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Builds and pushes certctl-server and certctl-agent images to ghcr.io
when a version tag (v*) is pushed. Also creates a GitHub Release with
auto-generated release notes and Docker pull instructions.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- POSTGRES_PASSWORD and CERTCTL_API_KEY read from .env file
- Added deploy/.env.example with documentation
- Agent key volume (agent_keys) for key persistence across restarts
- Agent healthcheck via pgrep
- Resource limits: server 1CPU/512M, agent 0.5CPU/256M
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Exponential backoff on consecutive poll/heartbeat failures (max 5min)
- Panic recovery wrapper on agent.Run goroutine
- All 9 silent reportJobStatus errors now logged properly
- Key read failures return error and report job failure
- CommonName validation before CSR creation
- KeyDir permissions enforced with os.Chmod after MkdirAll
- splitPEMChain rewritten to use encoding/pem instead of string parsing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>