Skip to content
alexar76Public

About

THEMIS — publish-time admission gate for AIMarket: signed approve/review/reject for AI-agent supply-chain procurement (not Metis, not WARDEN).

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

THEMIS

CI Python >=3.11 84 tests passing Coverage above 98% Documentation in 5 languages AIMarket Protocol v2 OWASP Agentic Top 10 mapped Ed25519 signing License: MIT

🔄 Synced from the AI-Factory monorepo (append-only history). Pull requests are welcome — merged PRs are imported back and re-synced here. Issues · Pull requests

THEMIS — publish-time admission gate for AIMarket
Should this AI agent be allowed into your business? — landing → · dashboards / console → · Alien Monitor → · run locally → · full tutorial → · Hub admission →

THEMIS (Θέμις) — publish-time admission gate for AIMarket
Signed approve / review / reject · not Metis cognition · not WARDEN runtime

English · Русский · Español · Français · 中文 · Localization glossary

Gallery

Receipt cards below are screenshots of the live admission console at /ui/ after a real local /invoke (safe → approve, unsafe → reject). Capability id: agent.security.supply-chain.audit@v1.

Public dashboards (no factory admin):

Surface URL
Landing https://alexar76.github.io/themis/
Admission console (Pages) https://alexar76.github.io/themis/console/
Alien Monitor (telemetry) https://monitor.modelmarket.dev/
Local operator UI http://127.0.0.1:8080/ui/ after uv run python agent.py
uv run python agent.py
# open http://127.0.0.1:8080/ui/
THEMIS admission receipt — APPROVE THEMIS admission receipt — REJECT
Approve · score 100 · risk_tier low Reject · fail-closed findings
Raw live /invoke approve JSON Raw live /invoke reject JSON
Raw signed /invoke · approve Raw signed /invoke · reject
THEMIS vs WARDEN vs Metis role split
THEMIS admits · WARDEN gates invoke · Metis advises

Why this agent

Businesses are adding agents to real workflows, while the agent itself may execute code, read secrets, spend money, write to external systems, or call an unreviewed dependency. The OWASP Top 10 for Agentic Applications now explicitly includes identity and privilege abuse, AI-agent supply chain vulnerabilities, insecure inter-agent communication, cascading failures, and human-agent trust exploitation.

This reference agent turns a candidate AIMarket manifest, declared permissions, evidence, expected usage, and a buyer policy into one bounded report:

  • approve, review, or reject;
  • a deterministic score and risk tier;
  • projected monthly cost;
  • specific findings and remediations;
  • OWASP Agentic risk mappings;
  • an optional asynchronous Metis second opinion;
  • a request-bound Ed25519 signature (receipt).

It does not certify compliance or predict future behaviour. It helps a human make a better procurement decision from explicit evidence — and, when Hub admission mode is enabled, it is the publish admission check before a third-party capability enters the public catalogue.

Listing on Hub is already multi-layer (operator publish token, stake, manifest, signatures, trust floors) — not open signup. Consuming the ecosystem via ARGUS / aimarket-mcp does not require THEMIS. See supply-chain admission.

Golden path

candidate manifest + permissions + evidence + usage + policy
                              │
                              ▼
                 deterministic policy engine
                              │
            ┌─────────────────┴─────────────────┐
            ▼                                   ▼
 signed decision immediately          lazy Metis advisory job
 approve / review / reject             pending → completed

Metis never overrides the deterministic decision. It reviews the consistency of the report, not the truth or future safety of the candidate agent.

Quick start

git clone https://github.com/alexar76/themis.git
cd themis
uv sync --extra dev
uv run python configure_provider.py
uv run python -m pytest -q
uv run python agent.py
# open http://127.0.0.1:8080/ui/  — live admission console

In another terminal:

curl --fail-with-body -sS \
  -X POST http://127.0.0.1:8080/invoke \
  -H 'Content-Type: application/json' \
  --data-binary @examples/safe_candidate.json

The safe sample returns decision: approve. Open /ui/, load unsafe example, and observe a fail-closed REJECT receipt with live findings.

Input contract

Block Meaning
candidate AIMarket manifest being considered
permissions Declared powers: code, secrets, money, writes, network, personal data
evidence HTTPS references such as an SBOM, security policy, or independent audit
usage Expected call volume and data classification
policy Buyer's price, budget, identity, evidence, and verification requirements
request_metis Start an advisory Metis job without blocking the main decision

All models reject unknown fields. The service never fetches evidence URLs, so untrusted input cannot turn it into an SSRF proxy.

Lazy Metis status

Copy .env.example to .env and set METIS_API_KEY on the server. Do not send it from a browser. With request_metis: true, /invoke returns immediately:

{
  "metis": {
    "status": "pending",
    "verification_id": "...",
    "poll_url": "/verification/..."
  }
}

