Skip to content

feat(ans): add ANS agent lifecycle commands#46

Draft
Swaagie wants to merge 1 commit into
mainfrom
feat/ans-commands
Draft

feat(ans): add ANS agent lifecycle commands#46
Swaagie wants to merge 1 commit into
mainfrom
feat/ans-commands

Conversation

@Swaagie
Copy link
Copy Markdown
Member

@Swaagie Swaagie commented May 21, 2026

🗒️ the intent of this draft PR is scope discussion and gap identification. This was an easy proof of concept having worked on some fixes for the Rust ANS SDK.

Summary

Adds a godaddy ans command group with 14 subcommands covering the complete ANS agent lifecycle, following the existing Effect + EnvelopeWriter patterns exactly.

Command Description
register Register an agent (requires pre-generated CSR files — see Gap 2)
status Get registration status; next_actions adapts to lifecycle state
verify-acme Trigger ACME domain validation
verify-dns Trigger DNS record verification
submit-server-csr Submit a server CSR from a PEM file
submit-identity-csr Submit an identity CSR from a PEM file
csr-status Poll CSR submission status
revoke Revoke a registration with a typed reason enum
search Search agents by host, name, or version
resolve Resolve agents by hostname and version pattern
events Paginated audit event log
get-server-certs Retrieve issued server certificates
get-identity-certs Retrieve issued identity certificates
badge Transparency log entry + Merkle proof (hits transparency.ans.godaddy.com)

New files

  • src/core/ans.ts — REST API layer (typed response models + Effect-based API functions)
  • src/cli/commands/ans.ts — 14 subcommands, all Effect.gen + EnvelopeWriter
  • tests/integration/ans-smoke.test.ts — command tree, missing-creds error, revocation validation

Gap 1 — Authentication: OAuth vs API key

Current state: ANS commands authenticate via GODADDY_KEY + GODADDY_SECRET environment variables (Authorization: sso-key key:secret), matching the Go and Rust ANS CLIs.

What's not done: The existing godaddy auth login OAuth flow stores a Bearer token that ANS endpoints also accept — but only if the token carries the right ANS scope. The current default OAuth scopes (apps.app-registry:read/write) don't include ANS.

What needs discussion:

  • What is the OAuth scope for ANS? (e.g. ans:read ans:write?)
  • Should godaddy auth login request it by default, or as an opt-in --scope ans?
  • Should ANS commands try the Bearer token first and fall back to API key, or require explicit env vars?

Until this is resolved, users must set GODADDY_KEY and GODADDY_SECRET before running any godaddy ans command.


Gap 2 — CSR generation: no in-process CSR builder

Current state: godaddy ans register requires --server-csr-file and --identity-csr-file (paths to pre-generated PEM files). The Rust and Go CLIs auto-generate RSA-2048 CSRs with the correct SAN URI (ans://v{version}.{host}), EKU, and key usage extensions.

Why it's not auto-generated here: Node.js has no built-in ASN.1 CSR builder. Adding SAN URI to a CSR without a library requires manual DER/ASN.1 encoding. The most suitable library is @peculiar/x509, but adding a new dependency needs explicit approval.

What needs discussion:

  • Should @peculiar/x509 be added as a dependency? (it's actively maintained, MIT licensed, ~40KB)
  • Alternatively: should the ANS SDK expose a pre-built CSR generation endpoint so callers don't need a local PKI library?
  • Or: add a godaddy ans generate-csr subcommand that delegates to the Go or Rust CLI under the hood?

Until resolved, generate CSRs with: race-ready-ans register (Rust) or ans-cli generate-csr (Go), then pass the output files to godaddy ans register.


Implementation notes

  • Content-Length: 0 is set automatically on bodyless POST requests (Akamai requires this — without it you get HTTP 411 from the edge layer)
  • badge uses transparency.ans[.ote-]godaddy.com — a different base URL from the registry. The makeAnsRequest helper accepts a service parameter to switch
  • status next_actions are dynamic: verify-acme is shown when PENDING_VALIDATION, verify-dns when PENDING_CERTS, revoke always unless REVOKED
  • revoke validates the reason string client-side against the known enum before sending (ANS returns undocumented 422s for invalid reasons per-state)

Test plan

  • pnpm exec tsc --noEmit — passes
  • pnpm run build — passes
  • pnpm test tests/integration/ans-smoke.test.ts — validates command tree and error envelopes
  • Manual: GODADDY_KEY=xxx GODADDY_SECRET=yyy node dist/cli.js ans register --host example.ai --a2a-url https://example.ai/a2a --server-csr-file server.csr --identity-csr-file identity.csr

Adds `godaddy ans` command group with 14 subcommands covering the full
ANS agent lifecycle: register, status, verify-acme, verify-dns,
submit-server-csr, submit-identity-csr, csr-status, revoke, search,
resolve, events, get-server-certs, get-identity-certs, badge.

Authentication uses GODADDY_KEY + GODADDY_SECRET env vars (sso-key
format), matching the Go and Rust ANS SDK CLIs. Two gaps are left
intentionally unresolved and documented in the PR for discussion:
OAuth Bearer token integration and in-process CSR generation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant