Liking cljdoc? Tell your friends :D

com.blockether.vis.internal.credential-command

Command-backed provider credentials — the api_key_command config key.

A static api_key (or a ${NAME} reference to one) is only good for a long-lived secret. Short-lived SSO/gateway tokens come from a credential HELPER instead: a small program that prints a fresh token on stdout. This namespace runs that helper for a provider and hands the trimmed stdout back as the API key.

Three contracts hold this together:

  • No shell, ever. The configured value is a structured argv that is passed to ProcessBuilder verbatim. It is never joined, never split on whitespace, and never handed to sh -c, so a token containing shell metacharacters — or a config written by someone else — cannot become command injection.
  • The credential is write-once, in memory. Resolved stdout is returned to the caller and cached HERE. It is never persisted (nothing writes it back into :api-key), never logged, and never placed in an error message. Every diagnostic this namespace produces is built from argv[0], the exit code, and the helper's stderr — never its stdout.
  • Bounded and single-flight. One helper invocation per provider at a time, bounded by timeout-ms, with a successful token cached for success-ttl-ms and a failure remembered for failure-ttl-ms. A long-running gateway must not fork a token helper per turn, and an interactive helper must never be launched twice concurrently.

resolve! never throws: callers use its :error to render a provider as unavailable (providers/provider-status, doctor) or to drop it from the router build, exactly as an unresolved ${NAME} is handled today.

Command-backed provider credentials — the `api_key_command` config key.

A static `api_key` (or a `${NAME}` reference to one) is only good for a
long-lived secret. Short-lived SSO/gateway tokens come from a credential
HELPER instead: a small program that prints a fresh token on stdout. This
namespace runs that helper for a provider and hands the trimmed stdout back
as the API key.

Three contracts hold this together:

  - **No shell, ever.** The configured value is a structured argv that is
    passed to `ProcessBuilder` verbatim. It is never joined, never split on
    whitespace, and never handed to `sh -c`, so a token containing shell
    metacharacters — or a config written by someone else — cannot become
    command injection.
  - **The credential is write-once, in memory.** Resolved stdout is returned
    to the caller and cached HERE. It is never persisted (nothing writes it
    back into `:api-key`), never logged, and never placed in an error
    message. Every diagnostic this namespace produces is built from argv[0],
    the exit code, and the helper's stderr — never its stdout.
  - **Bounded and single-flight.** One helper invocation per provider at a
    time, bounded by `timeout-ms`, with a successful token cached for
    `success-ttl-ms` and a failure remembered for `failure-ttl-ms`. A
    long-running gateway must not fork a token helper per turn, and an
    interactive helper must never be launched twice concurrently.

`resolve!` never throws: callers use its `:error` to render a provider as
unavailable (`providers/provider-status`, `doctor`) or to drop it from the
router build, exactly as an unresolved `${NAME}` is handled today.
raw docstring

argvclj

(argv v)

Normalize an api_key_command config value into a non-empty argv vector, or nil when it is absent or malformed.

A bare string is ONE argv element — it is deliberately NOT shell-split. The whole point of the structured form is that arguments are unambiguous, and silently splitting foo --env 'a b' would reintroduce exactly the quoting guesswork this key exists to avoid. Every element must be a non-blank string; anything else makes the value invalid rather than partially usable.

Normalize an `api_key_command` config value into a non-empty argv vector, or
nil when it is absent or malformed.

A bare string is ONE argv element — it is deliberately NOT shell-split. The
whole point of the structured form is that arguments are unambiguous, and
silently splitting `foo --env 'a b'` would reintroduce exactly the quoting
guesswork this key exists to avoid. Every element must be a non-blank string;
anything else makes the value invalid rather than partially usable.
sourceraw docstring

invalidate!clj

(invalidate! pid)

Forget pid's cached credential so the next resolve! re-runs the helper.

This is the refresh trigger: a 401 means the short-lived token the router baked in has expired, and the only way to learn the new one is to ask the helper again. Dropping the entry (rather than re-running here) keeps refresh lazy, single-flight, and on the thread that actually needs the token.

Forget `pid`'s cached credential so the next `resolve!` re-runs the helper.

This is the refresh trigger: a 401 means the short-lived token the router
baked in has expired, and the only way to learn the new one is to ask the
helper again. Dropping the entry (rather than re-running here) keeps refresh
lazy, single-flight, and on the thread that actually needs the token.
sourceraw docstring

peek-tokenclj

(peek-token pid v)

Cached result for pid WITHOUT running anything: {:token _}, {:error _}, or nil when nothing valid is cached.

This is the read for synchronous UI paths (initial-provider-status), which must never fork a subprocess to paint a frame — an unknown verdict there correctly renders as loading.

Cached result for `pid` WITHOUT running anything: `{:token _}`, `{:error _}`,
or nil when nothing valid is cached.

This is the read for synchronous UI paths (`initial-provider-status`), which
must never fork a subprocess to paint a frame — an unknown verdict there
correctly renders as `loading`.
sourceraw docstring

reset-cache!clj

(reset-cache!)

Drop every cached credential. For /reload and for tests.

Drop every cached credential. For `/reload` and for tests.
sourceraw docstring

resolve!clj

(resolve! pid v)

Resolve provider pid's credential from config value v, cached and single-flight. Returns {:token s} or {:error non-secret-message}; returns nil when v configures no command at all. Never throws.

BLOCKS for up to timeout-ms on a cold miss, so callers on a paint path want peek-token instead.

Resolve provider `pid`'s credential from config value `v`, cached and
single-flight. Returns `{:token s}` or `{:error non-secret-message}`; returns
nil when `v` configures no command at all. Never throws.

BLOCKS for up to `timeout-ms` on a cold miss, so callers on a paint path want
`peek-token` instead.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close