Skip to content

Commit 96928b0

Browse files
committed
test: generate TLS certs at runtime so CI does not depend on ignored examples/*.pem
- Add node-forge dev dependency and test/fixtures/tls-certs.ts helper - Refactor tls-manager.test.ts and tls-integration.test.ts to use generated certs - Fixes CI failures where examples/cert.pem and examples/key.pem are gitignored
1 parent b7a724f commit 96928b0

5 files changed

Lines changed: 100 additions & 18 deletions

File tree

bun.lock

Lines changed: 4 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
},
2929
"devDependencies": {
3030
"@types/bun": "^1.2.0",
31+
"node-forge": "^1.4.0",
3132
"prettier": "^3.6.2"
3233
},
3334
"main": "lib/index.js",

test/fixtures/tls-certs.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Runtime TLS certificate generation for tests.
3+
*
4+
* Avoids committing private keys to the repository while keeping TLS tests
5+
* self-contained and runnable in CI without external tools.
6+
*/
7+
8+
import * as forge from 'node-forge'
9+
import { mkdirSync, writeFileSync, existsSync } from 'fs'
10+
import { tmpdir } from 'os'
11+
import { join } from 'path'
12+
13+
export interface TestTLSCert {
14+
cert: string
15+
key: string
16+
certPath: string
17+
keyPath: string
18+
}
19+
20+
let cached: TestTLSCert | null = null
21+
22+
/**
23+
* Generates (or returns a cached) self-signed certificate/key pair.
24+
*/
25+
export function generateTestTLSCert(): TestTLSCert {
26+
if (cached) return cached
27+
28+
const keys = forge.pki.rsa.generateKeyPair(2048)
29+
const cert = forge.pki.createCertificate()
30+
cert.publicKey = keys.publicKey
31+
cert.serialNumber = '01'
32+
cert.validity.notBefore = new Date()
33+
cert.validity.notAfter = new Date()
34+
cert.validity.notAfter.setFullYear(cert.validity.notBefore.getFullYear() + 1)
35+
36+
const attrs = [
37+
{ name: 'commonName', value: 'localhost' },
38+
{ name: 'countryName', value: 'US' },
39+
{ shortName: 'ST', value: 'Test' },
40+
{ name: 'localityName', value: 'Test' },
41+
{ name: 'organizationName', value: 'Bungate Tests' },
42+
]
43+
cert.setSubject(attrs)
44+
cert.setIssuer(attrs)
45+
cert.setExtensions([
46+
{
47+
name: 'subjectAltName',
48+
altNames: [
49+
{ type: 2, value: 'localhost' },
50+
{ type: 7, ip: '127.0.0.1' },
51+
],
52+
},
53+
])
54+
55+
cert.sign(keys.privateKey, forge.md.sha256.create())
56+
57+
const certPem = forge.pki.certificateToPem(cert)
58+
const keyPem = forge.pki.privateKeyToPem(keys.privateKey)
59+
60+
const dir = join(tmpdir(), 'bungate-test-certs')
61+
if (!existsSync(dir)) {
62+
mkdirSync(dir, { recursive: true })
63+
}
64+
const certPath = join(dir, 'cert.pem')
65+
const keyPath = join(dir, 'key.pem')
66+
67+
writeFileSync(certPath, certPem)
68+
writeFileSync(keyPath, keyPem)
69+
70+
cached = { cert: certPem, key: keyPem, certPath, keyPath }
71+
return cached
72+
}

test/security/tls-integration.test.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ import { describe, test, expect, afterEach } from 'bun:test'
22
import { BunGateway } from '../../src/gateway/gateway'
33
import { BunGateLogger } from '../../src/logger/pino-logger'
44
import type { Server } from 'bun'
5+
import { generateTestTLSCert } from '../fixtures/tls-certs'
6+
7+
const testCert = generateTestTLSCert()
58

