Skip to content

Testing and CI

Ranesh Rajit edited this page Oct 8, 2026 · 4 revisions

Testing & CI

SelfTest - 86 checks, pure JDK, exit 1 on failure

javac -d out (Get-ChildItem -Recurse java/src/*.java)
java -cp out integrity.test.SelfTest

Coverage:

  • Keccak-256 vectors + all 4 function selectors (verified against ethers)
  • Ed25519 roundtrip, tampered field, wrong seq, corrupted signature
  • Raw-bytes hComb rule (and that hex-concat is a different wrong value)
  • Full attack table: OK, POLICY_BIN/CFG/MEM_CHANGED, MEASURE_MISMATCH_BIN/CFG/MEM, SIG_FAIL, COMB_MISMATCH, PREV_HASH_BREAK, STALE_REPLAY (old ts + seq reuse), CHAIN_MISMATCH (readback diverges)
  • Sustained-tamper regression (POLICY stays POLICY across cycles, recovery -> OK)
  • Verifier cursor: advances after linkage, cursor recovery across alternating verdicts
  • Chain receipts: only a mined 0x1 status counts as on-chain success
  • Merkle cached layers: layers()/proofFromLayers() single build, proofs verify/reject
  • getLatest return decode: wrapper offset + flat struct layouts, malformed payload -> null
  • Chain readback: matching record -> OK, divergent record -> CHAIN_MISMATCH comp=chain, unavailable -> degrades to no-readback
  • Chain pinning: matching pin accepted, mismatch refused, absent pin stays open (fresh-clone friendly); baseline parses chainContract + chainId
  • Key pinning: key swap -> KEY_MISMATCH, pin present + matching key -> OK, legacy unpinned baseline still boots
  • Witness: 3-line chain verifies, edited line breaks the chain, wrong boss key rejected
  • Dashboard: /api/status witness object serialized (chainOk / lines / lastSeq), null when unset
  • Merkle 10k-leaf build under budget + proof verify/reject
  • ABI layout: selectors, string offsets, seq word, sig offset
  • SeqStore roundtrip and genesis default
  • Status fields: chainPinned + lastReadback serialized in /api/status; /metrics emits Prometheus text (state, readback, seq, chain, batch, witness)
  • Env config: PORT parses (and rejects garbage), RPC_URL takes precedence over config/chain.json
  • Rotation: witness 50k-line rotation (archive + signed carry line, chain verifies across files), ledger rotation to a fresh active file
  • Raw tx signing: hardhat account0 address vector, EIP-155 unsigned RLP hashes to the official vector, ethers-cross-checked ecrecover vector, sign roundtrip (low-S, EIP-155 v, recovers own address), RLP golden values

CI - every push and PR

Workflow: .github/workflows/ci.yml

Gate Catches
javac full build compile breakage
javac --release 17 accidental Java 18+ APIs
SelfTest (86 checks) verifier/crypto/chain regressions
Counts + text hygiene gate badge/heading/table drift, stray em dashes, off-topic keywords
node --check web/app.js dashboard JS syntax
git ls-files --eol on the 2 hashed files LF/CRLF baseline portability break
Live smoke: boot -> must reach GREEN fresh-clone boot regression
Live smoke: tamper -> RED POLICY_CFG_CHANGED -> restore -> GREEN verdict regression
npx hardhat compile Solidity breakage
Chain e2e: hardhat node -> deploy -> Enroller pin -> GREEN + chainUp + readback=ok -> tamper RED -> restore GREEN -> wrong-contract pin refused chain path regressions

The live smoke test runs against a fresh checkout with auto-generated keys, which is why the committed baseline ships unpinned: every clone must boot GREEN on its own. The chain e2e step then runs the Enroller explicitly, which pins the key + chainContract + chainId for that workspace before the on-chain assertions.

Benchmarks

Measured numbers (not promises) live in the repository under docs/BENCHMARKS.md:

  • Pipeline avg 4ms (measure 0.6, sign 1.6, verify 2.0), worst 24ms over 20 trials.
  • Detection = next 5s interval + pipeline.
  • Merkle: 10k-leaf root ~93ms; 1 root/min = 0.0167 TPS vs naive 2000 TPS (120,000x headroom).

Clone this wiki locally