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 1603b77..39d0dbf 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,7 +56,32 @@ jobs: with: node-version-file: '.nvmrc' - - name: Require executor-backed GloriousFlywheel lane + - 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 2>/dev/null | head -1)" + test -x "${BIN}" + echo "GF_RBE_CHROMIUM_EXECUTABLE=${BIN}" >> "$GITHUB_ENV" + + - name: Resolve GloriousFlywheel substrate lane run: | set -euo pipefail if [ -z "${BAZEL_REMOTE_CACHE:-}" ]; then @@ -66,14 +89,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/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 }) => { 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}"