@harperfast/integration-testing 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +71 -5
  2. package/dist/harperLifecycle.d.ts +20 -0
  3. package/dist/harperLifecycle.js +71 -40
  4. package/dist/harperLifecycle.js.map +1 -1
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/security/certGenUtils.d.ts +52 -0
  9. package/dist/security/certGenUtils.js +170 -0
  10. package/dist/security/certGenUtils.js.map +1 -0
  11. package/dist/security/crl/generate-test-certs.d.ts +34 -0
  12. package/dist/security/crl/generate-test-certs.js +81 -0
  13. package/dist/security/crl/generate-test-certs.js.map +1 -0
  14. package/dist/security/ocsp/generate-test-certs.d.ts +55 -0
  15. package/dist/security/ocsp/generate-test-certs.js +106 -0
  16. package/dist/security/ocsp/generate-test-certs.js.map +1 -0
  17. package/dist/security/ocspServer.d.ts +18 -0
  18. package/dist/security/ocspServer.js +132 -0
  19. package/dist/security/ocspServer.js.map +1 -0
  20. package/dist/securityServices.d.ts +49 -0
  21. package/dist/securityServices.js +120 -0
  22. package/dist/securityServices.js.map +1 -0
  23. package/dist/src/harperLifecycle.d.ts +156 -0
  24. package/dist/src/harperLifecycle.js +315 -0
  25. package/dist/src/harperLifecycle.js.map +1 -0
  26. package/dist/src/index.d.ts +3 -0
  27. package/dist/src/index.js +4 -0
  28. package/dist/src/index.js.map +1 -0
  29. package/dist/src/loopbackAddressPool.d.ts +50 -0
  30. package/dist/src/loopbackAddressPool.js +337 -0
  31. package/dist/src/loopbackAddressPool.js.map +1 -0
  32. package/dist/src/run.d.ts +2 -0
  33. package/dist/src/run.js +94 -0
  34. package/dist/src/run.js.map +1 -0
  35. package/dist/src/security/certGenUtils.d.ts +52 -0
  36. package/dist/src/security/certGenUtils.js +170 -0
  37. package/dist/src/security/certGenUtils.js.map +1 -0
  38. package/dist/src/security/crl/generate-test-certs.d.ts +34 -0
  39. package/dist/src/security/crl/generate-test-certs.js +81 -0
  40. package/dist/src/security/crl/generate-test-certs.js.map +1 -0
  41. package/dist/src/security/ocsp/generate-test-certs.d.ts +55 -0
  42. package/dist/src/security/ocsp/generate-test-certs.js +106 -0
  43. package/dist/src/security/ocsp/generate-test-certs.js.map +1 -0
  44. package/dist/src/security/ocspServer.d.ts +18 -0
  45. package/dist/src/security/ocspServer.js +132 -0
  46. package/dist/src/security/ocspServer.js.map +1 -0
  47. package/dist/src/securityServices.d.ts +49 -0
  48. package/dist/src/securityServices.js +120 -0
  49. package/dist/src/securityServices.js.map +1 -0
  50. package/dist/src/targz.d.ts +6 -0
  51. package/dist/src/targz.js +20 -0
  52. package/dist/src/targz.js.map +1 -0
  53. package/package.json +1 -1
package/README.md CHANGED
@@ -97,30 +97,96 @@ Kills Harper, releases the loopback address back to the pool, and removes the in
97
97
 
98
98
  Helper to POST an operation to the Operations API and assert HTTP 200.
99
99
 
100
- ### `ContextWithHarper`
100
+ ### `createHarperContext(name?)`
101
101
 
102
- TypeScript interface for the test context populated by `startHarper()`. When using `node:test`, pass it as the suite context type:
102
+ Creates a plain object satisfying `HarperTestContext`, for use outside `node:test` (e.g. Playwright worker fixtures). The `name` is optional and used for log directory naming.
103
+
104
+ ```ts
105
+ // Playwright example
106
+ const ctx = createHarperContext(`worker-${workerInfo.workerIndex}`);
107
+ await startHarper(ctx);
108
+ ```
109
+
110
+ ### Types
111
+
112
+ There are four related TypeScript types — it helps to understand how they compose.
113
+
114
+ **`HarperContext`** is the instance data object stored at `ctx.harper` after `startHarper()` resolves. It describes a running Harper instance:
103
115
 
