Skip to content

Commit 409d899

Browse files
Merge pull request #10 from pipedrive/AINATIVEM-44
AINATIVEM-44 AES-256-GCM token encryption and docker-compose ComposeBuilder refactor
2 parents a9c8373 + ae5176a commit 409d899

4 files changed

Lines changed: 282 additions & 284 deletions

File tree

package-lock.json

Lines changed: 17 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: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@
1919
"dependencies": {
2020
"@clack/prompts": "^0.9.0",
2121
"dedent": "^1.7.2",
22-
"prettier": "^3.3.0"
22+
"prettier": "^3.3.0",
23+
"yaml": "^2.8.4"
2324
},
2425
"devDependencies": {
2526
"@eslint/js": "^9.0.0",

src/generators/node/database.test.ts

Lines changed: 65 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ describe('generateDatabase — docker-compose.yml', () => {
226226
expect(content).toContain('postgres:16');
227227
expect(content).toContain('db_data:/var/lib/postgresql/data');
228228
expect(content).toContain('pg_isready');
229-
expect(content).toContain("'-d', 'test-app'");
229+
expect(content).toContain(`POSTGRES_DB: ${pgOptions.projectName}`);
230230
expect(content).toContain('healthcheck');
231231
expect(content).toContain('backend');
232232
expect(content).toContain('tsx watch src/index.ts');
@@ -324,10 +324,10 @@ describe('generateDatabase — tokenRepository.ts', () => {
324324
expect(compose).toContain('app:');
325325
expect(compose).toContain('dockerfile: Dockerfile.app');
326326
expect(compose).toContain('user: root');
327-
expect(compose).toContain(
328-
'command: sh -c "chown -R node:node /app/node_modules && su-exec node sh -c \'echo Installing dependencies... && npm install --no-package-lock --no-audit --no-fund --loglevel=error && ./node_modules/.bin/tsx watch src/index.ts\'"',
329-
);
330-
expect(compose).toContain("'3000:3000'");
327+
expect(compose).toContain('tsx watch src/index.ts');
328+
expect(compose).toContain('su-exec node');
329+
expect(compose).toContain('chown -R node:node /app/node_modules');
330+
expect(compose).toContain('3000:3000');
331331
expect(compose).toContain('./package.json:/app/package.json:ro');
332332
expect(compose).toContain('app_node_modules:/app/node_modules');
333333
expect(compose).toContain('DATABASE_URL: file:./data.db');
@@ -337,10 +337,10 @@ describe('generateDatabase — tokenRepository.ts', () => {
337337
expect(compose).toContain('path: ./tsconfig.json');
338338
expect(compose).toContain('app-extension-ui:');
339339
expect(compose).toContain('dockerfile: Dockerfile.app-extension-ui');
340-
expect(compose).toContain(
341-
'command: sh -c "chown -R node:node /app/node_modules && su-exec node sh -c \'echo Installing dependencies... && npm install --no-package-lock --no-audit --no-fund --loglevel=error && npm run dev:frontend\'"',
342-
);
343-
expect(compose).toContain("'5173:5173'");
340+
expect(compose).toContain('npm run dev:frontend');
341+
expect(compose).toContain('su-exec node');
342+
expect(compose).toContain('chown -R node:node /app/node_modules');
343+
expect(compose).toContain('5173:5173');
344344
expect(compose).toContain('./package.json:/app/package.json:ro');
345345
expect(compose).toContain('app_extension_ui_node_modules:/app/node_modules');
346346
expect(compose).toContain('develop:');
@@ -386,6 +386,8 @@ describe('generateDatabase — tokenRepository.ts', () => {
386386
expect(compose).toContain('DATABASE_URL: postgresql://app:app@db:5432/test-app');
387387
expect(compose).toContain('depends_on:');
388388
expect(compose).toContain('condition: service_healthy');
389+
expect(compose).toContain('postgres_data:/var/lib/postgresql/data');
390+
expect(compose).not.toContain('db_data:');
389391
});
390392

391393
it('postgres schema uses text for access_token and refresh_token', async () => {
@@ -447,6 +449,60 @@ describe('generateDatabase — tokenRepository.ts', () => {
447449
});
448450
});
449451

452+
describe('generateDatabase — ComposeBuilder behavior', () => {
453+
it('sqlite compose has no db service and no database image', async () => {
454+
const { generateDatabase } = await import('./database.js');
455+
await generateDatabase(tmpDir, sqliteOptions);
456+
const content = await read('docker-compose.yml');
457+
expect(content).not.toContain('image:');
458+
expect(content).not.toContain('db:');
459+
});
460+
461+
it('postgres compose has db service with correct image, env, and healthcheck', async () => {
462+
const { generateDatabase } = await import('./database.js');
463+
await generateDatabase(tmpDir, pgOptions);
464+
const content = await read('docker-compose.yml');
465+
expect(content).toContain('postgres:16');
466+
expect(content).toContain('POSTGRES_USER: app');
467+
expect(content).toContain('POSTGRES_PASSWORD: app');
468+
expect(content).toContain(`POSTGRES_DB: ${pgOptions.projectName}`);
469+
expect(content).toContain('5432:5432');
470+
expect(content).toContain('pg_isready');
471+
expect(content).toContain('interval: 5s');
472+
expect(content).toContain('retries: 5');
473+
});
474+
475+
it('mysql compose has db service with correct image, env, and healthcheck', async () => {
476+
const { generateDatabase } = await import('./database.js');
477+
await generateDatabase(tmpDir, mysqlOptions);
478+
const content = await read('docker-compose.yml');
479+
expect(content).toContain('mysql:8');
480+
expect(content).toContain('MYSQL_ROOT_PASSWORD: app');
481+
expect(content).toContain('MYSQL_USER: app');
482+
expect(content).toContain(`MYSQL_DATABASE: ${mysqlOptions.projectName}`);
483+
expect(content).toContain('127.0.0.1:3307:3306');
484+
expect(content).toContain('mysqladmin');
485+
expect(content).toContain('interval: 5s');
486+
expect(content).toContain('retries: 5');
487+
});
488+
489+
it('when false: postgres compose without app extensions has no app-extension-ui service', async () => {
490+
const { generateDatabase } = await import('./database.js');
491+
await generateDatabase(tmpDir, pgOptions);
492+
const content = await read('docker-compose.yml');
493+
expect(content).not.toContain('app-extension-ui');
494+
expect(content).not.toContain('Dockerfile.app-extension-ui');
495+
});
496+
497+
it('mysql with app extensions uses mysql_data volume name', async () => {
498+
const { generateDatabase } = await import('./database.js');
499+
await generateDatabase(tmpDir, { ...mysqlOptions, appExtensions: ['custom-panel'] });
500+
const compose = await read('docker-compose.yml');
501+
expect(compose).toContain('mysql_data:/var/lib/mysql');
502+
expect(compose).not.toContain('db_data:');
503+
});
504+
});
505+
450506
describe('generateDatabase — Dockerfile', () => {
451507
it('generates Dockerfile with USER node when no app extensions', async () => {
452508
const { generateDatabase } = await import('./database.js');

0 commit comments

Comments
 (0)