Skip to content

auto-fix batch 2026-04-30 (CI gates + safe DOM swap)#498

Merged
intendednull merged 7 commits into
mainfrom
claude/friendly-maxwell-MVZZK
Apr 30, 2026
Merged

auto-fix batch 2026-04-30 (CI gates + safe DOM swap)#498
intendednull merged 7 commits into
mainfrom
claude/friendly-maxwell-MVZZK

Conversation

@intendednull
Copy link
Copy Markdown
Owner

Auto-fix batch run via /resolving-issues skill. Three audit-finding issues resolved sequentially on this branch — single PR, single CI run, single human review.

Fixes

Already-Fixed

None this run.

Parked

None this run — all three attempted issues landed.

Skill Evolution

6095f27 docs(skill): wasm-clippy gate when dual-target lib crate touched — adds an explicit cargo clippy --target wasm32-unknown-unknown <scope> --all-targets -- -D warnings step to the implementer's local merge gate. Surfaced this run because pre-existing wasm-only clippy errors in crates/web/src/components/message_row/day_separator.rs (3× unnecessary as u32 on js_sys::Date::get_month()) only fire on the wasm target — native clippy + wasm cargo check miss them together. Filed as separate follow-up #497 (out of scope for this batch; CI doesn't currently gate on wasm-clippy either, so it's not blocking).

Lessons Learned

Test plan

CI on this PR runs the full gate:

Manual smoke: open a server with pinned messages, click a pinned message in the pin sheet, confirm scroll-to-message still works (the behavior should be identical to the old eval-based path).


Generated by Claude Code

claude added 5 commits April 30, 2026 00:31
eslint.config.js banned waitForTimeout but no runner enforced it.
Add `lint` script to package.json and dedicated `lint` job to ci.yml.

placement: ci.yml not e2e.yml.
- e2e.yml's npm install hides inside scripts/setup-e2e.sh after the
  30-min just test-e2e-full step starts, no dep-install reuse to win.
- ci.yml runs parallel jobs on every PR, lint surfaces in seconds.

local verify: npm ci + npm run lint -> exit 0 (existing per-file
eslint-disable headers tracking #458 keep tree green).

Refs #491
scripts/check-no-test-hooks-in-prod.sh asserts prod trunk build does
not leak WillowTestHooks (third-party JS could otherwise read DAG
heads via window.__willow.snapshot). Previously only run by
`just check-all` -> never enforced on PRs / deploys.

ci.yml: dedicated `test-hooks-guard` job, parallel with clippy/test/
wasm/browser. fail-fast on PRs.
deploy.yml: belt-and-braces re-run immediately before
`Build web app`, catches force-pushed bypass past the CI gate.

pattern A (dedicated job) over B (`just check-all` in matrix):
- B drags `just test-browser` (Firefox + geckodriver + wasm-pack)
  into the same job and balloons wall-clock; browser tests already
  run via the existing `wasm-pack test` job.
- matches the sibling 22fc51b eslint wiring (parallel job, fail-fast).

action pins copied verbatim from existing ci.yml jobs (full SHAs,
trunk@0.21.14 matching deploy.yml). no new action authors -> no
dependabot surface bump.

note: script uses `trunk build --release --offline`, so the job
warms trunk's tool cache (wasm-bindgen-cli) with a non-`--offline`
build first; deploy.yml's existing `Build web app` step is now
preceded by the guard, so the guard's own trunk build doubles as
the cache-warm there.

local verify: trunk + just not in sandbox; script aborts at first
trunk invocation (exit 127), confirming fail-loud rather than
silent-pass on missing toolchain. YAML validated via
`python3 -c "import yaml; yaml.safe_load(...)"`. cargo fmt / clippy
untouched (workflow YAML only).

Refs #490
The `on_pinned_jump` callback in `crates/web/src/app.rs` interpolated
`msg_id` into a `js_sys::eval(format!(...))` string with only single-
quote stripping as sanitization. Reachable risk was low (today the id
is `EventHash::to_string()`, hex-only), but band-aid sanitization rots
and the pattern invites copy-paste. Swap for `web_sys::window() →
document() → get_element_by_id() → scroll_into_view_with_scroll_into_
view_options(...)` so adversarial ids become literal lookup keys with
no JS context to escape.

The other `js_sys::eval` sites in the web crate (theme bootstrap,
focus helpers, relay-url probe) all use static JS strings with no
interpolation and are out of scope for this fix; the `unsafe-eval`
CSP directive comment in `crates/web/tests/static_assets.rs` already
tracks them under #171 / #425.

Test coverage at the lowest tier covering DOM behavior — wasm-pack
browser tests in `crates/web/tests/browser.rs::pinned_jump_safe_scroll`:
realistic hex id (positive), missing id (negative, was implicit via
old `.ok()`), and adversarial ids with double-quotes / backslashes /
newlines / brackets (the cases the old `replace('\'', "")` band-aid
did not cover).

web-sys 0.3.95 already exposed `ScrollIntoViewOptions` with the
setter-style API the issue body proposed (`set_behavior`, `set_block`),
and the required features (`Window`, `Document`, `Element`,
`ScrollIntoViewOptions`, `ScrollBehavior`, `ScrollLogicalPosition`)
were already enabled in `crates/web/Cargo.toml` — no API adaptation,
no feature additions needed.

Verified: `cargo fmt --check` clean, `cargo check --target
wasm32-unknown-unknown -p willow-web [--tests]` clean, `cargo test
-p willow-web --lib` passes (73 tests). Browser tests compile-checked
via `cargo check --target wasm32-unknown-unknown -p willow-web
--tests`; not run locally (sandbox lacks wasm-pack/Firefox/geckodriver)
— CI will execute the headless run. Pre-existing clippy warnings in
`day_separator.rs` are unrelated and on master HEAD; not touched.

Refs #425
native clippy + wasm `cargo check` together miss wasm-only lints. seen
this batch in day_separator.rs (3x `as u32` on `js_sys::Date::get_month()`
which already returns u32 on wasm). filed as #497. add explicit
wasm-clippy step to step 7 gate so future implementers don't repeat.

Refs auto-fix batch claude/friendly-maxwell-MVZZK
@intendednull
Copy link
Copy Markdown
Owner Author

resolve conflicts

claude added 2 commits April 30, 2026 04:40
Conflict in crates/web/tests/browser.rs: both branches appended new test
modules at end of file. #425 added `mod pinned_jump_safe_scroll` (DOM
lookup tests for the eval -> safe-scroll swap); #496 added
`mod data_state_lifecycle` (transitionend lifecycle tests on
grove_drawer). Modules are orthogonal — kept both, ours first then
theirs, with the same blank-line separator main used.

