gcp-core

GCP core library - authentication, project config, and shared utilities

Files

FileDescription
kit.tomlPackage manifest with metadata and dependencies
src/gcp.kitOAuth 2.0 JWT auth, service accounts, and HTTP helpers
tests/gcp-core.test.kitTests for error types, OAuth scopes, and URL encoding
examples/basic.kitAuthenticate via metadata server and list buckets
examples/with-token.kitAuthenticate using explicit access token from gcloud CLI
LICENSEMIT license file

Dependencies

  • jwt

Installation

kit add gitlab.com/kit-lang/packages/kit-gcp-core.git

Usage

import Kit.GcpCore

License

MIT License - see LICENSE for details.

Exported Functions & Types

GCPError

GCP error type with specific variants for different failure modes.

Variants

GCPAuthError {message}
Authentication/authorization failed (token issues).
GCPCredentialError {message}
Problem loading or parsing credentials.
GCPNotFoundError {message, resource}
Resource not found (HTTP 404).
GCPPermissionDeniedError {message, resource}
Permission denied (HTTP 403).
GCPRateLimitError {message, retry-after-ms}
Rate limit exceeded (HTTP 429).
GCPQuotaExceededError {message, quota-metric}
Quota exceeded (HTTP 429 with quota reason).
GCPInvalidRequestError {message, field}
Invalid request parameters (HTTP 400).
GCPConflictError {message, resource}
Resource conflict (HTTP 409).
GCPPreconditionFailedError {message}
Precondition failed (HTTP 412).
GCPServerError {message, status}
Server error (HTTP 5xx).
GCPNetworkError {message}
Network/connection error.
GCPTimeoutError {message}
Request timeout.
GCPGenericError {message, status}
Generic error for other cases.

is-retryable?

Check if an error is retryable.

Returns true for transient errors that may succeed on retry: - Rate limit errors (with backoff) - Server errors (5xx) - Network errors - Timeout errors

GCPError -> Bool

error-from-status

Create appropriate error from HTTP status code.

Parameters:

Returns:

Int -> String -> String -> GCPError

with-retry

Retry a function with exponential backoff for retryable errors.

Executes the given function and retries if it fails with a retryable error. Uses exponential backoff starting at 100ms, doubling each retry up to max-delay-ms. For rate limit errors, uses the retry-after-ms hint if available.

Parameters:

Returns:

(() -> Result a GCPError) -> Int -> Result a GCPError

# Retry up to 3 times
match GCP.with-retry (fn() => GCP.get client url) 3
  | Ok response -> println "Success!"
  | Err e -> println "Failed after retries: ${show e}"

with-retry-backoff

Retry with custom backoff configuration.

Parameters:

(() -> Result a GCPError) -> Int -> Int -> Int -> Result a GCPError

# Start with 500ms delay, max 30 seconds
GCP.with-retry-backoff (fn() => GCP.get client url) 5 500 30000

load-service-account

Load service account credentials from JSON key file content.

Parses a Google Cloud service account JSON key file and extracts the credentials needed for authentication. The JSON should be in the format downloaded from the GCP Console (IAM & Admin > Service Accounts).

Parameters:

Returns:

String -> Result ServiceAccount GCPError

json = File.read "service-account.json"
match load-service-account json
  | Ok sa -> println "Loaded account: ${sa.client-email}"
  | Err err -> println "Error: ${err}"

Errors:
- Returns Err if required fields (project_id, private_key, client_email, token_uri) are missing

load-service-account-file

Load service account from file path.

String -> Result ServiceAccount GCPError

load-service-account-from-env

Load from GOOGLE_APPLICATION_CREDENTIALS environment variable.

() -> Result ServiceAccount GCPError

get-project-id-from-env

Get project ID from environment variables.

Checks the following environment variables in order: 1. GOOGLE_CLOUD_PROJECT (standard for Google Cloud SDK) 2. CLOUDSDK_CORE_PROJECT (gcloud CLI config) 3. GCP_PROJECT (common alternative) 4. GCLOUD_PROJECT (legacy)

Returns:

() -> Option String

match GCP.get-project-id-from-env()
  | Some project -> println "Project: ${project}"
  | None -> println "No project ID set"

get-access-token

Get access token for a service account with specific scopes.

ServiceAccount -> [String] -> Result AccessToken GCPError

client-with-token

Create GCP client with explicit access token.

String -> String -> GcpClient

client-from-metadata

Create client from metadata server (GCE, Cloud Run, GKE).

() -> Result GcpClient GCPError

client-from-env

Create client from environment. If GOOGLE_APPLICATION_CREDENTIALS is set, use it directly (local development). Otherwise try metadata server first (GCE, Cloud Run, GKE), then fall back to env var.

() -> Result GcpClient GCPError

client-from-service-account

Create a GCP client from service account credentials with specified scopes.

This authenticates using the service account's private key to sign a JWT, then exchanges the JWT for an access token via the OAuth 2.0 token endpoint.

Parameters:

Returns:

ServiceAccount -> [String] -> Result GcpClient GCPError

