Two bugs caused mTLS to be silently disabled when all issued client
certificates for a CA were revoked:
1. New cert-based trust model (caddy.ts): When deriving CA IDs from
trusted cert IDs, revoked certs were invisible (active-only query),
causing derivedCaIds to be empty and the domain to be dropped from
mTlsDomainMap entirely — no mTLS policy at all. Fix by falling back
to a cert-ID-to-CA-ID lookup that includes revoked certs, keeping the
domain in the map so it gets a fail-closed policy.
2. Legacy CA-based model (caddy-mtls.ts): buildClientAuthentication
returned null when all certs were revoked, relying on Caddy's
experimental "drop" TLS connection policy field which didn't work
reliably. Fix by pinning to the CA cert itself as a trusted_leaf_certs
entry — no client cert can hash-match a CA certificate (and presenting
the CA cert would require its private key, already a full compromise).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extract pemToBase64Der and buildClientAuthentication from caddy.ts into
a new caddy-mtls.ts module, adding groupMtlsDomainsByCaSet to group mTLS
domains by their CA fingerprint before building TLS connection policies.
Previously all mTLS domains sharing a cert type (auto-managed, imported,
or managed) were grouped into a single policy, causing CA union: a client
cert from CA_B could authenticate against a host that only trusted CA_A.
The fix creates one policy per unique CA set, ensuring strict per-host
CA isolation across all three TLS policy code paths.
Also adds:
- tests/unit/caddy-mtls.test.ts (26 tests) covering pemToBase64Der,
buildClientAuthentication, groupMtlsDomainsByCaSet, and cross-CA
isolation regression tests
- tests/unit/instance-sync-env.test.ts (33 tests) for the five pure
env-reading functions in instance-sync.ts
- tests/integration/instance-sync.test.ts (16 tests) for
buildSyncPayload and applySyncPayload using an in-memory SQLite db
- Fix tests/helpers/db.ts to use a relative import for db/schema so it
works inside vi.mock factory dynamic imports
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>