diff --git a/build-pipeline.js b/build-pipeline.js index e582c3d..5ef5d80 100644 --- a/build-pipeline.js +++ b/build-pipeline.js @@ -20,33 +20,91 @@ function cleanBuildDir() { fs.mkdirSync(BUILD_DIR, { recursive: true }); } +function removeSensitiveFiles(dir) { + if (!fs.existsSync(dir)) return; + + const gitDir = path.join(dir, '.git'); + if (fs.existsSync(gitDir)) { + fs.rmSync(gitDir, { recursive: true, force: true }); + } + + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const fullPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + if (entry.name === '.git') { + fs.rmSync(fullPath, { recursive: true, force: true }); + } else { + removeSensitiveFiles(fullPath); + } + } else { + if ( + entry.name.startsWith('.env') || + entry.name.endsWith('.key') || + entry.name.endsWith('.pem') || + entry.name === 'credentials.json' || + entry.name === '.gitlab-ci.yml' + ) { + fs.rmSync(fullPath, { force: true }); + } + } + } +} + function clonePrivateRepo(repoConfig, targetDir) { if (fs.existsSync(targetDir)) { fs.rmSync(targetDir, { recursive: true, force: true }); } + const token = process.env.GITLAB_TOKEN || process.env.VYLA_GITLAB_TOKEN; - const auth = token ? `oauth2:${token}@` : ''; - const repoUrl = `https://${auth}gitlab.com/${GITLAB_GROUP}/${repoConfig.name}.git`; - execSync(`git clone --depth 1 --branch ${repoConfig.branch} ${repoUrl} ${targetDir}`, { stdio: 'inherit' }); + const repoUrl = `https://gitlab.com/${GITLAB_GROUP}/${repoConfig.name}.git`; + + try { + if (token) { + const authHeader = Buffer.from(`oauth2:${token.trim()}`).toString('base64'); + execSync( + `git -c "http.extraHeader=Authorization: Basic ${authHeader}" clone --depth 1 --branch ${repoConfig.branch} ${repoUrl} "${targetDir}"`, + { stdio: 'inherit' } + ); + } else { + execSync( + `git clone --depth 1 --branch ${repoConfig.branch} ${repoUrl} "${targetDir}"`, + { stdio: 'inherit' } + ); + } + } finally { + const gitFolder = path.join(targetDir, '.git'); + if (fs.existsSync(gitFolder)) { + fs.rmSync(gitFolder, { recursive: true, force: true }); + } + } } async function build() { cleanBuildDir(); + for (const [key, config] of Object.entries(REPO_CONFIG)) { const targetDir = path.join(__dirname, key); + console.log(`Cloning ${config.name}...`); clonePrivateRepo(config, targetDir); + + console.log(`Installing production dependencies for ${config.name}...`); execSync('npm install --omit=dev', { cwd: targetDir, stdio: 'inherit' }); + + removeSensitiveFiles(targetDir); } const zip = new AdmZip(); const configDir = path.join(__dirname, 'config'); if (fs.existsSync(configDir)) { + removeSensitiveFiles(configDir); zip.addLocalFolder(configDir, 'config'); } for (const repo of REPOS) { const srcRepo = path.join(__dirname, repo); + removeSensitiveFiles(srcRepo); zip.addLocalFolder(srcRepo, repo); } @@ -54,6 +112,20 @@ async function build() { if (fs.existsSync(zipPath)) fs.rmSync(zipPath, { force: true }); zip.writeZip(zipPath); + const verificationZip = new AdmZip(zipPath); + const leakedEntries = verificationZip.getEntries().filter(e => + e.entryName.includes('.git/') || + e.entryName.includes('.git\\') || + e.entryName.startsWith('.env') || + e.entryName.includes('/.env') || + e.entryName.endsWith('config/encrypted-credentials.json') + ); + + if (leakedEntries.length > 0) { + fs.rmSync(zipPath, { force: true }); + throw new Error(`SECURITY ABORT: Archive contains forbidden files:\n${leakedEntries.map(e => e.entryName).join('\n')}`); + } + const hash = crypto.createHash('sha256'); hash.update(fs.readFileSync(zipPath)); const checksum = hash.digest('hex'); @@ -68,6 +140,8 @@ async function build() { for (const repo of REPOS) { fs.rmSync(path.join(__dirname, repo), { recursive: true, force: true }); } + + console.log('Build complete and verified clean.'); } build().catch(err => { diff --git a/frontend b/frontend deleted file mode 160000 index e23979c..0000000 --- a/frontend +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e23979cbe067245ebdd6db360c08aaa6dfd23024 diff --git a/package.json b/package.json index 4e3a59f..1ffe5f1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "vyla-go", - "version": "1.0.3", + "version": "1.0.5", "description": "Vyla Go Mobile Launcher", "main": "main.js", "scripts": { diff --git a/src-tauri/gen/android/buildSrc/src/main/java/com/vyla/go/kotlin/BuildTask.kt b/src-tauri/gen/android/buildSrc/src/main/java/com/vyla/go/kotlin/BuildTask.kt index a3de125..91c8683 100644 --- a/src-tauri/gen/android/buildSrc/src/main/java/com/vyla/go/kotlin/BuildTask.kt +++ b/src-tauri/gen/android/buildSrc/src/main/java/com/vyla/go/kotlin/BuildTask.kt @@ -21,7 +21,6 @@ open class BuildTask : DefaultTask() { runTauriCli(executable) } catch (e: Exception) { if (Os.isFamily(Os.FAMILY_WINDOWS)) { - // Try different Windows-specific extensions val fallbacks = listOf( "$executable.exe", "$executable.cmd", diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index c00a836..740eedd 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Vyla Go", - "version": "1.0.3", + "version": "1.0.5", "identifier": "com.vyla.go", "build": { "beforeDevCommand": "",