Skip to content

fix(ci): un-stale the apt layer behind the GHA cache + ignore gh os.Root CVE#143

Merged
spashii merged 1 commit into
mainfrom
fix/ci-trivy-stale-apt-cache
Jul 14, 2026
Merged

fix(ci): un-stale the apt layer behind the GHA cache + ignore gh os.Root CVE#143
spashii merged 1 commit into
mainfrom
fix/ci-trivy-stale-apt-cache

Conversation

@spashii

@spashii spashii commented Jul 14, 2026

Copy link
Copy Markdown
Member

What broke

Every PR branch went CI-red yesterday (#138#142 all fail the trivy step; the older green PRs just ran their checks before the CVEs published). Two causes:

  1. curl CVE-2026-5773 / CVE-2026-6276 — Debian shipped the fix (deb13u4) but the image stays on deb13u3: apt-get upgrade -y only runs at layer-build time, and cache-from: type=gha keeps serving the cached apt layer. The dockerfile's own comment history (gh CVE-2026-48501) shows this trap has bitten before.
  2. CVE-2026-39822 — Go stdlib os.Root symlink following inside /usr/bin/gh (built with Go 1.26.4, fixed in 1.26.5). Same family as the eight gh Go-stdlib CVEs already in .trivyignore; Sam runs gh against repos it cloned itself, not attacker-controlled trees.

The fix

  • New USER root → apt-get update && upgrade → USER sam layer below the source COPY, so it busts on every commit build and picks up security patches, while the expensive layers above stay cached. Known edge documented in the comment: re-running CI on a bit-identical branch still hits the cache; merging main forces the refresh.
  • CVE-2026-39822 added to the gh block in .trivyignore with rationale.

Merge order

Merge this first, then update the red branches from main (#138, #139, #140, #141, #142) — same unblock shape as June's #130.

Found during the 2026-07-14 follow-up to the monthly maintenance pass.

🤖 Generated with Claude Code

… CVE

Every branch went CI-red on 2026-07-13 when Debian shipped curl
8.14.1-2+deb13u4 (CVE-2026-5773, CVE-2026-6276): the dockerfile's
'apt-get upgrade -y' only patches at layer-build time, and the GHA
layer cache (cache-from: type=gha) kept serving the stale apt layer,
so the fix never entered the image. New refresh layer sits below the
source COPY — busts on every commit, catches security patches without
un-caching the expensive layers above.

Also adds CVE-2026-39822 (Go stdlib os.Root symlink following, via
/usr/bin/gh built on Go 1.26.4) to .trivyignore with rationale, same
family as the eight gh Go-stdlib ignores already documented there.

Merge this first, then update the red branches from main — same
unblock shape as PR #130 (June starlette CVEs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@spashii
spashii merged commit 24afe27 into main Jul 14, 2026
2 checks passed
@spashii
spashii deleted the fix/ci-trivy-stale-apt-cache branch July 14, 2026 16:27
spashii added a commit that referenced this pull request Jul 14, 2026
…ates real (#145)

## The finding

30 days of audit logs: **Exa's API never failed once (8/8 calls
healthy). Every "exa breaks" incident was agent-side**, in two modes:

1. **Session-killing tool hallucination (3 crashes).** The skill catalog
advertises `exa-search` in every system prompt, but no `exa_search` tool
was registered — Flash pattern-matched the name and emitted
`exa_search(...)` calls the ADK runner had no handler for → unhandled
exception → whole session dies with exit 1, no reply to the user (Jul 9
×2, Jul 13 ×1 — the last one misdiagnosed itself to Cesare as a
"document retrieval parsing error"). Sam journaled the root cause on Jul
9 and re-hit it Jul 13: prose can't patch a model prior.
2. **jq-eaten results (2 occurrences).** The skill's only curl template
piped to `jq`, which isn't installed in the container — searches
succeeded, got billed, output vanished.

## The fix

- **`exa_search` FunctionTool** in `adk_runner.py` with the exact name +
`query` arg Flash already tries to call. httpx (existing dep), results
formatted in Python (no shell parsing), Exa error tags surfaced as
strings (429/400/402 branchable), empty results phrased as guidance not
failure, per-query cost reported. Registered in `worker_tools` (→ main,
worker, pro_executor) and the `parallel_workers` fanout; mentor stays
read-only.
- **Skill rewritten** to what prose is for: when/when-not (native tool
first), cost discipline, and a jq-banned curl fallback for advanced
params — corrected against the 2026-07 Exa API docs (current `type`
enum, conditional response fields, category conflicts).

## Verification

- 5 new tests (signature pin, missing-key error,
never-raises-on-connect-failure, FunctionTool wrap, both registration
sites); full suite **310 passed**; ruff + ruff-S clean.
- **Live-verified** against the real API (~$0.02): happy path with cost
line, `include_domains`, and invalid key → `error: Exa HTTP 401
[INVALID_API_KEY]` as a string.
- Post-merge check (1 week): the crash signature (`exa_search` call →
session errored) should be extinct in `tool_calls/*.jsonl`, and no bash
entry should contain `api.exa.ai … | jq`.

Diagnosis produced by a 4-agent research workflow during the 2026-07-14
maintenance follow-up; full write-up available on request.

Tier 3 (runtime). Note: CI will stay red until #143 (trivy/apt-cache
fix) merges — same as the rest of the queue.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: sam-dembrane <sam-dembrane@sam2ks-MacBook-Pro.local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant