nw.secrets#
Execution secrets — credentials that reach execute and nothing else.
A caller’s bring-your-own API key has to reach the one place that spends it
(nw.Transform.execute(), or the render callable behind a
nw.jobs.enqueue()) without going through the graph: a key must
never be persisted in a node body, provenance, a falaw.Plan, a cache
key, a run record, the job index or a log line. This module is the seam that
carries it, and Secrets is what makes the invariant enforced rather
than promised.
The shape. execute(..., *, secrets=...) is a keyword-only argument,
passed accepts-it-or-not by nw.fan_out_execute() and by
nw.jobs.enqueue()’s dispatch — the same seam on_failure (nw#25) and
unit_instance_id (nw#44) use — so a Transform that spends a caller’s
credential declares the keyword, and one that does not never sees it.
Secrets are keyed by provider name ("fal", "elevenlabs", …): nw
owns FAL_SECRET, an app owns the names of the providers it calls.
Why a type, not a dict. A Secrets is a read-only
Mapping whose repr/str redact every value,
that refuses to be pickled, and that is deliberately not a dict — so
json.dumps (and pydantic) of anything that accidentally holds one raises
instead of writing the key. Absent values are dropped at construction, so a
boundary can pass an optional header value straight through:
Secrets(elevenlabs=request_header) is empty — and falsy — when the header
was not sent, which every consumer reads as “use the process environment”.
>>> s = Secrets(elevenlabs="sk-live-…", fal=None)
>>> sorted(s)
['elevenlabs']
>>> s
Secrets(<1 redacted: elevenlabs>)
>>> bool(Secrets(fal=None))
False
>>> import json
>>> json.dumps({"secrets": s}) # a record can never carry one by accident
Traceback (most recent call last):
...
TypeError: Object of type Secrets is not JSON serializable
Module Attributes
|
Functions
|
Coerce a caller-supplied mapping to |
|
Bind the secrets nw itself knows how to use, for the duration of a block. |
|
|
|
The exception to re-raise so that nothing it renders carries a secret. |
Classes
|
A read-only |
Exceptions
|
An exception re-raised in place of one whose rendered text quoted a secret and whose type could not be rebuilt with the scrubbed text. |
- nw.secrets.FAL_SECRET = 'fal'#
nw.BaseTransform.execute()and thenw.jobsworker bind it as the fal credential (falaw.using_fal_credentials()) for the duration of the call.- Type:
The secret name nw itself consumes
- exception nw.secrets.RedactedError(message, *, original_type)[source]#
Bases:
RuntimeErrorAn exception re-raised in place of one whose rendered text quoted a secret and whose type could not be rebuilt with the scrubbed text.
original_typenames what it stood in for, so a caller classifying on the falaw hierarchy still learns what happened;str()is the scrubbed rendering. The typed fallback ofredact_exception().
- class nw.secrets.Secrets(mapping=None, /, **named)[source]#
-
A read-only
{provider_name: key}mapping that never prints or persists.Construct from a mapping, keywords, or both;
None/empty values are dropped (absent means “not supplied”), a non-strkey or value is aTypeError— a secret is text, and an int or a bytes object here is a caller bug worth failing on.
- nw.secrets.as_secrets(secrets)[source]#
Coerce a caller-supplied mapping to
Secrets; empty →None.The nw entry points —
nw.BaseTransform.execute(),nw.fan_out_execute(),nw.jobs.enqueue()— run every incomingsecretsthrough this, so below them a Transform only ever sees the redacting type. A Transform that overridesexecuteand is called directly gets whatever the caller passed: an override that logs or formats itssecretsshouldas_secretsfirst (or the caller should hand it aSecrets), because a plaindictprints its values.>>> as_secrets(None) is None True >>> as_secrets({"fal": None}) is None True >>> as_secrets({"fal": "k"}) Secrets(<1 redacted: fal>)
- nw.secrets.redact(text, secrets)[source]#
textwith every secret value replaced by<redacted:name>.For the places nw persists free text it did not author — an exception message, a failure reason — while holding the values that must not land there. Cheap, exact-substring, and a no-op with no secrets.
- Return type:
>>> redact("boom: key sk-1 rejected", {"fal": "sk-1"}) 'boom: key <redacted:fal> rejected' >>> redact("nothing here", None) 'nothing here'
- nw.secrets.redact_exception(error, secrets)[source]#
The exception to re-raise so that nothing it renders carries a secret.
Scrubs
argsand__notes__in place and, whenstr(error)is still not clean — an exception whose message is built from a non-string arg (RuntimeError({"detail": key}),OSError(2, msg, path)) or a custom__str__— rebuilds it astype(error)(scrubbed_text), falling back toRedactedErrorwhen the type will not construct that way or still renders the secret. The cause/context chain is scrubbed the same way. Returns the object to raise: the original when it was already clean.Applied where nw lets an exception escape toward a store it does not own (the job worker: au persists the rendered text) or files it into a record it does (a fan-out unit’s
reason).- Return type:
- nw.secrets.using_secrets(secrets)[source]#
Bind the secrets nw itself knows how to use, for the duration of a block.
Today that is
FAL_SECRET: when present it becomes the fal credential (falaw.using_fal_credentials()) so everycall_falinside the block authenticates with the caller’s key instead of the server’sFAL_KEY. Anything else insecretsis left for the Transform that declared it. With no fal secret this is anullcontext, so thewithshape stays uniform.- Return type: