Skip to content

feat(cli): location auto-detect for client create (#84) - #93

Merged
saadqbal merged 2 commits into
developfrom
feat/84-location-autodetect
Jul 6, 2026
Merged

feat(cli): location auto-detect for client create (#84)#93
saadqbal merged 2 commits into
developfrom
feat/84-location-autodetect

Conversation

@LukasWodka

Copy link
Copy Markdown
Contributor

Summary

The deferred fast-follow from #92: client create now pre-fills its location prompt with an auto-detected electricityMaps zone (the backend's ZONE_CHOICES), so a cloud-hosted client doesn't have to look up its own zone.

Stacked on #92 (feat/84-client-commands) — it wires into that PR's client create. Retarget to develop once #92 merges.

How detection works (internal/geo)

Detect(ctx) returns a best-effort Zone{Code, Source, Confidence} or nil:

  1. Cloud instance metadata first (high confidence) — AWS (IMDSv2 token, IMDSv1 fallback), GCP, Azure, probed concurrently under one short deadline (first to answer wins, so a real cloud host responds in one round-trip instead of waiting through the others' timeouts). The region maps to an ISO country via a curated AWS/GCP/Azure table.
  2. IP geolocation fallback (low confidence, flagged) — Cloudflare's cdn-cgi/traceloc= (HTTPS, no API key) → ISO country.

The output is always an ISO alpha-2 country code, which is always a valid top-level ZONE_CHOICES value. An unmapped cloud region falls through to GeoIP rather than suggest a string the backend would reject.

UX

  • The detected zone pre-fills the prompt default; the user confirms with Enter or overrides — still never silent, never empty (the RFC requirement).
  • Best-effort: offline / egress-restricted / bare metal → empty default (the prior behavior). Detection only runs interactively when --location is omitted; --location X skips it entirely.

Tests

internal/geo: each provider, GeoIP fallback, unmapped-region fallthrough, nothing-detected, region→country table — endpoints mocked via httptest (the metadata/GeoIP URLs are overridable package vars). internal/cli: detected zone accepted as the default, end-to-end. A detectZone seam keeps the command tests hermetic (no real probes). Full go build / vet / test ./... green.

Follow-up noticed (separate)

location is CharField(choices=ZONE_CHOICES) — the backend ChoiceField rejects any value not in the list. cli#92's free-text --location (and a user override here) can still send an invalid zone that only fails at create time as a raw 400. Worth vendoring ZONE_CHOICES into the CLI to validate / offer a picker — happy to file that.

🤖 Generated with Claude Code

The deferred fast-follow from cli#92: pre-fill `client create`'s location
prompt with a detected electricityMaps zone (backend ZONE_CHOICES), so a
cloud-hosted client doesn't have to look up its own zone.
- internal/geo: Detect() probes cloud instance metadata first (AWS IMDSv2/v1,
GCP, Azure — concurrently under one short deadline, first wins → high
confidence), then Cloudflare IP geolocation (low confidence, flagged). Returns
an ISO country code, always a valid top-level zone; cloud regions map via a
curated AWS/GCP/Azure table, and an unmapped region falls through to GeoIP for
a valid zone rather than suggest something the backend would reject.
- client create: the detected zone pre-fills the prompt default (the user
confirms with Enter or overrides) — still never silent, never empty. A
detectZone seam keeps the command tests hermetic.
- Best-effort: offline / egress-restricted / bare metal → empty default (the
prior behavior). Only runs interactively when --location is omitted.
Tests: geo per-provider + GeoIP fallback + unmapped-region fallthrough +
nothing-detected + region→country table; cli accepts-detected-zone end-to-end.
go build/vet/test green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@saadqbal
saadqbalforce-pushed the feat/84-location-autodetect branch from 7efdd9c to edb8dedCompareJuly 6, 2026 14:27
@saadqbal
saadqbal marked this pull request as ready for review July 6, 2026 14:27
probeCloud returns on the first probe to report a region and leaves the
losing goroutines running to their deadline. They read the package-level
endpoint vars (awsIMDSBase/gcpMetaBase/azureIMDSBase) directly, so a
test's t.Cleanup — which restores those vars — races the still-running
goroutines under `go test -race` (TestDetect_* flaked in CI).
Snapshot the bases into locals synchronously, before spawning the
goroutines, and pass each into its detectX; the probes now touch only
captured locals, never the mutable globals. First-wins latency is
unchanged. `go test -race -count=30 ./internal/geo/...` clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@saadqbal
saadqbal merged commit 4f8f6e7 into developJul 6, 2026
14 checks passed
@saadqbal
saadqbal deleted the feat/84-location-autodetect branch July 10, 2026 10:37
Sign up for freeto 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.

2 participants

@LukasWodka@saadqbal