Skip to content

chore(deps): security sweep across web, functions, agent and workspaces - #80

Open
dylanroscover wants to merge 2 commits into
devfrom
chore/deps-security-sweep
Open

chore(deps): security sweep across web, functions, agent and workspaces#80
dylanroscover wants to merge 2 commits into
devfrom
chore/deps-security-sweep

Conversation

@dylanroscover

Copy link
Copy Markdown
Member

Resolves the Dependabot backlog locally in one coherent lockfile pass instead of merging 14 main-targeted PRs that would each have conflicted on lockfiles. Everything lands on dev; main is untouched.

Supersedes #37, #60, #65, #66, #67, #68, #69, #71, #72, #73, #74, #75, #78, #79 — close them once this merges.

Security result

lockfile before after
web/ 1 high + 15 moderate 0 high, 0 critical, 9 moderate
functions/ 26 alerts 0
root, cli/, sdks/node/ 12 alerts 0

The 9 residual web/ moderates were verified unreachable, not ignored:

  • uuid — every consumer (gaxios, teeny-request, google-gax) calls v4() with no buf argument; the advisory affects only v3/v5/v6 with buf. A full scan found zero v3/v5/v6 call sites in the tree.
  • @anthropic-ai/sdk — both advisories affect only the local filesystem memory tool, which this app does not use.

The catch that mattered

A blanket refresh introduces undici@5.29.0 via @ai-sdk/provider-utils@4.0.41 — a package that had no undici dependency at 4.0.40. 5.29.0 is the final release of the 5.x line, so ^5.29.0 can never resolve to a patched version, and it carries 12 advisories.

Merging the Dependabot batch as-is would have traded 7 fixed alerts for 12 new ones.

Pinned to undici@^7.28.0. The consuming code only uses Agent + fetch({dispatcher}) — a surface unchanged across 5.x–8.x — and upstream's own provider-utils@5.0.20 runs that same code against ^7.28.0.

Deliberate holds

JSON can't carry comments, so both are documented in the commit body:

  • undici: ^7.28.0 — revisit when @ai-sdk/anthropic moves to the provider-utils 5.x line (needs the ai@7 major).
  • eslint-plugin-react-hooks: 7.0.1 — 7.1.1 enables the React Compiler set-state-in-effect rule: 72 lint errors, zero code changes. That migration is real work and doesn't belong in a security sweep.

Also removed the @google-cloud/storage → fast-xml-parser ^4.5.4 override from web/ and functions/. It was originally added to fix a CVE, but the package now declares ^5.3.4 — the pin had inverted into holding a vulnerable 4.x in place. A good argument for giving overrides an expiry review.

functions/

firebase-admin ^12 → ^13.10, firebase-functions ^5 → ^6.6, with no source changes — all 12 entrypoints already use the v2 API, so the sole v6 breaking change (default entrypoint v1→v2) doesn't apply. Held at admin 13 on purpose: admin 14 requires Node ≥22 and the Cloud Functions runtime is pinned to Node 20.

⚠️ agent/ raises the Python floor to 3.10

requests, google-auth, google-auth-oauthlib, tzlocal, and setuptools now all require ≥3.10. This matches the Python 3.11.8 the installer actually bundles — the old "3.9+" claim in CLAUDE.md hadn't described the shipped runtime for some time, and is corrected here.

setuptools 75.6.0 → 83.0.0 closes the high-severity PackageIndex.download path traversal.

Dependabot config

target-branch: dev on all three ecosystems, so routine bumps soak on dev.owlette.app rather than landing on prod first. Security updates intentionally still target maintarget-branch doesn't move them, and a live CVE should keep a direct path to prod.

Adds dependabot-auto-merge.yml for patch/minor on green CI.

Two repo settings are required before auto-merge behaves correctly, and neither has been changed:

  1. "Allow auto-merge" is currently falsegh pr merge --auto fails without it.
  2. No branch protection or ruleset exists on dev or main. Auto-merge waits only for a branch's required checks; with none configured, PRs are mergeable on arrival and merge immediately, green or not.

Verification

suite result
web tsc --noEmit exit 0
web lint exit 0 (8 pre-existing warnings)
web jest 3586 passed, 4 skipped
web playwright e2e 296 passed, 2 skipped (7.8m)
functions build + tests exit 0, 256/256
agent pytest (py3.10.20) 608 passed, 6 skipped
cli + sdk workspace builds exit 0

