Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gt-imagent-tee — Imagent's sealed room

The TEE room that runs a miner's image agent, funded by the miner's own key, and returns images bound to a hardware attestation.

This is not a fork. Sealing, the miner-funded gateway, the egress-blocked agent network, attestation, and replay protection all come from kata-tee-runner. We implement its one seam, TeeJobProfile, and add the single thing Imagent cannot do without.

Why this repo exists

kata-tee-runner's gateway is deliberately policy-free:

"it does not select models, meter tokens, limit calls, or pay for inference"

That is correct for a generic runner and fatal for Imagent, whose entire claim is that the image model is fixed for every competitor. A miner paying with their own key would otherwise call a stronger model and win on model choice rather than on agent design.

So gt-imagent-tee inserts a policy gateway between the untrusted agent and the room's gateway. Both run inside the enclave, so both are covered by the attestation quote.

  miner's agent  ──►  policy gateway  ──►  kata gateway  ──►  provider
  (own container,     (model pin,          (signed route,      (miner's key
   no key, no         call budget,          miner's key)        pays)
   egress)            provenance)
        └────────────── all inside the sealed room ──────────────┘
Policy Why
Rewrite model to google/gemini-3.1-flash-image The fixed-model rule becomes true by construction, not by honour
4 generations per problem, hard The miner pays, so nothing else stops a rich miner making 500 calls and keeping the best. Otherwise we measure budget, not agent quality
Strip provider / models / route / transforms No silent re-routing to another backend
Inject the key at the gateway The agent never holds the miner's credential at all
Record every call Becomes attested provenance, not agent testimony

The pin rewrites rather than rejects: an honest agent that hardcodes the right model and a dishonest one that asks for a frontier model take the identical path. The attempt is still counted, so model_substitutions > 0 in the published provenance is proof of what a miner tried to do.

How a challenge runs

project_key is the challenge id, and the room binds it into the quote.

project_key ──► seed = sha256("imagent-challenge-v1:" + challenge_id)
            ──► the same 7 problems the validator generated locally
            ──► one budgeted token per problem
            ──► agent container on the sealed network
            ──► images + SHA-256 per image + attested provenance

The agent receives, per problem, an inference_api URL carrying an opaque token. It never sees the room's signed gateway route, so it cannot reach the upstream gateway directly and escape the pin. It never sees the API key. It cannot mint tokens, so it cannot award itself extra generations.

The quote covers the report; the report carries a hash per image; the bytes ride alongside. A validator hashes what it received and compares — swapped bytes fail the hash, a swapped hash fails the quote.

For miners: sealing your key

Run this on your own machine, before you open a pull request:

export IMAGENT_PROVIDER_KEY=sk-or-v1-...
python imagent_seal.py \
    --room        https://<room URL> \
    --bundle      submissions/<your-directory> \
    --measurement sha256:<the allowlisted room image> \
    --provider    openrouter

It fetches the room's sealing public key, checks the attestation quote against the image the competition allowlists, binds the credential to a hash of your bundle, and encrypts it. The output is ciphertext you commit.

Three things it deliberately refuses to do:

  • Seal without --measurement. Sealing to an unverified key hands your credential to whoever holds the matching private key. That is the one mistake in this flow that actually costs money.
  • Take the key as an argument. Arguments land in shell history and in the process table, so it reads IMAGENT_PROVIDER_KEY or prompts without echo.
  • Accept a symlink in a bundle. A link pointing outside the bundle would be hashed as content the room never receives.

Change any file in the bundle afterwards and the binding no longer matches — the room will refuse the run. Re-run the tool. Use --dry-run to see the binding and verify the room without sealing anything.

Layout

imagent_seal.py       the miner tool above
imagent_tee/
  policy.py       the policy gateway: model pin, per-problem budget, provenance
  tokens.py       signed per-problem inference tokens
  profile.py      the TeeJobProfile seam kata-tee-runner loads
  report.py       image hashing, prompt redaction, report shaping
  agent_main.py   entrypoint inside the untrusted agent container
Dockerfile        the room image: FROM kata-tee-runner + this profile
Dockerfile.agent  the per-job agent container

policy.py, tokens.py, and report.py are stdlib-only and pure, so the rules a miner is judged by can be read and re-derived without installing anything — and the full test suite runs without a TEE, Docker, or a GPU.

What is not here, on purpose

Answer keys, imagent_scoring, the pairwise judge, and the ranking stay validator-side in gt-imagent-bench. Whoever pays for the judge controls the judge. The room returns images and provenance; the validator grades them.

A TEE is not a sandbox. It proves which code was loaded, not that the code behaved. That is why the miner's agent runs in its own container with dropped capabilities, a read-only root, and no network — not in the room's process. Put an agent in-process with the harness inside a TEE and you get cryptographically signed cheating.

agent_main.py runs beside the miner's code and is therefore not a security boundary. Everything that must hold — the model pin, the budget, the wall clock, the image hashes — is enforced outside that container.

Deploying

See DEPLOY.md — build both images digest-pinned, run the room in a Phala TDX VM, read its measurement, seal the project's keys to it, and wire the validator.

Development

python -m pytest          # 40 tests, no TEE, no Docker, no GPU required

Status

Built: the policy gateway, tokens, report shaping, the profile, and both images.

The problem generator it depends on (imagent_bench.problems) is built, so a real project_key generates real problems. project_key="imagent-fixture" still selects a plumbing stub with no generator and no provider call.

Before deploying: replace both REPLACE_WITH_APPROVED_DIGEST placeholders, and allowlist the resulting room measurement in the validator.

About

Imagent's sealed-room TEE profile: fixed-model policy gateway, miner-funded inference, and the miner sealing tool.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages