Repository navigation
docs: document Enterprise secrets management - #1056
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
There was a problem hiding this comment.
Hello Rajiv,
Thank you for putting this guide together. Enterprise has needed a dedicated secrets page, and the source verification table in the description made it much easier to check each claim against the code. The structure (storage, scope, setup, usage, rotation, and external sync) reads well, and the warning about runtime access is a valuable addition.
I left a few inline suggestions. Most are small clarifications; there is one I'd like us to confirm before merging:
- Blocking: Agent Profile secret selection (line 70): the
OPENHANDS_API_KEYclaim may not hold at runtime, and provider tokens such asGITHUB_TOKENalso appear to be dropped. - Non-blocking: Page title (line 2): the title matches the personal secrets page.
- Non-blocking: Permissions table (line 30): clarify who can see and manage personal secrets.
- Non-blocking: Secret names (line 46): state the naming rule the API enforces.
- Non-blocking: Secret scope (line 52): note that scope can't be changed after creation.
- Non-blocking: Environment variables (line 58): secrets are exported when a command references them by name.
- Non-blocking: Per-conversation secrets (line 65): mention precedence and link the existing section.
- Non-blocking: Personal Agent Profiles (line 72): selected secrets filter personal profiles too.
- Non-blocking: Renaming and deleting (line 76): note the impact on Agent Profiles and automations.
- Non-blocking: Personal secret rotation (line 79): cover the UI and API paths.
- Non-blocking: API example (line 84): add authentication and a request example.
- Non-blocking: Cookbook rotation (line 103): clarify that the example deletes and re-creates shared values.
I'm happy to discuss any of these, and please let me know if I've misread the code anywhere.
Thank you very much 🙏
| @@ -0,0 +1,111 @@ | |||
| --- | |||
| title: Secrets Management | |||
There was a problem hiding this comment.
Hello Rajiv,
Non-blocking
Small suggestion: this page shares its title with the personal secrets page (/openhands/usage/settings/secrets-settings, also titled "Secrets Management"), so site search and the generated llms.txt would show two identical entries. Would a more specific title, such as "Organization Secrets" or "Enterprise Secrets Management", work for you? It would help readers pick the right page at a glance.
Thank you very much 🙏
|
|
||
| | Action | Member | Admin or Owner | | ||
| | --- | :---: | :---: | | ||
| | List secret names and descriptions | Yes | Yes | |
There was a problem hiding this comment.
Hello Rajiv,
Non-blocking
The table is a helpful summary. One possible ambiguity: the Yes in the Admin or Owner column for this row could be read as "Admins can list every member's personal secrets", which isn't the case. Everyone sees the shared secrets plus only their own personal secrets. What do you think about rewording the row to "List shared secrets and your own personal secrets (names and descriptions)"? Adding a row for "Create, edit, or delete your own personal secrets" (Yes / Yes) might also be useful, since the table currently covers only shared secrets.
Thank you very much 🙏
| 1. Select the organization that should own the secret. | ||
| 2. As an Admin or Owner, open `Settings > Secrets`. | ||
| 3. Select `Add a new secret`. | ||
| 4. Enter a name, value, and optional description. Use an environment variable name such as |
There was a problem hiding this comment.
Hello Rajiv,
Non-blocking
For shared secrets, this is enforced rather than recommended: the organization secrets API rejects names that don't start with a letter or underscore, or that contain characters other than ASCII letters, digits, and underscores. Would it make sense to state the rule directly? For example: "Names must start with a letter or underscore and contain only letters, digits, and underscores, such as TEAM_SERVICE_TOKEN." That would help Admins understand why a name like team-token is rejected.
Thank you very much 🙏
| 6. Select `Add secret`. | ||
|
|
||
| The secret appears under `Organization secrets`. Members can see its name and description and use | ||
| it in new conversations. Members cannot edit or delete it. Leave `Share with organization` unchecked |
There was a problem hiding this comment.
Hello Rajiv,
Non-blocking
It might help to mention that a secret's scope is fixed at creation. Admins also see the Share with organization checkbox on the edit form, but toggling it doesn't convert the secret: the update is sent to the other scope's endpoint and fails. A sentence such as "You can't change a secret's scope after creating it; to move it between personal and shared, delete it and create it again" could save readers some confusion.
Thank you very much 🙏
| ## Use Shared Secrets | ||
|
|
||
| By default, shared secrets are loaded alongside the user's personal secrets for the conversation's organization | ||
| and made available as environment variables. Tools can read `TEAM_SERVICE_TOKEN` from the environment |
There was a problem hiding this comment.
Hello Rajiv,
Non-blocking
A possible precision improvement here: the agent's terminal exports a secret into the shell only when the command text mentions the secret's name (SecretRegistry.get_secrets_as_env_vars in the SDK). So curl -H "Authorization: Bearer $TEAM_SERVICE_TOKEN" ... works, but a python deploy.py that reads the variable internally won't see it unless an earlier command in the session mentioned the name. Would you be open to noting that commands should reference the secret by name, for example TEAM_SERVICE_TOKEN=$TEAM_SERVICE_TOKEN python deploy.py?
Thank you very much 🙏
| An organization-scoped Agent Profile with an explicit secret list changes this default: it loads | ||
| only the listed organization secrets, plus the system-managed `OPENHANDS_API_KEY`. Personal secrets | ||
| are excluded, and the selected shared secrets retain their original names. Organization profiles | ||
| without an explicit list keep the combined personal and shared secrets. |
There was a problem hiding this comment.
Hello Rajiv,
Non-blocking
Personal Agent Profiles seem to filter secrets the same way: when a member selects specific secrets for their own profile, _apply_profile_secret_scope keeps only those names, so a shared secret is left out unless it's selected. As written, the section suggests that only organization profiles change the default. What do you think about adding a sentence such as "A personal Agent Profile with selected secrets loads only those secrets, so new shared secrets must be added to it explicitly"?
Thank you very much 🙏
|
|
||
| ## Edit, Rotate, or Delete a Secret | ||
|
|
||
| Admins and Owners can edit a shared secret's name and description or delete it from |
There was a problem hiding this comment.
Hello Rajiv,
Non-blocking
Would it be worth adding a short caution about renaming? A rename changes the environment variable name that tools and automations read. It also doesn't update organization Agent Profiles that list the old name, and deleting the secret has the same effect on those profiles. At launch, the missing reference is only logged on the server (agent_profile_org_secrets:unresolved_refs) and the agent runs without the secret, so the problem is easy to miss. A brief note to update affected Agent Profiles and automations after a rename or delete could help.
Thank you very much 🙏
| Admins and Owners can edit a shared secret's name and description or delete it from | ||
| `Settings > Secrets`. The edit form does not replace its value. | ||
|
|
||
| To replace a value through the UI, delete the shared secret and create it again with the new value. |
There was a problem hiding this comment.
Hello Rajiv,
Non-blocking
This section covers shared secrets well. Members will likely want to rotate personal secrets too, so it might be worth covering that case. In the UI, the add form rejects a name that already exists, so the path there is to delete and re-add. Through the API, POST /api/v1/secrets with the same name overwrites the personal value in place. The value-replacement endpoints below work only for shared secrets and return 404 for personal ones. Would you consider adding a sentence or two on rotating personal secrets?
Thank you very much 🙏
| check that your deployment's `/openapi.json` lists both dedicated value-replacement endpoints before | ||
| using this API flow: | ||
|
|
||
| 1. Read `GET /api/organizations/{org_id}/secrets/{secret_name}/version`. |
There was a problem hiding this comment.
Hello Rajiv,
Non-blocking
Thanks for documenting the conditional replacement flow; it's a much safer option than delete and re-create. The steps don't yet say how to authenticate or what the request body looks like, so a short example might make the flow easier to follow, for example:
curl -X PUT "https://<your-host>/api/organizations/$ORG_ID/secrets/TEAM_SERVICE_TOKEN/value" \
-H "Authorization: Bearer $OH_API_KEY" \
-H "Content-Type: application/json" \
--data @replacement.json # {"value": "...", "expected_version": "...", "request_id": "..."}It could also be worth noting two points from the replacement contract: an organization-bound API key must belong to {org_id}, and request bodies shouldn't be logged.
Thank you very much 🙏
| is not a live reference to the external vault. | ||
|
|
||
| See [AWS Secrets Sync](/cookbook/aws-secrets-sync) in the Enterprise Cookbook for a script that maps | ||
| AWS Secrets Manager values to personal or organization secrets, detects source rotation, and tracks |
There was a problem hiding this comment.
Hello Rajiv,
Non-blocking
Because this section comes right after the value-replacement API, readers may assume the cookbook script uses it. It actually rotates shared values by deleting and re-creating them (--allow-delete-recreate), so the same availability gap applies, and an interrupted run can leave the secret missing until someone completes recovery. Would you be open to mentioning that here? For example: "The example rotates shared values by deleting and re-creating them; it does not use the value-replacement API."
Thank you very much 🙏
|
Thanks for the detailed review, Hiep! I’ve pushed the corrections in f7e288e, including removing the automatic |
Summary of changes
Enterprise secrets management lacks a dedicated feature guide explaining storage, personal and organization-wide secrets, and external vault synchronization.
Add
enterprise/secrets-management.mdxunder Enterprise Feature Guides. Explain encrypted storage, personal versus organization-wide secrets, setup, permissions, Agent Profile secret selection, runtime access, and rotation limits. Link to the Enterprise Cookbook AWS Secrets Sync example for customer-operated vault synchronization. Changes are limited to the new Enterprise page and its entry under Enterprise Feature Guides indocs.json. Existing open-source and Cloud documentation is unchanged.Validation
mint broken-links: passed, no broken links.git diff origin/main --check: passed.python3 -m json.tool docs.json: passed.13f2a01aeeb087007b1d71e4be218c3f73555167, after correcting Agent Profile selection and rotation guidance. The Enterprise guide is unchanged by the subsequent scope-only commit, which restores the general and Cloud pages. This is an agent review, not a GitHub approval.d79511626afbb6e1bb9cc42cfe8d58b67cfb2446.Source verification
Cookbook scope checked against
cookbook/aws-secrets-sync.mdxin the docs base: user-operated scheduler, mapped imports, source rotation handling, and recovery/compatibility caveats. No generated cookbook files changed.Additional source verification: org Agent Profile secret selection.