diff --git a/.github/workflows/canary-release.yml b/.github/workflows/canary-release.yml index b414098aec..e7c00d9a2d 100644 --- a/.github/workflows/canary-release.yml +++ b/.github/workflows/canary-release.yml @@ -4,6 +4,11 @@ on: pull_request: types: [closed] +permissions: + contents: write + id-token: write + pull-requests: write + jobs: canary-release: name: Canary Release @@ -35,15 +40,22 @@ jobs: - name: Run canary release id: release env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + BASE_REF: ${{ github.event.pull_request.base.ref }} run: | - output=$(node packages/zero/tool/release.ts canary ${{ github.event.pull_request.base.ref }} --yes --skip-tests 2>&1 | tee /dev/stderr) + set -euo pipefail + + if [[ ! "$BASE_REF" =~ ^[A-Za-z0-9._/-]+$ ]]; then + echo "Invalid base ref: $BASE_REF" >&2 + exit 1 + fi + + output=$(node packages/zero/tool/release.ts canary "$BASE_REF" --yes 2>&1 | tee /dev/stderr) version=$(echo "$output" | grep -oP 'Published @rocicorp/zero@\K[^\s]+') echo "version=$version" >> "$GITHUB_OUTPUT" - name: Comment on PR env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ github.token }} run: | gh pr comment ${{ github.event.pull_request.number }} --body "## Canary Release Published diff --git a/packages/zero/tool/release.ts b/packages/zero/tool/release.ts index dac769b63a..b6ab533f81 100644 --- a/packages/zero/tool/release.ts +++ b/packages/zero/tool/release.ts @@ -12,6 +12,9 @@ async function main() { const {mode, from, remote, allowLocalChanges, dockerOnly, yes} = parseArgs(); try { + validateGitArg('ref', from); + validateGitArg('remote', remote); + // Find the git root directory const gitRoot = execute('git rev-parse --show-toplevel', {stdio: 'pipe'}); @@ -327,6 +330,22 @@ function parseReleaseVersionFromTag(ref: string) { return match?.[1]; } +function validateGitArg(name: string, value: string) { + if ( + value === '' || + value.startsWith('-') || + value.includes('..') || + value.includes('//') || + value.includes('@{') || + value.endsWith('/') || + value.endsWith('.') || + value.endsWith('.lock') || + !/^[A-Za-z0-9._/-]+$/.test(value) + ) { + throw new Error(`Invalid ${name}: ${value}`); + } +} + async function releaseCanary( currentVersion: string, remote: string, @@ -591,7 +610,6 @@ function pushGit(commitHash: string, destTag: string, remote: string) { function pushNPM(version: string, isCanary: boolean) { if (isCanary) { execute('npm publish --tag=canary', {cwd: basePath('packages', 'zero')}); - execute(`npm dist-tag rm @rocicorp/zero@${version} canary`); return; }