Files
bun.sh/test/js/bun/secrets-ci-setup.md
Jarred Sumner 707fc4c3a2 Introduce Bun.secrets API (#21973)
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>
2025-08-23 06:57:00 -07:00

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

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:

  1. Detect CI environment - Checks if running on Linux + Ubuntu/Debian in CI
  2. Install packages - Automatically installs required packages if missing
  3. Setup keyring - Creates keyring directory and configuration
  4. Initialize services - Starts D-Bus and gnome-keyring-daemon
  5. 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

  1. Detection: Tests check if running on Linux + Ubuntu/Debian in CI
  2. Packages: Verify libsecret is available
  3. Directory: Create ~/.local/share/keyrings/ directory
  4. Keyring: Create login.keyring file with empty password setup
  5. Daemon: Start gnome-keyring-daemon with login keyring
  6. D-Bus: Ensure D-Bus session is available for communication
  7. 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-dev package
  • Verify with: pkg-config --exists libsecret-1

"Cannot autolaunch D-Bus without X11 $DISPLAY"

  • Run tests inside dbus-run-session
  • Set DISPLAY=:99 environment 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 --login flag

"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