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
|
Join sanitized parts with |
Return the process-wide default store. |
|
|
Deterministic short tag from a parts dict + secret. |
Sanitize a single component of a workload tag. |
Classes
Process-local dict-backed store. |
|
|
File-backed store using |
|
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 adigest_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
TagStorethat recordstag → partsat mint time so lookups can recover identity later.
- class geeViz.eeAuth.tags.TagStore(*args, **kwargs)[source]¶
Bases:
ProtocolMinimal 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).
- class geeViz.eeAuth.tags.InMemoryTagStore[source]¶
Bases:
objectProcess-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.
- class geeViz.eeAuth.tags.SQLiteTagStore(path: str | Path | None = None)[source]¶
Bases:
objectFile-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.