6.0 KiB
6.0 KiB
Tasks — testing-integration-step-ca
1. Package scaffolding
- 1.1 Create
packages/dev/testing-integration-step-ca/with the standard layout (package.json,tsconfig.json,vite.config.ts,README.md,src/index.ts,src/fixture/). - 1.2
package.json: name@suaveplan/testing-integration-step-ca, version0.1.0,peerDependenciesfor@suaveplan/testing-integrationandtestcontainers(NOTdependencies),dependenciesfor@suaveplan/errorand@suaveplan/typesonly. - 1.3 Subpath exports:
.,./fixture,./constants. - 1.4 Add the package to
CLAUDE.mdPackagessection, then runbun scripts/folder-reorg/generate-manifest.ts.
2. Image + constants
- 2.1 Pin
smallstep/step-cato a specific tag + digest insrc/constants/index.tsasSTEPCA_IMAGE. - 2.2 Define
STEPCA_HEALTH_TIMEOUT_MS = 60_000,STEPCA_HEALTH_POLL_INTERVAL_MS = 1000. - 2.3 Define
STEPCA_ENV_VARS = ['STEPCA_URL','STEPCA_ROOT_CERT_PEM','STEPCA_ROOT_CERT_PATH','STEPCA_FINGERPRINT','STEPCA_PROVISIONER_PASSWORD'] as const. - 2.4 Define
STEPCA_DEFAULT_PROVISIONER = 'api',STEPCA_DEFAULT_DNS = 'localhost,step-ca',STEPCA_INTERNAL_PORT = 8443.
3. Error codes
- 3.1 Register codes via
@suaveplan/error'sdefineCodeswith prefixINTEGRATION.STEP_CA.*:INIT_FAILED,JWK_PROVISIONER_FAILED,ROOT_READ_FAILED,FINGERPRINT_FAILED,ISSUE_CERT_FAILED,PARSE_PEM_FAILED,HEALTH_TIMEOUT.
4. Fixture core (src/fixture/step-ca-fixture.ts)
- 4.1 Implement
StepCaFixture implements ServiceFixture<StepCaConfig>withname === 'step-ca'. - 4.2 Constructor options:
{ image?; caName?; dnsNames?; provisionerName?; healthTimeoutMs?; healthPollIntervalMs?; containerFactory?; execFn?; fetchFn? }. - 4.3
start()env-bridge: when ALL FIVESTEPCA_ENV_VARSare set+non-empty → return passthrough config; partial (4 of 5) → fall through to container mode. - 4.4 Container mode: start container via factory (default: dynamic
GenericContainerimport), expose internal8443→ host port, set environment variables required by step-ca. - 4.5 Init sequence (steps 1–6 from proposal §What Changes/Container mode); each step wrapped in a try/catch that throws the matching
INTEGRATION.STEP_CA.*error with the underlying stderr attached. - 4.6 Materialize
rootCertPemto a host-side tmpfile (fs.mkdtempSync+tmp/<name>.crt), setrootCertPathaccordingly. - 4.7 If
waitForHealth()rejects, stop the container exactly once and clear the reference before re-throwing.
5. Health probe
- 5.1
healthCheck()returnsfalsewhen no container started. - 5.2 Container mode:
GET https://localhost:<caPort>/healthvia injectedfetchFn(defaultglobalThis.fetch) with TLS verification disabled (use a per-callhttps.AgentorBun-equivalent that the injected fetch can apply). Returnres.ok. Network errors →false. - 5.3
waitForHealth()delegates tonew HealthPoller({ timeoutMs, intervalMs }).poll(this)withSTEPCA_HEALTH_TIMEOUT_MS/STEPCA_HEALTH_POLL_INTERVAL_MSdefaults. - 5.4 Timeout rejection MUST be a
TestEnvironmentErrorwhose message containsHealth check timed out for fixture "step-ca".
6. issueCert() helper
- 6.1 Signature
issueCert({ commonName, sans?, ttl? }) → Promise<{ certPem; keyPem; chainPem; serial }>. - 6.2 Shells
step ca certificate <commonName> <crt> <key> --provisioner <provName> --provisioner-password-file <pwFile> --not-after=<ttl> --san <san1> --san <san2> ...inside the container via injectedexecFn. - 6.3 Reads cert + key from container, splits leaf + chain via PEM block parser (own implementation; no external dep), extracts serial via
step certificate inspect --format json. - 6.4 Throws
INTEGRATION.STEP_CA.ISSUE_CERT_FAILEDon non-zero exit;INTEGRATION.STEP_CA.PARSE_PEM_FAILEDon malformed PEM. - 6.5 Verifies
commonNameis non-empty before shelling — empty →INTEGRATION.STEP_CA.ISSUE_CERT_FAILED(no shell invocation).
7. Tests (100% Istanbul, per AGENTS.md §7)
- 7.1
src/fixture/step-ca-fixture.test.ts— passthrough mode (full + partial), container mode happy path, init sequence command order, image override,containerFactoryinjection,execFninjection,fetchFninjection, health-check truth table,waitForHealthtimeout + cleanup,stop()idempotency. - 7.2
src/fixture/step-ca-fixture-issue-cert.test.ts— issueCert happy path (with mockedexecFn), SAN passthrough, TTL passthrough, malformed PEM rejection, empty commonName rejection, non-zero exit rejection. - 7.3
src/fixture/step-ca-fixture-parse.test.ts— PEM block splitter (leaf + chain), serial extraction, edge cases (empty input, missing END line, multiple chain certs). - 7.4 Integration-level smoke test
src/fixture/step-ca-fixture.integration.test.ts(gated byINTEGRATION_DOCKER=1) that actually boots the container, issues a cert, and verifies the leaf chains to the root using Node'stls.createSecureContext({ ca: rootCertPem }).
8. Pre-publish gate
- 8.1
bunx turbo lint typecheck test --filter=@suaveplan/testing-integration-step-cagreen. - 8.2
bunx turbo test:coverage --filter=@suaveplan/testing-integration-step-careports 100% on touched modules. - 8.3 Spec-conformance test file (
src/fixture/step-ca-fixture.spec-conformance.test.ts) asserts every "Verified by" anchor inspecs/testing-integration-step-ca/spec.mdresolves to a real test.
9. Documentation
- 9.1 Root
README.mdfor the package: purpose, basic example (new StepCaFixture()+issueCert), advanced example (using the root cert withNODE_EXTRA_CA_CERTSand Playwright--ignore-certificate-errors-spki-list), API reference, implementation notes, ≥200 words. - 9.2 Co-located
.mdfor each implementation file perCLAUDE.mdDocumentation rules.
10. Archive
- 10.1 On ship: fold the spec delta into
openspec/specs/testing-integration-step-ca/spec.mdand move this folder toopenspec/archive/<yyyy-mm-dd>-testing-integration-step-ca/.