104
116
  ```ts
105
117
  interface HarperContext {
106
- dataRootDir: string; // Harper install directory
118
+ dataRootDir: string; // absolute path to the Harper install directory
107
119
  admin: { username: string; password: string };
108
120
  httpURL: string; // e.g. 'http://127.0.0.2:9926'
109
121
  operationsAPIURL: string; // e.g. 'http://127.0.0.2:9925'
110
122
  hostname: string; // e.g. '127.0.0.2'
111
123
  process: ChildProcess;
112
- logDir?: string;
124
+ logDir?: string; // set when HARPER_INTEGRATION_TEST_LOG_DIR is configured
125
+ startupOutput?: { stdout: string; stderr: string }; // captured startup output
126
+ }
127
+ ```
128
+
129
+ **`HarperTestContext`** is the minimal context shape accepted by `startHarper()`, `setupHarperWithFixture()`, `killHarper()`, and `teardownHarper()`. It is intentionally loose so it can be satisfied by a plain object or a `node:test` context:
130
+
131
+ ```ts
132
+ interface HarperTestContext {
133
+ name?: string; // used for log directory naming
134
+ harper?: Partial<HarperContext>; // populated by startHarper()
135
+ }
136
+ ```
137
+
138
+ **`StartedHarperTestContext`** is the same as `HarperTestContext` but with `harper` guaranteed to be a fully populated `HarperContext`. It is the return type of `startHarper()` and `setupHarperWithFixture()`, and the required parameter type of `killHarper()` and `teardownHarper()`:
139
+
140
+ ```ts
141
+ interface StartedHarperTestContext extends HarperTestContext {
142
+ harper: HarperContext;
113
143
  }
114
144
  ```
115
145
 
146
+ **`ContextWithHarper`** is for `node:test` only. It extends both `SuiteContext` and `TestContext` from `node:test` with `harper: HarperContext`, so you can use it as the typed context parameter in a `suite()` callback:
147
+
148
+ ```ts
149
+ // node:test usage
150
+ suite('my suite', (ctx: ContextWithHarper) => {
151
+ before(async () => { await startHarper(ctx); });
152
+ after(async () => { await teardownHarper(ctx); });
153
+
154
+ test('example', async () => {
155
+ const res = await fetch(ctx.harper.httpURL);
156
+ });
157
+ });
158
+ ```
159
+
160
+ If you are not using `node:test`, use `createHarperContext()` to create a plain `HarperTestContext` instead.
161
+
116
162
  ### Server Log Capture
117
163
 
118
- When `HARPER_INTEGRATION_TEST_LOG_DIR` is set, each Harper instance writes its logs to a per-suite subdirectory. Logs from passing suites are automatically cleaned up; only failing suite logs are retained.
164
+ When `HARPER_INTEGRATION_TEST_LOG_DIR` is set, each Harper instance writes its logs to a per-suite subdirectory. Logs are preserved for the lifetime of the log directory. In CI, combine with artifact upload steps that run on failure to capture logs from failing runs.
119
165
 
120
166
  ```sh
121
167
  HARPER_INTEGRATION_TEST_LOG_DIR=/tmp/harper-test-logs npx harper-integration-test-run "integrationTests/**/*.test.ts"
122
168
  ```
123
169
 
170
+ Additionally, `startupOutput` on `HarperContext` provides the captured stdout/stderr from Harper startup for programmatic access (e.g. attaching to Playwright test results).
171
+
172
+ ### `HarperStartupError`
173
+
174
+ When Harper fails to start or times out, a `HarperStartupError` is thrown. It extends `Error` and includes structured `stdout` and `stderr` properties for diagnostics:
175
+
176
+ ```ts
177
+ import { HarperStartupError } from '@harperfast/integration-testing';
178
+
179
+ try {
180
+ await startHarper(ctx);
181
+ } catch (error) {
182
+ if (error instanceof HarperStartupError) {
183
+ console.error('Startup failed:', error.message);
184
+ console.error('stdout:', error.stdout);
185
+ console.error('stderr:', error.stderr);
186
+ }
187
+ }
188
+ ```
189
+
124
190
  ### `targz(dirPath)`
125
191
 
126
192
  Packs and compresses a directory into a base64-encoded tar.gz string. Useful for `deploy_component` Operations API calls.
@@ -30,6 +30,12 @@ export declare const OPERATIONS_API_PORT = 9925;
30
30
  export declare const DEFAULT_ADMIN_USERNAME = "admin";
31
31
  export declare const DEFAULT_ADMIN_PASSWORD = "Abc1234!";
32
32
  export declare const DEFAULT_STARTUP_TIMEOUT_MS: number;
33
+ /**
34
+ * The runtime to use for running Harper during tests.
35
+ * Set via the HARPER_RUNTIME environment variable ('node' or 'bun').
36
+ * Defaults to 'node'.
37
+ */
38
+ export declare const HARPER_RUNTIME: 'node' | 'bun';
33
39
  /**
34
40
  * Options for setting up a Harper instance.
35
41
  */
@@ -76,6 +82,11 @@ export interface HarperContext {
76
82
  process: ChildProcess;
77
83
  /** Absolute path to the log directory for this suite (only set when HARPER_INTEGRATION_TEST_LOG_DIR is configured) */
78
84
  logDir?: string;
85
+ /** Captured stdout/stderr from Harper startup, up to the point it reported ready. */
86
+ startupOutput?: {
87
+ stdout: string;
88
+ stderr: string;
89
+ };
79
90
  }