Poll GET /verification/{verification_id} until completed, not_performed, timeout, unavailable, or failed. Jobs are memory-bounded and expire; upstream errors are reduced to an allowlisted reason rather than leaking infrastructure details.

MCP verdict

GET /mcp/verdict?package=npm:<name> (or pypi:<name>, or endpoint=https://…) returns approve, review, reject or unknown for an MCP server or package, with every reason, decided on HISTOR's evidence and signed by this provider's key (X-Provider-Signature, capability agent.security.mcp.verdict@v1, over the exact query). HISTOR's own signed /check answer travels with it as the evidence.

Policy themis-mcp/2: reject for block-tier patterns, decoy credential access/transmission, persistence or an extra recipient observed in the sandbox; review for provenance/publisher/dependency changes, lookalikes, network attempts (including tool calls), advisory patterns, classifier flags or recent definition changes; unknown for missing, incomplete, stale or mismatched evidence. Approve requires all mandatory checks to be complete and bound to the observed subject. Package build attestation presence is not verification: a package needs verified artifact evidence before approval.

THEMIS verifies the exact signed HISTOR /check answer and its query binding. Set THEMIS_HISTOR_ISSUER_DID to pin the issuer; otherwise key discovery uses the configured HISTOR HTTPS origin. No unsigned second record enters the decision. Invalid signatures or unavailable evidence return 503. A stale signed answer yields unknown. The decision carries all evidence used and is cached for ten minutes. See observer and evidence limitations.

Security boundary

  • request bodies are bounded to 256 KiB;
  • duplicate JSON keys and unknown fields are rejected;
  • candidate URLs are parsed but never contacted;
  • evidence references are never fetched;
  • an evidence reference counts toward the buyer's evidence floor only when it is bound to a SHA-256 digest, so decorative links cannot satisfy procurement;
  • attestations are verified offline against their own canonical statement — never by fetching;
  • a signature that does not verify is a finding, while a merely absent one is scored only when policy asks for it;
  • the provider identity is a persistent Ed25519 key stored with mode 0600;
  • the response signature covers the exact submitted input and result;
  • Metis credentials remain server-side;
  • Metis jobs have hard capacity, concurrency, response-size, timeout, and TTL bounds;
  • Metis job state is per-process by default; METIS_JOB_DB moves it to a shared store so any replica can answer any poll, and THEMIS_REPLICAS>1 without one refuses to start;
  • Python dependencies are locked in uv.lock, including the Docker image build;
  • OpenAPI, Swagger, and ReDoc routes are disabled;
  • the Docker image runs as an unprivileged user and expects a persistent key volume;
  • direct callers are not authenticated or billed: keep the port private behind Hub and HTTPS ingress.

See SECURITY.md and the architecture.

Attestations

A URL is a claim. A URL with a digest identifies an artifact. A URL with a digest and a signature is a claim someone put their key behind — the only one of the three this service can check without fetching anything.

uv run python attest.py evidence --kind sbom \
  --url https://vendor.example.com/sbom.json --sha256 <64-hex>
uv run python attest.py permissions --dossier examples/safe_candidate.json

Paste the printed object into the dossier as evidence[].attestation or permissions_attestation. The report's attestations block then records exactly what was verified: how many references were signed, whether any issuer was independent of the candidate, and whether the permission declaration is bound to provider_pubkey.

Policy field Default Effect
require_evidence_digests true Undigested references never count toward the evidence floor
require_evidence_attestation false Every counted reference needs a verified signature
require_independent_attestation false At least one issuer must not be the candidate's own key
require_permission_attestation false The declaration must be signed by provider_pubkey
trusted_evidence_issuers [] When set, only these issuer keys satisfy an attestation

Declared permissions remain a declaration — this does not make them true. It makes a false one signed, attributable and therefore slashable.

Publish to Hub

Replace invoke_url with the deployed HTTPS endpoint and set a stable publisher_id, then:

uv run python configure_provider.py
uv run python validate_manifest.py
aimarket publish capability.json --hub https://modelmarket.dev

Publishing remains an explicit operator action because Hub identity, stake, trust policy, and production reachability cannot safely be inferred by a project generator.

Alien Monitor

After Hub registration and a real Hub invoke, admission telemetry appears on the Alien Monitor THEMIS node (dossier-free receipts from Hub GET /supply/audits). This repository does not inject its own permanent 3D node from an unauthenticated client.

Learn by rebuilding it

The five-language lesson starts from the actual command below and recreates this repository step by step:

uvx create-aimarket-agent themis --kind tool --metis

Open the complete English tutorial.

License

MIT. OWASP names and identifiers are used for mapping and remain property of their respective owner.

About

THEMIS — publish-time admission gate for AIMarket: signed approve/review/reject for AI-agent supply-chain procurement (not Metis, not WARDEN).

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages