QuantEcon / QuantEcon/actions

fix(preview): surface deploy errors, pin CLIs, remove unsafe fork guidance

Open
#105 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug high-priority security
Dominant language
Shell
Stars
0
Forks
1
Avg merge
32m
Merged PRs (30d)
3

Description

Three problems in the two preview actions, from the 2026-07 maintenance audit.

1. A failed Cloudflare deploy produces no diagnostic output

preview-cloudflare/action.yml:93-98 runs DEPLOY_OUTPUT=$(wrangler pages deploy … 2>&1) under bash -eo pipefail: the assignment aborts the step on failure, and 2>&1 sent wrangler's stderr into the variable, so nothing is printed — the log ends at the 🔍 Deploying preview… line at :90. Every reporting path is therefore unreachable: the ::group::Deployment Output dump at :102-104 and the error branch at :106-109. The exit-code capture at :100 is dead both ways — on failure the step is already gone, on success DEPLOY_EXIT_CODE can only read 0.

Fix: wrangler … 2>&1 | tee "$RUNNER_TEMP/wrangler.log"; EXIT=${PIPESTATUS[0]}, plus ::error:: on failure — neither preview action has any ::error:: annotation today.

The companion half, the fatal URL grep, is already fixed: v0.11.1 (#131) made deploy-url a constructed alias at preview-cloudflare/action.yml:124, and the surviving deployment-url extraction at :131-134 ends || true.

preview-netlify/action.yml:72-78 has the same abort-before-dump problem (dump at :80-82) but does not redirect stderr, so netlify's human-readable error still reaches the log and only the captured --json error payload is discarded.

Separate Netlify defect: preview-netlify/action.yml:85 pipes the captured output into python3 -c "…json.load…", which exits non-zero on non-JSON stdout; under set -e the assignment aborts the step, so the "Raw output was:" guard at :88-93 cannot fire in the case it was written for. It only fires on valid JSON that lacks deploy_url/url.

2. netlify-cli@latest / wrangler@latest installed at run time and handed deploy credentials

preview-netlify/action.yml:59 and preview-cloudflare/action.yml:71. The repo SHA-pins every third-party Action against tag hijacking (CHANGELOG.md:328-331, the [0.8.0] Security entry), then fetches two unpinned npm packages with very large dependency trees on every PR and invokes them with the deploy tokens. .github/dependabot.yml declares only conda (:21), github-actions (:77) and docker (:113) — no npm ecosystem, so nothing would keep a pin current either.

Fix: pin exact versions and add npm to Dependabot, or pre-install both CLIs into the images.

Related: preview-netlify/action.yml:75 puts --auth="…" on the command line, landing in the generated step script on disk (PLAN item 8). The same step interpolates four more ${{ }} values — :66, :67, :73, :74 — and has no env: block at all (:61-65). v0.11.1 moved the Cloudflare equivalents into env: at preview-cloudflare/action.yml:77-85; move all five Netlify values in one edit, not just the token.

3. Both READMEs recommend pull_request_target for fork PRs

preview-netlify/README.md:173 and preview-cloudflare/README.md:182 — under a heading titled "Security". Following it means building and executing fork-authored notebooks in a context holding NETLIFY_AUTH_TOKEN / CLOUDFLARE_API_TOKEN and a write-scoped GITHUB_TOKEN — the classic pwn-request pattern. It does not even work: the fork branch of the trust check tests github.event_name = 'pull_request' (preview-netlify/action.yml:39, preview-cloudflare/action.yml:51), so under pull_request_target it never fires and every fork PR is marked trusted; the deploy step then gates on the same condition (preview-netlify/action.yml:63, preview-cloudflare/action.yml:75) and is skipped outright, producing no preview at all.

Fix: delete the parenthetical; replace with an explicit warning that fork previews are unsupported and pull_request_target must not be used with these actions.

Checklist

  • tee + PIPESTATUS rewrite of the wrangler capture
  • Make the Cloudflare URL grep non-fatal — done in v0.11.1 (#131): constructed alias URL plus a || true-guarded deployment-url extraction
  • Same treatment for the netlify capture so the --json payload survives, and make the json-parse pipeline at preview-netlify/action.yml:85 non-fatal so the raw-output guard can actually fire
  • ::error:: annotations on deploy failure in both actions
  • Pin netlify-cli and wrangler to exact versions; add npm to dependabot.yml
  • Move the Netlify auth token — and the other four interpolated inputs — into env:
  • Delete the pull_request_target recommendation from both READMEs; replace with a warning

Sequencing

Land the README pull_request_target deletion first: a two-line doc change with no code risk, and preview-*/README.md matches the harness IGNORED regex at .github/workflows/test-actions.yml:112, so it skips the harness rather than queueing behind the shell rewrite. The harness has no preview jobs, so the shell changes get no automated coverage — they need manual verification on a real PR against both providers.

Closes PLAN item 8.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the README sections at preview-netlify/README.md:173 and preview-cloudflare/README.md:182, then inspect the capture and credential-handling steps in both action.yml files. Review .github/dependabot.yml and the harness guidance in .github/workflows/test-actions.yml:112. Done means the unsafe guidance is replaced, both actions report deploy failures safely, credentials and CLI versions are handled as specified, and both providers receive manual verification because the harness has no preview jobs.

Written by the indexing model from the issue text.

Assessment

Tech stack
github-actions, node.js, python, shell
Domain
ci-cd, devops, documentation, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.