mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-19 11:31:03 +00:00
* feat: upload CLI binaries to CDN during release and gate workflow to core team
- Extend scripts/build/cli/upload.ts with uploadCliRelease() that pushes
archives + checksums to R2 under versioned (cli/v{VERSION}/) and latest
(cli/latest/) paths, plus a version.txt for lightweight latest resolution
- Update scripts/build/cli.ts entry point with --release/--version/--binaries-dir
flags (existing no-args behavior preserved for upload:cli-installers)
- Rewrite install.sh and install.ps1 to fetch from cdn.browseros.com instead of
GitHub releases API — eliminates rate limits and API dependency
- Add environment: release-core to release-cli.yml for core-team gating via
GitHub environment protection rules
- Add Bun setup + CDN upload step to the workflow between build and GitHub release
* fix: address review feedback for PR #602
- Make loadProdEnv return empty map when .env.production is absent so
pickEnv falls through to process.env in CI (Greptile P1)
- Add semver format validation for version string in install.sh and
install.ps1 to guard against malformed CDN responses
- Pass inputs.version via env var instead of inline ${{ }} interpolation
to prevent command injection in workflow shell
45 lines
1.3 KiB
TypeScript
45 lines
1.3 KiB
TypeScript
import { existsSync, readFileSync } from 'node:fs'
|
|
import { join } from 'node:path'
|
|
|
|
import { parse } from 'dotenv'
|
|
|
|
import type { R2Config } from '../server/types'
|
|
|
|
const PROD_ENV_PATH = join('apps', 'cli', '.env.production')
|
|
|
|
function pickEnv(name: string, fileEnv: Record<string, string>): string {
|
|
const value = process.env[name] ?? fileEnv[name]
|
|
if (!value || value.trim().length === 0) {
|
|
throw new Error(`Missing required environment variable: ${name}`)
|
|
}
|
|
return value
|
|
}
|
|
|
|
function loadProdEnv(rootDir: string): Record<string, string> {
|
|
const prodEnvPath = join(rootDir, PROD_ENV_PATH)
|
|
if (!existsSync(prodEnvPath)) {
|
|
// In CI, credentials come from process.env — no .env file needed
|
|
return {}
|
|
}
|
|
return parse(readFileSync(prodEnvPath, 'utf-8'))
|
|
}
|
|
|
|
export interface CliUploadConfig {
|
|
r2: R2Config
|
|
}
|
|
|
|
export function loadCliUploadConfig(rootDir: string): CliUploadConfig {
|
|
const fileEnv = loadProdEnv(rootDir)
|
|
return {
|
|
r2: {
|
|
accountId: pickEnv('R2_ACCOUNT_ID', fileEnv),
|
|
accessKeyId: pickEnv('R2_ACCESS_KEY_ID', fileEnv),
|
|
secretAccessKey: pickEnv('R2_SECRET_ACCESS_KEY', fileEnv),
|
|
bucket: pickEnv('R2_BUCKET', fileEnv),
|
|
downloadPrefix: '',
|
|
uploadPrefix:
|
|
process.env.R2_UPLOAD_PREFIX ?? fileEnv.R2_UPLOAD_PREFIX ?? 'cli',
|
|
},
|
|
}
|
|
}
|