From 5e0f757931293d019ba9d62a4c113647c32d21be Mon Sep 17 00:00:00 2001 From: Jess Sullivan Date: Tue, 14 Jul 2026 05:15:13 -0400 Subject: [PATCH 1/4] fix(ci): align bazel-remote-gates with shared-cache-backed GF enrollment The GF exchange stopped granting executor tokens to this repo's PR refs (and the consumer registry now records substrate_mode=shared-cache-backed, latch remote_processes=0), so the gates lane's hard executor requirement has structurally redded every PR since ~07-10 while main stayed green. Request cache-write on trusted main pushes, cache-read on PR refs, strip the executor attachment for mode/endpoint agreement, and skip cache uploads under read-only tokens. --- .github/workflows/ci.yml | 22 +++++++++++++++------- scripts/bazel-cache-backed.sh | 5 +++++ 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1603b77..d70d6c1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,7 @@ jobs: with: node-version-file: '.nvmrc' - - name: Require executor-backed GloriousFlywheel lane + - name: Resolve GloriousFlywheel substrate lane run: | set -euo pipefail if [ -z "${BAZEL_REMOTE_CACHE:-}" ]; then @@ -66,14 +66,22 @@ jobs: exit 1 fi - if [ -z "${BAZEL_REMOTE_EXECUTOR:-}" ]; then - echo "::error::BAZEL_REMOTE_EXECUTOR is missing. Refusing to run check/test/e2e as shared-cache local work while this lane is named RBE." - exit 1 + # This repo's GF consumer-registry entry is substrate_mode= + # shared-cache-backed (latch: remote_processes=0), so executor + # tokens are not ours to mint — the exchange grants cache-write + # only to trusted default-branch pushes and cache-read to any + # enrolled ref. Strip the executor attachment so the wrapper and + # cache-attachment-contract agree on shared-cache mode. + echo "GF_BAZEL_SUBSTRATE_MODE=shared-cache-backed" >> "$GITHUB_ENV" + echo "BAZEL_REMOTE_EXECUTOR=" >> "$GITHUB_ENV" + echo "BAZEL_REMOTE_EXECUTOR_CACHE=" >> "$GITHUB_ENV" + if [ "${GITHUB_EVENT_NAME}" = "push" ] && [ "${GITHUB_REF}" = "refs/heads/main" ]; then + echo "GF_REAPI_TOKEN_EXCHANGE_REQUEST=cache-write" >> "$GITHUB_ENV" + else + echo "GF_REAPI_TOKEN_EXCHANGE_REQUEST=cache-read" >> "$GITHUB_ENV" + echo "GF_BAZEL_CACHE_ROLE=read-only" >> "$GITHUB_ENV" fi - echo "GF_BAZEL_SUBSTRATE_MODE=executor-backed" >> "$GITHUB_ENV" - echo "GF_BAZEL_REMOTE_EXECUTION_PLATFORM=${GF_BAZEL_REMOTE_EXECUTION_PLATFORM:-gloriousflywheel-rbe-linux-x86_64}" >> "$GITHUB_ENV" - - name: Mint GloriousFlywheel REAPI token env: GF_REAPI_TOKEN_EXCHANGE_TTL: 45m diff --git a/scripts/bazel-cache-backed.sh b/scripts/bazel-cache-backed.sh index 6de50f5..864d0b2 100755 --- a/scripts/bazel-cache-backed.sh +++ b/scripts/bazel-cache-backed.sh @@ -169,6 +169,11 @@ info) --remote_default_exec_properties="gf.platform=${remote_execution_platform}" ) fi + # GF cache-read tokens (PR refs) cannot upload; skip the writes rather + # than spraying per-action upload warnings against the denied scope. + if [[ ${GF_BAZEL_CACHE_ROLE:-} == "read-only" ]]; then + executor_args+=(--remote_upload_local_results=false) + fi configure_gf_reapi_credentials "${remote_executor:-${effective_remote_cache}}" if [[ -n ${BAZEL_REMOTE_INSTANCE_NAME:-} ]]; then validate_runtime_value "BAZEL_REMOTE_INSTANCE_NAME" "${BAZEL_REMOTE_INSTANCE_NAME}" From 07cca0c6b885e7478c06687d1215de1b4f39006e Mon Sep 17 00:00:00 2001 From: Jess Sullivan Date: Tue, 14 Jul 2026 05:40:39 -0400 Subject: [PATCH 2/4] fix(bazel): adopt rules_tectonic 0.2.1 (sandbox-writable tectonic cache); align cv e2e with TeX-source scrub --- MODULE.bazel | 2 +- MODULE.bazel.lock | 23 ++++++++++++----------- e2e/cv.spec.ts | 8 +++++--- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/MODULE.bazel b/MODULE.bazel index 5129a4a..0bdf6e9 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -18,7 +18,7 @@ bazel_dep(name = "aspect_rules_js", version = "2.9.1") # repo (sensitive STR-variant content) so it is pinned via git_override; CI # uses an SSH deploy key (secret SPEAR_RESUMES_DEPLOY_KEY) to fetch it. bazel_dep(name = "spear_resumes", version = "0.2.0") -bazel_dep(name = "rules_tectonic", version = "0.1.0") +bazel_dep(name = "rules_tectonic", version = "0.2.1") git_override( module_name = "spear_resumes", diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 980d411..79b0ca4 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -295,7 +295,8 @@ "https://raw.githubusercontent.com/tinyland-inc/bazel-registry/main/modules/rules_shell/0.2.0/MODULE.bazel": "not found", "https://raw.githubusercontent.com/tinyland-inc/bazel-registry/main/modules/rules_shell/0.4.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/tinyland-inc/bazel-registry/main/modules/rules_tectonic/0.1.0/MODULE.bazel": "fd7541eb2e5ee8bf67c2d3d488bee1d704780908be59a74ea66c08a553db978e", - "https://raw.githubusercontent.com/tinyland-inc/bazel-registry/main/modules/rules_tectonic/0.1.0/source.json": "fdf07b1d311f2e1604cb0419f1abfb8e946b68ed4fe4475deabac654c63cfdd0", + "https://raw.githubusercontent.com/tinyland-inc/bazel-registry/main/modules/rules_tectonic/0.2.1/MODULE.bazel": "d27cedc62fd965088b28d3652ea5f958854e663a86627ca4b75fdaa28cf5c300", + "https://raw.githubusercontent.com/tinyland-inc/bazel-registry/main/modules/rules_tectonic/0.2.1/source.json": "086584fbd4abfa31ddacd93d1de866c26a5bde3b141a6d3cfea570a9a168c9eb", "https://raw.githubusercontent.com/tinyland-inc/bazel-registry/main/modules/stardoc/0.5.1/MODULE.bazel": "not found", "https://raw.githubusercontent.com/tinyland-inc/bazel-registry/main/modules/stardoc/0.5.3/MODULE.bazel": "not found", "https://raw.githubusercontent.com/tinyland-inc/bazel-registry/main/modules/stardoc/0.5.6/MODULE.bazel": "not found", @@ -3332,8 +3333,8 @@ }, "@@rules_tectonic+//tectonic:extensions.bzl%tectonic_toolchains_ext": { "general": { - "bzlTransitiveDigest": "66LRKHXKUH+q8uH6+6d+KnjoTNcZ4yYrBudzp5UEvuc=", - "usagesDigest": "y+yWafrxKIeof9aN3VxOg9k1k2TkRHUhgSBGsEYFE30=", + "bzlTransitiveDigest": "oErt/QW0CGr7iHs7iHFvCfmEYKHePePOt9fELKtfNhI=", + "usagesDigest": "09kIi0Ua3jNyEspxL1v1+Q9qbXHU8LURsUAMOnqb4h4=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, @@ -3342,32 +3343,32 @@ "repoRuleId": "@@rules_tectonic+//tectonic/private:tectonic_repository.bzl%tectonic_repository", "attributes": { "platform": "linux_amd64", - "version": "0.16.0", - "integrity": "sha256-u7dymLnRorkR5yXLBExdkkncZ0PwzUifTQzzSKShhJE=" + "version": "0.16.9", + "integrity": "sha256-YLE6CCauetnONLSi3wa/8s/Ppt2oqRVHfAy7hOGkqQI=" } }, "tectonic_linux_arm64": { "repoRuleId": "@@rules_tectonic+//tectonic/private:tectonic_repository.bzl%tectonic_repository", "attributes": { "platform": "linux_arm64", - "version": "0.16.0", - "integrity": "sha256-YPhCHB2jBQzHZuJasHAVMelYPM+gbWoYT9TtkCHGtCc=" + "version": "0.16.9", + "integrity": "sha256-+ao5AX29UfER/bk92iIheMvlHIGTUI/FZ7UjzHT/+cE=" } }, "tectonic_darwin_amd64": { "repoRuleId": "@@rules_tectonic+//tectonic/private:tectonic_repository.bzl%tectonic_repository", "attributes": { "platform": "darwin_amd64", - "version": "0.16.0", - "integrity": "sha256-BzG/VFkduy3LBuskzEImzzNWzGntO9+vul97sq9+wSY=" + "version": "0.16.9", + "integrity": "sha256-ediDn6NZS/6psr8qwKBFW8xNDelWpeXEAxB+mnL3noY=" } }, "tectonic_darwin_arm64": { "repoRuleId": "@@rules_tectonic+//tectonic/private:tectonic_repository.bzl%tectonic_repository", "attributes": { "platform": "darwin_arm64", - "version": "0.16.0", - "integrity": "sha256-VnjinNE+srbZhWatmkKOnj/6fVxos5KOlEy9Nj0zrDY=" + "version": "0.16.9", + "integrity": "sha256-7bZ8YaunaCifbaRByeb1I8+v9PiypXCFI+8pxUP46I4=" } } }, diff --git a/e2e/cv.spec.ts b/e2e/cv.spec.ts index 7df211a..9fe3cb6 100644 --- a/e2e/cv.spec.ts +++ b/e2e/cv.spec.ts @@ -28,15 +28,17 @@ test.describe('CV page', () => { await expect(page.getByRole('link', { name: 'Download Précis PDF' })).toBeVisible(); }); - test('Resume download and source links visible by default', async ({ page }) => { + test('Resume download link visible by default, TeX source stays scrubbed', async ({ page }) => { await expect(page.getByRole('link', { name: 'Download Resume PDF' })).toBeVisible(); - await expect(page.getByRole('link', { name: 'View TeX Source' })).toBeVisible(); + // spear-resumes TeX sources went private (81655ce); the source link + // must stay off the public /cv surface. + await expect(page.getByRole('link', { name: 'View TeX Source' })).toHaveCount(0); }); test('switching to Full CV tab updates links', async ({ page }) => { await page.getByRole('button', { name: 'Full CV' }).click(); await expect(page.getByRole('link', { name: 'Download Full CV PDF' })).toBeVisible(); - await expect(page.getByRole('link', { name: 'View TeX Source' })).toBeVisible(); + await expect(page.getByRole('link', { name: 'View TeX Source' })).toHaveCount(0); }); test('PDF iframe is present', async ({ page }) => { From 4a60123596213a5361bcfb9e46e48754666a6b5f Mon Sep 17 00:00:00 2001 From: Jess Sullivan Date: Tue, 14 Jul 2026 05:53:16 -0400 Subject: [PATCH 3/4] fix(ci): provision Chromium on the dind runner for browser gates The executor image shipped /bin/chromium; the local lane has no browser. Install playwright's chromium (with system deps) when no system browser exists, cache it, and pass the resolved path through --test_env instead of hardcoding the executor path in .bazelrc. --- .bazelrc | 6 +++++- .github/workflows/ci.yml | 27 +++++++++++++++++++++++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/.bazelrc b/.bazelrc index 5a49856..c6d275a 100644 --- a/.bazelrc +++ b/.bazelrc @@ -17,7 +17,11 @@ build --action_env=TZ=UTC test --test_output=errors test --test_timeout=120,600,1800,3600 -test --test_env=GF_RBE_CHROMIUM_EXECUTABLE=/bin/chromium +# Pass the browser path through from the lane (executor images ship +# /bin/chromium; the dind runner provisions one in ci.yml and exports +# GF_RBE_CHROMIUM_EXECUTABLE). No hardcoded value: an absent var lets +# the run-*-bazel.mjs candidate scan handle system chromium paths. +test --test_env=GF_RBE_CHROMIUM_EXECUTABLE build:local --disk_cache=~/.cache/bazel-jesssullivan-github-io diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d70d6c1..a798f32 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,8 +47,6 @@ jobs: id-token: write runs-on: tinyland-dind timeout-minutes: 60 - env: - GF_RBE_CHROMIUM_EXECUTABLE: /bin/chromium steps: - uses: actions/checkout@v6 with: @@ -58,6 +56,31 @@ jobs: with: node-version-file: '.nvmrc' + - name: Cache Playwright browsers + uses: actions/cache@v5 + with: + path: ~/.cache/ms-playwright + key: ms-playwright-${{ runner.os }}-${{ hashFiles('package-lock.json') }} + + - name: Provision Chromium for browser gates + run: | + set -euo pipefail + # Executor images ship /bin/chromium; the dind runner image ships no + # browser, so the puppeteer smoke and playwright e2e need one + # provisioned here. Playwright's installer also pulls the shared + # system libraries the binary links against. + for c in /bin/chromium /usr/bin/chromium /usr/bin/chromium-browser /usr/bin/google-chrome; do + if [ -x "$c" ]; then + echo "System chromium present at $c" + exit 0 + fi + done + PLAYWRIGHT_VERSION="$(node -p "require('./package.json').devDependencies['@playwright/test'].replace(/^[^0-9]*/, '')")" + npx --yes "playwright@${PLAYWRIGHT_VERSION}" install --with-deps chromium + BIN="$(ls -d "${HOME}/.cache/ms-playwright"/chromium-*/chrome-linux/chrome | head -1)" + test -x "${BIN}" + echo "GF_RBE_CHROMIUM_EXECUTABLE=${BIN}" >> "$GITHUB_ENV" + - name: Resolve GloriousFlywheel substrate lane run: | set -euo pipefail From a8ffa9e309550ba077db0012d8f8ce21472af834 Mon Sep 17 00:00:00 2001 From: Jess Sullivan Date: Tue, 14 Jul 2026 06:01:56 -0400 Subject: [PATCH 4/4] fix(ci): match Chrome-for-Testing chrome-linux64 layout in browser provisioning --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a798f32..39d0dbf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,7 +77,7 @@ jobs: done PLAYWRIGHT_VERSION="$(node -p "require('./package.json').devDependencies['@playwright/test'].replace(/^[^0-9]*/, '')")" npx --yes "playwright@${PLAYWRIGHT_VERSION}" install --with-deps chromium - BIN="$(ls -d "${HOME}/.cache/ms-playwright"/chromium-*/chrome-linux/chrome | head -1)" + BIN="$(ls -d "${HOME}/.cache/ms-playwright"/chromium-*/chrome-linux*/chrome 2>/dev/null | head -1)" test -x "${BIN}" echo "GF_RBE_CHROMIUM_EXECUTABLE=${BIN}" >> "$GITHUB_ENV"