build: add ESLint to script/lint and containerize linting (closes #152)
Some checks failed
check / check (push) Failing after 2m16s

script/lint ran `prettier --check .`, byte for byte what script/fmt-check
runs, so make check checked formatting twice and did no static analysis on
a cryptocurrency wallet. Two used-but-not-imported crashes shipped past it.

ESLint is pinned in package.json with @eslint/js recommended as the base and
a flat config in eslint.config.js. no-undef and no-unused-vars are restated
error-level so a future recommended-set change cannot downgrade them.
Globals are declared per tree rather than globally, because a too-wide set
hides the next unimported identifier: browser for the popup and content
scripts, service worker for src/background/ and src/shared/, browser for the
one documented POPUP ONLY module in src/shared/, jest for tests/, node for
build.js, and both for the e2e harnesses, which carry the callbacks they
ship into the page inline.

Two rules new to the recommended set are off, and both would have cost
something to satisfy. no-useless-assignment flags the `password = null` and
`decryptedSecret = null` wipes in approval.js and confirmTx.js: those
assignments are dead by construction, which is the point of them, and the
rule's fix is to delete the wipe. preserve-caught-error would change what
the wallet's error paths throw, which is a decision of its own.

Every remaining violation is fixed: 41 unused bindings and 53 undefined
identifiers. Unused catch bindings became `catch {`, which the repo already
used; the shared init(ctx) view signature keeps its parameter as _ctx in the
three views that do not read it. src/shared/uniswap.js keeps its unused
V2_SWAP_EXACT_OUT decoder behind a scoped disable, because deleting it would
widen the gap it represents rather than close it (#283).

Linting is containerized. script/lint builds the Dockerfile's new lint stage
so the ESLint deciding whether this repo is green is the pinned one and not
whatever the host has; AUTISTMASK_LINT_NATIVE, set only in that image, is
what makes make check inside the CI build lint in place instead of recursing
into docker. The check stage takes a COPY --from=lint dependency so a lint
failure fails the whole build early rather than racing it.

No --fix anywhere in the lint path: make check remains non-mutating.

The README claim that a used-but-not-imported identifier is invisible to
make check, and the same claim in script/test-e2e, are no longer true and
are corrected.
This commit is contained in:
2026-08-14 04:16:47 +00:00
parent 0be20d7270
commit 7270480e0b
32 changed files with 647 additions and 83 deletions

28
TODO.md
View File

@@ -32,19 +32,30 @@ The backlog lives on the
[Gitea tracker](https://git.eeqj.de/sneak/AutistMask/issues), which is
authoritative; this file does not duplicate it. Full policy file set present.
Real-browser end-to-end suites (`make test-e2e` for Chrome,
`make test-e2e-firefox` for Firefox) now sit alongside `make check`, which
cannot see a runtime `ReferenceError` in a popup view.
`make test-e2e-firefox` for Firefox) sit alongside `make check`, which now does
static analysis as well as formatting.
# Next Step
Land [#152](https://git.eeqj.de/sneak/AutistMask/issues/152): add ESLint to
`script/lint`. `make check` is `prettier --check` only today and cannot catch
undefined identifiers, which is how
[#150](https://git.eeqj.de/sneak/AutistMask/issues/150) and
[#151](https://git.eeqj.de/sneak/AutistMask/issues/151) shipped.
Pre-1.0 security review of the extension (key handling, DEBUG mode policy, RPC
input validation) before any 1.0rc tag. Individual filed issues are parts of it,
but the review is broader than any of them.
# Completed Steps
- 2026-08-14: `make check` does static analysis. `script/lint` ran
`prettier --check .`, byte-identical to `script/fmt-check`, so a wallet with
two shipped used-but-not-imported crashes behind it was green. ESLint is now
pinned in `package.json` with `@eslint/js` recommended as the base, flat
config in `eslint.config.js`, `no-undef` and `no-unused-vars` error-level, and
globals declared per tree — browser for the popup and content scripts, service
worker for `src/background/` and `src/shared/`, jest for `tests/`, node for
`build.js`. It found 41 unused bindings and 53 undefined identifiers; all are
fixed, and dropping a call to an unimported `foo()` into any `src/` file fails
`make lint`. Linting is also containerized now: `script/lint` builds the
Dockerfile's new `lint` stage, so the ESLint that decides whether this repo is
green is the pinned one and not the host's
([#152](https://git.eeqj.de/sneak/AutistMask/issues/152)).
- 2026-08-12: EIP-1193 error codes now reach the page. `src/content/inpage.js`
rebuilt every failure as `new Error(error.message)`, so the code the
background produced and the content script relayed intact was dropped in the
@@ -365,9 +376,6 @@ undefined identifiers, which is how
Only work that has no issue of its own belongs here; everything else is on the
tracker.
- Pre-1.0 security review of the extension (key handling, DEBUG mode policy, RPC
input validation) before any 1.0rc tag. Individual filed issues are parts of
it, but the review is broader than any of them.
- Decide whether docker-in-docker makes `make test-e2e` and
`make test-e2e-firefox` runnable in the Gitea workflow. Extending the Chrome
suite itself is tracked as