HarperFast / HarperFast/harper-pro
fix(certificates): add_certificate does not fall back to reading the private key from disk, unlike create_csr
- Dominant language
- JavaScript
- Stars
- 3
- Forks
- 0
- Avg merge
- 1d 21h
- Merged PRs (30d)
- 80
Description
## Summary
`add_certificate` cannot resolve a private key for a supplied non-CA certificate when the matching key exists on disk but is not in the in-memory `privateKeys` map. The call fails and the certificate is not added, even though the correct key is sitting in the keys directory.
`createCsr` already handles exactly this case with a disk fallback. `addCertificate` does not. The two code paths are inconsistent.
## Root cause
`addCertificate` (`security/certificate.ts`, current `main`) resolves the key by scanning `getPrivateKeys()` only:
```ts
const privateKeys: Map = getPrivateKeys();
...
} else {
// No key provided — search existing keys to see if one matches this cert.
for (const [keyName, key] of privateKeys) {
if (x509Cert.checkPrivateKey(createPrivateKey(key))) { ... }
}
}
if (!is_authority && !private_key && !matchingKeyFound)
throw new ClientError('A suitable private key was not found for this certificate');
```
Per the comment in `createCsr`, that map is populated from **config-referenced paths only**. A Harper-generated CA key that exists on disk but is not named in `tls.privateKey` never appears there, so the lookup fails.
`createCsr` covers this by reading the key from the keys directory by `private_key_name`:
```ts
private_key = await readFile(join(hdbKeysDir, cert.private_key_name));
```
That fallback was added in b454b9a3 ("fix: read Harper CA private key from disk when not in privateKeys Map", 2026-05-13), which did not touch `addCertificate`.
This is reachable on any node where the CA key was auto-generated rather than configured — i.e. the normal state after Harper regenerates a CA, where the key lands as `privateKey.pem`.
## Reproduction
On a node whose Harper CA key exists on disk but is not referenced by `harper-config.yaml`:
1. `create_csr` → returns `pem` and `privateKeyName`
2. `sign_certificate` with that CSR → returns `certificate`
3. `add_certificate` with `name`, `certificate`, `uses: ["replication"]`, `is_authority: false` and **no** `private_key`
Observed: `A suitable private key was not found for this certificate`. `list_certificates` shows the certificate was not added. Passing `private_key` explicitly succeeds.
## Impact
Found during recovery of a 34-node dev cluster on 5.1.15. Because every node in that cluster was in the auto-generated-CA state, `add_certificate` failed on all of them, and no replication certificates were installed.
## Suggested fix
Give `addCertificate` the same disk fallback `createCsr` has: when no key is provided and none matches in the `privateKeys` map, attempt to read the key from the keys directory by `private_key_name` before failing.
## Secondary — needs confirmation on a 5.1.15 build
The failure was originally reported as *silent*: HTTP 200 with the failure text in a bare `message` field (the same field used for success, `"Successfully added certificate: "`), with no `error` key. Repair tooling that checks for a non-2xx status or an `error` key read that as success and continued against an unmodified cluster.
That does not match current source and could not be reproduced from it:
- `security/certificate.ts` **throws** `ClientError`, which sets `statusCode = 400` (core `utility/errors/hdbError.ts:49`), and has done so since Feb 2026 — before 5.1.15.
- Core's error serializer emits `{ error, message, status }` (`server/serverHelpers/contentTypes.ts:47`) and `server/http.ts:829` writes the real status.
So the 200-with-bare-`message` shape is likely specific to the operations UDS client path or to the 5.1.15 build rather than to this operation. Worth confirming separately — if an operation error can reach a caller status-200 and success-shaped, that is a broader operations-API problem than this ticket, and it belongs in core.
## Environment
- harper-pro 5.1.15, single container per host (legacy 1:1 topology)
- Reproduced on multiple nodes via the operations UDS
- Related but distinct: the RSA-only key-parsing defect already tracked separately; that was the root cause of the incident this was found during. This issue is only about key resolution in `add_certificate`.
Contributor guide
Assessment
This issue has not been assessed yet.