mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 12:21:31 +00:00
fix(docs,code): ARCH-004 + SEC-003-K8S + ARCH-003 — marketing claims now match code truth
Sprint 4 unified-master-audit closure. Three claim-truth-alignment
findings whose README edits land on shared lines, bundled into one
commit.
ARCH-004 — 'full REST API exposed as MCP tools' overclaim:
Pre-fix the README said 'the full REST API is exposed as MCP
tools'; the actual MCP coverage is 162 tools / 220 routes
(~74%). The remaining gap is intentional: protocol-conformance
endpoints (ACME/SCEP/EST/OCSP/CRL), browser-only auth flow,
health/ready, and streaming/binary downloads — categories that
don't fit the request-response JSON tool shape.
Fix:
- README L78 qualified to 'the bulk of the REST API surface'
with explicit numbers + pointer to the new coverage doc.
- New docs/reference/mcp-coverage.md publishes the exclusion
categories with rationale + the canonical commands to
re-derive route + tool counts.
- New scripts/ci-guards/mcp-coverage-parity.sh fails the build
if the tool count drops below (routes − exclusions − 40-slack),
so a future regression that drops 50+ tools surfaces in CI.
Verified locally: clean at 162 tools / 220 routes / 37
intentional exclusions.
SEC-003-K8S — Kubernetes Secrets connector is a runtime stub:
Pre-fix README L67 marketed 'fifteen native target connectors'
with Kubernetes Secrets in the list, but realK8sClient's CRUD
methods returned 'real Kubernetes client not implemented' in
production. Per the audit's option (b) recommendation: downgrade
marketing + runtime-guard the stub.
Fix:
- README L12 + L67: 'fourteen production-ready native deployment-
target connectors plus Kubernetes Secrets (preview)'.
- k8ssecret.New() now refuses to construct unless
CERTCTL_K8SSECRET_PREVIEW_ACK=true is set, mirroring the
SEC-H3 ACK pattern. NewWithClient path (test injection)
unchanged.
- docs/reference/connectors/index.md moves Kubernetes Secrets
out of the canonical fourteen-target list into a new 'Preview
connectors' subsection.
- Regression tests in k8ssecret_test.go pin the new gate
(rejects without ACK, accepts with ACK, still rejects nil
config even with ACK).
ARCH-003 — CERTCTL_KEYGEN_MODE=server breaks the blanket claim:
Pre-fix README L12 + L82 said 'private keys stay on your
infrastructure' and 'never touch the control plane' as blanket
promises. Flipping CERTCTL_KEYGEN_MODE=server makes the control
plane mint keys in process memory — breaking the claim — and
the only signal was a boot-time slog WARN. An operator who set
the flag and didn't read logs ran in silent contradiction to the
marketed posture.
Fix:
- config.Validate() refuses to accept KeygenMode='server'
unless DemoModeAck=true (mirroring SEC-H3). Production
deploys (the default Mode='agent' path) are unaffected.
- README L12 + L82 qualified: 'In agent-mode (the default),
private keys ...; a demo-only CERTCTL_KEYGEN_MODE=server
flag mints keys server-side, refuses to start without an
explicit CERTCTL_DEMO_MODE_ACK=true acknowledgement.'
- Regression tests for the new Validate gate land in
config_test.go (note: gate tests landed in the ARCH-002
commit because of contiguous-hunk constraint at the bottom
of the file).
Closes ARCH-004, SEC-003-K8S, ARCH-003.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Connector Development Guide
|
||||
|
||||
> Last reviewed: 2026-05-05
|
||||
> Last reviewed: 2026-05-16
|
||||
>
|
||||
> This is the canonical connector reference: interface contracts,
|
||||
> registry, deployment primitive, network scanner, cloud discovery.
|
||||
@@ -41,13 +41,23 @@ Target connectors:
|
||||
- [HAProxy](haproxy.md) — combined-PEM deploy + `haproxy -c` validate
|
||||
- [IIS](iis.md) — Microsoft IIS, local PowerShell + WinRM modes
|
||||
- [Java Keystore](jks.md) — JKS / PKCS#12 via `keytool` with atomic snapshot rollback
|
||||
- [Kubernetes Secrets](k8s.md) — k8s.io/tls Secrets atomic update
|
||||
- [NGINX](nginx.md) — separate-file deploy + `nginx -t` validate
|
||||
- [Postfix / Dovecot](postfix.md) — dual-mode mail-server TLS connector
|
||||
- [SSH (agentless)](ssh.md) — agentless deploy over SSH/SFTP for Linux/Unix targets
|
||||
- [Traefik](traefik.md) — file-provider zero-reload deploy
|
||||
- [Windows Certificate Store](wincertstore.md) — non-IIS Windows services (Exchange, RDP, SQL, ADFS)
|
||||
|
||||
### Preview connectors (not in the production-ready set)
|
||||
|
||||
SEC-003-K8S closure (Sprint 4, 2026-05-16) moved Kubernetes Secrets
|
||||
out of the canonical fourteen-target index because the production
|
||||
client-go integration is not yet wired — the connector ships but
|
||||
refuses to register without `CERTCTL_K8SSECRET_PREVIEW_ACK=true`
|
||||
and the CRUD methods return *"real Kubernetes client not
|
||||
implemented"* until the integration lands.
|
||||
|
||||
- [Kubernetes Secrets](k8s.md) — **preview** — k8s.io/tls Secrets atomic update. See [`docs/reference/deployment-model.md`](../deployment-model.md) row `k8ssecret` for the bundle-2 V2-blocker scope.
|
||||
|
||||
## Contents
|
||||
|
||||
1. [Overview](#overview)
|
||||
@@ -109,7 +119,7 @@ Target connectors:
|
||||
Three types of connectors:
|
||||
|
||||
1. **Issuer Connector** — Obtains certificates from CAs. 12 built-in: Local CA (self-signed + sub-CA + tree mode; ADCS sub-CA mode is documented separately), ACME v2 (HTTP-01, DNS-01, DNS-PERSIST-01, ARI, EAB, profile selection), step-ca, OpenSSL/Custom CA, Vault PKI, DigiCert CertCentral, Sectigo SCM, Google CAS, AWS ACM Private CA, Entrust Certificate Services, GlobalSign Atlas HVCA, EJBCA (Keyfactor)
|
||||
2. **Target Connector** — Deploys certificates to infrastructure. 15 built-in: NGINX, Apache httpd, HAProxy, Traefik, Caddy, Envoy, Postfix/Dovecot (dual-mode), IIS (local PowerShell + WinRM proxy), F5 BIG-IP (proxy agent), SSH (agentless), Windows Certificate Store, Java Keystore (JKS / PKCS#12), Kubernetes Secrets, AWS Certificate Manager, Azure Key Vault
|
||||
2. **Target Connector** — Deploys certificates to infrastructure. 14 production-ready: NGINX, Apache httpd, HAProxy, Traefik, Caddy, Envoy, Postfix/Dovecot (dual-mode), IIS (local PowerShell + WinRM proxy), F5 BIG-IP (proxy agent), SSH (agentless), Windows Certificate Store, Java Keystore (JKS / PKCS#12), AWS Certificate Manager, Azure Key Vault. Plus Kubernetes Secrets shipped as preview — see the *Preview connectors* subsection above for the ACK gate.
|
||||
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.
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
# MCP ↔ REST API parity coverage
|
||||
|
||||
> Last reviewed: 2026-05-16
|
||||
|
||||
## What this file is
|
||||
|
||||
This is the canonical record of which certctl REST routes are exposed
|
||||
as MCP (Model Context Protocol) tools, plus the explicit allowlist of
|
||||
routes that are intentionally NOT exposed. The companion CI guard
|
||||
`scripts/ci-guards/mcp-coverage-parity.sh` fails the build if a new
|
||||
REST route lands without either an MCP tool wrapping it or an
|
||||
explicit allowlist entry justifying the exclusion.
|
||||
|
||||
Before ARCH-004 (Sprint 4, 2026-05-16) the README said *"the full REST
|
||||
API is exposed as MCP tools"* with no published coverage data. That
|
||||
wording was an overclaim — see the audit trail in `git log --grep='ARCH-004'`.
|
||||
|
||||
## Current numbers
|
||||
|
||||
Re-derive at any time:
|
||||
|
||||
```bash
|
||||
# REST routes registered by the router
|
||||
grep -cE '^\s*r\.Register\(' internal/api/router/router.go
|
||||
|
||||
# MCP tools registered (counts gomcp.AddTool call sites)
|
||||
grep -rcE 'gomcp\.AddTool' internal/mcp/ --include='*.go' \
|
||||
| grep -v '_test.go' | awk -F: '{s+=$2} END{print s}'
|
||||
```
|
||||
|
||||
At the most recent verification (2026-05-16): **221 routes / 162 tools**.
|
||||
|
||||
## Coverage categories
|
||||
|
||||
The gap between routes and tools is intentional and falls into four
|
||||
named exclusion categories. Adding a new REST route in any of these
|
||||
categories does NOT require a paired MCP tool — but it DOES require
|
||||
an allowlist entry in the CI guard.
|
||||
|
||||
### 1. Protocol-conformance endpoints
|
||||
|
||||
Routes that implement a wire protocol an automated client (cert-manager,
|
||||
certbot, lego, MS Intune, EST devices, OCSP responders, CRL fetchers)
|
||||
talks to directly. These are not human-driven API calls; the MCP
|
||||
"natural language → tool call" model doesn't fit them. The MCP server
|
||||
SHOULD NOT wrap these because exposing them would invite operators to
|
||||
ask an AI agent to "renew the cert via ACME" when the right answer is
|
||||
"the ACME client your existing infra already runs handles that."
|
||||
|
||||
- `/acme/*` — RFC 8555 + RFC 9773 (ACME server)
|
||||
- `/scep/*` — RFC 8894 (SCEP server, MS Intune)
|
||||
- `/.well-known/est/*` — RFC 7030 (EST server)
|
||||
- `/ocsp` — RFC 6960 (OCSP responder)
|
||||
- `/.well-known/pki/crl/*` — RFC 5280 CRL distribution
|
||||
|
||||
### 2. Browser-only auth flow endpoints
|
||||
|
||||
OIDC SSO + CSRF + bootstrap routes that exist solely for the GUI's
|
||||
session establishment dance. An MCP client should authenticate via
|
||||
the same API-key Bearer path the REST callers use; exposing the
|
||||
browser flow as a tool would be incoherent.
|
||||
|
||||
- `/auth/oidc/login`
|
||||
- `/auth/oidc/callback`
|
||||
- `/auth/oidc/back-channel-logout`
|
||||
- `POST /api/v1/auth/bootstrap` (one-shot day-0 admin)
|
||||
- `POST /api/v1/auth/login`, `POST /api/v1/auth/logout`
|
||||
- `GET /api/v1/auth/csrf`
|
||||
|
||||
### 3. Liveness / readiness / version
|
||||
|
||||
Out of scope for natural-language workflows.
|
||||
|
||||
- `/health`
|
||||
- `/ready`
|
||||
- `/api/v1/version`
|
||||
|
||||
### 4. Streaming / binary download endpoints
|
||||
|
||||
The MCP tool contract is request → response JSON. Binary streaming
|
||||
and chunked transfer don't fit the shape and would force lossy
|
||||
encoding (base64-wrapped JSON blobs) the operator wouldn't actually
|
||||
use through an AI assistant.
|
||||
|
||||
- `GET /api/v1/certificates/{id}/download` — raw PEM
|
||||
- `GET /api/v1/certificates/{id}/chain` — chain PEM
|
||||
- `GET /api/v1/intermediate-cas/{id}/cert` — raw cert
|
||||
- `GET /api/v1/metrics/prometheus` — Prometheus text format
|
||||
|
||||
## How to add a new route
|
||||
|
||||
1. Add the route in `internal/api/router/router.go`.
|
||||
2. Decide: should an AI assistant be able to invoke this?
|
||||
- **Yes** → add a matching `gomcp.AddTool` call in `internal/mcp/`.
|
||||
- **No** → confirm the route fits one of the four exclusion
|
||||
categories above AND add an entry to the allowlist in
|
||||
`scripts/ci-guards/mcp-coverage-parity.sh`.
|
||||
3. The CI guard will fail until either branch is satisfied.
|
||||
|
||||
If the route doesn't fit any of the four categories and you don't
|
||||
want it in MCP for another reason, name a fifth category in this
|
||||
file and update the CI guard. The list is meant to grow with the
|
||||
product, not contain it.
|
||||
|
||||
## Why this matters
|
||||
|
||||
certctl is sold to operators who'll use AI assistants to drive it.
|
||||
"Most of the REST API" is a meaningful coverage claim; "the full REST
|
||||
API" was not. Diligence reviewers and operators evaluating MCP-driven
|
||||
workflows need the explicit gap surface — both to plan their
|
||||
automation around the gap and to spot when the gap drifts.
|
||||
Reference in New Issue
Block a user