{"id":50844533,"url":"https://github.com/godaddy/ans","last_synced_at":"2026-06-14T08:33:45.816Z","repository":{"id":356404289,"uuid":"1231342894","full_name":"godaddy/ans","owner":"godaddy","description":"Open-source reference implementation of the Agent Name Service (ANS) based on the IETF draft — registry, transparency log, and offline verifier in Go.","archived":false,"fork":false,"pushed_at":"2026-06-13T14:03:50.000Z","size":1388,"stargazers_count":2,"open_issues_count":14,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-14T08:33:44.859Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/godaddy.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-06T21:47:50.000Z","updated_at":"2026-06-10T17:45:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/godaddy/ans","commit_stats":null,"previous_names":["godaddy/ans"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/godaddy/ans","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fans","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fans/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fans/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fans/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/godaddy","download_url":"https://codeload.github.com/godaddy/ans/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Fans/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34315072,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-14T02:00:07.365Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-14T08:33:45.717Z","updated_at":"2026-06-14T08:33:45.807Z","avatar_url":"https://github.com/godaddy.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ans — Agent Name Service\n\n`ans` is an open-source implementation of the Agent Name Service\n(ANS), a registry + transparency log for discovering and verifying\nAI agents by name. Every registered agent gets:\n\n- A versioned DNS-style name: `ans://v1.0.0.my-agent.example.com`\n- A publicly-auditable event history (append-only Merkle log)\n- SCITT COSE_Sign1 receipts proving the agent's state at a point in time\n- Identity certificates signed by a private CA for mTLS between agents\n- Optional BYOC server certificates + pinned TLSA records\n\nThe wire shape — event envelope, SCITT COSE receipts, sumdb-note\ncheckpoints, `/root-keys` format — is the public contract. Offline\nverifiers and TL clients depend on it byte-for-byte.\n\n## Binaries\n\n| Binary | Port | Role |\n| --- | --- | --- |\n| `ans-ra` | 18080 | Registration Authority — accepts registrations, issues identity certs, tracks lifecycle |\n| `ans-tl` | 18081 | Transparency Log — durable Merkle-tree append log, serves badges + receipts |\n| `ans-verify` | — | Offline CLI verifier for SCITT COSE receipts and status tokens |\n| `ans-dns` | 15353 | Dev-only authoritative DNS server with `install` / `clear` subcommands for local end-to-end verify-dns testing |\n\nBoth daemons (`ans-ra`, `ans-tl`) serve Swagger UI at `/docs` —\nbrowse \u003chttp://localhost:18080/docs\u003e (RA) and\n\u003chttp://localhost:18081/docs\u003e (TL) after `make build \u0026\u0026\nscripts/demo/start.sh`. The raw OpenAPI bytes live at\n`/docs/openapi.yaml` on each host.\n\nTo call protected endpoints from Swagger UI's \"Try it out\" button:\nclick **Authorize** in the top-right and paste the static API key.\nThe quickstart defaults are:\n\n- RA: `ans-dev-key-change-me` (from `config/ra-local.yaml`)\n- TL: `tl-internal-key` (from `config/tl-local.yaml`)\n\nThe RA writes signed events; the TL verifies, ingests, and publishes\nthem. An operator can run just the TL (for read-only verification) or\nboth together (full registry).\n\n## Quickstart (60 seconds)\n\n```bash\n# Prereqs: Go 1.26+, openssl, curl, jq\ngit clone https://github.com/godaddy/ans\ncd ans\nmake build                        # builds bin/ans-ra, bin/ans-tl, bin/ans-verify, bin/ans-dns\nscripts/demo/start.sh             # starts both daemons against ./data/demo\nscripts/demo/run-lifecycle.sh     # registers an agent, verifies the receipt end-to-end\n```\n\nExpected output (last few lines):\n\n```\n━━━ 13. Offline verify (bin/ans-verify) ━━━\n  ✓ Fetched 2 verification key(s) from /root-keys\n  ✓ 1602 bytes (Content-Type: application/scitt-receipt+cose)\n  ✓ VERIFIED (kid \u003c8-char-hex\u003e matched key directly)\n```\n\nTear down with `scripts/demo/stop.sh` or `scripts/demo/stop.sh --clean`\nto wipe the data directory.\n\n### Local DNS testing with `ans-dns`\n\nThe default DNS verifier in `config/ra-local.yaml` is `noop`, which\naccepts any DNS state. To exercise the real `lookup` verifier\nend-to-end without touching public DNS, run the bundled\nauthoritative server:\n\n```bash\n# In one terminal: start the dev DNS server (serves ./data/demo/dns)\nbin/ans-dns serve --addr 127.0.0.1:15353\n\n# In another: install the records the RA expects after verify-acme\nbin/ans-dns install --api-key \u003capi-key\u003e http://localhost:18080 \u003cagentId\u003e\n\n# Switch ra-local.yaml to dns.type=lookup pointed at 127.0.0.1:15353\n# and re-run verify-dns; ans-tl observes the AGENT_REGISTERED event.\n\n# Tear down:\nbin/ans-dns clear \u003cagentId\u003e\n```\n\n`ans-dns` is dev-only. Production deployments use the `lookup`\nverifier against the operator's existing authoritative DNS.\n\n## Docker\n\n```bash\n# Build images for the long-running daemons\nmake docker-build\n\n# Or bring the stack up with compose (RA + TL, with healthchecks)\ndocker compose up --build\n```\n\nCompose persists `ra-data`, `ra-keys`, and `tl-data` volumes so\nrestarts are cheap; `docker compose down -v` wipes them. `ans-verify`\nand `ans-dns` are local-development binaries and ship from `make\nbuild` only — they are not in the compose stack.\n\n## Architecture\n\nHexagonal / ports-and-adapters. The domain model (`internal/domain`)\nhas zero framework or storage dependencies. Services depend on port\ninterfaces (`internal/port`) which adapters in `internal/adapter/`\nimplement against real drivers.\n\n```\ncmd/ans-ra/main.go ───────┐\n                          ├─► internal/ra/service ─► port.AgentStore     ─► internal/adapter/store/sqlite\ncmd/ans-tl/main.go ───────┤                          port.KeyManager     ─► internal/adapter/keymanager\n                          │                          port.DNSVerifier    ─► internal/adapter/dns\n                          └─► internal/tl/service ─► port.RenewalStore   ─► …\n\ncmd/ans-verify/main.go ─► internal/tl/receipt   (Verify, ExtractKID, ComputeLeafHash)\ncmd/ans-dns/main.go    ─► miekg/dns authoritative server + RA-driven record install/clear\n```\n\nSee `spec/api-spec-v2.yaml` + `spec/api-spec-tl-v2.yaml` for the\nauthoritative OpenAPI contracts.\n\n## Core contracts\n\n**Event envelope (signed on the RA side):**\n\n```json\n{\n  \"payload\": {\n    \"logId\": \"\u003cuuid\u003e\",\n    \"producer\": {\n      \"event\": { \"ansId\": \"...\", \"ansName\": \"ans://...\", \"eventType\": \"AGENT_REGISTRATION\", ... },\n      \"keyId\": \"ans-ra-signer\",\n      \"signature\": \"\u003cdetached JWS over JCS(event)\u003e\"\n    }\n  },\n  \"schemaVersion\": \"V1\",\n  \"signature\": \"\u003cTL attestation JWS\u003e\",\n  \"status\": \"ACTIVE\"\n}\n```\n\n**Receipts (SCITT COSE_Sign1, RFC 8152 tag 18):**\n\n- Protected header: `{1:-7 (ES256), 4:\u003ckid 4-byte SPKI hash\u003e, 395:1 (RFC 9162), 15:{1:\u003cissuer\u003e, 6:\u003ciat\u003e}}`\n- Unprotected header: `{396:{-1:treeSize, -2:leafIndex, -3:path[][], -4:rootHash}}`\n- Payload: the JCS-canonical event bytes (the *same bytes* the leaf hash is computed over)\n- Signature: ES256 over the RFC 8152 §4.4 Sig_structure\n\n**Leaf hash:** RFC 6962 — `SHA-256(0x00 || payload)`.\n\n**Root-keys endpoint** (`GET /root-keys`) emits the\nsumdb-note verification-key format (one line per key):\n\n```\n\u003corigin\u003e+\u003ckeyhash-hex\u003e+\u003cbase64(0x02 || SPKI-DER)\u003e\n```\n\nwhere `keyhash-hex` is the first 4 bytes of `SHA-256(SPKI-DER)` as\nzero-padded big-endian hex. Verifiers match this against the `kid`\nin the receipt's protected header for O(1) key lookup.\n\nThe TL signs every outbound artifact (checkpoints, attestations,\nreceipts, status tokens) with a single ECDSA P-256 key. `/root-keys`\nadvertises exactly one line.\n\n## Verification workflow\n\nAny third party can verify an agent's state cryptographically without\ntrusting the TL operator beyond the advertised verifier keys:\n\n```bash\n# Fetch receipt + keys + verify\nans-verify -url https://tl.example.com -agent \u003cagentId\u003e\n\n# Or, air-gapped (receipt already on disk, key pinned in CI):\nans-verify -pubkey ./trusted-tl.pub -agent \u003cagentId\u003e \\\n  -url file://./receipt.cbor\n```\n\nThe verifier:\n\n1. Fetches `/root-keys` (or reads a pinned PEM).\n2. Fetches the receipt CBOR.\n3. Parses COSE_Sign1, extracts the inclusion proof from label 396.\n4. Maps the receipt's 4-byte `kid` → verifier key in O(1).\n5. Walks the Merkle path from `SHA-256(0x00 || payload)` to\n   `rootHash`; rejects any mismatch.\n6. ES256-verifies the signature over Sig_structure.\n7. Cross-checks that the receipt's computed leaf hash matches the\n   badge's `merkleProof.leafHash` (same leaf in the same tree).\n\n## Configuration\n\nBoth daemons read YAML via [koanf](https://github.com/knadh/koanf).\nThe shipped quickstart configs are under `config/`:\n\n- `config/ra-local.yaml` — local-filesystem dev config (SQLite, self-CA, noop DNS)\n- `config/tl-local.yaml` — same for the TL\n- `config/ra-docker.yaml` / `config/tl-docker.yaml` — compose-friendly paths + log format\n\nEvery YAML key is overridable via env vars using the `_` → `.` dotted\nform (e.g. `ANS_RA_SERVER__PORT=18090`).\n\n## Auth\n\nTwo providers ship today:\n\n- **Static API key** (quickstart): accepts both `Authorization: Bearer\n  \u003ckey\u003e` (ans-native form) and `Authorization: sso-key\n  \u003capiKey\u003e:\u003capiSecret\u003e` (the form generated SDK clients use). The\n  static key is treated as admin, so it can hit\n  `/internal/v1/producer-keys`.\n- **OIDC**: standard bearer-token validation against an issuer URL.\n  Configure admin groups with `auth.oidc.admin-groups[]`.\n\nEvery GET under `/v1/agents/`, `/v1/log/`, and the tlog-tiles paths\n(`/checkpoint`, `/root-keys`, `/tile/*`) is anonymous when\n`auth.public-read: true` (the default for the TL quickstart config) —\nverifiers never need credentials.\n\n## Pluggable architecture\n\nEvery external dependency lives behind a port interface in\n`internal/port/`. Defaults target local development; you can swap any\nof them at the port boundary without touching the service layer.\n\n| Concern | Default adapter | Common production swap |\n| --- | --- | --- |\n| Auth | Static API key + OIDC | OIDC against your IdP |\n| Identity cert issuance | File-backed self-signed CA | Cloud KMS-backed CA |\n| Server cert issuance | Self-signed CA + BYOC PEM | ACME / public CA / BYOC PEM |\n| DNS verification | `noop` and `lookup` (real miekg/dns queries with DNSSEC AD-bit propagation) | `lookup` against your authoritative DNS |\n| Signing keys | File-based ECDSA P-256 | Cloud KMS adapter |\n| Storage | SQLite | Postgres / managed RDBMS |\n\nCloud-KMS, Postgres, and managed-DNS adapters are\ncontribution-shaped — see `CONTRIBUTING.md`.\n\n## Development\n\n```bash\nmake test         # unit tests\nmake test-cover   # with coverage, enforces the repo gate (≥90%)\nmake test-race    # race detector\nmake check        # fmt + vet + lint + test-cover (pre-commit gate)\n```\n\nTest coverage targets: 100% on `internal/domain` and `internal/crypto`\n(with annotated SAFETY exceptions for unreachable defensive\nbranches), ≥90% overall across `internal/` (enforced by `make\ntest-cover`). Adapter packages under `internal/adapter/` are the\nprimary remaining gap — contributions welcome, see\n`CONTRIBUTING.md`.\n\nContributing guide: [`CONTRIBUTING.md`](CONTRIBUTING.md).\nProject conventions for code generation tools: [`CLAUDE.md`](CLAUDE.md).\n\n## Status\n\nShipped: full V1 + V2 RA surface (register, verify-acme, verify-dns,\nrevoke, list, detail, identity/server cert GET + POST, CSR status,\nrenewal lifecycle with BYOC + CSR paths, renewal expiry sweep) • TL\ningest, badge, audit, SCITT COSE receipts (tag 18, ES256), SCITT\nstatus tokens (1h TTL, terminal-state aware), root-keys (sumdb-note\nformat), JSON + raw checkpoint, paginated checkpoint history, schema\nlookup, Merkle tiles • Producer-key admin CRUD\n(`/internal/v1/producer-keys`) • `ans-verify` CLI that fetches +\nverifies both receipts and status tokens • `ans-dns` dev DNS server\nwith `install` / `clear` for verify-dns end-to-end testing.\n\nFollow-up opportunities (community): cloud-KMS / Postgres /\nmanaged-DNS adapters, real ACME DNS-01 verifier wiring, additional\nschema versions.\n\n## License\n\nMIT License. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgodaddy%2Fans","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgodaddy%2Fans","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgodaddy%2Fans/lists"}