Skip to content

feat: domain availability + suggest via spec-generated client#59

Merged
jpage-godaddy merged 14 commits into
rust-portfrom
domain-avail-api
Jun 15, 2026
Merged

feat: domain availability + suggest via spec-generated client#59
jpage-godaddy merged 14 commits into
rust-portfrom
domain-avail-api

Conversation

@jpage-godaddy

@jpage-godaddy jpage-godaddy commented Jun 12, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a gddy domain command group (available, suggest) and establishes two reusable patterns: a spec-generated typed HTTP client and per-environment auth that composes OAuth with an sso-key bypass.

  • domains-client crate — generates a typed reqwest client from a vendored, trimmed OpenAPI 3.0 spec via progenitor in build.rs (scripts/regenerate-spec.sh converts the upstream Swagger 2.0 Domains spec and trims it to the two GET ops). Pinned to progenitor 0.11 so the whole workspace stays on one reqwest 0.12 + ring-based rustls stack — avoids aws-lc-rs and keeps the Windows-msvc cross-build clean. The crate exposes client_with_auth(...) so the CLI owns the Authorization header and never crosses the reqwest version boundary.
  • CompositeAuthProvider (auth.rs) — wraps the OAuth provider; for domain:* commands with a configured sso-key it returns Authorization: sso-key KEY:SECRET, otherwise it delegates to OAuth (the domain endpoints are OAuth-enabled). Scoped by req.command so other commands are unaffected.
  • Scopesdomain available/suggest declare domains.domain:read (per gdcorp-domains/api-domain-data oauthscopewhitelist.json) via CommandSpec::with_scopes, so OAuth scope step-up mints a token carrying it.
  • Env configEnvEntry/ResolvedEnv gain optional domains_api_url (defaults to api_url) and an sso-key (api_key/api_secret), resolved from the gitignored environments.toml and <ENV>_API_URL/<ENV>_API_KEY/<ENV>_API_SECRET env vars (env-var pair wins; resolved atomically per layer). Secrets are never accepted as CLI args (CWE-214). Built-in ote/prod OAuth client ids updated.
  • DebuggabilityRUST_LOG=gddy=debug now logs the resolved OAuth client id / auth+token URLs (env-override aware, no secrets).

Verification

  • cargo fmt, cargo clippy --all-targets --workspace -- -D warnings, cargo test --workspace (147 pass), cargo build — all green.
  • regenerate-spec.sh reproduces domains.oas3.json deterministically (hermetic build; no network at build time).
  • End-to-end against OTE/dev/test: domain available/suggest hit …/v1/domains/{available,suggest} with correct query params and the right Authorization scheme (sso-key when a key is configured, captured on a local server; OAuth bearer otherwise). Honors --env.

🤖 Generated with Claude Code

Adds a `gddy domain` command group with `available` and `suggest`, built on two
patterns:

- Spec-generated HTTP client: new `domains-client` workspace crate generates a
  typed reqwest client from a vendored, trimmed OpenAPI 3.0 spec via progenitor
  at build time (scripts/regenerate-spec.sh converts the upstream Swagger 2.0
  Domains spec). Pinned to progenitor 0.11 to keep the workspace on one
  reqwest 0.12 + ring rustls stack (clean Windows cross-build).
- Composite auth: `CompositeAuthProvider` wraps the OAuth provider and, for
  `domain:*` commands with a configured sso-key, authenticates with
  `Authorization: sso-key KEY:SECRET`; otherwise it falls back to OAuth (the
  domain endpoints are OAuth-enabled). Commands declare the `domains.domain:read`
  scope (per the api-domain-data scope whitelist) so OAuth scope step-up mints a
  token that carries it.

Environment config gains optional per-env `domains_api_url`, `api_key`,
`api_secret` (sso-key), resolved with the existing env-var/flag precedence; adds
`--api-key`/`--api-secret` global flags and a `rust/examples/environments.toml`
template for internal dev/test. Built-in ote/prod OAuth client ids updated; adds
RUST_LOG=debug visibility into the resolved OAuth client/endpoints in auth.rs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds domain-availability functionality to the Rust gddy CLI by introducing a new domain command group backed by a spec-generated Domains API client, along with environment + auth plumbing to support either OAuth or an sso-key bypass.

Changes:

  • Add gddy domain available and gddy domain suggest commands using a typed client generated from a vendored OpenAPI 3.0 spec.
  • Introduce CompositeAuthProvider to choose sso-key auth for domain:* when configured, otherwise delegate to OAuth/PKCE (including scope step-up).
  • Extend environment resolution to support domains_api_url plus optional api_key/api_secret, with config/env-var precedence and global CLI overrides.

