Skip to content

fix: post-chain-cut remediation (CI / integrity) - #47

Closed
marceloceccon wants to merge 1 commit into
developfrom
fix/post-chain-cut-remediation-2026-09-24
Closed

marceloceccon wants to merge 1 commit into
developfrom
fix/post-chain-cut-remediation-2026-09-24

Conversation

@marceloceccon

Copy link
Copy Markdown
Member

Covers R3 — restore npm run lint and npm run build.

Toolchain only. No public API change; version deliberately stays 0.5.0. Chain-cut guarantees re-verified: archive/solana/ still unwired, exports still . / ./tron / ./headless / ./wc / ./styles.css, and the 137 / 900–902 drop guards still pass.

Lint was crashing, not failing

eslint-plugin-react under ESLint 10 threw TypeError: contextOrFilename.getFilename is not a function before linting a single file. I checked the registry: no published eslint-plugin-react (max 7.37.5, peers eslint ^3 … ^9.7) or eslint-plugin-jsx-a11y (max 6.10.2, peers … ^9) supports ESLint 10. So the honest minimal fix is to pin the linter, not chase the plugins: eslint + @eslint/js ^10 → ^9.39.5.

.npmrc is deleted. The legacy-peer-deps=true workaround I added during the chain cut existed only because ESLint 10 broke the peer graph. With eslint 9 the graph resolves strictly — npm ci now succeeds with no flags. That workaround is gone rather than inherited.

⚠️ One honest trade: eslint 9.39.5 installs with a "no longer supported" deprecation notice. A supported-but-broken linter vs. an EOL-but-working one. The real exit is upstream — either those two plugins ship ESLint 10 support, or they get dropped. Logged for humanpending.md.

23 previously-masked errors surfaced; 14 fixed

Rule n How
no-unnecessary-type-assertion 7 eslint --fix
prefer-for-of 3 index loops → for…of (incl. permitDomainKey)
prefer-optional-chain 2 in payment-config-verifier.ts
require-await 2 test double → Promise.resolve / Promise.reject
unused eslint-disable 1 replaced with one that states why the cast exists

Two of those land in the signed-config verifier and in permitDomainKey (which computes the permit-allowlist digest), so I applied them by hand, not via a fixer, and proved them behaviour-neutral: the permit-allowlist, payment-config-verifier and api-client suites pass 26/26.

The remaining 9 are react-hooks/set-state-in-effect, new in eslint-plugin-react-hooks v7. They flag a pre-existing pattern in the payment modals where an effect mirrors a status prop onto a local step state machine. Fixing that is a genuine refactor of live payment-flow state, which does not belong in a CI-repair PR that cannot drive a wallet end to end. The rule is set to warn, with the reasoning written inline in eslint.config.js and a named follow-up. Lint reports 0 errors, 10 warnings and exits 0. No security or correctness rule was relaxed.

Build failed in two places

  1. Tailwind v4 moved its PostCSS plugin to a separate package; passing tailwindcss itself as a plugin throws. Added @tailwindcss/postcss, repointed postcss.config.js.
  2. esbuild was never installed → Cannot find package 'esbuild'. Two independent causes:
    • overrides.esbuild pinned ^0.25.0 while Vite 8.3.1 peers ^0.27.0 || ^0.28.0 — an unsatisfiable slot, so npm installed nothing at all. Raised to ^0.28.1, which also clears GHSA-gv7w-rqvm-qjhr (high, esbuild < 0.28.1) and GHSA-g7r4-m6w7-qqqr. The old ^0.25.0 pin was itself vulnerable to both.
    • Vite declares esbuild as an optional peer, so it is never pulled in transitively. Added as an explicit devDependency.

Verification — executed, clean node_modules each time

  • npm ci (no flags, no .npmrc) → clean
  • npm run typecheck → PASS
  • npm run lint → exit 0, 0 errors / 10 warnings
  • npx vitest run → 165 passed, 4 failed
  • npm run build → PASS; dist/ has no solana entry, styles.css emitted
  • npm audit → 0 vulnerabilities (was 10 high / 16 moderate / 2 low). No --force; the only version changes are the ones above.
  • Simulated the supply-chain job: npm ci --ignore-scripts && npm run build succeeds, and npm pack --dry-run ships 68 files with no src/ or archive/.

Still failing, deliberately

The 4 signPermit cases in permit-allowlist.test.ts hit ADR-0004's KNOWN_PERMIT_TOKENS gate with a non-allow-listed token domain, and the shipped allowlist holds one placeholder digest. Making them pass means deciding the real allowlist contents. The gate was not weakened and the tests were not mocked out, per the handoff.

D4a still blank. No Polygon or Solana revival. Do not merge without Marcelo go.

Toolchain only. No public API change; version deliberately stays 0.5.0. Every
chain-cut guarantee intact: archive/solana still unwired, exports map unchanged,
137 / 900-902 drop guards still pass.

LINT — was crashing, now runs clean
eslint-plugin-react under ESLint 10 threw "contextOrFilename.getFilename is not a
function" before linting a single file. No published eslint-plugin-react (max
7.37.5, peers eslint ^3..^9.7) or eslint-plugin-jsx-a11y (max 6.10.2, peers ..^9)
supports ESLint 10, so the honest minimal fix is to pin the linter rather than the
plugins: eslint + @eslint/js ^10 -> ^9.39.5.

  - .npmrc DELETED. The legacy-peer-deps=true workaround added during the chain cut
    existed only because ESLint 10 broke the peer graph. With eslint 9 the graph
    resolves strictly and `npm ci` succeeds with no flags.
  - Caveat: eslint 9.39.5 warns "no longer supported". That is the trade — a
    supported-but-broken linter vs an EOL-but-working one. The real exit is
    upstream; logged in humanpending.md.

With lint actually executing, 23 masked errors surfaced. 14 mechanical ones fixed:
7 no-unnecessary-type-assertion (--fix), 3 prefer-for-of, 2 prefer-optional-chain,
2 require-await, 1 unused eslint-disable (replaced with one that states why the
cast exists). The prefer-optional-chain and prefer-for-of edits land in the
signed-config verifier and in permitDomainKey, so they were applied by hand, not by
a fixer, and proven behaviour-neutral: permit-allowlist + payment-config-verifier +
api-client suites pass 26/26.

The remaining 9 are react-hooks/set-state-in-effect, new in
eslint-plugin-react-hooks v7, flagging a pre-existing pattern in the payment modals
(an effect mirroring a `status` prop onto a local `step` machine). That is a real
refactor of live payment-flow state and does not belong in a CI-repair change, so
the rule is set to `warn` with the rationale inline in eslint.config.js. Lint now
reports 0 errors / 10 warnings and exits 0. No security or correctness rule relaxed.

BUILD — failed in two places, both fixed
1. Tailwind v4 moved its PostCSS plugin out; passing `tailwindcss` directly throws.
   Added @tailwindcss/postcss and repointed postcss.config.js.
2. esbuild was never installed, so Vite died with "Cannot find package 'esbuild'":
   - overrides.esbuild pinned ^0.25.0 while Vite 8.3.1 peers ^0.27.0 || ^0.28.0 —
     an unsatisfiable slot, so npm installed nothing. Raised to ^0.28.1, which also
     clears GHSA-gv7w-rqvm-qjhr (HIGH, esbuild < 0.28.1) and GHSA-g7r4-m6w7-qqqr.
     The old ^0.25.0 pin was itself vulnerable to both.
   - Vite declares esbuild as an OPTIONAL peer, so it is never installed
     transitively. Added as an explicit devDependency.

Verified locally (executed), from a clean node_modules each time
  - npm ci (no flags, no .npmrc): clean.
  - npm run typecheck: PASS.
  - npm run lint: exit 0 — 0 errors, 10 warnings.
  - npx vitest run: 165 passed, 4 failed.
  - npm run build: PASS. dist/ has no solana entry; styles.css emitted.
  - npm audit: 0 vulnerabilities (was 10 high / 16 moderate / 2 low). No --force.
  - Simulated the supply-chain job: `npm ci --ignore-scripts && npm run build`
    succeeds, and `npm pack --dry-run` ships 68 files with no src/ or archive/.

Still failing, deliberately untouched: the 4 signPermit cases in
permit-allowlist.test.ts hit ADR-0004's KNOWN_PERMIT_TOKENS gate with a
non-allow-listed token domain, and the shipped allowlist holds one placeholder
digest. Making them pass means deciding the real allowlist contents. The gate was
NOT weakened and the tests were NOT mocked out.
@marceloceccon

Copy link
Copy Markdown
Member Author

Superseded by #48, which carries this PR's commit verbatim (58c1815) and adds the HP-5 real permit allowlist (the 4 failing signPermit tests now pass: 199 passed / 0 failed) plus reference-aware pay-ins. Not closing it — that's the owner's call when #48 is decided.

marceloceccon added a commit that referenced this pull request Sep 30, 2026
…-2026-09-29

demo-95: reference-aware pay (payIn*WithReference), real permit allowlist (HP-5), 0.6.0 — supersedes #47
@marceloceccon

Copy link
Copy Markdown
Member Author

superseded by #48

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