69
describe('TLS Integration with Gateway', () => {
710
let gateways: BunGateway[] = []
@@ -45,8 +48,8 @@ describe('TLS Integration with Gateway', () => {
4548
security: {
4649
tls: {
4750
enabled: true,
48-
cert: './examples/cert.pem',
49-
key: './examples/key.pem',
51+
cert: testCert.certPath,
52+
key: testCert.keyPath,
5053
minVersion: 'TLSv1.2',
5154
},
5255
},
@@ -87,8 +90,8 @@ describe('TLS Integration with Gateway', () => {
8790
security: {
8891
tls: {
8992
enabled: true,
90-
cert: './examples/cert.pem',
91-
key: './examples/key.pem',
93+
cert: testCert.certPath,
94+
key: testCert.keyPath,
9295
redirectHTTP: true,
9396
redirectPort: httpPort,
9497
},
@@ -176,8 +179,8 @@ describe('TLS Integration with Gateway', () => {
176179
security: {
177180
tls: {
178181
enabled: true,
179-
cert: readFileSync('./examples/cert.pem'),
180-
key: readFileSync('./examples/key.pem'),
182+
cert: readFileSync(testCert.certPath),
183+
key: readFileSync(testCert.keyPath),
181184
},
182185
},
183186
routes: [
@@ -202,8 +205,8 @@ describe('TLS Integration with Gateway', () => {
202205
security: {
203206
tls: {
204207
enabled: true,
205-
cert: './examples/cert.pem',
206-
key: './examples/key.pem',
208+
cert: testCert.certPath,
209+
key: testCert.keyPath,
207210
minVersion: 'TLSv1.3',
208211
},
209212
},

test/security/tls-manager.test.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ import {
66
} from '../../src/security/tls-manager'
77
import type { TLSConfig } from '../../src/security/config'
88
import { readFileSync } from 'fs'
9+
import { generateTestTLSCert } from '../fixtures/tls-certs'
10+
11+
const testCert = generateTestTLSCert()
912

1013
describe('TLSManager', () => {
1114
const validConfig: TLSConfig = {
1215
enabled: true,
13-
cert: './examples/cert.pem',
14-
key: './examples/key.pem',
16+
cert: testCert.certPath,
17+
key: testCert.keyPath,
1518
minVersion: 'TLSv1.2',
1619
}
1720

@@ -153,8 +156,8 @@ describe('TLSManager', () => {
153156
})
154157

155158
test('should accept certificate as Buffer', async () => {
156-
const certBuffer = readFileSync('./examples/cert.pem')
157-
const keyBuffer = readFileSync('./examples/key.pem')
159+
const certBuffer = readFileSync(testCert.certPath)
160+
const keyBuffer = readFileSync(testCert.keyPath)
158161
const config: TLSConfig = {
159162
enabled: true,
160163
cert: certBuffer,
@@ -171,7 +174,7 @@ describe('TLSManager', () => {
171174
const config: TLSConfig = {
172175
enabled: true,
173176
cert: './nonexistent-cert.pem',
174-
key: './examples/key.pem',
177+
key: testCert.keyPath,
175178
}
176179
const manager = new TLSManager(config)
177180
await expect(manager.loadCertificates()).rejects.toThrow(
@@ -182,7 +185,7 @@ describe('TLSManager', () => {
182185
test('should throw error for invalid key path', async () => {
183186
const config: TLSConfig = {
184187
enabled: true,
185-
cert: './examples/cert.pem',
188+
cert: testCert.certPath,
186189
key: './nonexistent-key.pem',
187190
}
188191
const manager = new TLSManager(config)
@@ -201,9 +204,9 @@ describe('TLSManager', () => {
201204
test('should load CA certificate when provided', async () => {
202205
const config: TLSConfig = {
203206
enabled: true,
204-
cert: './examples/cert.pem',
205-
key: './examples/key.pem',
206-
ca: './examples/cert.pem', // Using cert as CA for testing
207+
cert: testCert.certPath,
208+
key: testCert.keyPath,
209+
ca: testCert.certPath, // Using cert as CA for testing
207210
}
208211
const manager = new TLSManager(config)
209212
await manager.loadCertificates()

0 commit comments

Comments
 (0)