Skip to content

tech: Run the test suite without repository secrets - #397

Merged
DarthMike merged 3 commits into
developfrom
tech/test-key-without-secrets
Aug 13, 2026
Merged

DarthMike merged 3 commits into
developfrom
tech/test-key-without-secrets

Conversation

@DarthMike

@DarthMike DarthMike commented Aug 13, 2026 •

Copy link
Copy Markdown
Member

Makes the suite runnable with no credentials, so pull requests from forks get a real CI signal and a fresh clone can run swift test immediately.

Unblocks #392, which is currently red through no fault of its own.

The problem

GitHub never gives repository secrets to pull requests from forks. setupKey.sh therefore wrote privateKey = "", which compiles — so this was never a build failure, despite appearances. The suite got as far as the first test that force-unwrapped an account built from that key and died:

error: Process ... exited with unexpected signal code 6

Signal 6 is an abort, and it takes the whole test process with it, so every suite after it never ran. Same pattern as the Linux abort in #395: what looks like a couple of failing tests is actually most of the suite never executing.

What actually needed the key

Three different needs were hidden behind one secret. Only the first is secret at all:

need tests secret?
Pay for gas testEthSendRawTransaction yes
A specific key — derive an address, produce a deterministic signature testLoadAccountAndAddress, …Multiple, zkSync signing test no: needs a key, not the key
Name an address on chain getTransactionCount ×2, getBalance no: an address is public

Two further suites — OffchainLookupTests and EthereumClientZKSyncTests — built accounts from the key and never used them. That is most of why the abort had such a wide blast radius.

Changes

  • Funded key → TESTS_PRIVATEKEY environment variable. setupKey.sh and the generated TestConfig_private.swift are deleted; CI already exported this variable alongside running the script.
  • Throwaway key committed as TestConfig.signingPrivateKey — the well-known Anvil/Hardhat account #0, public by design and holding nothing. Used wherever a key is needed but funds are not.
  • Funded address committed as TestConfig.publicKey, unchanged in value. It was already in setupKey.sh in the clear; an address is not a secret, and the nonce and log fixtures are its on-chain history.
  • One skip. testEthSendRawTransaction calls requireFundedPrivateKey(), which throws XCTSkip with an explanation when the variable is absent.
  • Dead accounts deleted from OffchainLookupTests and EthereumClientZKSyncTests.
  • CI runs on pushes to develop, since a fork's PR cannot exercise the funded test before it merges.

🤖 Generated with Claude Code

Pull requests from forks never receive secrets, so setupKey.sh wrote an
empty private key and the suite aborted with signal 6 the moment a test
force-unwrapped an account built from it. That took every later suite with
it, so outside contributions could not get a usable CI signal at all, and
a fresh clone could not run the tests without being handed the key.

Almost nothing actually needed that key. Three separate needs were hidden
behind it: paying for gas, having a specific key to derive an address or
produce a deterministic signature, and simply naming an address on chain.
Only the first is secret.

Split them. Address-only tests use the funded account's address, which is
public and now committed. Signing and identity tests use a throwaway key,
also committed — the well-known Anvil account #0, which holds nothing.
The funded key moves to the TESTS_PRIVATEKEY environment variable, so the
generated file and setupKey.sh are gone, and it is read straight from the
environment CI already sets.

That leaves one test that spends Ether. It skips when the key is absent
rather than failing. Two other suites held accounts built from the key
that were never used at all, which is most of why the abort had such a
wide blast radius; those are deleted.

The zkSync signing test now signs with the throwaway key, so its expected
value is regenerated. It also recovers the signer from the EIP-712 digest
and asserts it matches, so the hash pins the encoding rather than just
recording whatever the code happened to emit.

CI also runs on pushes to develop, since a fork's pull request cannot
exercise the funded test before it merges.
@DarthMike
DarthMike requested review from a team and dmcrodrigues as code owners August 13, 2026 14:49
@DarthMike
DarthMike merged commit ee5079f into develop Aug 13, 2026
3 checks passed
@DarthMike
DarthMike deleted the tech/test-key-without-secrets branch August 13, 2026 16:40
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