Fix e2e-anvil.sh: EXIT trap kill 0 and MockReserveCl8y log extraction #279

Closed
opened 2026-06-02 13:45:10 +00:00 by PlasticDigits · 8 comments
PlasticDigits commented 2026-06-02 13:45:10 +00:00 (Migrated from gitlab.com)

Summary

Fix scripts/e2e-anvil.sh so the Anvil + DeployDev + Playwright pipeline completes reliably. Today the script can exit during the post-deploy dev-wallet seed step when MockReserveCl8y is not parsed from the deploy log, and the EXIT trap can kill 0 (terminate the whole process group) before Playwright runs.

Parent / context: Follow-up from #266 verification and !399.


Current codebase

scripts/e2e-anvil.sh

  • Starts Anvil, calls yieldomega_anvil_deploy_dev from scripts/lib/anvil_deploy_dev.sh, builds frontend with Arena v2 VITE_*, runs npm run preview, then Playwright e2e/anvil-arena-*.spec.ts.

  • EXIT trap (line ~15):

    trap 'rm -f "${DEPLOY_LOG}" "${E2E_ENV_FILE}"; kill "${PREVIEW_PID:-0}" 2>/dev/null || true; kill "${ANVIL_PID:-0}" 2>/dev/null || true' EXIT
    

    When PREVIEW_PID or ANVIL_PID is unset, ${VAR:-0} expands to 0, and kill 0 signals the entire shell process group — observed as abrupt script termination mid-deploy (before Playwright).

yieldomega_anvil_deploy_dev seed block

After DeployDev, when YIELDOMEGA_SEED_EVM_DEV_WALLETS=1 (default) and DOUB/CRED are set:

CL8Y=$(_yieldomega_extract_addr "MockReserveCl8y")
# ...
bash scripts/seed-evm-dev-wallets-anvil.sh  # CL8Y optional inside seed script

_yieldomega_extract_addr greps deploy log for lines matching ^[[:space:]]*MockReserveCl8y: + hex address.

DeployDev.s.sol logging mismatch

When no RESERVE_ASSET_ADDRESS / USDM_ADDRESS is set, DeployDev deploys mock CL8Y and logs:

console.log("MockReserveCl8y deployed (dev only):", reserveAsset);

Other contracts use the pattern console.log("Doubloon:", address(doub)); which does match the extractor (Doubloon:). MockReserveCl8y: never appears in the log, so CL8Y is always empty in e2e-anvil.sh even on successful deploy.

A separate line console.log("MockReserveCl8y seeded for E2E mock wallet"); has no address.

scripts/seed-evm-dev-wallets-anvil.sh

  • Requires DOUB and CRED; CL8Y mint is optional (if [[ -n "${CL8Y:-}" ]]).
  • Empty CL8Y alone should not fail seeding — so the “CL8Y absent” symptom is a red herring unless combined with trap/set -e elsewhere.

Why this is needed

  1. CI / release confidence: bash scripts/e2e-anvil.sh is the documented gate for Arena Anvil E2E (docs/testing/e2e-anvil.md, optional workflow .github/workflows/e2e-anvil.yml). A silent mid-script exit blocks the full Playwright suite.
  2. Operator time: Contributors assume green e2e-anvil.sh means wallet-write specs are covered; false negatives waste debugging time.
  3. CL8Y seed parity: E2E mock wallet and KEY_EVM_* wallets should receive mock CL8Y when DeployDev deploys MockReserveCl8y — today the address is never passed to the seed script from e2e-anvil.sh.
  4. Trap safety: kill 0 on EXIT is a footgun for any early failure (deploy, seed, build), not only CL8Y.

