From 68344a0973a7b175f5306a0e20b06a0e7bd96244 Mon Sep 17 00:00:00 2001 From: Nick Vigilante Date: Mon, 20 Jul 2026 17:34:36 -0400 Subject: [PATCH] ci(.github/workflows/deploy-docs.yaml): surface bounded error code on failure, not raw body (#26917) ## What On failure, the `deploy-docs` jobs (`algolia-and-isr` and `vercel-rebuild`) print the HTTP status and a **bounded error code** extracted from the response (`(.error | objects | .code)`), never the raw response body. Comments that wrongly described the run log as "restricted to repo collaborators" are corrected, including a pre-existing one. ## Why This repository is public, so GitHub Actions run logs are world-readable. The existing design deliberately keeps free-form upstream strings out of the public step summary via a jq allowlist. Printing the raw response body to the run log has the same public visibility, so it would defeat that intent. Surfacing only the bounded error code (for example `bad_request`) is safe and enough to diagnose failures like the deploy hook's recent HTTP 400. ## Scope and risk - One file, `+15/-5`, success path untouched. - Editing this workflow does not trigger it (its `push` trigger is scoped to `docs/**`), so merging is safe. - `actionlint` clean. The jq extraction was verified to emit only the bounded `code`, never `message` or free-form string errors.
Context / decision log - This started from a `vercel-rebuild` failure (HTTP 400 on every full-rebuild trigger since 2026-06-18) whose reason was never surfaced in CI. - Root cause was operational: the docs site's production branch moved from `master` to `main`, which invalidated the old deploy hook. It was fixed separately by repointing the hook, and the workflow is green again. - The first revision of this PR logged the raw response body to the run log. `coder-agents-review` (CRF-1, P2) correctly flagged that public-repo run logs are world-readable, so that would leak the free-form strings the allowlist exists to suppress. Revised to surface only the bounded error code, and to correct the false "restricted to repo collaborators" comments (CRF-2 nit: comment blocks shortened).
--- Generated by Coder Agents on behalf of @nickvigilante. --- .github/workflows/deploy-docs.yaml | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy-docs.yaml b/.github/workflows/deploy-docs.yaml index 5eed05185b..5adbed6e9f 100644 --- a/.github/workflows/deploy-docs.yaml +++ b/.github/workflows/deploy-docs.yaml @@ -429,9 +429,9 @@ jobs: # recordsByType) that may reflect upstream error strings. This # repository is public, so the step summary is visible to # anyone with read access; filter those fields out before the - # summary is written. The full response remains in the curl - # output captured in the workflow logs, which are restricted - # to repo collaborators. + # summary is written. The full response stays in a temp file and + # is never printed: run logs are public for this repository, so + # the raw body must not reach them either. # # Keep this allowlist in sync with SyncResponseBody in # coder/coder.com/src/pages/api/algolia-docs-sync.ts; add a @@ -475,10 +475,19 @@ jobs: echo echo "### Error" echo - echo "The request failed. See the workflow logs for the full handler response; the step summary suppresses free-form error strings because this repository is public." + echo "The request failed. The raw response body is not shown because this repository is public; only the allowlisted fields above and the bounded error code (in the run log) are surfaced." fi } >> "$GITHUB_STEP_SUMMARY" if [ "$RC" -ne 0 ]; then + # This repository is public: run logs and the step summary are + # both world-readable, so surface only the bounded error code, + # never the raw response body. Sanitize the extracted code so the + # "bounded" claim holds literally: `tr -cd` drops anything outside + # [A-Za-z0-9_.-] (removing newlines and `::` so a hostile response + # body can't inject a runner workflow command) and `head -c 64` + # caps the length. + ERR_CODE=$(jq -r '(.error | objects | .code) // empty' "$RESPONSE" 2>/dev/null | tr -cd 'A-Za-z0-9_.-' | head -c 64 || true) + echo "Algolia docs sync request failed: HTTP ${HTTP_STATUS:-n/a}, error code: ${ERR_CODE:-unknown}." exit "$RC" fi @@ -540,9 +549,18 @@ jobs: echo echo "### Error" echo - echo "The request failed. See the workflow logs for the full hook response; the step summary suppresses free-form error strings because this repository is public." + echo "The request failed. The raw response body is not shown because this repository is public; only the allowlisted fields above and the bounded error code (in the run log) are surfaced." fi } >> "$GITHUB_STEP_SUMMARY" if [ "$RC" -ne 0 ]; then + # This repository is public: run logs and the step summary are + # both world-readable, so surface only the bounded error code, + # never the raw response body. Sanitize the extracted code so the + # "bounded" claim holds literally: `tr -cd` drops anything outside + # [A-Za-z0-9_.-] (removing newlines and `::` so a hostile response + # body can't inject a runner workflow command) and `head -c 64` + # caps the length. + ERR_CODE=$(jq -r '(.error | objects | .code) // empty' "$RESPONSE" 2>/dev/null | tr -cd 'A-Za-z0-9_.-' | head -c 64 || true) + echo "Vercel deploy hook request failed: HTTP ${HTTP_STATUS:-n/a}, error code: ${ERR_CODE:-unknown}." exit "$RC" fi