MergeGate BASE, BASE-SEPOLIA
Measured, not asserted

Verifier

The advantage is not that grading happens in a sandbox; plenty of things run in sandboxes. It is that the provider cannot influence the grader, and that this is demonstrable rather than asserted.

Pinned environment

Contracts pin this image by digest. A tag would let the graded environment drift after funding.

verifier image
us-central1-docker.pkg.dev/quick-catcher-470218-b0/mergegate/verifier@sha256:2e81501ef459f2a520c0ac08c5fd51962af2290c666d2374681e9619cc015b0a
execution environment
gen2 (gVisor)
resources
2 vCPU / 4Gi
timeout
600s
egress
deny-tcp-egress-except-google-restricted-vip-199.36.153.4/30; dns-resolution-available
network
mergegate-sealed / mergegate-sealed-uc1
service account
none, no cloud identity in the sandbox
writable paths
/workspace
retries
0, a retried evaluation is a second evaluation

How a submission is graded

Steps 2 and 5 are deliberately redundant. The guard already rejects grader-path edits, so the purge should never find anything, but a defense that depends on one check being correct fails when that check is wrong.

  1. 1
    Materialize the pinned base tree
    git archive emits tree contents only, so .git never exists to leak a reference solution.
  2. 2
    Guard every touched path
    A protected- or grader-path violation is a hard reject and the pinned commands never run.
  3. 3
    Apply the provider diff
    Allowed source paths only, as explicit file changes, never a shell patch of attacker-controlled input.
  4. 4
    Quarantine provider test hooks
    src/conftest.py sits inside an allowed path and pytest would still execute it. Allowed to write is not allowed to grade.
  5. 5
    Purge grader paths, inject the buyer's bundle
    The graded bytes are the buyer's, whatever the provider submitted.
  6. 6
    Run only the pinned commands
    argv vectors with no shell, in a rebuilt environment with no inherited secrets.
  7. 7
    Install the runtime grader guard
    An audit hook loaded outside the workspace stops provider code reading the graded tests. Blocking edits was not enough: code that reads them can answer from them without implementing anything.
  8. 8
    Hash the tree and bind the result
    tree_hash and submission_sha go into the receipt, so payment is for that exact artifact.
Probe exit code
21
Default Cloud Run
→
25
Sealed VPC

Each bit of the exit code is one destination. The change from 21 to 25 is the whole measurement: the same probe, run twice, against two configurations.

Network posture: measured

mergegate.verifier.egress_probe, executed inside the same sealed Cloud Run Job that grades submissions, on the same pinned image. Each result is a bit of the exit code as well as structured stdout: an early configuration surfaced no output at all, so the exit status is kept as the channel that survives logging breaking. A loopback control bit is included so a broken probe reports itself instead of masquerading as a perfect seal.

Destination Default Cloud Run Sealed VPC
loopback (control) reachable reachable
1.1.1.1:443 reachable blocked
142.250.72.46:443 blocked blocked
199.36.153.4:443 (restricted Google API VIP) reachable reachable
DNS resolution reachable reachable

The first configuration reached the public internet. Cloud Run grants egress by default. An earlier version of this system asserted default-deny while the deployed job could reach Cloudflare, and because the manifest writes that field into a signed receipt, it would have signed a false statement. The claim is now deny-tcp-egress-except-google-restricted-vip-199.36.153.4/30; dns-resolution-available.

Why one destination is still reachable. A completely sealed job cannot receive its inputs. They arrive on a Cloud Storage volume, and gcsfuse dials storage.googleapis.com from inside the same network namespace as the graded code, so a flat deny fails the mount and the job never starts — which is exactly how the first live sealed run died. Exactly one destination is therefore allowed, Google's restricted API VIP. Graded code can open a socket to it and holds no credentials to use there, but unauthenticated is a weaker claim than unreachable, so it is stated rather than rounded away. DNS likewise still resolves and remains a residual signalling channel.

Anti-gaming defenses

Each attack below is executed against a real repository with a real pytest process and asserted to fail. Mocking the runner would prove nothing; the grade has to actually be computed.

P1.1
A conftest.py hook that forces every outcome to pass
Quarantined before the run and recorded as a tamper signal, not silently fixed up.
P1.1
A sitecustomize.py that executes before any test is imported
Same quarantine: hooks the provider introduced or modified anywhere are removed.
P1.1b
Reading the graded tests at run time and answering from them
A submission that implemented nothing passed this way before the guard existed. Grader reads from provider source now raise.
P1.2
Reading the reference solution out of .git history
History never reaches the workspace, so there is nothing to read.
P1.3
Rewriting the graded tests
Rejected outright; the buyer's bundle also overwrites them regardless.
P1.3
Correct code that also disables the deploy gate
Rejected before any command runs; passing tests cannot rescue a path violation.
P0.4
Force-pushing a new head SHA after a PASS
A new SHA supersedes the previous artifact and invalidates its verification.

Scope: a run proves whether the submission satisfied the buyer's pinned contract. It does not assess code quality, security, or mergeworthiness.