npm package: @ksense-tech/bws-ctl
Description: Bitwarden Secrets Manager helper CLI (doctor/pull/push/diff/project list/search)
Author: Ksense Technologies
Latest version: 0.2.1

# bws-ctl

A lightweight, bash-based CLI for working with Bitwarden Secrets Manager.

bws-ctl helps teams:

- Pull secrets into local .env files
- Push syncs a local .env files up to Bitwarden Secrets which will create, update, or delete secrets
- Diff local envs vs Bitwarden secrets (git-style)
- Sync secrets from one Bitwarden project to another
- List and search Bitwarden Secrets Manager projects
- Validate local setup and access with a doctor command

Designed for developer computers, CI, and automation, with minimal setup and strong guardrails.

## Requirements

### Required
- Bash 4+
  - macOS: `brew install bash`
  - Linux: usually already available
  - Windows: use WSL
- Bitwarden Secrets Manager CLI (bws)
- jq (JSON parsing)
- `BWS_ACCESS_TOKEN` set in your environment

### Optional
- fzf – enables interactive fuzzy project search
  - macOS: `brew install fzf`
  - Ubuntu: `sudo apt install fzf`
  - Windows (WSL): `sudo apt install fzf`

## Installation

### Run without installing (recommended)

Always runs the latest published version:
```bash
npx @ksense-tech/bws-ctl --help
```

### Install globally (optional)
```bash
npm install -g @ksense-tech/bws-ctl
bws-ctl --help
```

⚠️ Global installs depend on your Node version and PATH.  
If you use nvm, npx is usually more reliable.

## Authentication & Configuration

1. Bitwarden access token

   Create a machine account in Bitwarden Secrets Manager and generate an access token.

   Set it in your shell:
```bash
   export BWS_ACCESS_TOKEN="your-token"
```

   This token's permissions determine which projects you can access.

2. Project ID configuration (required for pull/push/diff)

   bws-ctl resolves the project ID in this order:
   - `--project-id <id>` flag
   - `BWS_PROJECT_ID` environment variable
   - `BWS_PROJECT_ID` found in a local env file:
     - `.env`
     - `.env.local`
     - `.env.development.local`

   Recommended (per project)

   Add to your project's `.env` (or `.env.local`):
```
   BWS_PROJECT_ID="your-secrets-project-id"
```

## Commands

### doctor

Validate local setup, dependencies, and access.
```bash
bws-ctl doctor
```

What it checks:
- Bash version
- bws availability
- jq availability
- fzf availability (optional)
- `BWS_ACCESS_TOKEN`
- Project ID resolution
- Optional live Bitwarden access checks

Skip network calls:
```bash
bws-ctl doctor --skip-network
```

### pull

Export secrets from Bitwarden into a local env file.
```bash
bws-ctl pull
```

Options:
```bash
bws-ctl pull --out .env.local
bws-ctl pull --project-id <id>
```

Default output file:
- `.env.local`

The generated file includes an auto-generated header and should be added to `.gitignore`.

### diff

Show differences between your local env file and Bitwarden secrets.
```bash
bws-ctl diff
```

Output is git-style, with values shown:
```diff
-DATABASE_URL=postgres://old
+DATABASE_URL=postgres://new
+PRINT_MODE=debug
```

Options:
```bash
bws-ctl diff --project-id <id>
bws-ctl diff --prune
```

`--prune` also shows secrets that exist in Bitwarden but not in your env file.

### push

Sync a local env file into Bitwarden.
```bash
bws-ctl push
```

Behavior:
- Creates missing secrets
- Updates secrets only when values differ
- Does not delete secrets unless `--prune` is used

Options:
```bash
bws-ctl push --dry-run
bws-ctl push --prune
bws-ctl push --project-id <id>
```

Always dry-run first
```bash
bws-ctl push --dry-run
```

### sync

Sync secrets from one Bitwarden project to another.
```bash
bws-ctl sync
```

Behavior:
- Creates missing secrets
- Updates secrets only when values differ
- Does not delete secrets unless `--prune` is used

Options:
```bash
bws-ctl sync --source-project-id <id>
bws-ctl sync --target-project-id <id>
bws-ctl sync --dry-run
bws-ctl sync --prune
```

Aliases: 
```bash
  --src <id>    same as --source-project-id
  --dst <id>    same as --target-project-id
```

Always dry-run first
```bash
bws-ctl sync --src a123 --dst b456 --prune --dry-run
```

### project list

List all Bitwarden Secrets Manager projects (name + ID).
```bash
bws-ctl project list
```

### project search

Search projects by name.
```bash
bws-ctl project search test
```

Interactive fuzzy search (if fzf is installed):
```bash
bws-ctl project search --fzf
```

If no search term is provided and fzf is available, it will automatically open the fuzzy picker.

## Typical Workflows

### Local development
```bash
# once per repo
echo 'BWS_PROJECT_ID="abc123"' >> .env

bws-ctl doctor
bws-ctl pull
bws-ctl diff
```

### Updating dev secrets
```bash
bws-ctl diff
bws-ctl push --dry-run
bws-ctl push
```

### CI / automation
```bash
export BWS_ACCESS_TOKEN="ci-token"
export BWS_PROJECT_ID="project-id"

bws-ctl pull --out .env
```

## Security Model

- Access is controlled entirely by the Bitwarden machine account token
- Knowing a project ID does not grant access
- Developers should typically have:
  - Read or read/write access to dev projects
  - No access to staging or prod projects
- Production tokens should never live on developer laptops

## Notes & Best Practices

- Do not commit generated env files
- Prefer `npx @ksense-tech/bws-ctl` over global installs
- Use `--dry-run` before `push`
- Keep `.env` files local and ignored
- Use `project list` / `project search` to discover project IDs

## Troubleshooting

- `command not found: bws-ctl`
  - Use `npx @ksense-tech/bws-ctl`
  - Or ensure your npm global bin directory is in PATH
  - If using nvm, ensure the same Node version is active
- Missing project id
  - Set `BWS_PROJECT_ID`
  - Or add it to `.env`
  - Or pass `--project-id`
- `permission denied` from Bitwarden
  - Check the machine account's project access
  - Run `bws-ctl doctor`