Fail production frontend builds when VITE_E2E_MOCK_WALLET is set (#327) #500

Merged
PlasticDigits merged 1 commit from issue-327-production-mock-wallet-gate into main 2026-06-15 01:01:25 +00:00
PlasticDigits commented 2026-06-14 22:56:53 +00:00 (Migrated from gitlab.com)

Summary

Implements GitLab #327 (parent #325 audit F-05 recommendation #3): production frontend builds now fail closed when VITE_E2E_MOCK_WALLET=1 would be inlined into dist/.

  • frontend/vite.config.ts — calls assertProductionBuildEnv at vite build start; clear error message; ANVIL_E2E=1 bypass for scripts/e2e-anvil.sh only.
  • frontend/src/lib/viteProductionEnvGuard.ts — testable guard module + Vitest coverage.
  • scripts/check-frontend-vite-env.sh --production — deploy-script check that rejects mock wallet in merged .env* files.
  • scripts/qa/build-frontend-for-rabby.sh — exports empty VITE_E2E_MOCK_WALLET so .env.local mock flags cannot leak into Rabby builds.
  • CI — unit-tests → frontend-test job asserts VITE_E2E_MOCK_WALLET=1 npm run build exits non-zero.
  • Docs — docs/testing/e2e-anvil.md, docs/testing/ci.md, INV-FRONTEND-327-PRODUCTION-MOCK-WALLET in invariants.

vite dev and Anvil auto-mock without VITE_E2E_MOCK_WALLET are unchanged.

Acceptance checklist

Criterion Command / step Result
npm run build with VITE_E2E_MOCK_WALLET=1 fails with clear error cd frontend && VITE_CHAIN_ID=31337 VITE_RPC_URL=http://127.0.0.1:8545 VITE_TIME_ARENA_ADDRESS=0x…01 VITE_PODIUM_VAULTS_ADDRESS=0x…02 VITE_REFERRAL_REGISTRY_ADDRESS=0x…03 VITE_E2E_MOCK_WALLET=1 npm run build PASS (exit 1, message cites #327)
Anvil E2E still passes bash scripts/e2e-anvil.sh PASS (7/7 Playwright specs)
Rabby build path mock-free bash scripts/qa/build-frontend-for-rabby.sh (needs Anvil stack .env.local) SKIP (no stack .env.local in agent VM; script unchanged + empty export guard)
CI catches regression .github/workflows/unit-tests.yml → frontend-test mock-wallet step PASS (added; runs on merge gate)
Dev-mode Anvil auto-mock unchanged frontend/src/wagmi-config.ts + wagmi-config.test.ts PASS (no edits to dev mock path)
Frontend unit suite cd frontend && npm run typecheck && npm run lint && npm test PASS
Clean production build cd frontend with required VITE_* (no mock) → npm run build PASS
Deploy env script guard bash scripts/check-frontend-vite-env.sh --production with VITE_E2E_MOCK_WALLET=1 in .env.production.local PASS (rejects mock)

Third-party verification

  1. Check out branch issue-327-production-mock-wallet-gate.
  2. cd frontend && npm ci && npm run typecheck && npm run lint && npm test → green.
  3. cd frontend && VITE_E2E_MOCK_WALLET=1 npm run build → must fail before writing dist/.
  4. export PATH="$HOME/.foundry/bin:$PATH" && bash scripts/e2e-anvil.sh → green (mock allowed via ANVIL_E2E=1).
  5. With Anvil stack up: bash scripts/qa/build-frontend-for-rabby.sh then grep -rq 'mock({ accounts' frontend/dist/assets/ → no matches.
## Summary Implements GitLab #327 (parent #325 audit F-05 recommendation #3): production frontend builds now **fail closed** when `VITE_E2E_MOCK_WALLET=1` would be inlined into `dist/`. - **`frontend/vite.config.ts`** — calls `assertProductionBuildEnv` at `vite build` start; clear error message; **`ANVIL_E2E=1`** bypass for `scripts/e2e-anvil.sh` only. - **`frontend/src/lib/viteProductionEnvGuard.ts`** — testable guard module + Vitest coverage. - **`scripts/check-frontend-vite-env.sh --production`** — deploy-script check that rejects mock wallet in merged `.env*` files. - **`scripts/qa/build-frontend-for-rabby.sh`** — exports empty `VITE_E2E_MOCK_WALLET` so `.env.local` mock flags cannot leak into Rabby builds. - **CI** — `unit-tests` → `frontend-test` job asserts `VITE_E2E_MOCK_WALLET=1 npm run build` exits non-zero. - **Docs** — `docs/testing/e2e-anvil.md`, `docs/testing/ci.md`, `INV-FRONTEND-327-PRODUCTION-MOCK-WALLET` in invariants. `vite dev` and Anvil auto-mock without `VITE_E2E_MOCK_WALLET` are unchanged. ## Acceptance checklist | Criterion | Command / step | Result | |-----------|----------------|--------| | `npm run build` with `VITE_E2E_MOCK_WALLET=1` fails with clear error | `cd frontend && VITE_CHAIN_ID=31337 VITE_RPC_URL=http://127.0.0.1:8545 VITE_TIME_ARENA_ADDRESS=0x…01 VITE_PODIUM_VAULTS_ADDRESS=0x…02 VITE_REFERRAL_REGISTRY_ADDRESS=0x…03 VITE_E2E_MOCK_WALLET=1 npm run build` | **PASS** (exit 1, message cites #327) | | Anvil E2E still passes | `bash scripts/e2e-anvil.sh` | **PASS** (7/7 Playwright specs) | | Rabby build path mock-free | `bash scripts/qa/build-frontend-for-rabby.sh` (needs Anvil stack `.env.local`) | **SKIP** (no stack `.env.local` in agent VM; script unchanged + empty export guard) | | CI catches regression | `.github/workflows/unit-tests.yml` → `frontend-test` mock-wallet step | **PASS** (added; runs on merge gate) | | Dev-mode Anvil auto-mock unchanged | `frontend/src/wagmi-config.ts` + `wagmi-config.test.ts` | **PASS** (no edits to dev mock path) | | Frontend unit suite | `cd frontend && npm run typecheck && npm run lint && npm test` | **PASS** | | Clean production build | `cd frontend` with required `VITE_*` (no mock) → `npm run build` | **PASS** | | Deploy env script guard | `bash scripts/check-frontend-vite-env.sh --production` with `VITE_E2E_MOCK_WALLET=1` in `.env.production.local` | **PASS** (rejects mock) | ## Third-party verification 1. Check out branch `issue-327-production-mock-wallet-gate`. 2. `cd frontend && npm ci && npm run typecheck && npm run lint && npm test` → green. 3. `cd frontend && VITE_E2E_MOCK_WALLET=1 npm run build` → **must fail** before writing `dist/`. 4. `export PATH="$HOME/.foundry/bin:$PATH" && bash scripts/e2e-anvil.sh` → green (mock allowed via `ANVIL_E2E=1`). 5. With Anvil stack up: `bash scripts/qa/build-frontend-for-rabby.sh` then `grep -rq 'mock({ accounts' frontend/dist/assets/` → no matches.
PlasticDigits commented 2026-06-14 23:01:13 +00:00 (Migrated from gitlab.com)

Security review — MR !500

Commit reviewed: a9bb2e219e5cc3765efcb1a048ce3d2e9b5f5fa2

Scope: Production build guard for VITE_E2E_MOCK_WALLET (frontend/vite.config.ts, viteProductionEnvGuard.ts, scripts/check-frontend-vite-env.sh --production, scripts/qa/build-frontend-for-rabby.sh, CI regression step, docs/invariants).

Outcome: FINDINGS: 0 medium+

Prior threads: None (first security review on this MR).

Summary

This MR implements fail-closed hardening for audit F-05 (#327): production vite build aborts when VITE_E2E_MOCK_WALLET=1 would be inlined, with a documented ANVIL_E2E=1 bypass for scripts/e2e-anvil.sh only. The Rabby build script change (export VITE_E2E_MOCK_WALLET= instead of unset) correctly prevents .env.local mock flags from overriding the guard via Vite’s process.env precedence.

Review traced attacker-controlled inputs to sinks:

Area Result
Mock wallet in CDN bundle Guard blocks command === "build" + VITE_E2E_MOCK_WALLET=1; wagmi-config.ts only enables mock on strict === "1"; production import.meta.env.DEV is false so dev auto-mock path is inactive
ANVIL_E2E=1 bypass Intentional, shell-export only (not loaded from .env* files); requires build-environment control — not an external attack path
Shell / deploy scripts No injection sinks; env parsing is assignment-only
EVM / contracts No onchain changes
New dependencies None

Verified locally: VITE_E2E_MOCK_WALLET=1 npm run build fails; empty-export Rabby-style build succeeds without inlining mock; ANVIL_E2E=1 + mock allows E2E build as designed.

Security review: no medium+ findings on this diff.

## Security review — MR !500 **Commit reviewed:** `a9bb2e219e5cc3765efcb1a048ce3d2e9b5f5fa2` **Scope:** Production build guard for `VITE_E2E_MOCK_WALLET` (`frontend/vite.config.ts`, `viteProductionEnvGuard.ts`, `scripts/check-frontend-vite-env.sh --production`, `scripts/qa/build-frontend-for-rabby.sh`, CI regression step, docs/invariants). **Outcome:** `FINDINGS: 0` medium+ **Prior threads:** None (first security review on this MR). ### Summary This MR implements fail-closed hardening for audit F-05 (#327): production `vite build` aborts when `VITE_E2E_MOCK_WALLET=1` would be inlined, with a documented `ANVIL_E2E=1` bypass for `scripts/e2e-anvil.sh` only. The Rabby build script change (`export VITE_E2E_MOCK_WALLET=` instead of `unset`) correctly prevents `.env.local` mock flags from overriding the guard via Vite’s `process.env` precedence. Review traced attacker-controlled inputs to sinks: | Area | Result | |------|--------| | Mock wallet in CDN bundle | Guard blocks `command === "build"` + `VITE_E2E_MOCK_WALLET=1`; `wagmi-config.ts` only enables mock on strict `=== "1"`; production `import.meta.env.DEV` is false so dev auto-mock path is inactive | | `ANVIL_E2E=1` bypass | Intentional, shell-export only (not loaded from `.env*` files); requires build-environment control — not an external attack path | | Shell / deploy scripts | No injection sinks; env parsing is assignment-only | | EVM / contracts | No onchain changes | | New dependencies | None | Verified locally: `VITE_E2E_MOCK_WALLET=1 npm run build` fails; empty-export Rabby-style build succeeds without inlining mock; `ANVIL_E2E=1` + mock allows E2E build as designed. **Security review: no medium+ findings on this diff.**
PlasticDigits (Migrated from gitlab.com) merged commit ecb17aad3c into main 2026-06-15 01:01:25 +00:00
PlasticDigits commented 2026-06-15 01:01:26 +00:00 (Migrated from gitlab.com)

mentioned in commit ecb17aad3c

mentioned in commit ecb17aad3c87f090c49cfe7b28fcf6ba5debfebb
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
code/yieldomega!500
No description provided.