Pre-existing, not introduced: cli/__tests__/commands/readiness-docs.test.ts fails on Windows (path separators) — confirmed failing identically on dev with the original dependencies; passes on CI's Linux runners.

🤖 Generated with Claude Code

Clears the Dependabot backlog by resolving it locally in one coherent
lockfile pass rather than merging 14 main-targeted PRs that would each
have conflicted. Supersedes #37, #60, #65-69, #71-75, #78, #79.

Results - npm audit, production + dev scope:
  web/         1 high + 15 moderate  ->  0 high, 0 critical, 9 moderate
  functions/   26 alerts             ->  0
  root, cli/, sdks/node/             ->  0

The 9 residual moderates in web/ were verified unreachable, not ignored:
every uuid consumer (gaxios, teeny-request, google-gax) calls v4() with no
buf argument and the tree contains zero v3/v5/v6 call sites, while the two
@anthropic-ai/sdk advisories only affect the local filesystem memory tool,
which this app does not use.

functions/: firebase-admin ^12 -> ^13.10, firebase-functions ^5 -> ^6.6.
Required no source changes - all 12 entrypoints already use the v2 API, so
the sole v6 breaking change (default entrypoint v1 -> v2) does not apply.
Stayed on admin 13 deliberately: admin 14 requires Node >=22 and this
codebase pins the Cloud Functions runtime to Node 20.

Two new web/ overrides, both deliberate holds (JSON cannot carry comments,
so the rationale lives here):

  undici ^7.28.0 - @ai-sdk/provider-utils 4.0.41 introduced a dependency on
  undici ^5.29.0. 5.29.0 is the final release of the 5.x line, so that range
  can never resolve to a patched version, and it carries 12 advisories. The
  consuming code only uses Agent + fetch({dispatcher}), a surface unchanged
  across 5.x-8.x, and upstream's own provider-utils 5.0.20 runs that same
  code against undici ^7.28.0. Revisit when @ai-sdk/anthropic moves to the
  provider-utils 5.x line (needs the ai@7 major).

  eslint-plugin-react-hooks 7.0.1 - 7.1.1 enables the React Compiler
  set-state-in-effect rule, producing 72 lint errors with zero code changes.
  That rule migration is real work and does not belong in a security sweep.
  Revisit as its own task.

Also removed the @google-cloud/storage -> fast-xml-parser ^4.5.4 override
from both web/ and functions/. It was added to fix a CVE, but the package
now declares ^5.3.4, so the pin had inverted into holding a vulnerable 4.x
in place.

agent/: raises the supported floor to Python 3.10 (requests, google-auth,
google-auth-oauthlib, tzlocal and setuptools all now require >=3.10). This
matches the Python 3.11.8 the installer actually bundles; the previous
"3.9+" claim in CLAUDE.md no longer described the shipped runtime and has
been corrected. setuptools 75.6.0 -> 83.0.0 closes the high-severity
PackageIndex.download path traversal.

Dependabot now targets dev so routine bumps soak on dev.owlette.app instead
of landing on prod first. Security updates intentionally still go to main -
target-branch does not move them, and a live CVE should keep a direct path.
Adds a patch/minor auto-merge workflow; note it needs "Allow auto-merge"
plus required status checks on the target branch, or auto-merge fires on
arrival rather than on green.

Verified: web tsc 0, lint 0 errors, jest 3586 passed, playwright 296 passed
(2 skipped); functions build 0 + 256/256; agent pytest 608 passed on 3.10.20;
cli/sdk workspace builds 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Aug 4, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
owlette Ignored Ignored Aug 4, 2026 8:19pm

contents: read
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6

- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
Comment thread .github/workflows/e2e.yml
timeout-minutes: 30
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
Comment thread .github/workflows/e2e.yml
persist-credentials: false

- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6

- name: Setup Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
timeout-minutes: 5
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
persist-credentials: false

- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v6
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
The cache key read the semver *range* from web/package.json (^1.59.1 ->
1.59.1) while its own comment claimed it tracked the version pinned in
web/package-lock.json. Those agree only until a lockfile-only bump moves
the resolved version without touching the range.

The dependency refresh in the parent commit did exactly that (1.59.1 ->
1.62.1), so the key stayed playwright-Linux-1.59.1, hit a cache populated
with the old browsers, and skipped the cache-hit-guarded install step. The
run then died on a missing chromium_headless_shell-1234 build.

Reads packages['node_modules/@playwright/test'].version from the lockfile
instead. Still no node_modules required, so the step order is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <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.

2 participants