80
91
  /**
81
92
  * Test context interface with Harper instance details, for use with node:test.
@@ -89,6 +100,15 @@ export interface HarperContext {
89
100
  export interface ContextWithHarper extends SuiteContext, TestContext {
90
101
  harper: HarperContext;
91
102
  }
103
+ /**
104
+ * Error thrown when a Harper process fails to start or times out.
105
+ * Includes captured stdout and stderr for diagnostics.
106
+ */
107
+ export declare class HarperStartupError extends Error {
108
+ stdout: string;
109
+ stderr: string;
110
+ constructor(message: string, stdout: string, stderr: string);
111
+ }
92
112
  /**
93
113
  * Sets up a Harper instance with a component pre-installed from a local directory.
94
114
  *
@@ -1,5 +1,5 @@
1
1
  import { spawn, ChildProcess } from 'node:child_process';
2
- import { createWriteStream, existsSync, rmSync } from 'node:fs';
2
+ import { createWriteStream, existsSync } from 'node:fs';
3
3
  import { join, basename } from 'node:path';
4
4
  import { tmpdir } from 'node:os';
5
5
  import { mkdtemp, mkdir, rm, cp } from 'node:fs/promises';
@@ -19,13 +19,19 @@ export function createHarperContext(name) {
19
19
  // Constants
20
20
  const HTTP_PORT = 9926;
21
21
  const HTTPS_PORT = 9927;
22
+ const MQTT_PORT = 1883;
23
+ const MQTTS_PORT = 8883;
22
24
  export const OPERATIONS_API_PORT = 9925;
23
25
  export const DEFAULT_ADMIN_USERNAME = 'admin';
24
26
  export const DEFAULT_ADMIN_PASSWORD = 'Abc1234!';
25
- export const DEFAULT_STARTUP_TIMEOUT_MS = process.env.HARPER_INTEGRATION_TEST_STARTUP_TIMEOUT_MS
26
- ? parseInt(process.env.HARPER_INTEGRATION_TEST_STARTUP_TIMEOUT_MS, 10)
27
- : 30000;
27
+ export const DEFAULT_STARTUP_TIMEOUT_MS = parseInt(process.env.HARPER_INTEGRATION_TEST_STARTUP_TIMEOUT_MS || '', 10) || 60000;
28
28
  const LOG_DIR = process.env.HARPER_INTEGRATION_TEST_LOG_DIR;
29
+ /**
30
+ * The runtime to use for running Harper during tests.
31
+ * Set via the HARPER_RUNTIME environment variable ('node' or 'bun').
32
+ * Defaults to 'node'.
33
+ */
34
+ export const HARPER_RUNTIME = process.env.HARPER_RUNTIME || 'node';
29
35
  /**
30
36
  * Gets the path to the Harper CLI script.
31
37
  *
@@ -65,6 +71,14 @@ function getHarperScript(harperBinPath) {
65
71
  ` - HARPER_INTEGRATION_TEST_INSTALL_SCRIPT environment variable\n` +
66
72
  ` - Install 'harper' as a dependency in your project`);
67
73
  }
74
+ /**
75
+ * Strips ANSI escape sequences (colors, bold, underline, cursor movement, etc.) from a string.
76
+ */
77
+ // eslint-disable-next-line no-control-regex
78
+ const ANSI_REGEX = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nq-uy=><~]/g;
79
+ function stripAnsi(str) {
80
+ return str.replace(ANSI_REGEX, '');
81
+ }
68
82
  /**
69
83
  * Sanitizes a string for use as a filesystem directory name.
70
84
  */
@@ -74,17 +88,42 @@ function sanitizeForFilesystem(name) {
74
88
  .replace(/_+/g, '_')
75
89
  .substring(0, 100);
76
90
  }
91
+ /**
92
+ * Error thrown when a Harper process fails to start or times out.
93
+ * Includes captured stdout and stderr for diagnostics.
94
+ */
95
+ export class HarperStartupError extends Error {
96
+ stdout;
97
+ stderr;
98
+ constructor(message, stdout, stderr) {
99
+ let fullMessage = message;
100
+ if (stdout) {
101
+ fullMessage += `\n\nstdout:\n${stdout}`;
102
+ }
103
+ if (stderr) {
104
+ fullMessage += `\n\nstderr:\n${stderr}`;
105
+ }
106
+ super(fullMessage);
107
+ this.name = 'HarperStartupError';
108
+ this.stdout = stdout;
109
+ this.stderr = stderr;
110
+ }
111
+ }
77
112
  /**
78
113
  * Runs a Harper CLI command and captures output.
79
114
  *
80
115
  * When `logDir` is provided, stdout and stderr are also written to files
81
116
  * (`stdout.log` and `stderr.log`) in that directory.
82
117
  *
83
- * @throws {AssertionError} If the command exits with a non-zero status code
118
+ * @throws {HarperStartupError} If the command times out or exits with a non-zero status code
84
119
  */
85
- function runHarperCommand({ args, env, completionMessage, logDir, harperBinPath, }) {
120
+ function runHarperCommand({ args, env, completionMessage, logDir, harperBinPath, timeoutMs, }) {
86
121
  const harperScript = getHarperScript(harperBinPath);
87
- const proc = spawn('node', ['--trace-warnings', '--force-node-api-uncaught-exceptions-policy=true', harperScript, ...args], {
122
+ const runtime = HARPER_RUNTIME;
123
+ const runtimeArgs = runtime === 'bun'
124
+ ? [harperScript, ...args]
125
+ : ['--trace-warnings', '--force-node-api-uncaught-exceptions-policy=true', harperScript, ...args];
126
+ const proc = spawn(runtime, runtimeArgs, {
88
127
  env: { ...process.env, ...env },
89
128
  });
90
129
  let stdoutStream;
@@ -93,32 +132,27 @@ function runHarperCommand({ args, env, completionMessage, logDir, harperBinPath,
93
132
  stdoutStream = createWriteStream(join(logDir, 'stdout.log'));
94
133
  stderrStream = createWriteStream(join(logDir, 'stderr.log'));
95
134
  }
135
+ const effectiveTimeout = timeoutMs ?? DEFAULT_STARTUP_TIMEOUT_MS;
96
136
  return new Promise((resolve, reject) => {
97
137
  let stdout = '';
98
138
  let stderr = '';
99
139
  let timer = setTimeout(() => {
100
- let errorMessage = `Harper process timed out after ${DEFAULT_STARTUP_TIMEOUT_MS}ms`;
101
- if (stdout) {
102
- errorMessage += `\n\nstdout:\n${stdout}`;
103
- }
104
- if (stderr) {
105
- errorMessage += `\n\nstderr:\n${stderr}`;
106
- }
107
- reject(errorMessage);
140
+ reject(new HarperStartupError(`Harper process timed out after ${effectiveTimeout}ms`, stdout, stderr));
108
141
  proc.kill();
109
- }, DEFAULT_STARTUP_TIMEOUT_MS);
142
+ }, effectiveTimeout);
110
143
  proc.stdout?.on('data', (data) => {
111
- const dataString = data.toString();
112
- stdoutStream?.write(data);
144
+ const dataString = stripAnsi(data.toString());
145
+ stdoutStream?.write(dataString);
113
146
  if (completionMessage && dataString.includes(completionMessage)) {
114
147
  clearTimeout(timer);
115
- resolve(proc);
148
+ resolve({ process: proc, stdout, stderr });
116
149
  }
117
150
  stdout += dataString;
118
151
  });
119
152
  proc.stderr?.on('data', (data) => {
120
- stderrStream?.write(data);
121
- stderr += data.toString();
153
+ const dataString = stripAnsi(data.toString());
154
+ stderrStream?.write(dataString);
155
+ stderr += dataString;
122
156
  });
123
157
  proc.on('error', (error) => {
124
158
  reject(error);
@@ -126,15 +160,12 @@ function runHarperCommand({ args, env, completionMessage, logDir, harperBinPath,
126
160
  proc.on('exit', (statusCode, signal) => {
127
161
  clearTimeout(timer);
128
162
  if (statusCode === 0) {
129
- resolve(proc);
163
+ resolve({ process: proc, stdout, stderr });
130
164
  }
131
165
  else {
132
- let errorMessage = `Harper process failed with exit code/signal ${statusCode ?? signal}`;
166
+ const errorMessage = `Harper process failed with exit code/signal ${statusCode ?? signal}`;
133
167
  stderrStream?.write(errorMessage);
134
- if (stderr) {
135
- errorMessage += `\n\nstderr:\n${stderr}`;
136
- }
137
- reject(errorMessage);
168
+ reject(new HarperStartupError(errorMessage, stdout, stderr));
138
169
  }
139
170
  stdoutStream?.end();
140
171
  stderrStream?.end();
@@ -192,26 +223,18 @@ export async function startHarper(ctx, options) {
192
223
  let logDir;
193
224
  if (LOG_DIR) {
194
225
  const suiteName = sanitizeForFilesystem(ctx.name || 'unknown');
195
- logDir = join(LOG_DIR, `${suiteName}-${sanitizeForFilesystem(loopbackAddress)}`);
226
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
227
+ logDir = join(LOG_DIR, `${suiteName}-${sanitizeForFilesystem(loopbackAddress)}-${timestamp}`);
196
228
  await mkdir(logDir, { recursive: true });
197
229
  }
198
230
  // Point Harper's log directory to the suite log dir so hdb.log is preserved for upload
199
231
  const config = { ...options?.config };
200
232
  if (logDir) {
201
233
  config.logging = { ...config.logging, root: logDir };
202
- // Clean up log directory on successful exit — only keep logs when tests fail
203
- process.on('exit', (code) => {
204
- if (code === 0) {
205
- try {
206
- rmSync(logDir, { recursive: true, force: true });
207
- }
208
- catch { }
209
- }
210
- });
211
234
  }
212
235
  const args = [
213
236
  `--ROOTPATH=${dataRootDir}`,
214
- '--DEFAULTS_MODE=dev',
237
+ `--AUTHENTICATION_AUTHORIZELOCAL=true`,
215
238
  `--HDB_ADMIN_USERNAME=${DEFAULT_ADMIN_USERNAME}`,
216
239
  `--HDB_ADMIN_PASSWORD=${DEFAULT_ADMIN_PASSWORD}`,
217
240
  '--THREADS_COUNT=1',
@@ -219,6 +242,8 @@ export async function startHarper(ctx, options) {
219
242
  `--NODE_HOSTNAME=${loopbackAddress}`,
220
243
  `--HTTP_PORT=${loopbackAddress}:${HTTP_PORT}`,
221
244
  `--OPERATIONSAPI_NETWORK_PORT=${loopbackAddress}:${OPERATIONS_API_PORT}`,
245
+ `--MQTT_NETWORK_PORT=${loopbackAddress}:${MQTT_PORT}`,
246
+ `--MQTT_NETWORK_SECUREPORT=${loopbackAddress}:${MQTTS_PORT}`,
222
247
  '--LOGGING_LEVEL=debug',
223
248
  '--LOGGING_STDSTREAMS=false',
224
249
  ];
@@ -232,12 +257,13 @@ export async function startHarper(ctx, options) {
232
257
  HARPER_SET_CONFIG: JSON.stringify(config),
233
258
  ...options?.env,
234
259
  };
235
- const harperProcess = await runHarperCommand({
260
+ const result = await runHarperCommand({
236
261
  args,
237
262
  env: harperEnv,
238
263
  completionMessage: 'successfully started',
239
264
  logDir,
240
265
  harperBinPath: options?.harperBinPath,
266
+ timeoutMs: options?.startupTimeoutMs,
241
267
  });
242
268
  ctx.harper = {
243
269
  dataRootDir,
@@ -248,8 +274,9 @@ export async function startHarper(ctx, options) {
248
274
  httpURL: `http://${loopbackAddress}:${HTTP_PORT}`,
249
275
  operationsAPIURL: `http://${loopbackAddress}:${OPERATIONS_API_PORT}`,
250
276
  hostname: loopbackAddress,
251
- process: harperProcess,
277
+ process: result.process,
252
278
  logDir,
279
+ startupOutput: { stdout: result.stdout, stderr: result.stderr },
253
280
  };
254
281
  return ctx;
255
282
  }
@@ -258,6 +285,8 @@ export async function startHarper(ctx, options) {
258
285
  * @param ctx
259
286
  */
260
287
  export async function killHarper(ctx) {
288
+ if (!ctx.harper?.process)
289
+ return;
261
290
  await new Promise((resolve) => {
262
291
  let timer;
263
292
  ctx.harper.process.on('exit', () => {
@@ -297,6 +326,8 @@ export async function killHarper(ctx) {
297
326
  * ```
298
327
  */
299
328
  export async function teardownHarper(ctx) {
329
+ if (!ctx.harper)
330
+ return;
300
331
  await killHarper(ctx);
301
332
  await releaseLoopbackAddress(ctx.harper.hostname);
302
333
  // a few retries are typically necessary, might take a sec for a process to finish, especially since rocksdb may be flushing
@@ -1 +1 @@
1
- {"version":3,"file":"harperLifecycle.js","sourceRoot":"","sources":["../src/harperLifecycle.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"harperLifecycle.js","sourceRoot":"","sources":["../src/harperLifecycle.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { startHarper, setupHarperWithFixture, killHarper, teardownHarper, sendOperation, createHarperContext, OPERATIONS_API_PORT, DEFAULT_ADMIN_USERNAME, DEFAULT_ADMIN_PASSWORD, DEFAULT_STARTUP_TIMEOUT_MS, type StartHarperOptions, type HarperContext, type HarperTestContext, type StartedHarperTestContext, type ContextWithHarper, } from './harperLifecycle.ts';
1
+ export { startHarper, setupHarperWithFixture, killHarper, teardownHarper, sendOperation, createHarperContext, HarperStartupError, OPERATIONS_API_PORT, DEFAULT_ADMIN_USERNAME, DEFAULT_ADMIN_PASSWORD, DEFAULT_STARTUP_TIMEOUT_MS, HARPER_RUNTIME, type StartHarperOptions, type HarperContext, type HarperTestContext, type StartedHarperTestContext, type ContextWithHarper, } from './harperLifecycle.ts';
2
2
  export { validateLoopbackAddressPool, getNextAvailableLoopbackAddress, releaseLoopbackAddress, releaseAllLoopbackAddressesForCurrentProcess, } from './loopbackAddressPool.ts';
3
3
  export { targz } from './targz.ts';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { startHarper, setupHarperWithFixture, killHarper, teardownHarper, sendOperation, createHarperContext, OPERATIONS_API_PORT, DEFAULT_ADMIN_USERNAME, DEFAULT_ADMIN_PASSWORD, DEFAULT_STARTUP_TIMEOUT_MS, } from "./harperLifecycle.js";
1
+ export { startHarper, setupHarperWithFixture, killHarper, teardownHarper, sendOperation, createHarperContext, HarperStartupError, OPERATIONS_API_PORT, DEFAULT_ADMIN_USERNAME, DEFAULT_ADMIN_PASSWORD, DEFAULT_STARTUP_TIMEOUT_MS, HARPER_RUNTIME, } from "./harperLifecycle.js";
2
2
  export { validateLoopbackAddressPool, getNextAvailableLoopbackAddress, releaseLoopbackAddress, releaseAllLoopbackAddressesForCurrentProcess, } from "./loopbackAddressPool.js";
3
3
  export { targz } from "./targz.js";
4
4
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,WAAW,EACX,sBAAsB,EACtB,UAAU,EACV,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,GAM1B,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACN,2BAA2B,EAC3B,+BAA+B,EAC/B,sBAAsB,EACtB,4CAA4C,GAC5C,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,WAAW,EACX,sBAAsB,EACtB,UAAU,EACV,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,mBAAmB,EACnB,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,cAAc,GAMd,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACN,2BAA2B,EAC3B,+BAA+B,EAC/B,sBAAsB,EACtB,4CAA4C,GAC5C,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Pure Node.js X.509 certificate and CRL generation utilities
3
+ *
4
+ * Uses Node.js built-in webcrypto (Ed25519) + pkijs for ASN.1 encoding.
5
+ * No openssl CLI dependency — fully portable across macOS and Linux.
6
+ */
7
+ import * as pkijs from 'pkijs';
8
+ declare const OCSP_SIGNING_OID = "1.3.6.1.5.5.7.3.9";
9
+ declare const CLIENT_AUTH_OID = "1.3.6.1.5.5.7.3.2";
10
+ export interface Ed25519KeyPair {
11
+ privateKey: CryptoKey;
12
+ publicKey: CryptoKey;
13
+ /** PKCS8 PEM string */
14
+ privateKeyPem: string;
15
+ }
16
+ export declare function generateEd25519KeyPair(): Promise<Ed25519KeyPair>;
17
+ /** Convert a pkijs Certificate to PEM string */
18
+ export declare function certToPem(cert: pkijs.Certificate): string;
19
+ /** Convert a pkijs CertificateRevocationList to PEM string */
20
+ export declare function crlToPem(crl: pkijs.CertificateRevocationList): string;
21
+ interface CertOptions {
22
+ serialNumber: number;
23
+ subject: {
24
+ CN: string;
25
+ O?: string;
26
+ };
27
+ issuer: {
28
+ CN: string;
29
+ O?: string;
30
+ };
31
+ validDays: number;
32
+ issuerKey: CryptoKey;
33
+ subjectPublicKey: CryptoKey;
34
+ isCA?: boolean;
35
+ extensions?: pkijs.Extension[];
36
+ }
37
+ /** Create a signed Ed25519 X.509 v3 certificate */
38
+ export declare function createCertificate(opts: CertOptions): Promise<pkijs.Certificate>;
39
+ /** Create a CRL Distribution Points extension */
40
+ export declare function makeCRLDistributionPointsExt(url: string): pkijs.Extension;
41
+ /** Create an Authority Info Access extension with an OCSP URL */
42
+ export declare function makeOCSPAIAExt(url: string): pkijs.Extension;
43
+ /** Create an Extended Key Usage extension */
44
+ export declare function makeExtKeyUsageExt(oids: string[]): pkijs.Extension;
45
+ export { OCSP_SIGNING_OID, CLIENT_AUTH_OID };
46
+ /** Create a signed X.509v2 CRL */
47
+ export declare function createCRL(issuerCert: pkijs.Certificate, issuerKey: CryptoKey, revokedSerials: number[]): Promise<pkijs.CertificateRevocationList>;
48
+ /**
49
+ * Sign a pkijs BasicOCSPResponse with an Ed25519 key.
50
+ * Must be called after tbsResponseData.responses is populated.
51
+ */
52
+ export declare function signBasicOCSPResponse(basicResponse: pkijs.BasicOCSPResponse, privateKey: CryptoKey): Promise<void>;
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Pure Node.js X.509 certificate and CRL generation utilities
3
+ *
4
+ * Uses Node.js built-in webcrypto (Ed25519) + pkijs for ASN.1 encoding.
5
+ * No openssl CLI dependency — fully portable across macOS and Linux.
6
+ */
7
+ import { webcrypto } from 'node:crypto';
8
+ import * as pkijs from 'pkijs';
9
+ import * as asn1js from 'asn1js';
10
+ // Ed25519 OID (RFC 8410)
11
+ const ED25519_OID = '1.3.101.112';
12
+ // Standard extension OIDs
13
+ const BASIC_CONSTRAINTS_OID = '2.5.29.19';
14
+ const CRL_DISTRIBUTION_POINTS_OID = '2.5.29.31';
15
+ const AUTHORITY_INFO_ACCESS_OID = '1.3.6.1.5.5.7.1.1';
16
+ const EXT_KEY_USAGE_OID = '2.5.29.37';
17
+ const OCSP_SIGNING_OID = '1.3.6.1.5.5.7.3.9';
18
+ const CLIENT_AUTH_OID = '1.3.6.1.5.5.7.3.2';
19
+ const OCSP_ACCESS_METHOD_OID = '1.3.6.1.5.5.7.48.1';
20
+ // Configure pkijs to use Node.js webcrypto
21
+ pkijs.setEngine('node', new pkijs.CryptoEngine({ name: 'node', crypto: webcrypto }));
22
+ export async function generateEd25519KeyPair() {
23
+ // Ed25519 is supported at runtime (Node 20+) but @types/node lacks dedicated types for it
24
+ const keyPair = (await webcrypto.subtle.generateKey({ name: 'Ed25519' }, true, [
25
+ 'sign',
26
+ 'verify',
27
+ ]));
28
+ const pkcs8 = await webcrypto.subtle.exportKey('pkcs8', keyPair.privateKey);
29
+ const b64 = Buffer.from(pkcs8).toString('base64');
30
+ const lines = b64.match(/.{1,64}/g).join('\n');
31
+ const privateKeyPem = `-----BEGIN PRIVATE KEY-----\n${lines}\n-----END PRIVATE KEY-----\n`;
32
+ return { privateKey: keyPair.privateKey, publicKey: keyPair.publicKey, privateKeyPem };
33
+ }
34
+ /**
35
+ * Sign a pkijs Certificate or CertificateRevocationList with an Ed25519 key.
36
+ * Bypasses pkijs's sign() method which does not support Ed25519.
37
+ */
38
+ async function signWithEd25519(obj, privateKey) {
39
+ const algId = new pkijs.AlgorithmIdentifier({ algorithmId: ED25519_OID });
40
+ obj.signature = algId;
41
+ obj.signatureAlgorithm = algId;
42
+ const tbsBer = obj.encodeTBS().toBER();
43
+ obj.tbsView = new Uint8Array(tbsBer);
44
+ const sig = await webcrypto.subtle.sign('Ed25519', privateKey, tbsBer);
45
+ obj.signatureValue = new asn1js.BitString({ valueHex: sig });
46
+ }
47
+ /** Convert a pkijs Certificate to PEM string */
48
+ export function certToPem(cert) {
49
+ const der = cert.toSchema(false).toBER();
50
+ const b64 = Buffer.from(der).toString('base64');
51
+ return `-----BEGIN CERTIFICATE-----\n${b64.match(/.{1,64}/g).join('\n')}\n-----END CERTIFICATE-----\n`;
52
+ }
53
+ /** Convert a pkijs CertificateRevocationList to PEM string */
54
+ export function crlToPem(crl) {
55
+ const der = crl.toSchema(false).toBER();
56
+ const b64 = Buffer.from(der).toString('base64');
57
+ return `-----BEGIN X509 CRL-----\n${b64.match(/.{1,64}/g).join('\n')}\n-----END X509 CRL-----\n`;
58
+ }
59
+ /** Create a signed Ed25519 X.509 v3 certificate */
60
+ export async function createCertificate(opts) {
61
+ const cert = new pkijs.Certificate();
62
+ cert.version = 2; // v3
63
+ cert.serialNumber = new asn1js.Integer({ value: opts.serialNumber });
64
+ const now = new Date();
65
+ cert.notBefore.value = now;
66
+ cert.notAfter.value = new Date(now.getTime() + opts.validDays * 24 * 60 * 60 * 1000);
67
+ // Build subject RDN
68
+ const buildRDN = (dn, target) => {
69
+ target.typesAndValues.push(new pkijs.AttributeTypeAndValue({
70
+ type: '2.5.4.3',
71
+ value: new asn1js.Utf8String({ value: dn.CN }),
72
+ }));
73
+ if (dn.O) {
74
+ target.typesAndValues.push(new pkijs.AttributeTypeAndValue({
75
+ type: '2.5.4.10',
76
+ value: new asn1js.Utf8String({ value: dn.O }),
77
+ }));
78
+ }
79
+ };
80
+ buildRDN(opts.subject, cert.subject);
81
+ buildRDN(opts.issuer, cert.issuer);
82
+ // Import public key into SubjectPublicKeyInfo
83
+ const spki = await webcrypto.subtle.exportKey('spki', opts.subjectPublicKey);
84
+ const spkiAsn1 = asn1js.fromBER(spki);
85
+ cert.subjectPublicKeyInfo.fromSchema(spkiAsn1.result);
86
+ // Add basic constraints extension (always present)
87
+ cert.extensions = [];
88
+ const bc = new pkijs.BasicConstraints({ cA: opts.isCA === true });
89
+ cert.extensions.push(new pkijs.Extension({
90
+ extnID: BASIC_CONSTRAINTS_OID,
91
+ critical: true,
92
+ extnValue: bc.toSchema().toBER(),
93
+ }));
94
+ // Add caller-supplied extensions
95
+ if (opts.extensions) {
96
+ cert.extensions.push(...opts.extensions);
97
+ }
98
+ await signWithEd25519(cert, opts.issuerKey);
99
+ return cert;
100
+ }
101
+ /** Create a CRL Distribution Points extension */
102
+ export function makeCRLDistributionPointsExt(url) {
103
+ const dp = new pkijs.DistributionPoint({
104
+ distributionPoint: [new pkijs.GeneralName({ type: 6, value: url })],
105
+ });
106
+ const cdp = new pkijs.CRLDistributionPoints({ distributionPoints: [dp] });
107
+ return new pkijs.Extension({
108
+ extnID: CRL_DISTRIBUTION_POINTS_OID,
109
+ critical: false,
110
+ extnValue: cdp.toSchema().toBER(),
111
+ });
112
+ }
113
+ /** Create an Authority Info Access extension with an OCSP URL */
114
+ export function makeOCSPAIAExt(url) {
115
+ const desc = new pkijs.AccessDescription({
116
+ accessMethod: OCSP_ACCESS_METHOD_OID,
117
+ accessLocation: new pkijs.GeneralName({ type: 6, value: url }),
118
+ });
119
+ const aia = new pkijs.InfoAccess({ accessDescriptions: [desc] });
120
+ return new pkijs.Extension({
121
+ extnID: AUTHORITY_INFO_ACCESS_OID,
122
+ critical: false,
123
+ extnValue: aia.toSchema().toBER(),
124
+ });
125
+ }
126
+ /** Create an Extended Key Usage extension */
127
+ export function makeExtKeyUsageExt(oids) {
128
+ const seq = new asn1js.Sequence({
129
+ value: oids.map((oid) => new asn1js.ObjectIdentifier({ value: oid })),
130
+ });
131
+ return new pkijs.Extension({
132
+ extnID: EXT_KEY_USAGE_OID,
133
+ critical: false,
134
+ extnValue: seq.toBER(),
135
+ });
136
+ }
137
+ export { OCSP_SIGNING_OID, CLIENT_AUTH_OID };
138
+ /** Create a signed X.509v2 CRL */
139
+ export async function createCRL(issuerCert, issuerKey, revokedSerials) {
140
+ const crl = new pkijs.CertificateRevocationList();
141
+ crl.version = 1; // CRLv2 = version field value 1
142
+ // Copy issuer from CA cert subject
143
+ crl.issuer = issuerCert.subject;
144
+ const now = new Date();
145
+ const next = new Date(now.getTime() + 30 * 24 * 60 * 60 * 1000);
146
+ crl.thisUpdate = new pkijs.Time({ type: 0, value: now });
147
+ crl.nextUpdate = new pkijs.Time({ type: 0, value: next });
148
+ if (revokedSerials.length > 0) {
149
+ crl.revokedCertificates = revokedSerials.map((serial) => new pkijs.RevokedCertificate({
150
+ userCertificate: new asn1js.Integer({ value: serial }),
151
+ revocationDate: new pkijs.Time({ type: 0, value: now }),
152
+ }));
153
+ }
154
+ await signWithEd25519(crl, issuerKey);
155
+ return crl;
156
+ }
157
+ /**
158
+ * Sign a pkijs BasicOCSPResponse with an Ed25519 key.
159
+ * Must be called after tbsResponseData.responses is populated.
160
+ */
161
+ export async function signBasicOCSPResponse(basicResponse, privateKey) {
162
+ const algId = new pkijs.AlgorithmIdentifier({ algorithmId: ED25519_OID });
163
+ basicResponse.signatureAlgorithm = algId;
164
+ // Encode the TBS response data
165
+ const tbsDer = basicResponse.tbsResponseData.toSchema(true).toBER();
166
+ basicResponse.tbsResponseData.tbsView = new Uint8Array(tbsDer);
167
+ const sig = await webcrypto.subtle.sign('Ed25519', privateKey, tbsDer);
168
+ basicResponse.signature = new asn1js.BitString({ valueHex: sig });
169
+ }
170
+ //# sourceMappingURL=certGenUtils.js.map