Constraints and guardrails

  • Arena v2 only — do not reintroduce TimeCurve env or routes (#266).
  • Never commit Anvil private keys to the repo; seeding uses known dev keys only on chain 31337.
  • Minimal diff — fix trap + address extraction; avoid refactoring unrelated deploy paths.
  • start-local-anvil-stack.sh shares anvil_deploy_dev.sh; keep behavior consistent (or document intentional differences).
  • AGPL-3.0; follow .cursor/skills/yieldomega-guardrails/SKILL.md.

Relevant files

Area Files
E2E entrypoint scripts/e2e-anvil.sh
Shared deploy scripts/lib/anvil_deploy_dev.sh
Wallet seed scripts/seed-evm-dev-wallets-anvil.sh, scripts/lib/evm_dev_keys.sh
Deploy log source contracts/script/DeployDev.s.sol
Docs / CI docs/testing/e2e-anvil.md, .github/workflows/e2e-anvil.yml
Playwright frontend/e2e/anvil-arena-*.spec.ts

A. Fix EXIT trap (required)

Replace kill "${PREVIEW_PID:-0}" / kill "${ANVIL_PID:-0}" with guarded kills, e.g. only kill when PID is set and > 0:

if [[ -n "${PREVIEW_PID:-}" ]] && [[ "${PREVIEW_PID}" -gt 0 ]]; then kill "${PREVIEW_PID}" 2>/dev/null || true; fi
if [[ -n "${ANVIL_PID:-}" ]] && [[ "${ANVIL_PID}" -gt 0 ]]; then kill "${ANVIL_PID}" 2>/dev/null || true; fi

Apply the same pattern anywhere else using ${PID:-0} for cleanup.

B. Fix MockReserveCl8y address extraction (required)

Pick one (or combine):

  1. Align DeployDev log to console.log("MockReserveCl8y:", reserveAsset); (matches other contracts), or
  2. Extend _yieldomega_extract_addr with an alternate pattern for MockReserveCl8y deployed, or
  3. Fallback: read mock CL8Y from contracts/broadcast/DeployDev.s.sol/31337/run-latest.json when log grep fails.

Prefer (1) + (3) fallback for robustness across Foundry versions.

  • If seed-evm-dev-wallets-anvil.sh fails, print a clear error before EXIT (trap should not mask the message).
  • Consider set +e around seed with explicit exit code check so trap cleanup does not use kill 0 before stderr is flushed.

D. Tests / docs

  • Add a small shell test or CI step that greps a fixture deploy log and asserts CL8Y non-empty after extract.
  • Update docs/testing/e2e-anvil.md troubleshooting for trap + CL8Y.

Acceptance criteria

  • bash scripts/e2e-anvil.sh runs to completion (Playwright anvil-arena-*.spec.ts) on a clean VM with Foundry + Node + Chromium.
  • After DeployDev with default mock CL8Y, yieldomega_anvil_deploy_dev sets non-empty CL8Y (or seed uses broadcast fallback).
  • EXIT trap never invokes kill 0 when PREVIEW_PID / ANVIL_PID are unset.
  • scripts/start-local-anvil-stack.sh path still seeds wallets when enabled (no regression).
  • bash -x scripts/e2e-anvil.sh does not terminate between deploy and npm run build on success path.

Test plan — functional paths

# Path Expected
1 Fresh run bash scripts/e2e-anvil.sh Exit 0; Playwright summary printed
2 YIELDOMEGA_SEED_EVM_DEV_WALLETS=0 bash scripts/e2e-anvil.sh Still completes; seed skipped
3 YIELDOMEGA_DEPLOY_KUMBAYA=0 bash scripts/e2e-anvil.sh Completes; ETH pay spec skipped/fixme as today
4 Deploy with RESERVE_ASSET_ADDRESS set (no mock deploy) No CL8Y mint; script still completes
5 Interrupt script during Playwright Trap kills preview + anvil only, not parent shell
6 Re-run after partial failure No zombie anvil on 8545 / 4173

Test plan — attack / abuse vectors

Vector Test Expected
Trap kills unrelated processes Run e2e-anvil.sh in shared tmux session; fail early Only script-managed PIDs stopped; no kill 0
Log injection / forged DEPLOY_LOG Point DEPLOY_LOG at attacker-controlled file with fake MockReserveCl8y: Seed mints only on local Anvil; no mainnet keys in script
Wrong CL8Y address seeded Corrupt log line with random 0x… cast mint fails loudly; script exits non-zero with message
Resource exhaustion Low disk during forge build Non-zero exit; trap cleanup without hanging

Verification criteria

  • Local: full bash scripts/e2e-anvil.sh green.
  • rg 'kill "\$\{PREVIEW_PID:-0\}"' scripts/ → empty (or documented exception).
  • Unit/smoke: fixture log → extract CL8Y address matches DeployDev broadcast.
  • Optional: workflow_dispatch e2e-anvil workflow green.
  • Link fix MR to this issue; close when merged.
## Summary Fix `scripts/e2e-anvil.sh` so the Anvil + DeployDev + Playwright pipeline completes reliably. Today the script can exit during the post-deploy **dev-wallet seed** step when **`MockReserveCl8y`** is not parsed from the deploy log, and the EXIT trap can **`kill 0`** (terminate the whole process group) before Playwright runs. **Parent / context:** Follow-up from [#266](https://gitlab.com/PlasticDigits/yieldomega/-/issues/266) verification and [!399](https://gitlab.com/PlasticDigits/yieldomega/-/merge_requests/29). --- ## Current codebase ### `scripts/e2e-anvil.sh` - Starts Anvil, calls `yieldomega_anvil_deploy_dev` from [`scripts/lib/anvil_deploy_dev.sh`](scripts/lib/anvil_deploy_dev.sh), builds frontend with Arena v2 `VITE_*`, runs `npm run preview`, then Playwright `e2e/anvil-arena-*.spec.ts`. - EXIT trap (line ~15): ```bash trap 'rm -f "${DEPLOY_LOG}" "${E2E_ENV_FILE}"; kill "${PREVIEW_PID:-0}" 2>/dev/null || true; kill "${ANVIL_PID:-0}" 2>/dev/null || true' EXIT ``` When **`PREVIEW_PID`** or **`ANVIL_PID`** is unset, **`${VAR:-0}`** expands to **`0`**, and **`kill 0`** signals the **entire shell process group** — observed as abrupt script termination mid-deploy (before Playwright). ### `yieldomega_anvil_deploy_dev` seed block After DeployDev, when `YIELDOMEGA_SEED_EVM_DEV_WALLETS=1` (default) and `DOUB`/`CRED` are set: ```bash CL8Y=$(_yieldomega_extract_addr "MockReserveCl8y") # ... bash scripts/seed-evm-dev-wallets-anvil.sh # CL8Y optional inside seed script ``` **`_yieldomega_extract_addr`** greps deploy log for lines matching `^[[:space:]]*MockReserveCl8y:` + hex address. ### `DeployDev.s.sol` logging mismatch When no `RESERVE_ASSET_ADDRESS` / `USDM_ADDRESS` is set, DeployDev deploys mock CL8Y and logs: ```solidity console.log("MockReserveCl8y deployed (dev only):", reserveAsset); ``` Other contracts use the pattern `console.log("Doubloon:", address(doub));` which **does** match the extractor (`Doubloon:`). **`MockReserveCl8y:`** never appears in the log, so **`CL8Y` is always empty** in `e2e-anvil.sh` even on successful deploy. A separate line `console.log("MockReserveCl8y seeded for E2E mock wallet");` has **no address**. ### `scripts/seed-evm-dev-wallets-anvil.sh` - Requires `DOUB` and `CRED`; **`CL8Y` mint is optional** (`if [[ -n "${CL8Y:-}" ]]`). - Empty `CL8Y` alone should **not** fail seeding — so the “CL8Y absent” symptom is a **red herring** unless combined with trap/`set -e` elsewhere. --- ## Why this is needed 1. **CI / release confidence:** `bash scripts/e2e-anvil.sh` is the documented gate for Arena Anvil E2E ([`docs/testing/e2e-anvil.md`](docs/testing/e2e-anvil.md), optional workflow [`.github/workflows/e2e-anvil.yml`](.github/workflows/e2e-anvil.yml)). A silent mid-script exit blocks the full Playwright suite. 2. **Operator time:** Contributors assume green `e2e-anvil.sh` means wallet-write specs are covered; false negatives waste debugging time. 3. **CL8Y seed parity:** E2E mock wallet and `KEY_EVM_*` wallets should receive mock CL8Y when DeployDev deploys `MockReserveCl8y` — today the address is never passed to the seed script from `e2e-anvil.sh`. 4. **Trap safety:** `kill 0` on EXIT is a footgun for any early failure (deploy, seed, build), not only CL8Y. --- ## Constraints and guardrails - **Arena v2 only** — do not reintroduce TimeCurve env or routes ([#266](https://gitlab.com/PlasticDigits/yieldomega/-/issues/266)). - **Never commit Anvil private keys** to the repo; seeding uses known dev keys only on chain **31337**. - **Minimal diff** — fix trap + address extraction; avoid refactoring unrelated deploy paths. - **`start-local-anvil-stack.sh`** shares `anvil_deploy_dev.sh`; keep behavior consistent (or document intentional differences). - **AGPL-3.0**; follow [`.cursor/skills/yieldomega-guardrails/SKILL.md`](.cursor/skills/yieldomega-guardrails/SKILL.md). --- ## Relevant files | Area | Files | |------|--------| | E2E entrypoint | [`scripts/e2e-anvil.sh`](scripts/e2e-anvil.sh) | | Shared deploy | [`scripts/lib/anvil_deploy_dev.sh`](scripts/lib/anvil_deploy_dev.sh) | | Wallet seed | [`scripts/seed-evm-dev-wallets-anvil.sh`](scripts/seed-evm-dev-wallets-anvil.sh), [`scripts/lib/evm_dev_keys.sh`](scripts/lib/evm_dev_keys.sh) | | Deploy log source | [`contracts/script/DeployDev.s.sol`](contracts/script/DeployDev.s.sol) | | Docs / CI | [`docs/testing/e2e-anvil.md`](docs/testing/e2e-anvil.md), [`.github/workflows/e2e-anvil.yml`](.github/workflows/e2e-anvil.yml) | | Playwright | [`frontend/e2e/anvil-arena-*.spec.ts`](frontend/e2e/) | --- ## Recommended direction ### A. Fix EXIT trap (required) Replace `kill "${PREVIEW_PID:-0}"` / `kill "${ANVIL_PID:-0}"` with guarded kills, e.g. only kill when PID is set and `> 0`: ```bash if [[ -n "${PREVIEW_PID:-}" ]] && [[ "${PREVIEW_PID}" -gt 0 ]]; then kill "${PREVIEW_PID}" 2>/dev/null || true; fi if [[ -n "${ANVIL_PID:-}" ]] && [[ "${ANVIL_PID}" -gt 0 ]]; then kill "${ANVIL_PID}" 2>/dev/null || true; fi ``` Apply the same pattern anywhere else using `${PID:-0}` for cleanup. ### B. Fix MockReserveCl8y address extraction (required) Pick one (or combine): 1. **Align DeployDev log** to `console.log("MockReserveCl8y:", reserveAsset);` (matches other contracts), **or** 2. **Extend `_yieldomega_extract_addr`** with an alternate pattern for `MockReserveCl8y deployed`, **or** 3. **Fallback:** read mock CL8Y from `contracts/broadcast/DeployDev.s.sol/31337/run-latest.json` when log grep fails. Prefer **(1) + (3) fallback** for robustness across Foundry versions. ### C. Seed failure visibility (recommended) - If `seed-evm-dev-wallets-anvil.sh` fails, print a clear error before EXIT (trap should not mask the message). - Consider `set +e` around seed with explicit exit code check so trap cleanup does not use `kill 0` before stderr is flushed. ### D. Tests / docs - Add a small shell test or CI step that greps a fixture deploy log and asserts `CL8Y` non-empty after extract. - Update [`docs/testing/e2e-anvil.md`](docs/testing/e2e-anvil.md) troubleshooting for trap + CL8Y. --- ## Acceptance criteria - [ ] `bash scripts/e2e-anvil.sh` runs to completion (Playwright `anvil-arena-*.spec.ts`) on a clean VM with Foundry + Node + Chromium. - [ ] After DeployDev with default mock CL8Y, `yieldomega_anvil_deploy_dev` sets non-empty **`CL8Y`** (or seed uses broadcast fallback). - [ ] EXIT trap never invokes **`kill 0`** when `PREVIEW_PID` / `ANVIL_PID` are unset. - [ ] `scripts/start-local-anvil-stack.sh` path still seeds wallets when enabled (no regression). - [ ] `bash -x scripts/e2e-anvil.sh` does not terminate between deploy and `npm run build` on success path. --- ## Test plan — functional paths | # | Path | Expected | |---|------|----------| | 1 | Fresh run `bash scripts/e2e-anvil.sh` | Exit 0; Playwright summary printed | | 2 | `YIELDOMEGA_SEED_EVM_DEV_WALLETS=0 bash scripts/e2e-anvil.sh` | Still completes; seed skipped | | 3 | `YIELDOMEGA_DEPLOY_KUMBAYA=0 bash scripts/e2e-anvil.sh` | Completes; ETH pay spec skipped/fixme as today | | 4 | Deploy with `RESERVE_ASSET_ADDRESS` set (no mock deploy) | No CL8Y mint; script still completes | | 5 | Interrupt script during Playwright | Trap kills preview + anvil only, not parent shell | | 6 | Re-run after partial failure | No zombie anvil on 8545 / 4173 | --- ## Test plan — attack / abuse vectors | Vector | Test | Expected | |--------|------|----------| | **Trap kills unrelated processes** | Run `e2e-anvil.sh` in shared tmux session; fail early | Only script-managed PIDs stopped; no `kill 0` | | **Log injection / forged DEPLOY_LOG** | Point `DEPLOY_LOG` at attacker-controlled file with fake `MockReserveCl8y:` | Seed mints only on local Anvil; no mainnet keys in script | | **Wrong CL8Y address seeded** | Corrupt log line with random `0x…` | `cast` mint fails loudly; script exits non-zero with message | | **Resource exhaustion** | Low disk during `forge build` | Non-zero exit; trap cleanup without hanging | --- ## Verification criteria - [ ] Local: full `bash scripts/e2e-anvil.sh` green. - [ ] `rg 'kill "\$\{PREVIEW_PID:-0\}"' scripts/` → empty (or documented exception). - [ ] Unit/smoke: fixture log → extract `CL8Y` address matches DeployDev broadcast. - [ ] Optional: `workflow_dispatch` e2e-anvil workflow green. - [ ] Link fix MR to this issue; close when merged.
PlasticDigits commented 2026-06-02 13:45:19 +00:00 (Migrated from gitlab.com)

marked as related to #266

marked as related to #266
ghost1 commented 2026-06-03 11:41:00 +00:00 (Migrated from gitlab.com)

mentioned in commit 0fda44fdcdab35b89e1b2e17f9f080d8bd332d80

mentioned in commit 0fda44fdcdab35b89e1b2e17f9f080d8bd332d80
ghost1 commented 2026-06-03 11:41:50 +00:00 (Migrated from gitlab.com)

mentioned in commit 7f2cce9383

mentioned in commit 7f2cce93839962de73d36858cbb1a1ca26c21e05
PlasticDigits commented 2026-06-03 11:42:05 +00:00 (Migrated from gitlab.com)

Implementation (agent)

Branch: cursor/e2e-anvil-trap-cl8y-279-222d — MR pending merge to protected main.

What changed

  1. EXIT trap — scripts/e2e-anvil.sh uses _e2e_anvil_cleanup + _yieldomega_kill_pid_if_set so unset PREVIEW_PID / ANVIL_PID never invoke kill 0.
  2. MockReserveCl8y — DeployDev.s.sol logs MockReserveCl8y:; anvil_deploy_dev.sh resolves CL8Y from log and falls back to contracts/broadcast/DeployDev.s.sol/31337/run-latest.json.
  3. Seed visibility — failed seed-evm-dev-wallets-anvil.sh returns a clear error (works with #281 yieldomega_resolve_seed_minter_pk).
  4. Cloud agents — e2e-anvil.sh unsets KEY_EVM_* overrides so seeding targets Anvil accounts #0–#2.
  5. Docs — e2e-anvil §279, invariants INV-ANVIL-E2E-279-*, manual QA §279, guardrails + skills/README.md.

Verification checklist (QA)

  • bash scripts/verify-e2e-anvil-trap.sh → OK
  • bash scripts/test-anvil-deploy-cl8y-extract.sh → ok
  • bash scripts/verify-evm-dev-wallet-seed-anvil.sh → PASS (CL8Y balances)
  • bash scripts/e2e-anvil.sh → exit 0; Playwright 6/6 anvil-arena-*.spec.ts
  • YIELDOMEGA_SEED_EVM_DEV_WALLETS=0 bash scripts/e2e-anvil.sh still completes
  • Early failure (e.g. bad deploy) does not kill parent shell / tmux session

Agent-run results

Item Command Result
Trap regression verify-e2e-anvil-trap.sh PASS
CL8Y extract test-anvil-deploy-cl8y-extract.sh PASS
Dev-wallet seed verify-evm-dev-wallet-seed-anvil.sh PASS
Full E2E ANVIL_PORT=8549 bash scripts/e2e-anvil.sh PASS (6/6)

Please run the checklist on a clean VM after MR merge.

Request: QA agent team — please verify the checklist above on merge.


Issue left open until MR is merged and QA signs off.

## Implementation (agent) Branch: `cursor/e2e-anvil-trap-cl8y-279-222d` — MR pending merge to protected `main`. ### What changed 1. **EXIT trap** — `scripts/e2e-anvil.sh` uses `_e2e_anvil_cleanup` + `_yieldomega_kill_pid_if_set` so unset `PREVIEW_PID` / `ANVIL_PID` never invoke `kill 0`. 2. **MockReserveCl8y** — `DeployDev.s.sol` logs `MockReserveCl8y:`; `anvil_deploy_dev.sh` resolves CL8Y from log and falls back to `contracts/broadcast/DeployDev.s.sol/31337/run-latest.json`. 3. **Seed visibility** — failed `seed-evm-dev-wallets-anvil.sh` returns a clear error (works with #281 `yieldomega_resolve_seed_minter_pk`). 4. **Cloud agents** — `e2e-anvil.sh` unsets `KEY_EVM_*` overrides so seeding targets Anvil accounts #0–#2. 5. **Docs** — [e2e-anvil §279](docs/testing/e2e-anvil.md#anvil-e2e-trap-and-mock-cl8y-extract-gitlab-279), invariants `INV-ANVIL-E2E-279-*`, manual QA §279, guardrails + `skills/README.md`. ### Verification checklist (QA) - [ ] `bash scripts/verify-e2e-anvil-trap.sh` → **OK** - [ ] `bash scripts/test-anvil-deploy-cl8y-extract.sh` → **ok** - [ ] `bash scripts/verify-evm-dev-wallet-seed-anvil.sh` → **PASS** (CL8Y balances) - [ ] `bash scripts/e2e-anvil.sh` → exit 0; Playwright **6/6** `anvil-arena-*.spec.ts` - [ ] `YIELDOMEGA_SEED_EVM_DEV_WALLETS=0 bash scripts/e2e-anvil.sh` still completes - [ ] Early failure (e.g. bad deploy) does not kill parent shell / tmux session ### Agent-run results | Item | Command | Result | |------|---------|--------| | Trap regression | `verify-e2e-anvil-trap.sh` | PASS | | CL8Y extract | `test-anvil-deploy-cl8y-extract.sh` | PASS | | Dev-wallet seed | `verify-evm-dev-wallet-seed-anvil.sh` | PASS | | Full E2E | `ANVIL_PORT=8549 bash scripts/e2e-anvil.sh` | PASS (6/6) | Please run the checklist on a clean VM after MR merge. **Request:** QA agent team — please verify the checklist above on merge. --- Issue left **open** until MR is merged and QA signs off.
PlasticDigits commented 2026-06-03 11:42:48 +00:00 (Migrated from gitlab.com)

mentioned in merge request !409

mentioned in merge request !409
PlasticDigits commented 2026-06-03 11:54:33 +00:00 (Migrated from gitlab.com)

mentioned in commit c373b32777

mentioned in commit c373b32777eb5062dd7a7ca7927f78e02787b0b2
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-06-03 11:54:33 +00:00
ghost1 commented 2026-06-03 12:16:34 +00:00 (Migrated from gitlab.com)

mentioned in merge request !406

mentioned in merge request !406
PlasticDigits commented 2026-06-03 13:25:01 +00:00 (Migrated from gitlab.com)

mentioned in issue #263

mentioned in issue #263
Sign in to join this conversation.
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#279
No description provided.