TypeScript SSL certificate generation
- Dominant language
- TypeScript
- Stars
- 481
- Forks
- 108
- Avg merge
- 6d 8h
- Merged PRs (30d)
- 5
Description
## Parent PRD
#1670
## What to build
Replace `setup-ssl.sh` with a TypeScript implementation that uses the [`selfsigned`](https://www.npmjs.com/package/selfsigned) npm package (18M weekly downloads, MIT, WebCrypto-based) to generate self-signed SSL certificates. This eliminates the dependency on the system `openssl` package entirely, since Node.js bundles its own OpenSSL internally.
When `HOST` is set, generate:
1. Root CA: self-signed RSA 2048, SHA-256, 356-day validity, subject `/CN=Graph Explorer/C=US/L=Seattle`
2. Server key + cert: RSA 2048, signed by root CA, 365-day validity, SHA-256, with SAN `DNS.1 = $HOST:*` and key usage extensions
SANs, key usage, and basic constraints are passed programmatically to `selfsigned.generate()`, eliminating the need for `csr.conf` and `cert.conf` template files.
When `HOST` is not set, validate that existing cert files exist at `CERT_DIR` and reuse them. Error clearly if certs are missing.
### File changes
| Action | File | Notes |
|--------|------|-------|
| **New** | `proxy-server/src/setup-ssl.ts` | Exports `setupSsl(certDir, host?)` function |
| **New** | `proxy-server/src/setup-ssl-cli.ts` | CLI entry point reading `CERT_DIR`/`HOST` from env |
| **Modify** | `proxy-server/package.json` | Add `selfsigned` dependency |
| **Modify** | `docker-entrypoint.sh` | Call `node dist/setup-ssl-cli.js` instead of `./setup-ssl.sh` |
| **Modify** | `Dockerfile` | Remove `openssl` from `yum install` |
| **Modify** | `proxy-server/src/server.test.ts` | Replace `openssl` CLI in `createTempCerts()` with `selfsigned` |
| **Modify** | `docker-entrypoint.test.ts` | Update setup-ssl stub |
| **Delete** | `setup-ssl.sh` | Replaced by TypeScript |
| **Delete** | `cert-info/cert.conf`, `cert-info/csr.conf` | OpenSSL-specific, no longer needed |
### Backward compatibility
- **User-mounted certs**: Still work. Validation checks for `rootCA.key`, `rootCA.crt`, `server.key`, `server.crt`. Drop `server.csr` from required list (never used by the server).
- **Environment variables**: `HOST`, `CERT_DIR`, `PROXY_SERVER_HTTPS_CONNECTION` unchanged.
- **Output files**: Same paths, same PEM format. `server.csr` no longer generated (intermediate artifact the server never reads).
### Risks to consider
- **New dependency**: `selfsigned` pulls in `@peculiar/x509` and `pkijs`. All WebCrypto-based, no native code. Pin exact version.
- **`reflect-metadata` polyfill**: May be needed by `@peculiar/x509`. Test whether Node 24 has native support. Only runs at startup, not in the main server process.
- **Async API**: `selfsigned` v5 is async-only. Fine for a standalone CLI script.
### Suggested PR sequence
1. Add `selfsigned` + create `setup-ssl.ts` with tests (no behavior change)
2. Replace `openssl` CLI usage in `server.test.ts`
3. Switch `docker-entrypoint.sh` to Node.js script, delete `setup-ssl.sh`
4. Remove `openssl` from Dockerfile + clean up config files
## Acceptance criteria
- [ ] Generates the same cert chain as `setup-ssl.sh` when `HOST` is set
- [ ] Reuses existing certs when `HOST` is not set and certs exist
- [ ] Errors clearly when `HOST` is not set and certs are missing
- [ ] Uses `selfsigned` npm package — no system `openssl` dependency
- [ ] `csr.conf` and `cert.conf` template files are deleted
- [ ] `openssl` removed from Dockerfile `yum install`
- [ ] Generated certs work with `https.createServer`
- [ ] Generated server cert has correct SAN entries and is signed by root CA
- [ ] Unit tests cover cert generation, cert reuse, and missing cert error paths
- [ ] Docker image builds and runs successfully without system `openssl`
## Blocked by
None — can start immediately
## User stories addressed
- User story 5
- User story 6
## Related Issues
- Part of #1670
Contributor guide
Assessment
This issue has not been assessed yet.