Validated configuration — and the client handle you pass to every API call.
A %Config{} is cheap, immutable, and stateless: build it once and hand it to
GcpCompute.Instances/GcpCompute.Operations (or the GcpCompute facade).
There is no process to supervise — Req manages connection pooling under the
hood.
Building a config
# Production: tokens minted by Goth
{:ok, config} =
GcpCompute.Config.production(
project: "my-project",
zone: "us-central1-a",
goth: MyApp.Goth
)
# From application env
{:ok, config} = GcpCompute.Config.from_env(:my_app, :gcp_compute)
# Local / emulator / tests (static token)
{:ok, config} = GcpCompute.Config.local(project: "my-project")Options
:project(String.t/0) - Required. GCP project id.:zone(String.t/0) - Default zone for zonal operations. The default value is"us-central1-a".:token_provider- A{module, arg}implementingGcpCompute.TokenProvider. The default value is{GcpCompute.TokenProvider.Goth, GcpCompute.Goth}.:base_url(String.t/0) - Compute API base URL. Override for the emulator or a proxy. Treated as trusted application config — exactly like:req_options. Never derive it from user input, a request parameter, or a tenant record: it is the one remaining SSRF vector, and every request carries a live bearer token, so a hostile:base_url(http://169.254.169.254/..., an attacker's collector) exfiltrates the credential on the first call. A trailing/is trimmed when the config is built. The default value is"https://compute.googleapis.com/compute/v1".:req_options(keyword/0) - Extra options merged into everyReqrequest (e.g.:adapterfor tests,:retry). Treated as trusted application config: the request:method,:url, and:authare always computed by the library and layered on top, soreq_optionscannot override the target URL or drop the bearer token. It can still set transport and connection options (:connect_options, includingverify) — that is the app owner's choice, not attacker-controlled input.The library also supplies two defaults with
Keyword.put_new, so anything you set here wins::receive_timeout— 30 s (Req's own default is 15 s, shorter than a normal Compute round trip). Theoperations.waitlong poll overrides it per-call with ~150 s.:decoders— response JSON is decoded with Elixir's nativeJSONon 1.18+, falling back toJasonbelow that. NativeJSONis ~36% faster end-to-end on a largelist_page/2response. Override withdecoders: [json: &my_decoder/1]if you need custom decoding.
The default value is
[].:allow_insecure(boolean/0) - Permit a non-https://:base_url. Off by default: a bearer token is never sent in cleartext unless you explicitly opt in. Settrueonly for a local emulator/proxy on a trusted network (local/1sets it for you). Independent of the token provider — even aStatictoken stays TLS-only unless this is set.When it is set and the
:base_urlhost is not loopback, link-local, RFC1918, or an internal-only name,new/1logs aLogger.warning— that combination ships a live bearer token in cleartext across a routable network.The default value is
false.
Summary
Functions
Fetch a fresh access token using the configured GcpCompute.TokenProvider.
Load options from application env and build a config.
Build a config for local development, the emulator, or tests.
Same as local/1 but raises on invalid options.
Build and validate a config from a keyword list.
Same as new/1 but raises ArgumentError on invalid options.
Build a production config that mints tokens via Goth.
Types
Functions
@spec fetch_token(t()) :: {:ok, GcpCompute.TokenProvider.token()} | {:error, term()} | term()
Fetch a fresh access token using the configured GcpCompute.TokenProvider.
The expected return is {:ok, GcpCompute.TokenProvider.token()} or
{:error, reason} — but the return type is deliberately not narrowed to
that. The provider is caller-supplied code that can violate the behaviour, and
the library's internal request layer normalizes whatever actually comes back
into %GcpCompute.Error{reason: :invalid_token_provider_return}. Narrowing
this spec would make Dialyzer prove that normalization unreachable and delete
the only thing standing between a third-party provider and a CaseClauseError
that inspect/1s the token into a crash report.
@spec from_env(atom(), atom()) :: {:ok, t()} | {:error, GcpCompute.Error.t()}
Load options from application env and build a config.
config :my_app, :gcp_compute,
project: "my-project",
zone: "europe-west4-a",
token_provider: {GcpCompute.TokenProvider.Goth, MyApp.Goth}
{:ok, config} = GcpCompute.Config.from_env(:my_app, :gcp_compute)
@spec local(keyword()) :: {:ok, t()} | {:error, GcpCompute.Error.t()}
Build a config for local development, the emulator, or tests.
Defaults allow_insecure: true
local/1 opts you out of the TLS requirement so an http:// emulator URL
works out of the box. Never combine it with a production token. With
allow_insecure: true, local(project: "p", token: real_token, base_url: "http://collector.example.com/v1") sends that live bearer token in
cleartext to whatever host you named. new/1 logs a Logger.warning when
the host is not loopback/link-local/RFC1918/internal, but the request is
still made — pass allow_insecure: false to force TLS even locally.
Defaults to a Static token provider so you never touch Goth. Pass :token
to set the static token (default "local-token"), and :base_url to point at
an emulator.
{:ok, config} = GcpCompute.Config.local(project: "p", base_url: "http://localhost:8080/compute/v1")
Same as local/1 but raises on invalid options.
@spec new(keyword()) :: {:ok, t()} | {:error, GcpCompute.Error.t()}
Build and validate a config from a keyword list.
Returns {:ok, config} or {:error, %GcpCompute.Error{reason: :invalid_config}}
whose :message carries the precise validation failure.
Same as new/1 but raises ArgumentError on invalid options.
@spec production(keyword()) :: {:ok, t()} | {:error, GcpCompute.Error.t()}
Build a production config that mints tokens via Goth.
Pass :goth (the registered Goth name) instead of :token_provider.
{:ok, config} = GcpCompute.Config.production(project: "p", goth: MyApp.Goth)Uses a Goth token provider with allow_insecure defaulting to false, so
new/1's https rule applies: the :base_url must be https:// and a bearer
token can't be sent in cleartext.