diff --git a/.github/workflows/runtime_prereleases.yml b/.github/workflows/runtime_prereleases.yml index 147ec0a496dc8..19cc47f1ce508 100644 --- a/.github/workflows/runtime_prereleases.yml +++ b/.github/workflows/runtime_prereleases.yml @@ -29,6 +29,9 @@ jobs: publish_prerelease: name: Publish prelease (${{ inputs.release_channel }}) ${{ inputs.commit_sha }} @${{ inputs.dist_tag }} runs-on: ubuntu-latest + permissions: + # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run + actions: read steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 diff --git a/.github/workflows/runtime_prereleases_manual.yml b/.github/workflows/runtime_prereleases_manual.yml index 77d3fd5e4304b..3cf2786cce68f 100644 --- a/.github/workflows/runtime_prereleases_manual.yml +++ b/.github/workflows/runtime_prereleases_manual.yml @@ -16,6 +16,9 @@ jobs: publish_prerelease_canary: name: Publish to Canary channel uses: facebook/react/.github/workflows/runtime_prereleases.yml@main + permissions: + # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run + actions: read with: commit_sha: ${{ inputs.prerelease_commit_sha }} release_channel: stable @@ -36,6 +39,9 @@ jobs: publish_prerelease_experimental: name: Publish to Experimental channel uses: facebook/react/.github/workflows/runtime_prereleases.yml@main + permissions: + # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run + actions: read # NOTE: Intentionally running these jobs sequentially because npm # will sometimes fail if you try to concurrently publish two # different versions of the same package, even if they use different diff --git a/.github/workflows/runtime_prereleases_nightly.yml b/.github/workflows/runtime_prereleases_nightly.yml index 4622e15f55ad5..2405283ded116 100644 --- a/.github/workflows/runtime_prereleases_nightly.yml +++ b/.github/workflows/runtime_prereleases_nightly.yml @@ -14,6 +14,9 @@ jobs: publish_prerelease_canary: name: Publish to Canary channel uses: facebook/react/.github/workflows/runtime_prereleases.yml@main + permissions: + # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run + actions: read with: commit_sha: ${{ github.sha }} release_channel: stable @@ -24,6 +27,9 @@ jobs: publish_prerelease_experimental: name: Publish to Experimental channel uses: facebook/react/.github/workflows/runtime_prereleases.yml@main + permissions: + # We use github.token to download the build artifact from a previous runtime_build_and_test.yml run + actions: read # NOTE: Intentionally running these jobs sequentially because npm # will sometimes fail if you try to concurrently publish two # different versions of the same package, even if they use different diff --git a/scripts/release/shared-commands/download-build-artifacts.js b/scripts/release/shared-commands/download-build-artifacts.js index cf7301688027a..23e3541110fe1 100644 --- a/scripts/release/shared-commands/download-build-artifacts.js +++ b/scripts/release/shared-commands/download-build-artifacts.js @@ -3,8 +3,9 @@ const {join} = require('path'); const theme = require('../theme'); const {exec} = require('child-process-promise'); -const {existsSync, readFileSync} = require('fs'); +const {existsSync, mkdtempSync, readFileSync} = require('fs'); const {logPromise} = require('../utils'); +const os = require('os'); if (process.env.GH_TOKEN == null) { console.log( @@ -21,6 +22,15 @@ const GITHUB_HEADERS = ` -H "Authorization: Bearer ${process.env.GH_TOKEN}" \ -H "X-GitHub-Api-Version: 2022-11-28"`.trim(); +async function executableIsAvailable(name) { + try { + await exec(`which ${name}`); + return true; + } catch (_error) { + return false; + } +} + function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } @@ -78,10 +88,27 @@ async function getArtifact(workflowRunId, artifactName) { async function processArtifact(artifact, commit, releaseChannel) { // Download and extract artifact const cwd = join(__dirname, '..', '..', '..'); + const tmpDir = mkdtempSync(join(os.tmpdir(), 'react_')); await exec(`rm -rf ./build`, {cwd}); await exec( - `curl -L ${GITHUB_HEADERS} ${artifact.archive_download_url} \ - > a.zip && unzip a.zip -d . && rm a.zip build2.tgz && tar -xvzf build.tgz && rm build.tgz`, + `curl -L ${GITHUB_HEADERS} ${artifact.archive_download_url} > artifacts_combined.zip`, + { + cwd: tmpDir, + } + ); + + // Use https://cli.github.com/manual/gh_attestation_verify to verify artifact + if (executableIsAvailable('gh')) { + await exec( + `gh attestation verify artifacts_combined.zip --repo=${OWNER}/${REPO}`, + { + cwd: tmpDir, + } + ); + } + + await exec( + `unzip ${tmpDir}/artifacts_combined.zip -d . && rm build2.tgz && tar -xvzf build.tgz && rm build.tgz`, { cwd, }