Reviewed changes

Copilot reviewed 11 out of 13 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
rust/src/main.rs Registers the domain module, switches to composite auth, and adds global --api-key/--api-secret flags.
rust/src/environments/mod.rs Adds domains_api_url + optional sso-key creds to resolved environments, including env-var + config precedence and tests.
rust/src/domain/mod.rs Implements domain available and domain suggest commands and response formatting.
rust/src/auth.rs Adds debug logging for resolved OAuth params and implements CompositeAuthProvider with sso-key bypass for domain:*.
rust/examples/environments.toml Provides an internal template showing env config + override options for domains/OAuth.
rust/domains-client/src/lib.rs Exposes the generated Domains client and a helper to build an authenticated reqwest client.
rust/domains-client/build.rs Generates the typed client at build time from the vendored OpenAPI 3.0 spec.
rust/domains-client/Cargo.toml Declares the domains-client crate and pins generator/client dependencies.
rust/domains-client/scripts/regenerate-spec.sh Documents + automates re-vendoring/trimming/converting the upstream spec.
rust/domains-client/openapi/domains.oas3.json Vendored, trimmed OpenAPI 3.0 spec for the two Domains GET endpoints.
rust/Cargo.toml Adds domains-client to the workspace and main crate dependencies.
rust/Cargo.lock Locks new dependencies introduced by the generated client pipeline.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread rust/src/main.rs Outdated
Comment thread rust/src/main.rs Outdated
Comment thread rust/src/auth.rs
Comment thread rust/src/environments/mod.rs Outdated
Comment thread rust/src/environments/mod.rs Outdated
Comment thread rust/src/environments/mod.rs
Comment thread rust/src/domain/mod.rs Outdated
…g fixes

Addresses Copilot review on PR #59:
- --api-key/--api-secret now require each other (clap `requires`), so a lone
  flag errors at parse time instead of being silently ignored.
- ResolvedEnv/ResolvedDomains/EnvEntry no longer derive Debug; hand-written
  Debug impls redact the sso-key api_key/api_secret fields to avoid credential
  leakage via {:?}.
- auth debug log adds auth_url_from_env_var for consistency with client_id/token_url.
- domain module docs corrected: the endpoints accept sso-key OR OAuth bearer.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated 1 comment.

Comment thread rust/src/domain/mod.rs
Addresses Copilot round-2 review on PR #59: adds domain_commands_require_auth,
mirroring application_list_requires_auth — builds the CLI with no auth provider
and asserts `domain available`/`suggest` are rejected at credential resolution
(exit 2, provider error) before the handler runs, guarding against accidentally
marking them no_auth.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated 2 comments.

Comment thread rust/domains-client/src/lib.rs Outdated
Comment thread rust/domains-client/scripts/regenerate-spec.sh
Addresses Copilot round-3 review on PR #59:
- domains-client/src/lib.rs: move the #![allow(...)] onto a `generated` module
  wrapping the progenitor include! (re-exported via `pub use generated::*`), so
  the hand-written client_with_auth/BuildError are linted by the workspace again.
- regenerate-spec.sh: pin swagger2openapi@7.0.8 so spec regeneration is
  deterministic (verified the committed domains.oas3.json is unchanged).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated 3 comments.

Comment thread rust/src/environments/mod.rs Outdated
Comment thread rust/src/auth.rs Outdated
Comment thread rust/examples/environments.toml Outdated
Addresses Copilot round-4 review on PR #59: reword the ResolvedEnv api_key
field doc, the CompositeAuthProvider doc, and the environments.toml template so
none imply OAuth is unavailable for domain commands or that api_key/api_secret
affect non-domain commands. Docs only; no behavior change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated 1 comment.

Comment thread rust/src/environments/mod.rs Outdated
Addresses Copilot round-5 review on PR #59: <ENV>_API_KEY/<ENV>_API_SECRET and
the file's api_key/api_secret were applied independently, so an env-var key
could combine with a file secret (or vice versa) into a bogus sso-key pair and
confusing 401s. Resolve the pair atomically from a single layer (env-var pair
wins over the file pair); a partial pair yields no sso-key (domain commands fall
back to OAuth), matching the --api-key/--api-secret flag pairing. Adds tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated 2 comments.

Comment thread rust/src/domain/mod.rs
Comment thread rust/src/auth.rs Outdated
Addresses Copilot round-6 review on PR #59: make `env_prefix` public and call it
from `log_resolved_oauth` instead of re-deriving the uppercase/`-`→`_` prefix, so
the convention has a single authority and can't drift.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated no new comments.