json = File.read "service-account.json"
match load-service-account json
  | Ok sa ->
    match client-from-service-account sa [scope-storage-full]
      | Ok client -> # Use client for storage operations
      | Err e -> println "Auth failed: ${Show.show e}"
  | Err e -> println "Load failed: ${Show.show e}"

is-token-expired?

Check if token is expired (with 5 minute buffer).

Returns true if the token will expire within 5 minutes, giving time to refresh before actual expiration.

Parameters:

Returns:

GcpClient -> Bool

if GCP.is-token-expired? client then
  match GCP.refresh-token client
    | Ok new-client -> # use new-client
    | Err e -> println "Refresh failed: ${e}"

refresh-token

Refresh access token using the appropriate method.

Automatically detects how to refresh based on the client configuration: - If the client has service account credentials (private key), uses those to generate a new token with the cloud-platform scope. - Otherwise, attempts to use the metadata server (for GCE/Cloud Run/GKE).

Parameters:

Returns:

GcpClient -> Result GcpClient GCPError

if GCP.is-token-expired? client then
  match GCP.refresh-token client
    | Ok refreshed -> do-something refreshed
    | Err e -> println "Refresh failed: ${e}"

refresh-token-with-scopes

Refresh access token with specific OAuth scopes.

Use this when you need specific scopes instead of the default cloud-platform scope.

Parameters:

Returns:

GcpClient -> [String] -> Result GcpClient GCPError

scopes = [GCP.scope-storage-full, GCP.scope-bigquery]
match GCP.refresh-token-with-scopes client scopes
  | Ok refreshed -> do-something refreshed
  | Err e -> println "Refresh failed: ${e}"

ensure-valid-token

Ensures the client has a valid (non-expired) token.

If the token is expired or about to expire, automatically refreshes it. If the token is still valid, returns the client unchanged.

This is useful as a wrapper before making API calls to ensure the token is always valid.

Parameters:

Returns:

GcpClient -> Result GcpClient GCPError

match GCP.ensure-valid-token client
  | Ok valid-client ->
    match GCP.get valid-client some-url
      | Ok response -> # handle response
      | Err e -> println "Request failed: ${e}"
  | Err e -> println "Token refresh failed: ${e}"

ensure-valid-token-with-scopes

Ensures the client has a valid token with specific scopes.

Like ensure-valid-token, but allows specifying the scopes for refresh.

Parameters:

Returns:

GcpClient -> [String] -> Result GcpClient GCPError

get

Make authenticated GET request.

GcpClient -> String -> Result HTTP.Response HTTP.Error

post

Make authenticated POST request.

GcpClient -> String -> String -> Result HTTP.Response HTTP.Error

put

Make authenticated PUT request.

GcpClient -> String -> String -> Result HTTP.Response HTTP.Error

delete

Make authenticated DELETE request.

GcpClient -> String -> Result HTTP.Response HTTP.Error

request

Make authenticated request with custom headers.

GcpClient -> String -> String -> String -> [HTTP.Header] -> Result HTTP.Response HTTP.Error

scope-cloud-platform

Cloud Platform (broad access - use when you need multiple services).

String

scope-cloud-platform-readonly

String

scope-storage-read

Cloud Storage.

String

scope-storage-write

String

scope-storage-full

String

scope-bigquery

BigQuery.

String

scope-bigquery-readonly

String

scope-bigquery-insert

String

scope-compute

Compute Engine.

String

scope-compute-readonly

String

scope-pubsub

Pub/Sub.

String

scope-datastore

Firestore / Datastore.

String

scope-firestore

String

scope-sqlservice-admin

Cloud SQL.

String

scope-spanner-admin

Spanner.

String

scope-spanner-data

String

scope-secretmanager

Secret Manager.

String

scope-cloudfunctions

Cloud Functions.

String

scope-run

Cloud Run.

String

scope-run-admin

String

scope-tasks

Cloud Tasks.

String

scope-scheduler

Cloud Scheduler.

String

scope-iam

IAM.

String

scope-logging-read

Logging.

String

scope-logging-write

String

scope-logging-admin

String

scope-monitoring

Monitoring.

String

scope-monitoring-read

String

scope-monitoring-write

String

scope-cloudkms

Cloud KMS (Key Management Service).

String

scope-dns

Cloud DNS.

String

scope-dns-readonly

String

scope-containerregistry

Container Registry / Artifact Registry.

String

scope-artifactregistry

String

scope-container

Kubernetes Engine (GKE).

String

scope-aiplatform

Vertex AI / AI Platform.

String

scope-service-management

Service Management.

String

scope-service-management-readonly

String

scope-servicecontrol

Service Control.

String

scope-trace-append

Trace.

String

scope-trace-readonly

String

scope-source-read

Source Repositories.

String

scope-source-write

String

scope-sheets

Sheets (for data pipelines that use Sheets).

String

scope-sheets-readonly

String

scope-drive

Drive (for data pipelines that use Drive).

String

scope-drive-readonly

String

scope-drive-file

String

scope-gmail-send

Gmail (for automated email workflows).

String

scope-gmail-readonly

String

scope-calendar

Calendar.

String

scope-calendar-readonly

String

scope-userinfo-email

User info.

String

scope-userinfo-profile

String

scope-openid

String

url-encode

URL encode a string.

String -> String