View source on GitHub
How It Works
The script creates missing entries, skips unchanged AWS versions, and updates changed versions only for mappings already owned by its journal. Unknown existing names or edited ARN/field mappings are refused; use a new destination name or operator recovery. Source deletion and removed mappings never cause destination deletion.Prerequisites
- Python 3.10+ on Linux or macOS;
boto3andrequestsfromrequirements.txt. - AWS credentials through the Boto3 credential chain.
Grant
DescribeSecretandGetSecretValueon the mapped ARNs; see the IAM example and AWS access documentation. Customer-managed encryption keys may requirekms:Decrypt. - An organization-bound OpenHands API key injected as
OH_API_KEY. Shared-secret writes require owner/admin permission. Keep credentials out of mappings and command arguments.GET /api/keys/currentreturns organization and user IDs; verify they match the intended account and organization before configuring them.
Run It
From this directory, install dependencies:json_field selects one top-level string
field; omit it for the whole string. Binary values are unsupported.
- Organization Secrets
- Personal Secrets
Copy mapping.example.json to After the source version changes, run:
mapping.local.json and
edit it. Use the same journal for preview, initial import, and recurring sync.--apply to preview without reading values. Unchanged versions print:
chmod 700). Run one exclusive writer per destination and alert on any nonzero
exit; successful mappings remain committed when another fails.
Secret Name Collisions
On the tested API, personal secrets belong to a user within the effective organization. Personal and shared names are separate namespaces; neither create endpoint rejects a name used in the other scope. The personal value keeps the bare name; the shared value receives a suffix (_2, _3, …)
in that user’s conversations and GET /api/v1/secrets/search. The stored shared
name remains unchanged in the organization listing.
Personal preflight rejects mapped names that match shared names as listed in the
search results. A shared secret created later can appear already suffixed, so the
next sync does not detect that base-name collision. Use team/system prefixes
and reserve managed names across scopes; this script cannot enforce that policy.
Updates and Recovery
Personal values use upsert. This recipe rotates shared values with DELETE then POST, only with--sync --allow-delete-recreate. It validates the new AWS value
before deleting anything. The existing organization metadata PUT cannot replace
values; the newer value-replacement API is separate (see Compatibility).
New conversations receive updated values; running conversations can retain old
values. Credential revocation is a separate process. Keep exclusive control of
managed names: the operations used here have no conditional-write contract, and
the local journal lock cannot coordinate other clients. Out-of-band destination
value changes are not detected.
A
deleted checkpoint also blocks if the entry is unexpectedly present; reconcile
it before proceeding. Do not erase the journal to bypass uncertainty. Values and
tokens are not intentionally logged or stored in it; disable HTTP/SDK wire logging
in your runner.
Adapt to Another Vault
In sync_secrets.py, replacecurrent_version() and
read_value() with your vault’s metadata/version and value API calls. Adjust the
client factory, ARN-to-region parsing in sync(), mapping validation, and source
error handling. Keep a stable source ID and version token; read the exact requested
version and fail safely if it changes between metadata and value reads.
Keep the OpenHands adapters and journal for the destination side. Other vaults
are extension points, not included integrations; qualify their authentication,
versioning, retries, and synthetic-secret delivery before use.
APIs Used
Compatibility
The maintainer review validated this script at2e83432 on Enterprise 1.74.0, using simulated AWS
(moto) and real OpenHands APIs and agent consumption of rotated values. Qualify
your deployment before importing real credentials; this is not a minimum-version
or blanket compatibility guarantee.
Enterprise 1.81.0 added atomic shared-value replacement through separate
GET .../secrets/{name}/version and PUT .../secrets/{name}/value endpoints.
This recipe does not use or qualify them and still deletes/re-creates shared
values on newer servers. Adopting that API requires a separately tested adapter
and conditional-version/retry handling; the ordinary metadata PUT remains
metadata-only. Inspect your deployment’s /openapi.json before choosing a path.
Related
OpenHands Secrets Management
Managing and using secrets
AWS GetSecretValue
Exact version reads
Per-Conversation Secrets
A separate delivery scope

