Skip to content

Commit d550e5c

Browse files
Merge branch 'main' into cursor/weekly-release-v1.2.0-231a
2 parents 64aa1e0 + e7834df commit d550e5c

2 files changed

Lines changed: 45 additions & 4 deletions

File tree

CLAUDE.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,21 @@ Admins can **View as** a sub-user from the top-right of the home layout (`Profil
238238
`hermes_requires <0.20.0` on a "verified" 401 that came from a hand-rolled
239239
`hermes serve` run rather than `hermes webui`. 0.20.0 works. Verify against the
240240
real start path before writing a version constraint.
241+
5. **The agent image build clones two third-party repos over the public internet,
242+
unauthenticated.** `agent/Dockerfile` fetches `NousResearch/hermes-agent` and
243+
`nesquena/hermes-webui` at build time. GitHub rate-limits unauthenticated
244+
requests *per source IP*, and Actions runners share pooled egress addresses, so
245+
`docker compose build` intermittently died on `fatal: unable to access ...: The
246+
requested URL returned error: 429` (exit 128) — 2 of 15 runs, always on branches
247+
whose diff had nothing to do with the agent. Both clones now retry 5x with
248+
backoff, and still print FATAL and exit 1 on exhaustion so a genuinely dead
249+
upstream cannot yield an image with no runtime in it. Two lessons worth keeping:
250+
a CI failure that is *intermittent and unrelated to the diff* is a network or
251+
rate-limit signature, not a code defect — read the log before bisecting the
252+
branch; and the webui clone's pre-existing `|| git clone` fallback looked like
253+
resilience but only ever handled a *moved ref*, re-issuing the identical refused
254+
request against a 429. A fallback that fails the same way as the thing it backs
255+
up is not a fallback.
241256

242257
### Verification Anti-Patterns (do not repeat)
243258

agent/Dockerfile

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,24 @@ ARG AGENT_RUNTIME_REF=v2026.8.18
5252
ARG AGENT_API_REPO=https://github.com/nesquena/hermes-webui.git
5353
ARG AGENT_API_REF=v0.52.76
5454

55-
# Runtime engine (Python agent)
56-
RUN git clone --depth 1 --branch "${AGENT_RUNTIME_REF}" "${AGENT_RUNTIME_REPO}" runtime \
55+
# Runtime engine (Python agent).
56+
#
57+
# The clone retries with backoff. github.com rate-limits *unauthenticated*
58+
# requests per source IP, and CI runners share pooled egress addresses, so a
59+
# cold clone here intermittently returns HTTP 429 and took the whole image
60+
# build down with it (`fatal: unable to access ...: error: 429`, exit 128 --
61+
# 2 of 15 `docker compose build` runs). This is not CI-only defensiveness: a
62+
# self-host user behind a shared NAT hits the identical refusal. Retry is the
63+
# right layer precisely because the condition is transient; the loop still
64+
# exits non-zero and loudly on the last attempt rather than continuing with no
65+
# runtime cloned.
66+
RUN n=0; rm -rf runtime; \
67+
until git clone --depth 1 --branch "${AGENT_RUNTIME_REF}" "${AGENT_RUNTIME_REPO}" runtime; do \
68+
n=$((n+1)); \
69+
if [ "$n" -ge 5 ]; then echo "FATAL: clone of ${AGENT_RUNTIME_REPO} failed after 5 attempts" >&2; exit 1; fi; \
70+
echo "clone attempt $n failed (HTTP 429 / transient network); retrying in $((n*15))s" >&2; \
71+
rm -rf runtime; sleep $((n*15)); \
72+
done \
5773
&& cd runtime \
5874
&& UV_NO_CONFIG=1 uv sync \
5975
&& if [ -d .venv ] && [ ! -d venv ]; then ln -sfn .venv venv; fi \
@@ -64,8 +80,18 @@ RUN git clone --depth 1 --branch "${AGENT_RUNTIME_REF}" "${AGENT_RUNTIME_REPO}"
6480

6581
# HTTP API surface the frontend / backend talk to (:8787).
6682
# Default branch is master (not main). Fall back to HEAD if the ref moves.
67-
RUN (git clone --depth 1 --branch "${AGENT_API_REF}" "${AGENT_API_REPO}" api \
68-
|| git clone --depth 1 "${AGENT_API_REPO}" api) \
83+
#
84+
# Same 429 retry as the runtime clone above. Note the inner `||` fallback
85+
# handles only a *moved ref*; on a rate-limit it just re-issues the same
86+
# refused request, so it needed the outer retry to be any use at all.
87+
RUN n=0; rm -rf api; \
88+
until (git clone --depth 1 --branch "${AGENT_API_REF}" "${AGENT_API_REPO}" api \
89+
|| git clone --depth 1 "${AGENT_API_REPO}" api); do \
90+
n=$((n+1)); \
91+
if [ "$n" -ge 5 ]; then echo "FATAL: clone of ${AGENT_API_REPO} failed after 5 attempts" >&2; exit 1; fi; \
92+
echo "clone attempt $n failed (HTTP 429 / transient network); retrying in $((n*15))s" >&2; \
93+
rm -rf api; sleep $((n*15)); \
94+
done \
6995
&& cd api \
7096
&& if [ -f requirements.txt ]; then \
7197
UV_NO_CONFIG=1 uv pip install --python /opt/deepsql-agent/runtime/venv/bin/python -r requirements.txt; \

0 commit comments

Comments
 (0)