geeViz.eeAuth.tags

Earth Engine workload-tag helpers.

EE workload tags surface in GCP Billing under the goog-earth-engine-workload-tag label, so tagged calls can be broken down per user / session / source. This module builds well-formed tags from arbitrary string parts (sanitizing each so the result is always accepted by EE).

EE constraints (from ee/_state.py validation):

  • 1 - 63 characters

  • begins and ends with a lowercase alphanumeric [a-z0-9]

  • middle characters: [a-z0-9_-] (lowercase alphanumeric, dash, underscore)

No uppercase, no ., no other punctuation. Anything outside that set (@, spaces, slashes, dots, uppercase, etc.) gets sanitized to -.

Separator: ``__`` (double underscore). Single - already appears inside sanitized parts (e.g. ihousman-redcastleresources-com), so we reserve double underscore as the between-parts delimiter. That makes tags trivially parseable with tag.split("__"):

agent__run_code__ihousman-redcastleresources-com__db208a06-1c49

To keep __ an unambiguous separator, runs of _ within a part get collapsed to a single _ during sanitization (so an input like run__code becomes run_code). Underscores from sources like tool names — run_code, map_control — pass through intact because they’re already singletons.

Functions

build_workload_tag(*parts)

Join sanitized parts with __ and clamp to EE's 63-char limit.

default_tag_store()

Return the process-wide default store.

mint_workload_tag(parts, *, secret[, ...])

Deterministic short tag from a parts dict + secret.

sanitize_workload_tag_part(s)

Sanitize a single component of a workload tag.

Classes

InMemoryTagStore()

Process-local dict-backed store.

SQLiteTagStore([path])

File-backed store using sqlite3 (stdlib, no extra deps).

TagStore(*args, **kwargs)

Minimal contract for tag → parts persistence.

geeViz.eeAuth.tags.sanitize_workload_tag_part(s: str) str[source]

Sanitize a single component of a workload tag.

  • Lowercases.

  • Replaces disallowed characters with -.

  • Collapses runs of - to a single -.

  • Collapses runs of _ to a single _ so the __ separator stays unambiguous when parts are joined.

  • Strips leading/trailing - and _ (EE rejects tags that don’t begin and end with an alphanumeric).

geeViz.eeAuth.tags.build_workload_tag(*parts: str) str[source]

Join sanitized parts with __ and clamp to EE’s 63-char limit.

Empty / falsy parts are dropped. The final tag is guaranteed to satisfy EE’s regex: [a-z0-9][a-z0-9_\-]{0,61}[a-z0-9]. Returns an empty string if everything was dropped — callers should treat empty as “no tag” and skip the workload-tag header / body field entirely.

geeViz.eeAuth.tags.mint_workload_tag(parts: dict[str, Any], *, secret: str, digest_size: int = 8) str[source]

Deterministic short tag from a parts dict + secret.

Returns wl_<hex> where the hex is a digest_size-byte blake2b of the canonicalised parts (default 16 hex chars → collision probability ~10⁻⁹ at millions of tags). Same input always yields the same tag.

The tag is NOT reversible on its own — pair with a TagStore that records tag parts at mint time so lookups can recover identity later.

class geeViz.eeAuth.tags.TagStore(*args, **kwargs)[source]

Bases: Protocol

Minimal contract for tag → parts persistence.

Implementations MUST be thread-safe (the proxy calls concurrently from request handlers) and idempotent on put (mint is deterministic — re-inserting the same (tag, parts) is a no-op, not an error).

put(tag: str, parts: dict[str, Any]) None[source]
lookup(tag: str) dict[str, Any] | None[source]
class geeViz.eeAuth.tags.InMemoryTagStore[source]

Bases: object

Process-local dict-backed store.

Fast, zero-dependency, but the mapping dies with the Python process and doesn’t cross processes/instances. Use for one-shot scripts and unit tests; use SQLiteTagStore (or a Postgres impl) for anything that outlives the process.

put(tag: str, parts: dict[str, Any]) None[source]
lookup(tag: str) dict[str, Any] | None[source]
class geeViz.eeAuth.tags.SQLiteTagStore(path: str | Path | None = None)[source]

Bases: object

File-backed store using sqlite3 (stdlib, no extra deps).

Survives kernel restarts and re-runs of the same script. Single-file, typically at ~/.geeViz/workload_tags.db. Suitable for notebooks and single-instance CLIs; NOT suitable for multi-instance Cloud Run (each instance would have its own file, cross-instance lookups would silently miss). Use a Postgres impl for that.

Concurrent read/write across threads in one process is safe (sqlite3 connection is created per-call with a short-lived cursor). Multiple processes sharing the same file also work (sqlite handles the file lock), though heavy write contention will degrade.

put(tag: str, parts: dict[str, Any]) None[source]
lookup(tag: str) dict[str, Any] | None[source]
geeViz.eeAuth.tags.default_tag_store() TagStore[source]

Return the process-wide default store. First call constructs SQLiteTagStore() at ~/.geeViz/workload_tags.db. Callers who want in-memory or a custom store should set it explicitly via eeCreds.setTagStore(...) before eeCreds.start().