fix(ci): include bun.lock in image build for deterministic install

CI evals all failed on PR #1363 with:
  error: Could not resolve: "smart-buffer". Maybe you need to "bun install"?
  error: Could not resolve: "ip-address". Maybe you need to "bun install"?
  at /opt/node_modules_cache/socks/build/client/socksclient.js:15

The cached node_modules layer in the pre-baked Docker image had
`socks` (the new dep) but was missing its transitive deps (smart-buffer,
ip-address). The image build copied only package.json into the build
context — without bun.lock, `bun install` resolved a different tree
than local `bun install` did, dropping required transitive deps.

Reproduces locally as 229 packages (correct) when bun.lock is present
or absent. Why CI diverged isn't fully understood — possibly Docker
layer cache reuse across image rebuilds — but the deterministic fix is
to include the lockfile in the image build context and use
`--frozen-lockfile`, matching what every CI doc recommends.

Changes:
- .github/docker/Dockerfile.ci: COPY bun.lock alongside package.json,
  switch `bun install` → `bun install --frozen-lockfile` so any future
  lockfile drift fails loudly during image build instead of producing
  a partially-installed cache that breaks downstream eval jobs.
- .github/workflows/evals.yml: include bun.lock in the image-tag hash
  so adding/removing a dep invalidates the image, AND copy bun.lock
  into the docker context alongside package.json.
- .github/workflows/evals-periodic.yml: same updates.
- .github/workflows/ci-image.yml: rebuild trigger now fires on bun.lock
  changes too; build context includes bun.lock.

Image hash changes → fresh image gets built on next CI run → install
matches the lockfile exactly → no missing transitive deps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-05-07 15:45:04 -07:00
parent f3b54ecc99
commit 38fd67b67e
4 changed files with 13 additions and 8 deletions

View File

@@ -89,10 +89,14 @@ RUN for i in 1 2 3; do \
&& fc-cache -f \
&& rm -rf /var/lib/apt/lists/*
# Pre-install dependencies (cached layer — only rebuilds when package.json changes)
COPY package.json /workspace/
# Pre-install dependencies (cached layer — only rebuilds when package.json or
# bun.lock changes). Copy BOTH so install is deterministic and matches local
# resolution. Without bun.lock here, bun install resolved transitive deps
# differently in CI vs local (observed on v1.28.0.0: socks landed but
# smart-buffer + ip-address didn't make it into the cached node_modules).
COPY package.json bun.lock /workspace/
WORKDIR /workspace
RUN bun install && rm -rf /tmp/*
RUN bun install --frozen-lockfile && rm -rf /tmp/*
# Install Playwright Chromium to a shared location accessible by all users
ENV PLAYWRIGHT_BROWSERS_PATH=/opt/playwright-browsers

View File

@@ -9,6 +9,7 @@ on:
paths:
- '.github/docker/Dockerfile.ci'
- 'package.json'
- 'bun.lock'
# Manual trigger
workflow_dispatch:
@@ -22,7 +23,7 @@ jobs:
- uses: actions/checkout@v4
# Copy lockfile + package.json into Docker build context
- run: cp package.json .github/docker/
- run: cp package.json bun.lock .github/docker/
- uses: docker/login-action@v3
with:

View File

@@ -25,7 +25,7 @@ jobs:
- uses: actions/checkout@v4
- id: meta
run: echo "tag=${{ env.IMAGE }}:${{ hashFiles('.github/docker/Dockerfile.ci', 'package.json') }}" >> "$GITHUB_OUTPUT"
run: echo "tag=${{ env.IMAGE }}:${{ hashFiles('.github/docker/Dockerfile.ci', 'package.json', 'bun.lock') }}" >> "$GITHUB_OUTPUT"
- uses: docker/login-action@v3
with:
@@ -43,7 +43,7 @@ jobs:
fi
- if: steps.check.outputs.exists == 'false'
run: cp package.json .github/docker/
run: cp package.json bun.lock .github/docker/
- if: steps.check.outputs.exists == 'false'
uses: docker/build-push-action@v6

View File

@@ -25,7 +25,7 @@ jobs:
- uses: actions/checkout@v4
- id: meta
run: echo "tag=${{ env.IMAGE }}:${{ hashFiles('.github/docker/Dockerfile.ci', 'package.json') }}" >> "$GITHUB_OUTPUT"
run: echo "tag=${{ env.IMAGE }}:${{ hashFiles('.github/docker/Dockerfile.ci', 'package.json', 'bun.lock') }}" >> "$GITHUB_OUTPUT"
- uses: docker/login-action@v3
with:
@@ -43,7 +43,7 @@ jobs:
fi
- if: steps.check.outputs.exists == 'false'
run: cp package.json .github/docker/
run: cp package.json bun.lock .github/docker/
- if: steps.check.outputs.exists == 'false'
uses: docker/build-push-action@v6