This PR adds `Bun.secrets`, a new API for securely storing and
retrieving credentials using the operating system's native credential
storage locally. This helps developers avoid storing sensitive data in
plaintext config files.
```javascript
// Store a GitHub token securely
await Bun.secrets.set({
service: "my-cli-tool",
name: "github-token",
value: "ghp_xxxxxxxxxxxxxxxxxxxx"
});
// Retrieve it when needed
const token = await Bun.secrets.get({
service: "my-cli-tool",
name: "github-token"
});
// Use with fallback to environment variable
const apiKey = await Bun.secrets.get({
service: "my-app",
name: "api-key"
}) || process.env.API_KEY;
```
Marking this as a draft because Linux and Windows have not been manually
tested yet. This API is only really meant for local development usecases
right now, but it would be nice if in the future to support adapters for
production or CI usecases.
### Core API
- `Bun.secrets.get({ service, name })` - Retrieve a stored credential
- `Bun.secrets.set({ service, name, value })` - Store or update a
credential
- `Bun.secrets.delete({ service, name })` - Delete a stored credential
### Platform Support
- **macOS**: Uses Keychain Services via Security.framework
- **Linux**: Uses libsecret (works with GNOME Keyring, KWallet, etc.)
- **Windows**: Uses Windows Credential Manager via advapi32.dll
### Implementation Highlights
- Non-blocking - all operations run on the threadpool
- Dynamic loading - no hard dependencies on system libraries
- Sensitive data is zeroed after use
- Consistent API across all platforms
## Use Cases
This API is particularly useful for:
- CLI tools that need to store authentication tokens
- Development tools that manage API keys
- Any tool that currently stores credentials in `~/.npmrc`,
`~/.aws/credentials` or in environment variables that're globally loaded
## Testing
Comprehensive test suite included with coverage for:
- Basic CRUD operations
- Empty strings and special characters
- Unicode support
- Concurrent operations
- Error handling
All tests pass on macOS. Linux and Windows implementations are complete
but would benefit from additional platform testing.
## Documentation
- Complete API documentation in `docs/api/secrets.md`
- TypeScript definitions with detailed JSDoc comments and examples
---------
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Claude Bot <claude-bot@bun.sh>
Co-authored-by: Claude <noreply@anthropic.com>
5.6 KiB
Secrets API CI Setup Guide
This guide explains how to run the Bun.secrets API tests in CI environments on Linux (Ubuntu/Debian).
Overview
The Bun.secrets API uses the system keyring to store credentials securely. On Linux, this requires:
- libsecret library for Secret Service API integration
- gnome-keyring daemon for credential storage
- D-Bus session for communication
- Proper keyring initialization
Automatic CI Setup (Recommended)
The secrets test automatically detects CI environments and sets up everything needed:
# Just run the test normally - setup happens automatically!
bun test test/js/bun/secrets.test.ts
The test will:
- Detect CI environment - Checks if running on Linux + Ubuntu/Debian in CI
- Install packages - Automatically installs required packages if missing
- Setup keyring - Creates keyring directory and configuration
- Initialize services - Starts D-Bus and gnome-keyring-daemon
- Run tests - Executes all secrets API tests
Manual CI Setup
If automatic setup doesn't work, you can pre-install packages:
# Install packages in CI setup step
apt-get update && apt-get install -y libsecret-1-dev gnome-keyring dbus-x11
# Run tests normally
bun test test/js/bun/secrets.test.ts
Required Packages
On Ubuntu/Debian systems, install these packages:
apt-get install -y \
libsecret-1-dev \ # libsecret development headers
gnome-keyring \ # GNOME Keyring daemon
dbus-x11 # D-Bus X11 integration
Environment Variables
The test automatically detects CI environments and sets up the keyring. You can force setup with:
FORCE_KEYRING_SETUP=1 bun test test/js/bun/secrets.test.ts
How It Works
- Detection: Tests check if running on Linux + Ubuntu/Debian in CI
- Packages: Verify libsecret is available
- Directory: Create
~/.local/share/keyrings/directory - Keyring: Create
login.keyringfile with empty password setup - Daemon: Start
gnome-keyring-daemonwith login keyring - D-Bus: Ensure D-Bus session is available for communication
- Tests: Run secrets tests which use the Secret Service API
Platform Support
- ✅ Linux (Ubuntu/Debian): Full support with automatic CI setup
- ✅ Linux (Other): Manual setup required (see above commands)
- ⚠️ macOS: Uses macOS Keychain (different implementation)
- ⚠️ Windows: Uses Windows Credential Manager (different implementation)
API Behavior
Empty String as Delete
The Bun.secrets.set() method now supports deleting credentials by passing an empty string:
// These are equivalent:
await Bun.secrets.delete({ service: "myapp", name: "token" });
await Bun.secrets.set({ service: "myapp", name: "token", value: "" });
Benefits:
- Windows compatibility - Required by Windows Credential Manager API
- Simplified workflows - Single method for set/delete operations
- Batch operations - Easy to clear multiple credentials in loops
Behavior:
- Setting an empty string deletes the credential if it exists
- No error if the credential doesn't exist (consistent with
delete()) - Returns normally (no special return value)
Unrestricted Access for CI Environments
The allowUnrestrictedAccess parameter allows credentials to be stored without user interaction on macOS:
// For CI environments where user interaction is not possible
await Bun.secrets.set({
service: "ci-deployment",
name: "api-key",
value: process.env.API_KEY,
allowUnrestrictedAccess: true // Bypass macOS keychain user prompts
});
Security Considerations:
- ⚠️ Use with caution - When
allowUnrestrictedAccess: true, any application can read the credential - ✅ Recommended for CI - Useful in headless CI environments like MacStadium or GitHub Actions
- 🔒 Default is secure - When
false(default), only your application can access the credential - 🖥️ macOS only - This parameter is ignored on Linux and Windows platforms
When to Use:
- ✅ CI/CD pipelines that need to store credentials without user interaction
- ✅ Automated testing environments
- ✅ Headless server deployments on macOS
- ❌ Production applications with sensitive user data
- ❌ Desktop applications with normal user interaction
Troubleshooting
"libsecret not available"
- Install
libsecret-1-devpackage - Verify with:
pkg-config --exists libsecret-1
"Cannot autolaunch D-Bus without X11 $DISPLAY"
- Run tests inside
dbus-run-session - Set
DISPLAY=:99environment variable
"Object does not exist at path '/org/freedesktop/secrets/collection/login'"
- Create the login keyring file as shown above
- Start gnome-keyring-daemon with
--loginflag
"Cannot create an item in a locked collection"
- Initialize keyring with empty password:
echo -n "" | gnome-keyring-daemon --unlock - Ensure keyring file has
lock-on-idle=false
CI Configuration Examples
GitHub Actions
- name: Run secrets tests (auto-setup)
run: bun test test/js/bun/secrets.test.ts
Or with explicit package installation:
- name: Install keyring packages
run: |
sudo apt-get update
sudo apt-get install -y libsecret-1-dev gnome-keyring dbus-x11
- name: Run secrets tests
run: bun test test/js/bun/secrets.test.ts
BuildKite
steps:
- command: bun test test/js/bun/secrets.test.ts
label: "🔐 Secrets API Tests"
Docker
# Optional: pre-install packages for faster test startup
RUN apt-get update && apt-get install -y \
libsecret-1-dev \
gnome-keyring \
dbus-x11
# Run test normally - setup is automatic
RUN bun test test/js/bun/secrets.test.ts