verified: cargo fmt clean, cargo check --target wasm32-unknown-unknown
-p willow-web --tests clean, cargo clippy -p willow-web --all-targets
-- -D warnings clean.
This reverts commit b34d820.

Reverting because the new test-hooks-guard CI job hits a pre-existing
wasm-streams duplicate-symbol link error (issue tracked by PR #387):

  rust-lld: error: duplicate symbol: __wbg_intounderlyingbytesource_free
  rust-lld: error: duplicate symbol: __wbindgen_describe_intounderlyingbytesource_*
  ...

Two transitive crates pull conflicting versions:
  wasm-streams 0.4.2 <- server_fn 0.7.8 <- leptos 0.7.8
  wasm-streams 0.5.0 <- reqwest 0.13.2 <- iroh-relay

Trunk's prod build (cargo build --release --target wasm32-unknown-unknown
on the bin target) fails to link. The existing 'browser' CI job hits the
same bug but masks it via 'wasm-pack test ... | tee' under bash -e
without pipefail (tee's exit 0 swallows wasm-pack's failure). My new
step is a single command with no pipe -> bash -e propagates the failure
-> CI red.

Won't mask via tee; per CLAUDE.md 'No swallowing errors'. #490 has to
wait for #387 (leptos 0.7 -> 0.8 upgrade collapses the wasm-streams
duplication) to land. Filing follow-up issue noting the dependency
chain. Leaving the eslint CI wiring (#491) and the js_sys::eval safe-DOM
swap (#425) in place; both are unaffected by the wasm-streams bug.

Refs #490, #387
@intendednull intendednull merged commit 0b051c1 into main Apr 30, 2026
8 checks passed
@intendednull intendednull deleted the claude/friendly-maxwell-MVZZK branch April 30, 2026 06:03
intendednull pushed a commit that referenced this pull request Apr 30, 2026
… wasm clippy CI gate

caveman go: get_month already u32 on wasm32. cast bad. clippy yell. fix yell.

three sites swept in crates/web/src/components/message_row/day_separator.rs:
- ts_m: drop `as u32`
- now_m: drop `as u32`
- y_m: drop `as u32`

comment block above also tweaked to reflect that cast is no longer the
NaN-collapse vector for `get_month` / `get_date` (it's the implicit u32
return that does the collapsing now); behaviour identical, doc just true.

CI guard wired per issue Option 1 (no extra job, just a step in the
existing wasm job). add `components: clippy` to the toolchain action +
new step `cargo clippy --target wasm32-unknown-unknown -p willow-web
--all-targets -- -D warnings` after the existing wasm cargo check.

won't hit the wasm-streams duplicate-symbol blocker that reverted
PR #498's CI guard: clippy is check-style, never links the wasm
binary, so the duplicate-symbol link error can't fire here. verified
locally — `cargo clippy --target wasm32-unknown-unknown -p willow-web
--all-targets -- -D warnings` finishes clean, zero warnings.

Refs #497
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants