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
@@ -17,6 +17,10 @@ import {
} from '../common/enums';
import { ensureAppUrlEnv } from './app-url.util';
import { normalizeCreateApplicationDto } from './managed-service.util';
import {
assertRuntimeMatch,
detectRuntimeFromArchive,
} from '../build/runtime-detector';
@Injectable()
export class ApplicationsService {
@@ -271,12 +275,28 @@ export class ApplicationsService {
const zipPath = path.join(appDir, 'source.zip');
fs.writeFileSync(zipPath, file.buffer);
// Update app with code path
app.codePath = zipPath;
const saved = await this.appsRepository.save(app);
try {
const detected = await detectRuntimeFromArchive(zipPath);
assertRuntimeMatch(app.runtime, detected);
this.logger.log(`Uploaded code for ${app.name}${zipPath} (${(file.size / 1024).toFixed(1)} KB)`);
return saved;
app.codePath = zipPath;
const saved = await this.appsRepository.save(app);
if (detected.confidence === 'low') {
Object.assign(saved, {
runtimeWarning:
'Could not determine the project type from the archive with high confidence. Build may fail if the selected runtime is wrong.',
});
}
this.logger.log(`Uploaded code for ${app.name}${zipPath} (${(file.size / 1024).toFixed(1)} KB)`);
return saved;
} catch (err) {
if (fs.existsSync(zipPath)) {
fs.unlinkSync(zipPath);
}
throw err;
}
}
async uploadDbDump(id: string, userId: string, file: Express.Multer.File): Promise<Application> {