Skip to content

Autovara/kata-secrets

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

kata-secrets

Miner secret service and scoped inference proxy for Kata. See ../miner-secret-proxy-plan.md for the design and ../miner-secret-proxy-implementation-steps.md for the build order.

This is Step 2 of that plan: the secret service + proxy. It stores each miner's real provider key encrypted at rest and hands the sandboxed agent only a short-lived, PR/head-SHA-scoped run token — the raw key never reaches PRs, the validator, logs, or other miners.

Status

Built so far:

  • run_token.py — scoped, signed, expiring run tokens (condition b: tamper-proof per-request scope). Issue/verify with HMAC-SHA256; enforce_scope rejects replay against a different PR / head SHA / submission.
  • spend.py — per-run request/cost caps (condition c), reserved before the provider call and atomic under concurrency, keyed by the token's unique id.
  • crypto.py — at-rest encryption via cryptography MultiFernet (versioned rotation); non-reversible key fingerprint for duplicate detection.
  • store.py — encrypted, file-backed provider-key store keyed by the exact scope (repo + pull_number + head_sha + subnet_pack + mode + submission_id); register / status / revoke / internal get_provider_key. Only ciphertext and fingerprints touch disk.
  • credentials.py — run-credential issuance: verifies a key is registered and not revoked for the exact scope and provider, then mints a short-lived, scope-bound run token and returns the proxy endpoint + token. Never returns the raw provider key.
  • proxy.py/inference request logic: verify token → provider/model allowlist → per-run spend/request caps (keyed by the submission-evaluation scope, reserved before forwarding) → per-request revocation check → decrypt key → forward (injected) → metadata-only log. Never logs the key, prompt, or response body.
  • service.py — HTTP router + server exposing POST /api/miner-secrets, GET /api/miner-secrets/status, POST /api/internal/run-credentials, and POST /inference, with injected miner-auth / PR-author-verifier seams.
  • provider_forwarder.py — real Chutes/OpenRouter forwarder matching the SN60 Bitsec proxy (endpoints, auth headers, key prefixes, payload defaults), with an injected HTTP transport; plus a coarse prompt-token estimator for the cost cap.
  • github.py — GitHub-backed auth seams: build_github_miner_authenticator (miner GitHub-OAuth token → identity via /user) and build_github_pr_author_verifier (service token confirms the miner authored the PR). Injected transport.
  • app.py — env-driven assembly: load_secrets_config (pure) + build_router (wires all modules; network edges injectable) + main. Runnable as python -m kata_secrets.

The run token is scoped to the submission evaluation (repo + pull_number + head_sha + subnet_pack + mode + submission_id + provider) — the unit kata-bot knows before it invokes Kata. There is no separate run id.

Remaining before deploy: optional wallet-signature auth and retry/backoff on transient provider errors (Step 4 hardening). Conditions a (agent egress isolation) and d (secret service not reachable from the agent network) are deployment/topology controls.

Configuration

Required env for python -m kata_secrets:

  • KATA_SECRETS_MASTER_KEYS — comma-separated Fernet keys (newest first)
  • KATA_SECRETS_STORE_PATH — encrypted key-store path
  • KATA_SECRETS_TOKEN_SECRET — HMAC secret for run tokens
  • KATA_SECRETS_INTERNAL_TOKEN — bearer for /api/internal/run-credentials (matches kata-bot's KATA_SECRET_SERVICE_TOKEN)
  • KATA_SECRETS_PROXY_URL — public proxy base returned to agents
  • KATA_SECRETS_GITHUB_TOKEN — service token for PR-author verification

Optional: KATA_SECRETS_TOKEN_TTL_SECONDS (1800), KATA_SECRETS_ALLOWED_PROVIDERS (chutes,openrouter), KATA_SECRETS_ALLOWED_MODELS, KATA_SECRETS_MAX_REQUESTS_PER_RUN (200), KATA_SECRETS_MAX_COST_PER_RUN, KATA_SECRETS_GITHUB_API_URL, KATA_SECRETS_HOST (0.0.0.0), KATA_SECRETS_PORT (8099).

How a miner registers a key

The service hosts a small registration page at GET /miner/secrets (same origin as the API, strict Content-Security-Policy, no inline scripts). Point kata-bot's KATA_SECRET_REGISTRATION_URL at it; the bot's PR comment links a miner straight to a pre-filled form:

https://<secret-service-host>/miner/secrets?repo=<owner/repo>&pr=<number>&submission_id=<id>

On the page the miner enters a GitHub token (identity only — a token with no scopes/permissions is enough; the service reads /user to get their login and its own token to confirm they authored the PR), picks the provider, and pastes the provider API key. The page can auto-fill the PR head SHA from GitHub. Nothing is stored in the PR; the key is sent over HTTPS to /api/miner-secrets, encrypted at rest, and never displayed again.

Serve this page over HTTPS in production, and make sure only the public-facing secret service (not the inference proxy on bitsec-net) exposes it.

Programmatic alternative (curl)

The page is a thin client over the same API a miner can call directly:

curl -X POST https://<secret-service-host>/api/miner-secrets \
  -H "Authorization: Bearer <miner-github-token>" \
  -H "Content-Type: application/json" \
  -d '{"repo":"owner/kata","pull_number":42,
       "head_sha":"<PR head SHA>","subnet_pack":"sn60__bitsec","mode":"miner",
       "submission_id":"<id>","provider":"chutes","api_key":"<provider key>"}'

Check status with GET /api/miner-secrets/status?<scope query> and revoke with POST /api/miner-secrets/revoke (same auth + scope body).

In KATA_SECRETS_TEE_MODE=required the raw-key form is rejected; miners use python -m kata_secrets.client register (enclave-encrypted) instead. See the TEE plan.

Develop

uv sync --extra dev
uv run --extra dev python -m pytest
uv run --extra dev ruff check

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors