Unified · Split
| @@ -3,6 +3,9 @@ name: Publish (pkg.pr.new) · 2 unmodified lines | |||
| 3 | on: | 3 | on: |
| 4 | pull_request: | 4 | pull_request: |
| 5 | 5 | ||
| 6 | permissions: | ||
| 7 | contents: read | ||
| 8 | |||
| 6 | jobs: | 9 | jobs: |
| 7 | # Per-platform matrix: build the executor binary, tar it, upload to R2. | 10 | # Per-platform matrix: build the executor binary, tar it, upload to R2. |
| 8 | # The wrapper npm package is built later by the `publish` job which just | 11 | # The wrapper npm package is built later by the `publish` job which just |
| @@ -24,6 +27,8 @@ jobs: · 15 unmodified lines | |||
| 24 | runs-on: ${{ matrix.runner }} | 27 | runs-on: ${{ matrix.runner }} |
| 25 | steps: | 28 | steps: |
| 26 | - uses: actions/checkout@v4 | 29 | - uses: actions/checkout@v4 |
| 30 | with: | ||
| 31 | persist-credentials: false | ||
| 27 | 32 | ||
| 28 | - uses: oven-sh/setup-bun@v2 | 33 | - uses: oven-sh/setup-bun@v2 |
| 29 | with: | 34 | with: |
| @@ -60,8 +65,13 @@ jobs: · 30 unmodified lines | |||
| 60 | name: Publish | 65 | name: Publish |
| 61 | needs: build-preview-binary | 66 | needs: build-preview-binary |
| 62 | runs-on: ubuntu-latest | 67 | runs-on: ubuntu-latest |
| 68 | permissions: | ||
| 69 | contents: read | ||
| 70 | pull-requests: write | ||
| 63 | steps: | 71 | steps: |
| 64 | - uses: actions/checkout@v4 | 72 | - uses: actions/checkout@v4 |
| 73 | with: | ||
| 74 | persist-credentials: false | ||
| 65 | 75 | ||
| 66 | - uses: oven-sh/setup-bun@v2 | 76 | - uses: oven-sh/setup-bun@v2 |
| 67 | with: | 77 | with: |
| @@ -10,7 +10,7 @@ on: · 9 unmodified lines | |||
| 10 | type: string | 10 | type: string |
| 11 | 11 | ||
| 12 | permissions: | 12 | permissions: |
| 13 | contents: write | 13 | contents: read |
| 14 | 14 | ||
| 15 | concurrency: | 15 | concurrency: |
| 16 | group: publish-desktop-${{ github.ref }} | 16 | group: publish-desktop-${{ github.ref }} |
| @@ -18,6 +18,8 @@ concurrency: · 1 unmodified line | |||
| 18 | 18 | ||
| 19 | jobs: | 19 | jobs: |
| 20 | build: | 20 | build: |
| 21 | permissions: | ||
| 22 | contents: read | ||
| 21 | strategy: | 23 | strategy: |
| 22 | fail-fast: false | 24 | fail-fast: false |
| 23 | matrix: | 25 | matrix: |
| @@ -45,13 +47,25 @@ jobs: · 21 unmodified lines | |||
| 45 | - name: Checkout | 47 | - name: Checkout |
| 46 | uses: actions/checkout@v4 | 48 | uses: actions/checkout@v4 |
| 47 | with: | 49 | with: |
| 48 | ref: refs/tags/${{ inputs.tag }} | 50 | persist-credentials: false |
| 49 | 51 | ||
| 50 | - name: Setup Bun | 52 | - name: Setup Bun |
| 51 | uses: oven-sh/setup-bun@v2 | 53 | uses: oven-sh/setup-bun@v2 |
| 52 | with: | 54 | with: |
| 53 | bun-version: 1.3.11 | 55 | bun-version: 1.3.11 |
| 54 | 56 | ||
| 57 | - name: Validate release tag | ||
| 58 | env: | ||
| 59 | RAW_RELEASE_TAG: ${{ inputs.tag }} | ||
| 60 | run: bun run scripts/validate-release-ref.ts --tag-env RAW_RELEASE_TAG --write-env RELEASE_TAG | ||
| 61 | |||
| 62 | - name: Checkout release tag | ||
| 63 | env: | ||
| 64 | GH_TOKEN: ${{ github.token }} | ||
| 65 | run: | | ||
| 66 | git -c http.extraheader="AUTHORIZATION: bearer $GH_TOKEN" fetch --force --tags origin "refs/tags/$RELEASE_TAG:refs/tags/$RELEASE_TAG" | ||
| 67 | git checkout --detach "$RELEASE_TAG" | ||
| 68 | |||
| 55 | - name: Setup Node | 69 | - name: Setup Node |
| 56 | uses: actions/setup-node@v4 | 70 | uses: actions/setup-node@v4 |
| 57 | with: | 71 | with: |
| @@ -70,7 +84,7 @@ jobs: · 12 unmodified lines | |||
| 70 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | 84 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 71 | run: | | 85 | run: | |
| 72 | mkdir -p apps/desktop/resources | 86 | mkdir -p apps/desktop/resources |
| 73 | gh release download "${{ inputs.tag }}" --repo "${{ github.repository }}" --pattern "${{ matrix.cli-asset }}" --dir /tmp/cli-download | 87 | gh release download "$RELEASE_TAG" --repo "$GITHUB_REPOSITORY" --pattern "${{ matrix.cli-asset }}" --dir /tmp/cli-download |
| 74 | cd /tmp/cli-download | 88 | cd /tmp/cli-download |
| 75 | if [[ "${{ matrix.cli-asset }}" == *.tar.gz ]]; then | 89 | if [[ "${{ matrix.cli-asset }}" == *.tar.gz ]]; then |
| 76 | tar -xzf "${{ matrix.cli-asset }}" | 90 | tar -xzf "${{ matrix.cli-asset }}" |
| @@ -90,7 +104,7 @@ jobs: · 13 unmodified lines | |||
| 90 | shell: pwsh | 104 | shell: pwsh |
| 91 | run: | | 105 | run: | |
| 92 | New-Item -ItemType Directory -Force -Path "apps/desktop/resources" | 106 | New-Item -ItemType Directory -Force -Path "apps/desktop/resources" |
| 93 | gh release download "${{ inputs.tag }}" --repo "${{ github.repository }}" --pattern "${{ matrix.cli-asset }}" --dir "$env:TEMP/cli-download" | 107 | gh release download "$env:RELEASE_TAG" --repo "$env:GITHUB_REPOSITORY" --pattern "${{ matrix.cli-asset }}" --dir "$env:TEMP/cli-download" |
| 94 | Expand-Archive -Path "$env:TEMP/cli-download/${{ matrix.cli-asset }}" -DestinationPath "$env:TEMP/cli-extract" -Force | 108 | Expand-Archive -Path "$env:TEMP/cli-download/${{ matrix.cli-asset }}" -DestinationPath "$env:TEMP/cli-extract" -Force |
| 95 | Copy-Item "$env:TEMP/cli-extract/executor.exe" "apps/desktop/resources/executor.exe" | 109 | Copy-Item "$env:TEMP/cli-extract/executor.exe" "apps/desktop/resources/executor.exe" |
| 96 | if (Test-Path "$env:TEMP/cli-extract/emscripten-module.wasm") { | 110 | if (Test-Path "$env:TEMP/cli-extract/emscripten-module.wasm") { |
| @@ -119,8 +133,25 @@ jobs: · 22 unmodified lines | |||
| 119 | release: | 133 | release: |
| 120 | needs: build | 134 | needs: build |
| 121 | runs-on: ubuntu-latest | 135 | runs-on: ubuntu-latest |
| 136 | permissions: | ||
| 137 | contents: write | ||
| 122 | 138 | ||
| 123 | steps: | 139 | steps: |
| 140 | - name: Checkout validation script | ||
| 141 | uses: actions/checkout@v4 | ||
| 142 | with: | ||
| 143 | persist-credentials: false | ||
| 144 | |||
| 145 | - name: Setup Bun | ||
| 146 | uses: oven-sh/setup-bun@v2 | ||
| 147 | with: | ||
| 148 | bun-version: 1.3.11 | ||
| 149 | |||
| 150 | - name: Validate release tag | ||
| 151 | env: | ||
| 152 | RAW_RELEASE_TAG: ${{ inputs.tag }} | ||
| 153 | run: bun run scripts/validate-release-ref.ts --tag-env RAW_RELEASE_TAG --write-env RELEASE_TAG | ||
| 154 | |||
| 124 | - name: Download all artifacts | 155 | - name: Download all artifacts |
| 125 | uses: actions/download-artifact@v4 | 156 | uses: actions/download-artifact@v4 |
| 126 | with: | 157 | with: |
| @@ -133,5 +164,5 @@ jobs: · 6 unmodified lines | |||
| 133 | run: | | 164 | run: | |
| 134 | find artifacts -type f \( -name "*.dmg" -o -name "*.exe" -o -name "*.AppImage" -o -name "*.deb" \) | while read file; do | 165 | find artifacts -type f \( -name "*.dmg" -o -name "*.exe" -o -name "*.AppImage" -o -name "*.deb" \) | while read file; do |
| 135 | echo "Uploading: $file" | 166 | echo "Uploading: $file" |
| 136 | gh release upload "${{ inputs.tag }}" "$file" --repo "${{ github.repository }}" --clobber || true | 167 | gh release upload "$RELEASE_TAG" "$file" --repo "$GITHUB_REPOSITORY" --clobber || true |
| 137 | done | 168 | done |
| @@ -13,9 +13,7 @@ on: · 12 unmodified lines | |||
| 13 | type: string | 13 | type: string |
| 14 | 14 | ||
| 15 | permissions: | 15 | permissions: |
| 16 | actions: write | 16 | contents: read |
| 17 | contents: write | ||
| 18 | id-token: write | ||
| 19 | 17 | ||
| 20 | concurrency: | 18 | concurrency: |
| 21 | group: publish-executor-package-${{ github.ref }} | 19 | group: publish-executor-package-${{ github.ref }} |
| @@ -24,19 +22,35 @@ concurrency: · 2 unmodified lines | |||
| 24 | jobs: | 22 | jobs: |
| 25 | publish: | 23 | publish: |
| 26 | runs-on: ubuntu-latest | 24 | runs-on: ubuntu-latest |
| 25 | permissions: | ||
| 26 | actions: write | ||
| 27 | contents: write | ||
| 28 | id-token: write | ||
| 27 | 29 | ||
| 28 | steps: | 30 | steps: |
| 29 | - name: Checkout | 31 | - name: Checkout |
| 30 | uses: actions/checkout@v4 | 32 | uses: actions/checkout@v4 |
| 31 | with: | 33 | with: |
| 32 | fetch-depth: 0 | 34 | fetch-depth: 0 |
| 33 | ref: ${{ github.event_name == 'workflow_dispatch' && format('refs/tags/{0}', inputs.tag) || github.ref }} | 35 | persist-credentials: false |
| 34 | 36 | ||
| 35 | - name: Setup Bun | 37 | - name: Setup Bun |
| 36 | uses: oven-sh/setup-bun@v2 | 38 | uses: oven-sh/setup-bun@v2 |
| 37 | with: | 39 | with: |
| 38 | bun-version: 1.3.11 | 40 | bun-version: 1.3.11 |
| 39 | 41 | ||
| 42 | - name: Validate release tag | ||
| 43 | env: | ||
| 44 | RAW_RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} | ||
| 45 | run: bun run scripts/validate-release-ref.ts --tag-env RAW_RELEASE_TAG --write-env RELEASE_TAG | ||
| 46 | |||
| 47 | - name: Checkout release tag | ||
| 48 | env: | ||
| 49 | GH_TOKEN: ${{ github.token }} | ||
| 50 | run: | | ||
| 51 | git -c http.extraheader="AUTHORIZATION: bearer $GH_TOKEN" fetch --force --tags origin "refs/tags/$RELEASE_TAG:refs/tags/$RELEASE_TAG" | ||
| 52 | git checkout --detach "$RELEASE_TAG" | ||
| 53 | |||
| 40 | - name: Setup Node | 54 | - name: Setup Node |
| 41 | uses: actions/setup-node@v4 | 55 | uses: actions/setup-node@v4 |
| 42 | with: | 56 | with: |
| @@ -57,7 +71,6 @@ jobs: · 14 unmodified lines | |||
| 57 | - name: Publish package and create release | 71 | - name: Publish package and create release |
| 58 | env: | 72 | env: |
| 59 | GH_TOKEN: ${{ github.token }} | 73 | GH_TOKEN: ${{ github.token }} |
| 60 | RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} | ||
| 61 | run: | | 74 | run: | |
| 62 | export GITHUB_REF_TYPE=tag | 75 | export GITHUB_REF_TYPE=tag |
| 63 | export GITHUB_REF_NAME="$RELEASE_TAG" | 76 | export GITHUB_REF_NAME="$RELEASE_TAG" |
| @@ -67,5 +80,4 @@ jobs: · 3 unmodified lines | |||
| 67 | - name: Trigger desktop build | 80 | - name: Trigger desktop build |
| 68 | env: | 81 | env: |
| 69 | GH_TOKEN: ${{ github.token }} | 82 | GH_TOKEN: ${{ github.token }} |
| 70 | RELEASE_TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} | ||
| 71 | run: gh workflow run publish-desktop.yml -f tag="$RELEASE_TAG" | 83 | run: gh workflow run publish-desktop.yml -f tag="$RELEASE_TAG" |
| @@ -7,10 +7,7 @@ on: · 6 unmodified lines | |||
| 7 | - main | 7 | - main |
| 8 | 8 | ||
| 9 | permissions: | 9 | permissions: |
| 10 | actions: write | 10 | contents: read |
| 11 | contents: write | ||
| 12 | id-token: write | ||
| 13 | pull-requests: write | ||
| 14 | 11 | ||
| 15 | concurrency: | 12 | concurrency: |
| 16 | group: release-${{ github.ref }} | 13 | group: release-${{ github.ref }} |
| @@ -19,12 +16,18 @@ concurrency: · 2 unmodified lines | |||
| 19 | jobs: | 16 | jobs: |
| 20 | release: | 17 | release: |
| 21 | runs-on: ubuntu-latest | 18 | runs-on: ubuntu-latest |
| 19 | permissions: | ||
| 20 | actions: write | ||
| 21 | contents: write | ||
| 22 | id-token: write | ||
| 23 | pull-requests: write | ||
| 22 | 24 | ||
| 23 | steps: | 25 | steps: |
| 24 | - name: Checkout | 26 | - name: Checkout |
| 25 | uses: actions/checkout@v4 | 27 | uses: actions/checkout@v4 |
| 26 | with: | 28 | with: |
| 27 | fetch-depth: 0 | 29 | fetch-depth: 0 |
| 30 | persist-credentials: false | ||
| 28 | 31 | ||
| 29 | - name: Setup Bun | 32 | - name: Setup Bun |
| 30 | uses: oven-sh/setup-bun@v2 | 33 | uses: oven-sh/setup-bun@v2 |
| @@ -84,27 +87,36 @@ jobs: · 53 unmodified lines | |||
| 84 | 87 | ||
| 85 | echo "version=$version" >> "$GITHUB_OUTPUT" | 88 | echo "version=$version" >> "$GITHUB_OUTPUT" |
| 86 | 89 | ||
| 90 | - name: Validate release tag | ||
| 91 | if: steps.changesets.outputs.hasChangesets == 'false' && steps.detect_release.outputs.changed == 'true' | ||
| 92 | id: validate_release | ||
| 93 | env: | ||
| 94 | RELEASE_VERSION: ${{ steps.detect_release.outputs.version }} | ||
| 95 | run: bun run scripts/validate-release-ref.ts --version-env RELEASE_VERSION --output tag | ||
| 96 | |||
| 87 | - name: Create and push release tag | 97 | - name: Create and push release tag |
| 88 | if: steps.changesets.outputs.hasChangesets == 'false' && steps.detect_release.outputs.changed == 'true' | 98 | if: steps.changesets.outputs.hasChangesets == 'false' && steps.detect_release.outputs.changed == 'true' |
| 99 | env: | ||
| 100 | GH_TOKEN: ${{ github.token }} | ||
| 101 | RELEASE_TAG: ${{ steps.validate_release.outputs.tag }} | ||
| 89 | run: | | 102 | run: | |
| 90 | tag="v${{ steps.detect_release.outputs.version }}" | 103 | if git -c http.extraheader="AUTHORIZATION: bearer $GH_TOKEN" ls-remote --exit-code --tags origin "refs/tags/$RELEASE_TAG" >/dev/null 2>&1; then |
| 91 | if git ls-remote --exit-code --tags origin "refs/tags/$tag" >/dev/null 2>&1; then | 104 | echo "Tag $RELEASE_TAG already exists." |
| 92 | echo "Tag $tag already exists." | ||
| 93 | exit 0 | 105 | exit 0 |
| 94 | fi | 106 | fi |
| 95 | 107 | ||
| 96 | git config user.name "github-actions[bot]" | 108 | git config user.name "github-actions[bot]" |
| 97 | git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | 109 | git config user.email "41898282+github-actions[bot]@users.noreply.github.com" |
| 98 | git tag "$tag" | 110 | git tag "$RELEASE_TAG" |
| 99 | git push origin "$tag" | 111 | git -c http.extraheader="AUTHORIZATION: bearer $GH_TOKEN" push origin "$RELEASE_TAG" |
| 100 | 112 | ||
| 101 | - name: Trigger CLI publish | 113 | - name: Trigger CLI publish |
| 102 | if: steps.changesets.outputs.hasChangesets == 'false' && steps.detect_release.outputs.changed == 'true' | 114 | if: steps.changesets.outputs.hasChangesets == 'false' && steps.detect_release.outputs.changed == 'true' |
| 103 | env: | 115 | env: |
| 104 | GH_TOKEN: ${{ github.token }} | 116 | GH_TOKEN: ${{ github.token }} |
| 117 | RELEASE_TAG: ${{ steps.validate_release.outputs.tag }} | ||
| 105 | run: | | 118 | run: | |
| 106 | tag="v${{ steps.detect_release.outputs.version }}" | 119 | gh workflow run publish-executor-package.yml --ref "$RELEASE_TAG" -f tag="$RELEASE_TAG" |
| 107 | gh workflow run publish-executor-package.yml --ref "$tag" -f tag="$tag" | ||
| 108 | 120 | ||
| 109 | # Desktop build downloads CLI binaries from the release, so it must | 121 | # Desktop build downloads CLI binaries from the release, so it must |
| 110 | # run after CLI publish completes. Trigger it from the CLI workflow | 122 | # run after CLI publish completes. Trigger it from the CLI workflow |
| @@ -0,0 +1,70 @@ | |||
| 1 | #!/usr/bin/env bun | ||
| 2 | import { appendFileSync } from "node:fs"; | ||
| 3 | |||
| 4 | const RELEASE_VERSION_PATTERN = | ||
| 5 | /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|[A-Za-z-][0-9A-Za-z-]*))*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?$/u; | ||
| 6 | |||
| 7 | export const validateReleaseVersion = (value: string): string => { | ||
| 8 | if (!RELEASE_VERSION_PATTERN.test(value)) { | ||
| 9 | throw new Error(`Invalid release version: ${value}`); | ||
| 10 | } | ||
| 11 | return value; | ||
| 12 | }; | ||
| 13 | |||
| 14 | export const validateReleaseTag = (value: string): string => { | ||
| 15 | if (!value.startsWith("v")) { | ||
| 16 | throw new Error(`Invalid release tag: ${value}`); | ||
| 17 | } | ||
| 18 | validateReleaseVersion(value.slice(1)); | ||
| 19 | return value; | ||
| 20 | }; | ||
| 21 | |||
| 22 | const readEnv = (name: string): string => { | ||
| 23 | const value = process.env[name]; | ||
| 24 | if (!value) { | ||
| 25 | throw new Error(`Missing environment variable: ${name}`); | ||
| 26 | } | ||
| 27 | return value; | ||
| 28 | }; | ||
| 29 | |||
| 30 | const appendGitHubFile = (path: string | undefined, line: string): void => { | ||
| 31 | if (!path || !line) return; | ||
| 32 | appendFileSync(path, `${line}\n`, "utf8"); | ||
| 33 | }; | ||
| 34 | |||
| 35 | const run = (): void => { | ||
| 36 | const args = process.argv.slice(2); | ||
| 37 | const tagEnv = readOption(args, "--tag-env"); | ||
| 38 | const versionEnv = readOption(args, "--version-env"); | ||
| 39 | const writeEnv = readOption(args, "--write-env"); | ||
| 40 | const outputName = readOption(args, "--output"); | ||
| 41 | |||
| 42 | if (tagEnv && versionEnv) { | ||
| 43 | throw new Error("Use either --tag-env or --version-env, not both"); | ||
| 44 | } | ||
| 45 | if (!tagEnv && !versionEnv) { | ||
| 46 | throw new Error("Expected --tag-env or --version-env"); | ||
| 47 | } | ||
| 48 | |||
| 49 | const tag = tagEnv | ||
| 50 | ? validateReleaseTag(readEnv(tagEnv)) | ||
| 51 | : `v${validateReleaseVersion(readEnv(versionEnv!))}`; | ||
| 52 | |||
| 53 | appendGitHubFile(process.env.GITHUB_ENV, writeEnv ? `${writeEnv}=${tag}` : ""); | ||
| 54 | appendGitHubFile(process.env.GITHUB_OUTPUT, outputName ? `${outputName}=${tag}` : ""); | ||
| 55 | console.log(`Validated release tag ${tag}`); | ||
| 56 | }; | ||
| 57 | |||
| 58 | const readOption = (args: ReadonlyArray<string>, name: string): string | undefined => { | ||
| 59 | const index = args.indexOf(name); | ||
| 60 | if (index === -1) return undefined; | ||
| 61 | const value = args[index + 1]; | ||
| 62 | if (!value || value.startsWith("--")) { | ||
| 63 | throw new Error(`Missing value for ${name}`); | ||
| 64 | } | ||
| 65 | return value; | ||
| 66 | }; | ||
| 67 | |||
| 68 | if (import.meta.main) { | ||
| 69 | run(); | ||
| 70 | } | ||
| @@ -0,0 +1,55 @@ | |||
| 1 | import { describe, expect, it } from "@effect/vitest"; | ||
| 2 | import { readFileSync } from "node:fs"; | ||
| 3 | import { resolve } from "node:path"; | ||
| 4 | |||
| 5 | import { validateReleaseTag, validateReleaseVersion } from "../scripts/validate-release-ref"; | ||
| 6 | |||
| 7 | const workflow = (name: string): string => | ||
| 8 | readFileSync(resolve(import.meta.dirname, "..", ".github/workflows", name), "utf8"); | ||
| 9 | |||
| 10 | describe("release workflow hardening", () => { | ||
| 11 | it("accepts only semver release versions and v-prefixed semver tags", () => { | ||
| 12 | expect(validateReleaseVersion("1.2.3")).toBe("1.2.3"); | ||
| 13 | expect(validateReleaseVersion("1.2.3-beta.4")).toBe("1.2.3-beta.4"); | ||
| 14 | expect(validateReleaseTag("v1.2.3")).toBe("v1.2.3"); | ||
| 15 | expect(validateReleaseTag("v1.2.3-beta.4+build.5")).toBe("v1.2.3-beta.4+build.5"); | ||
| 16 | |||
| 17 | expect(() => validateReleaseVersion("v1.2.3")).toThrow(); | ||
| 18 | expect(() => validateReleaseVersion("1.2")).toThrow(); | ||
| 19 | expect(() => validateReleaseTag("1.2.3")).toThrow(); | ||
| 20 | expect(() => validateReleaseTag("v1.2.3; echo unsafe")).toThrow(); | ||
| 21 | expect(() => validateReleaseTag("v01.2.3")).toThrow(); | ||
| 22 | }); | ||
| 23 | |||
| 24 | it("validates release values through environment variables before shell use", () => { | ||
| 25 | const publishExecutor = workflow("publish-executor-package.yml"); | ||
| 26 | const release = workflow("release.yml"); | ||
| 27 | const publishDesktop = workflow("publish-desktop.yml"); | ||
| 28 | |||
| 29 | expect(publishExecutor).toContain( | ||
| 30 | "bun run scripts/validate-release-ref.ts --tag-env RAW_RELEASE_TAG --write-env RELEASE_TAG", | ||
| 31 | ); | ||
| 32 | expect(release).toContain( | ||
| 33 | "bun run scripts/validate-release-ref.ts --version-env RELEASE_VERSION --output tag", | ||
| 34 | ); | ||
| 35 | expect(publishDesktop).toContain( | ||
| 36 | "bun run scripts/validate-release-ref.ts --tag-env RAW_RELEASE_TAG --write-env RELEASE_TAG", | ||
| 37 | ); | ||
| 38 | |||
| 39 | expect(release).not.toContain('tag="v${{ steps.detect_release.outputs.version }}"'); | ||
| 40 | expect(publishDesktop).not.toContain("ref: refs/tags/${{ inputs.tag }}"); | ||
| 41 | expect(publishDesktop).not.toContain('gh release download "${{ inputs.tag }}"'); | ||
| 42 | expect(publishExecutor).not.toMatch(/\n\s+RELEASE_TAG: \$\{\{ github\.event_name/u); | ||
| 43 | }); | ||
| 44 | |||
| 45 | it("does not persist checkout credentials in release workflows", () => { | ||
| 46 | for (const name of [ | ||
| 47 | "publish-executor-package.yml", | ||
| 48 | "release.yml", | ||
| 49 | "publish-desktop.yml", | ||
| 50 | "pkg-pr-new.yml", | ||
| 51 | ]) { | ||
| 52 | expect(workflow(name)).toContain("persist-credentials: false"); | ||
| 53 | } | ||
| 54 | }); | ||
| 55 | }); | ||