29 test failures in new security audit suite (full_security_audit + spl_security) #72

Closed
opened 2026-03-24 08:02:53 +00:00 by Brouie · 6 comments
Brouie commented 2026-03-24 08:02:53 +00:00 (Migrated from gitlab.com)

147/176 pass, 29 fail on localnet. Failures span full_security_audit.test.ts, spl_security.test.ts, and duplicate tests in bridge.test.ts/faucet.test.ts.

Failing tests:

  1. registers a token mapping
  2. creates faucet config with correct fields
  3. fee + net_amount == gross_amount for all random amounts
  4. lock/unlock: bridge_token_balance == sum(deposits) - sum(fee_withdrawals) - sum(executions)
  5. mint/burn: supply_change == -(net_deposited) after deposits, restored after execution
  6. attacker cannot redirect SPL withdrawal to their token account
  7. admin cannot drain SPL fees beyond accrued per token_mapping
  8. passing a deposit PDA where a withdraw PDA is expected fails
  9. bridge balance after native withdrawal = previous_balance - withdrawal_amount + rent_return_from_PW_close
  10. SPL withdrawal cannot be executed via native path
  11. native SOL withdrawal cannot be executed via SPL path
  12. fees accrue independently per token mapping
    13-24. Various SPL deposit/withdraw/fee/hash/pause/mode tests
    25-26. Cross-path execution prevention
    27-28. SPL fee isolation E2E
  13. bad-path execution hardening (expects NotApproved, gets mint constraint error)

Common pattern: assertion mismatches — tests expect specific error codes but get account constraint errors instead. Likely PDA state conflicts from running all suites on same validator (earlier tests consume PDAs that later tests need fresh).

147/176 pass, 29 fail on localnet. Failures span full_security_audit.test.ts, spl_security.test.ts, and duplicate tests in bridge.test.ts/faucet.test.ts. Failing tests: 1. registers a token mapping 2. creates faucet config with correct fields 3. fee + net_amount == gross_amount for all random amounts 4. lock/unlock: bridge_token_balance == sum(deposits) - sum(fee_withdrawals) - sum(executions) 5. mint/burn: supply_change == -(net_deposited) after deposits, restored after execution 6. attacker cannot redirect SPL withdrawal to their token account 7. admin cannot drain SPL fees beyond accrued per token_mapping 8. passing a deposit PDA where a withdraw PDA is expected fails 9. bridge balance after native withdrawal = previous_balance - withdrawal_amount + rent_return_from_PW_close 10. SPL withdrawal cannot be executed via native path 11. native SOL withdrawal cannot be executed via SPL path 12. fees accrue independently per token mapping 13-24. Various SPL deposit/withdraw/fee/hash/pause/mode tests 25-26. Cross-path execution prevention 27-28. SPL fee isolation E2E 29. bad-path execution hardening (expects NotApproved, gets mint constraint error) Common pattern: assertion mismatches — tests expect specific error codes but get account constraint errors instead. Likely PDA state conflicts from running all suites on same validator (earlier tests consume PDAs that later tests need fresh).
PlasticDigits commented 2026-03-24 09:19:29 +00:00 (Migrated from gitlab.com)

mentioned in commit 70ed4d4c4a

mentioned in commit 70ed4d4c4ac6e634e9701d65c77ea5ceeb5d5f58
PlasticDigits commented 2026-03-24 09:19:45 +00:00 (Migrated from gitlab.com)

@Brouie — QA / dev review requested.

All 29 failures are resolved in commit 70ed4d4 on `feat/solana-integration`. Summary of fixes:

Program (Rust):

  • `withdraw_execute.rs` / `withdraw_execute_native.rs`: reordered `cancelled` check before `approved` check so cancelled withdrawals correctly surface `WithdrawalCancelled` instead of `NotApproved`.

Tests (TypeScript):

  • `full_security_audit.test.ts`: replaced Chai `.equal()` / `.lessThan()` with explicit boolean comparisons — Chai does not support native BigInt.
  • `security_audit.test.ts`: fixed cancel→reenable assertion — `reenable` resets approval, so the test now re-approves before executing.
  • `cancel_blocks_theft.test.ts`: removed unused `findBridgePda` import.

Result: 178/178 tests passing on localnet (0 failures).

Please pull `feat/solana-integration` and run `anchor test` to confirm.

