Detect and validate app runtime from uploaded archives.

Reject zip uploads when the selected runtime does not match archive contents, and re-validate before Kaniko builds to fail fast instead of producing the wrong Dockerfile.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
keyhan
2026-06-30 00:27:03 +03:30
parent 837f0fa63f
commit 8d1855b89c
21 changed files with 654 additions and 98 deletions
+63
View File
@@ -1,5 +1,6 @@
import { Test, TestingModule } from '@nestjs/testing';
import { ConfigService } from '@nestjs/config';
import * as path from 'path';
import { BuildService } from './build.service';
import { Application } from '../applications/entities/application.entity';
import { AppRuntime } from '../common/enums';
@@ -53,6 +54,21 @@ describe('BuildService', () => {
expect(dockerfile).toContain('EXPOSE 8080');
});
it('generates Go Dockerfile with cmd package when present in archive entries', () => {
const app = {
runtime: AppRuntime.GO,
runtimeVersion: '1.22',
port: 8080,
} as Application;
const dockerfile = (service as any).generateDockerfile(app, [
'go.mod',
'cmd/server/main.go',
]) as string;
expect(dockerfile).toContain('go build -a -installsuffix cgo -ldflags="-w -s" -o main ./cmd/server');
});
it('generates Node.js Dockerfile with default port', () => {
const app = {
runtime: AppRuntime.NODEJS,
@@ -64,5 +80,52 @@ describe('BuildService', () => {
expect(dockerfile).toContain('FROM node:20');
expect(dockerfile).toContain('EXPOSE 3000');
});
it('generates Laravel Dockerfile with artisan migrate', () => {
const app = {
runtime: AppRuntime.LARAVEL,
phpVersion: '8.3',
} as Application;
const dockerfile = (service as any).generateDockerfile(app) as string;
expect(dockerfile).toContain('php:8.3');
expect(dockerfile).toContain('artisan migrate');
});
it('generates WordPress Dockerfile with official image', () => {
const app = {
runtime: AppRuntime.WORDPRESS,
runtimeVersion: '6.4',
} as Application;
const dockerfile = (service as any).generateDockerfile(app) as string;
expect(dockerfile).toContain('wordpress:6.4');
});
it('generates Django Dockerfile with detected settings module', () => {
const app = {
runtime: AppRuntime.DJANGO,
runtimeVersion: '3.12',
} as Application;
const dockerfile = (service as any).generateDockerfile(app, ['myproject/settings.py']) as string;
expect(dockerfile).toContain('DJANGO_SETTINGS_MODULE=myproject.settings');
expect(dockerfile).toContain('gunicorn');
});
it('generates .NET Dockerfile that restores nested csproj', () => {
const app = {
runtime: AppRuntime.DOTNET,
runtimeVersion: '8.0',
} as Application;
const dockerfile = (service as any).generateDockerfile(app, ['src/App/App.csproj']) as string;
expect(dockerfile).toContain('CSPROJ="src/App/App.csproj"');
expect(dockerfile).toContain('dotnet publish "$CSPROJ"');
});
});
});