Secrets Management
The Admin UI provides a secure interface for managing secrets (API keys, tokens, and other credentials) that Starlark scripts can access. This page covers how to add, update, and remove secrets safely.
Overview
Secrets in OpenPact are:
- Stored securely - Encrypted at rest in the
secure/data/directory - Never exposed - Values are never returned via API or shown in the UI
- Automatically redacted - If a secret appears in script output, it's replaced with
[REDACTED:SECRET_NAME] - Scoped to scripts - Only available to Starlark scripts, not directly to the AI
Secrets UI
Navigate to /secrets to manage secrets.
┌────────────────────────────────── ───────────────────────────────┐
│ Secrets Management [+ Add Secret] │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Name │ Status │ Last Updated │ Actions │ │
│ ├────────────────────────────────────────────────────────────┤ │
│ │ WEATHER_API_KEY │ ● Set │ Jan 15, 2024 │ [Delete] │ │
│ │ GITHUB_TOKEN │ ● Set │ Jan 14, 2024 │ [Delete] │ │
│ │ SLACK_WEBHOOK │ ○ Not Set│ - │ [Set] │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
The interface shows:
- Secret name - The identifier used in scripts
- Status - Whether a value has been set
- Last updated - When the secret was last modified
- Actions - Set or delete the secret
Adding Secrets
Via Admin UI
- Click + Add Secret
- Enter the secret name (e.g.,
WEATHER_API_KEY) - Enter the secret value
- Click Save
Via API
POST /api/secrets/:name
Request:
{
"value": "sk-abc123..."
}
Response:
{
"name": "WEATHER_API_KEY",
"set": true
}
Via Configuration
Secrets can also be configured in openpact.yaml:
starlark:
secrets:
WEATHER_API_KEY: "${WEATHER_API_KEY}"
GITHUB_TOKEN: "${GITHUB_TOKEN}"
SLACK_WEBHOOK: "${SLACK_WEBHOOK_URL}"
When using environment variable references (${VAR}), the actual values come from the environment at startup.
Updating Secrets
To update an existing secret:
- Navigate to the Secrets page
- Find the secret you want to update
- Click on the secret name or the Update action
- Enter the new value
- Click Save
Updating a secret does not require re-approval of scripts that use it. The script continues working with the new value.
Deleting Secrets
To delete a secret:
- Navigate to the Secrets page
- Click Delete next to the secret
- Confirm the deletion
Via API
DELETE /api/secrets/:name
Response: 204 No Content
Deleting a secret will cause scripts that depend on it to fail. Review which scripts use a secret before deleting it.
Listing Secrets
Via API
GET /api/secrets
Response:
{
"secrets": [
{
"name": "WEATHER_API_KEY",
"set": true,
"last_updated": "2024-01-15T10:30:00Z"
},
{
"name": "GITHUB_TOKEN",
"set": true,
"last_updated": "2024-01-14T09:00:00Z"
}
]
}
The API never returns actual secret values - only metadata about which secrets exist.
Using Secrets in Scripts
Scripts access secrets using the secrets module:
def get_weather(city):
api_key = secrets.get("WEATHER_API_KEY")
url = format("https://api.weather.com/v1/current?key=%s&city=%s", api_key, city)
response = http.get(url)
return json.decode(response["body"])
Available Functions
| Function | Description |
|---|---|
secrets.get("NAME") | Get a secret value, returns empty string if not set |
secrets.list() | List available secret names (not values) |
Automatic Redaction
When scripts return data, OpenPact automatically scans for secret values and redacts them:
Example
Script:
api_key = secrets.get("API_KEY")
url = format("https://api.example.com?key=%s", api_key)
return {"url": url, "key": api_key}
What the AI sees:
{
"url": "https://api.example.com?key=[REDACTED:API_KEY]",
"key": "[REDACTED:API_KEY]"
}
Redaction Coverage
Redaction scans:
- Return values from scripts
- Error messages
- Nested data structures (dicts, lists, strings)
- Partial matches within strings
Security Best Practices
1. Use Specific Secrets
Create separate secrets for different purposes:
starlark:
secrets:
WEATHER_API_KEY: "${WEATHER_API_KEY}" # Only for weather scripts
STOCK_API_KEY: "${STOCK_API_KEY}" # Only for stock scripts
NOTIFICATION_WEBHOOK: "${SLACK_WEBHOOK}" # Only for notifications
This limits exposure if one secret is compromised.
2. Rotate Secrets Regularly
Set a schedule to rotate secrets:
- API keys: Every 90 days
- Tokens: When they expire or every 30 days
- Webhooks: When personnel changes
3. Use Least Privilege
Request only the permissions you need when creating API keys:
| Instead of | Use |
|---|---|
| Full admin access | Read-only access |
| All repositories | Specific repository access |
| Unlimited rate | Limited rate tier |
4. Monitor Secret Usage
Review which scripts use which secrets:
# Script metadata
# @name: weather.star
# @secrets: WEATHER_API_KEY
5. Never Log Secret Values
Avoid patterns that might leak secrets:
# BAD - might leak in logs
print("Using key: " + api_key)
# GOOD - reference by name only
print("Using secret: WEATHER_API_KEY")
6. Secure the Data Directory
The secrets file is stored in the secure/data/ directory (AI has zero access):
secure/
└── data/
└── secrets.json # Encrypted at rest
Ensure proper file permissions:
chmod 600 secure/data/secrets.json
chmod 700 secure/data/
chmod 700 secure/
7. Use Environment Variables in Production
For containerized deployments, inject secrets via environment:
docker run -e WEATHER_API_KEY="sk-..." openpact
Or use a secrets manager:
# docker-compose.yml with secrets
services:
openpact:
secrets:
- weather_api_key
environment:
WEATHER_API_KEY_FILE: /run/secrets/weather_api_key
secrets:
weather_api_key:
external: true
Storage Details
File-Based Storage
Secrets are stored in secure/data/secrets.json:
{
"WEATHER_API_KEY": {
"value": "encrypted:...",
"last_updated": "2024-01-15T10:30:00Z"
}
}
- File permissions: 0600 (owner read/write only)
- Values are encrypted using a key derived from the JWT secret
Environment Variable Override
Environment variables can override file-based secrets:
export OPENPACT_SECRET_WEATHER_API_KEY="sk-..."
Priority order:
- Environment variable (
OPENPACT_SECRET_*) - Admin UI / API set value
- Configuration file reference
Troubleshooting
Script reports "secret not found"
- Verify the secret name matches exactly (case-sensitive)
- Check if the secret has been set in the Admin UI
- Ensure the secret name is in the script's
@secretsmetadata
Secret appears in output (not redacted)
- The value might be transformed (base64, etc.) - redaction only catches exact matches
- Very short secrets (< 4 chars) may not be redacted to avoid false positives
- Report this as a security issue if it persists
Cannot delete secret
- Ensure no scripts currently depend on this secret
- Check for any pending script approvals that reference the secret