@Brouie — QA / dev review requested. All 29 failures are resolved in commit 70ed4d4 on \`feat/solana-integration\`. Summary of fixes: **Program (Rust):** - \`withdraw_execute.rs\` / \`withdraw_execute_native.rs\`: reordered \`cancelled\` check before \`approved\` check so cancelled withdrawals correctly surface \`WithdrawalCancelled\` instead of \`NotApproved\`. **Tests (TypeScript):** - \`full_security_audit.test.ts\`: replaced Chai \`.equal()\` / \`.lessThan()\` with explicit boolean comparisons — Chai does not support native BigInt. - \`security_audit.test.ts\`: fixed cancel→reenable assertion — \`reenable\` resets approval, so the test now re-approves before executing. - \`cancel_blocks_theft.test.ts\`: removed unused \`findBridgePda\` import. **Result:** 178/178 tests passing on localnet (0 failures). Please pull \`feat/solana-integration\` and run \`anchor test\` to confirm.
Brouie commented 2026-03-25 02:33:31 +00:00 (Migrated from gitlab.com)

Still 147/31 after docker restart + fresh deploy. Docker restart doesn't wipe ledger so old PDAs persist. Dev's 178/178 was likely on clean state. These failures are PDA state conflicts, not code bugs — need a way to reset docker Solana ledger or run suites independently. Can you confirm how to get clean state on docker validator?

Still 147/31 after docker restart + fresh deploy. Docker restart doesn't wipe ledger so old PDAs persist. Dev's 178/178 was likely on clean state. These failures are PDA state conflicts, not code bugs — need a way to reset docker Solana ledger or run suites independently. Can you confirm how to get clean state on docker validator?
PlasticDigits commented 2026-03-25 04:02:05 +00:00 (Migrated from gitlab.com)

mentioned in commit a60944ee26

mentioned in commit a60944ee2667f71229a20eb09c39541d13515fcc
PlasticDigits commented 2026-03-25 04:02:21 +00:00 (Migrated from gitlab.com)

@Brouie — the remaining failures are a port conflict / stale state issue, not code bugs. When Docker's solana service is running on port 8899, anchor test can't start its own clean validator and silently connects to the Docker one, which still has PDAs from previous runs. docker restart re-runs --reset but if you've already run tests against that validator, the state accumulates across invocations.

Pushed a60944e on feat/solana-integration with three new Makefile targets to handle this properly:

Automatically stops the Docker Solana validator if it's running, then runs anchor test which spins up its own ephemeral validator with a completely clean ledger. This is what you want for day-to-day test runs — guaranteed clean state every time, no PDA conflicts.

make solana-test-docker

For when you specifically need to test against the Docker validator (e.g. E2E flows that depend on other Docker services). This runs make solana-reset first (destroys and recreates the container), then runs anchor test --skip-local-validator against it. Clean ledger, but the Docker validator stays up afterward.

make solana-reset

Standalone target that recreates the Docker Solana container from scratch (docker compose rm -sf solana && docker compose up -d solana) and waits for the healthcheck. Use this when you need a fresh Docker validator for manual deploys or debugging — it's what docker restart should have been doing.

TL;DR: Pull feat/solana-integration and run make solana-test. That's it — 178/178.

@Brouie — the remaining failures are a **port conflict / stale state** issue, not code bugs. When Docker's `solana` service is running on port 8899, `anchor test` can't start its own clean validator and silently connects to the Docker one, which still has PDAs from previous runs. `docker restart` re-runs `--reset` but if you've already run tests against that validator, the state accumulates across invocations. Pushed `a60944e` on `feat/solana-integration` with three new Makefile targets to handle this properly: ### `make solana-test` (recommended for dev) Automatically stops the Docker Solana validator if it's running, then runs `anchor test` which spins up its own **ephemeral validator with a completely clean ledger**. This is what you want for day-to-day test runs — guaranteed clean state every time, no PDA conflicts. ### `make solana-test-docker` For when you specifically need to test against the **Docker validator** (e.g. E2E flows that depend on other Docker services). This runs `make solana-reset` first (destroys and recreates the container), then runs `anchor test --skip-local-validator` against it. Clean ledger, but the Docker validator stays up afterward. ### `make solana-reset` Standalone target that **recreates the Docker Solana container from scratch** (`docker compose rm -sf solana && docker compose up -d solana`) and waits for the healthcheck. Use this when you need a fresh Docker validator for manual deploys or debugging — it's what `docker restart` should have been doing. **TL;DR:** Pull `feat/solana-integration` and run `make solana-test`. That's it — 178/178.
Brouie commented 2026-03-25 04:42:47 +00:00 (Migrated from gitlab.com)

178/178 ALL PASS after anchor keys sync + make solana-test (clean ephemeral validator). Zero failures.

178/178 ALL PASS after anchor keys sync + make solana-test (clean ephemeral validator). Zero failures.
Brouie (Migrated from gitlab.com) closed this issue 2026-03-25 04:42:48 +00:00
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/cl8y-bridge-monorepo#72
No description provided.