Pull in the latest cli-engine patch release. No source changes required; build,
clippy (-D warnings), and the test suite (149) all pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jpage-godaddy jpage-godaddy requested a review from Copilot June 12, 2026 20:36

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 13 changed files in this pull request and generated no new comments.

Comment thread rust/examples/environments.toml Outdated

@runruh-godaddy runruh-godaddy left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a question about the listed examples in the open source repo

jpage-godaddy and others added 2 commits June 12, 2026 15:13
Switch the progenitor build to InterfaceStyle::Builder so operations expose
fluent, named setters (e.g. client.suggest().query(..).limit(..).send()) instead
of positional args. Call sites in domain/mod.rs now read clearly without an IDE
and only set the parameters they use — no more strings of `None` whose meaning
is opaque in a diff. No behavior change (verified: request omits unset optional
query params). fmt/clippy/test all pass (149).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 12 changed files in this pull request and generated 3 comments.

Comment thread rust/src/domain/mod.rs Outdated
Comment thread rust/src/auth.rs Outdated
Comment thread rust/src/auth.rs Outdated
Addresses deep-review findings on PR #59:

- domains-client: add offline httpmock tests for the generated client —
  available/suggest request shape (query-param names, Authorization/
  x-request-id/api-version headers) and response deserialization. The
  suggest test asserts each scalar lands in the correctly named query
  param, guarding the 10-positional-argument call against silent
  drift if the spec is regenerated (most params share Option types).
- domain: extract the sso-key-vs-Bearer scheme choice into a pure
  authorization_header() and unit-test it; the prior inline logic had
  no coverage.
- domain: emit `suggest` results as objects with a `domain` field and
  add .with_default_fields to both commands, so list output supports
  --fields/default-field projection (matches the application module).
- domain: pin the suggest() positional-argument order in a comment and
  document format_price's intentional whole-cent truncation (+ test).
- main: warn in --api-secret help that a value on the command line is
  visible in the process list / shell history.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 12 changed files in this pull request and generated 3 comments.

Comment thread rust/src/domain/mod.rs
Comment thread rust/src/domain/mod.rs
Comment thread rust/src/auth.rs Outdated
Addresses Copilot round-7 review on PR #59:
- format_price formats the sign explicitly and uses unsigned_abs, so sub-unit
  negatives render correctly (-500_000 -> "-0.50", not "0.50") and i64::MIN
  can't overflow. Adds negative-value tests.
- The api-key override Mutex now recovers the inner value on poison (with a
  tracing::warn) instead of silently dropping the override, which would have
  confusingly switched a domain command from sso-key to OAuth.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@jgowdy-godaddy

Copy link
Copy Markdown

Minor: the PR description is now slightly stale. It still lists "New `rust/examples/environments.toml` template for internal dev/test," but commit fe1d8f6 ("Don't expose environments") removed that file. Worth dropping that line (and refreshing the "147 pass" verification count) so the description matches the final diff.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 12 changed files in this pull request and generated no new comments.

Passing the sso-key as command-line arguments exposes it via the process list
and shell history (CWE-214). Remove the global --api-key/--api-secret flags and
the flag->override bridge before they ship in this PR. The sso-key now comes only
from the existing, non-CWE-214 sources: the <ENV>_API_KEY/<ENV>_API_SECRET env
vars or the gitignored environments.toml entry.

- main.rs: remove the two flag definitions and the apply_flags bridge.
- auth.rs: remove the API_KEY_OVERRIDE static + set_api_key_override/api_key_override
  and the lock helper; sso_key_credential now reads only environments::resolve_domains.

Env-var/config resolution, the sso-key vs Bearer scheme selection, and the pure
credential-factory tests are unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 12 changed files in this pull request and generated 1 comment.

Comment thread rust/src/environments/mod.rs Outdated
The atomic-pair comment in environments::resolve_with referenced the
--api-key/--api-secret flags removed earlier in this PR. Reworded to describe
only the env-var/config layers (the actual sources).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 12 changed files in this pull request and generated no new comments.

@jpage-godaddy

Copy link
Copy Markdown
Collaborator Author

Merging; if the domains team wants to chime in on this, we can circle back with updates.

@jpage-godaddy jpage-godaddy merged commit f56cd21 into rust-port Jun 15, 2026
2 checks passed
@jpage-godaddy jpage-godaddy deleted the domain-avail-api branch June 15, 2026 17:45
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.

4 participants