Secret
Secrets: named environment values for sandboxes, agents and apps.
openai = noclick.Secret.from_name("openai", values={"OPENAI_API_KEY": "sk-..."}, create_if_missing=True)
with noclick.Sandbox.create(secrets=[openai]) as sb:
sb.exec("python summarize.py") # reads os.environ["OPENAI_API_KEY"]A Connection is an account at a service NoClick calls for you, with tokens it
keeps fresh; a Secret is raw values for code you run. Values are write-only:
keys names them, and nothing reads one back.
class SecretNamed values, such as API keys, that the code you run reads from its environment: a sandbox's commands, an agent's shell, an app. Each key becomes an environment variable of that name. Values are write-only.
- Like every live object, it also has hydrate(), refresh() and raw.
| id | str | |
| name | str | |
| keys | list[str] | The names it holds, in order; never their values. |
| user_id | str | None | |
| created_at | Any | |
| updated_at | Any | When its values last changed. |
| used_by | list[dict[str, Any]] | Who reads it: |
| console_url | str | None | This secret in the developer console (None off the hosted API). |
createclassmethodasync
noclick.Secret.create(name, values=None, *, user=..., client=None) -> SecretCreate a secret called name (1-64 letters, digits and . _ -),
unique to its user (a taken name raises noclick.Conflict with
existing_id), holding values: up to 100 keys, each an environment
variable name (letters, digits and _, not starting with a digit; not
PATH, HOME or another the process sets, nor one starting LD_,
NC_ or NOCLICK_), each value a string of up to 32,768 characters.
Without values it starts empty, for someone to fill in from the console.
NoneWho the call acts for. Defaults to the user set by noclick.as_user (none: the account itself).
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
None)The new secret; its keys name what it holds.
import os
shipping = noclick.Secret.create("shipping", {"SHIPPING_API_KEY": os.environ["SHIPPING_API_KEY"]})
print(shipping.keys) # ['SHIPPING_API_KEY']from_nameclassmethod
noclick.Secret.from_name(
name, *, values=None, create_if_missing=False, user=..., client=None
) -> SecretA lazy reference to the secret called name. Acting for a user, that
user's own secret is found first, then the account's. With
create_if_missing=True your code is the definition: the current (or
given) user's is created on first use, holding values, and on one that
exists the keys in values are set to match (NoClick compares them, so
unchanged values change nothing). Keys it doesn't name are kept: remove one
with update.
NoneFalseWho the call acts for. Defaults to the user set by noclick.as_user (none: the account itself).
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
None)A secret that loads (or is created) the first time it's used. Nothing is sent yet.
Create it from your environment on the first run, and pick up a rotated key on the next:
import os
openai = noclick.Secret.from_name(
"openai", values={"OPENAI_API_KEY": os.environ["OPENAI_API_KEY"]}, create_if_missing=True,
)
with noclick.Sandbox.create(secrets=[openai]) as sb:
sb.exec("python summarize.py") # reads os.environ["OPENAI_API_KEY"]Or declare it empty and paste the values in the console:
erp = noclick.Secret.from_name("acme-erp", create_if_missing=True, user="acme")
print(erp.console_url)from_idclassmethod
noclick.Secret.from_id(secret_id, *, client=None, user=...) -> SecretA lazy reference to a secret by id.
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
None)Who the call acts for. Defaults to the user set by noclick.as_user (none: the account itself).
A secret that loads the first time you read a field. Nothing is sent yet.
openai = noclick.Secret.from_id("2a7f0c3e-9d1b-4e6a-8c5f-3b0e7d2a9c14")
print(openai.keys)getclassmethodasync
noclick.Secret.get(secret_id, *, user=..., client=None) -> SecretLoad a secret by id now; an unknown id raises noclick.NotFound.
Who the call acts for. Defaults to the user set by noclick.as_user (none: the account itself).
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
None)The secret, loaded: its key names, when they last changed, and who uses it. Never its values.
openai = noclick.Secret.get("2a7f0c3e-9d1b-4e6a-8c5f-3b0e7d2a9c14")
print(openai.name, openai.keys, openai.updated_at)listclassmethodasync
noclick.Secret.list(
*, limit=None, user_filter=None, user=..., client=None
) -> list[Secret]The current user's secrets and the account's (or those user_filter covers).
Return at most this many.
None)Which users a read covers: noclick.ALL_USERS, noclick.NO_USER, a User, or your id for one. It filters without acting as that user.
None)Who the call acts for. Defaults to the user set by noclick.as_user (none: the account itself).
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
None)Every matching secret, newest first, fetched page by page, with key names and never values.
for secret in noclick.Secret.list():
print(secret.name, secret.keys, secret.user_id) # user_id is None for the account's
everyone = noclick.Secret.list(user_filter=noclick.ALL_USERS) # every user's, plus your account'slist_pageclassmethodasync
noclick.Secret.list_page(
*, cursor=None, limit=None, user_filter=None, user=..., client=None
) -> PageOne page of secrets; pass next_cursor back as cursor.
The next_cursor of the page before; omit it for the first page.
None)Return at most this many.
None)Which users a read covers: noclick.ALL_USERS, noclick.NO_USER, a User, or your id for one. It filters without acting as that user.
None)Who the call acts for. Defaults to the user set by noclick.as_user (none: the account itself).
The client to send with; defaults to the module client built from NOCLICK_API_KEY.
None)A page whose data holds the secrets and whose next_cursor is None on the last page.
page = noclick.Secret.list_page(limit=50)
while True:
for secret in page.data:
print(secret.name, secret.keys)
if page.next_cursor is None:
break
page = noclick.Secret.list_page(limit=50, cursor=page.next_cursor)updateasync
secret.update(values, *, replace=False) -> SecretSet values. By default they merge: the keys you pass are set, a key
set to None is removed, and the rest are kept. replace=True makes
the secret hold exactly values. New sandboxes see the change at once,
agents from their next turn, and apps at their next deployment.
FalseThis secret, with its new keys and updated_at.
Rotate one key and keep the rest:
import os
openai = noclick.Secret.from_name("openai")
openai.update({"OPENAI_API_KEY": os.environ["NEW_OPENAI_API_KEY"]})Remove a key, or replace every value at once:
erp = noclick.Secret.from_name("acme-erp", user="acme")
erp.update({"ERP_TOKEN": None})
erp.update({"ERP_USER": "svc-noclick", "ERP_PASSWORD": "..."}, replace=True)
print(erp.keys) # ['ERP_PASSWORD', 'ERP_USER']versionsasync
secret.versions() -> list[Version]What it held before each change of the last 30 days, newest first: when each was replaced and the keys it held, never the values.
Each earlier version.
stripe = noclick.Secret.from_name("stripe")
for version in stripe.versions():
print(version.replaced_at, version.keys)restore_versionasync
secret.restore_version(version) -> SecretHold version's keys and values again (the values it holds now are kept as a version in turn).
Nothing is shown or sent: the earlier values come back sealed.
This secret, holding them.
Roll back a key that was rotated by mistake:
stripe = noclick.Secret.from_name("stripe")
stripe.restore_version(stripe.versions()[0])deleteasync
secret.delete() -> NoneDelete the secret and its values, for good (its earlier versions go with it).
While an agent lists it or an app binds it (used_by), this raises
noclick.Conflict; sandboxes already running keep their environment until they end.
noclick.Secret.from_name("old-provider").delete()Version
class VersionA value a secret or setting held before replaced_at. op says what replaced it: changed (a new
value) or deleted. A secret's version never shows its value: keys names what a noclick.Secret held
and environment is where an app's secret was set; a setting's shows its value.
| id | str | |
| name | str | |
| op | str | |
| replaced_at | Any | |
| environment | str | None | |
| keys | list[str] | None | |
| value | str | None | |
| raw | dict[str, Any] | The response JSON exactly as the API sent it. |