|
| 1 | +# Security-as-Code: Declarative Provider Management |
| 2 | + |
| 3 | +The **`nexus-cli`** tool brings a GitOps-compatible, Terraform-style workflow to managing your Nexus provider configurations. Instead of managing providers through direct API calls (which leave no version history and are impossible to review), you declare your desired state in a YAML manifest, commit it to your repository, and let `nexus-cli` reconcile the live Broker against that source of truth. |
| 4 | + |
| 5 | +!!! tip "Why this matters" |
| 6 | + Nexus holds Refresh Tokens and API Keys for every provider a workspace connects to — it is critical infrastructure. Without declarative management, a single bad API call can silently break all agents that depend on a provider, with no git history to recover from. |
| 7 | + |
| 8 | +--- |
| 9 | + |
| 10 | +## How It Works |
| 11 | + |
| 12 | +`nexus-cli` follows a **plan → confirm → apply** workflow: |
| 13 | + |
| 14 | +1. **Fetches** the current live state from `GET /v1/providers`. |
| 15 | +2. **Diffs** it against your `nexus-providers.yaml` manifest. |
| 16 | +3. **Prints** a human-readable plan showing creates, updates, and orphaned providers. |
| 17 | +4. **Applies** the changes only after you confirm with `yes` (or non-interactively in CI). |
| 18 | + |
| 19 | +--- |
| 20 | + |
| 21 | +## Installation |
| 22 | + |
| 23 | +Build from source within the repository: |
| 24 | + |
| 25 | +```bash |
| 26 | +cd nexus-cli |
| 27 | +go build -o nexus-cli . |
| 28 | +``` |
| 29 | + |
| 30 | +Or install directly: |
| 31 | + |
| 32 | +```bash |
| 33 | +go install github.com/Prescott-Data/nexus-framework/nexus-cli@latest |
| 34 | +``` |
| 35 | + |
| 36 | +--- |
| 37 | + |
| 38 | +## Configuration |
| 39 | + |
| 40 | +`nexus-cli` is configured via environment variables: |
| 41 | + |
| 42 | +| Variable | Description | Default | |
| 43 | +| :--- | :--- | :--- | |
| 44 | +| `BROKER_BASE_URL` | Base URL of the Nexus Broker | `http://localhost:8080` | |
| 45 | +| `API_KEY` | API key for Broker authentication | *(none)* | |
| 46 | + |
| 47 | +--- |
| 48 | + |
| 49 | +## The Provider Manifest |
| 50 | + |
| 51 | +Create a `nexus-providers.yaml` file and **commit it to your GitOps repository**. This file is your single source of truth for all provider configurations. |
| 52 | + |
| 53 | +Environment variables are expanded at runtime, so secrets never need to be hardcoded. |
| 54 | + |
| 55 | +```yaml title="nexus-providers.yaml" |
| 56 | +providers: |
| 57 | + - name: google-workspace |
| 58 | + auth_type: oauth2 |
| 59 | + client_id: "${GOOGLE_CLIENT_ID}" |
| 60 | + client_secret: "${GOOGLE_CLIENT_SECRET}" |
| 61 | + issuer: "https://accounts.google.com" |
| 62 | + enable_discovery: true |
| 63 | + scopes: |
| 64 | + - openid |
| 65 | + - email |
| 66 | + - profile |
| 67 | + - offline_access |
| 68 | + |
| 69 | + - name: github |
| 70 | + auth_type: oauth2 |
| 71 | + client_id: "${GITHUB_CLIENT_ID}" |
| 72 | + client_secret: "${GITHUB_CLIENT_SECRET}" |
| 73 | + auth_url: "https://github.com/login/oauth/authorize" |
| 74 | + token_url: "https://github.com/login/oauth/access_token" |
| 75 | + api_base_url: "https://api.github.com" |
| 76 | + enable_discovery: false |
| 77 | + scopes: |
| 78 | + - read:user |
| 79 | + - user:email |
| 80 | +``` |
| 81 | +
|
| 82 | +### Manifest Fields |
| 83 | +
|
| 84 | +| Field | Type | Description | |
| 85 | +| :--- | :--- | :--- | |
| 86 | +| `name` | string | Unique provider name (used as the reconciliation key) | |
| 87 | +| `auth_type` | string | `oauth2` or `api_key` | |
| 88 | +| `client_id` | string | OAuth client ID | |
| 89 | +| `client_secret` | string | OAuth client secret | |
| 90 | +| `issuer` | string | OIDC issuer URL for auto-discovery | |
| 91 | +| `auth_url` | string | Authorization endpoint (if not using discovery) | |
| 92 | +| `token_url` | string | Token endpoint (if not using discovery) | |
| 93 | +| `api_base_url` | string | Provider API root URL | |
| 94 | +| `enable_discovery` | bool | Use OIDC discovery if `true` | |
| 95 | +| `scopes` | list | Default scopes to request | |
| 96 | +| `params` | map | Provider-specific extra parameters | |
| 97 | + |
| 98 | +--- |
| 99 | + |
| 100 | +## Commands |
| 101 | + |
| 102 | +### `plan` — Preview Changes |
| 103 | + |
| 104 | +Show what would change without making any mutations: |
| 105 | + |
| 106 | +```bash |
| 107 | +nexus-cli plan |
| 108 | +# Or with a custom manifest path: |
| 109 | +nexus-cli plan --file ./path/to/nexus-providers.yaml |
| 110 | +``` |
| 111 | + |
| 112 | +**Example output:** |
| 113 | + |
| 114 | +``` |
| 115 | +Read 2 providers from nexus-providers.yaml |
| 116 | + |
| 117 | +--- Execution Plan --- |
| 118 | ++ CREATE : github |
| 119 | +~ UPDATE : google-workspace |
| 120 | +! ORPHAN : old-slack-provider (would be deleted if --prune was passed) |
| 121 | + |
| 122 | +Plan complete. Run 'nexus-cli apply' to perform these actions. |
| 123 | +``` |
| 124 | +
|
| 125 | +The symbols mean: |
| 126 | +
|
| 127 | +| Symbol | Action | |
| 128 | +| :--- | :--- | |
| 129 | +| `+` | Provider will be created | |
| 130 | +| `~` | Provider will be updated | |
| 131 | +| `-` | Provider will be deleted (only shown with `--prune`) | |
| 132 | +| `!` | Provider exists in live state but not in manifest (orphan) | |
| 133 | +
|
| 134 | +### `apply` — Apply Changes |
| 135 | +
|
| 136 | +Apply the manifest, with an interactive confirmation prompt: |
| 137 | +
|
| 138 | +```bash |
| 139 | +nexus-cli apply |
| 140 | +``` |
| 141 | + |
| 142 | +``` |
| 143 | +Read 2 providers from nexus-providers.yaml |
| 144 | +
|
| 145 | +--- Execution Plan --- |
| 146 | ++ CREATE : github |
| 147 | +~ UPDATE : google-workspace |
| 148 | +
|
| 149 | +Do you want to perform these actions? |
| 150 | + Nexus will perform the actions described above. |
| 151 | + Only 'yes' will be accepted to approve. |
| 152 | +
|
| 153 | + Enter a value: yes |
| 154 | +
|
| 155 | +--- Applying Changes --- |
| 156 | +Creating github... OK |
| 157 | +Updating google-workspace... OK |
| 158 | +``` |
| 159 | + |
| 160 | +#### Flags |
| 161 | + |
| 162 | +| Flag | Default | Description | |
| 163 | +| :--- | :--- | :--- | |
| 164 | +| `--file` | `nexus-providers.yaml` | Path to the manifest file | |
| 165 | +| `--prune` | `false` | Also delete providers in live state not in the manifest | |
| 166 | + |
| 167 | +!!! warning "Using `--prune`" |
| 168 | + The `--prune` flag will **delete** providers that exist in the Broker but are absent from your manifest. Only use this when you are certain your manifest is the complete desired state. Any agents depending on a pruned provider will immediately lose their connections. |
| 169 | + |
| 170 | +--- |
| 171 | + |
| 172 | +## CI/CD Integration |
| 173 | + |
| 174 | +The recommended pattern is to use `nexus-cli` in your GitHub Actions pipeline so that every change to the manifest goes through a code review + automated reconciliation cycle. |
| 175 | + |
| 176 | +A workflow is included at `.github/workflows/nexus-cli.yml` and runs automatically when `nexus-cli/nexus-providers.yaml` is modified: |
| 177 | + |
| 178 | +```yaml title=".github/workflows/nexus-cli.yml" |
| 179 | +on: |
| 180 | + pull_request: |
| 181 | + paths: ['nexus-cli/nexus-providers.yaml'] |
| 182 | + push: |
| 183 | + branches: [main] |
| 184 | + paths: ['nexus-cli/nexus-providers.yaml'] |
| 185 | + |
| 186 | +jobs: |
| 187 | + plan-or-apply: |
| 188 | + runs-on: ubuntu-latest |
| 189 | + steps: |
| 190 | + - uses: actions/checkout@v4 |
| 191 | + - uses: actions/setup-go@v5 |
| 192 | + with: |
| 193 | + go-version: '1.21' |
| 194 | + - run: go build -o nexus-cli |
| 195 | + working-directory: ./nexus-cli |
| 196 | + |
| 197 | + # On PRs: show a plan as a check |
| 198 | + - name: Plan (Pull Request) |
| 199 | + if: github.event_name == 'pull_request' |
| 200 | + env: |
| 201 | + BROKER_BASE_URL: ${{ secrets.BROKER_BASE_URL }} |
| 202 | + API_KEY: ${{ secrets.BROKER_API_KEY }} |
| 203 | + run: ./nexus-cli plan |
| 204 | + |
| 205 | + # On merge to main: apply with prune |
| 206 | + - name: Apply (Push to Main) |
| 207 | + if: github.event_name == 'push' |
| 208 | + env: |
| 209 | + BROKER_BASE_URL: ${{ secrets.BROKER_BASE_URL }} |
| 210 | + API_KEY: ${{ secrets.BROKER_API_KEY }} |
| 211 | + run: ./nexus-cli apply --prune <<< "yes" |
| 212 | + working-directory: ./nexus-cli |
| 213 | +``` |
| 214 | +
|
| 215 | +### Required GitHub Secrets |
| 216 | +
|
| 217 | +| Secret | Description | |
| 218 | +| :--- | :--- | |
| 219 | +| `BROKER_BASE_URL` | URL of your production Nexus Broker | |
| 220 | +| `BROKER_API_KEY` | API key for Broker authentication | |
| 221 | + |
| 222 | +--- |
| 223 | + |
| 224 | +## Best Practices |
| 225 | + |
| 226 | +1. **Treat `nexus-providers.yaml` as infrastructure code** — require PR reviews for all changes. |
| 227 | +2. **Never hardcode secrets** — always use `${ENV_VAR}` expansion and inject via CI secrets. |
| 228 | +3. **Start without `--prune`** — let orphans accumulate warnings first so you can audit them intentionally before deletion. |
| 229 | +4. **One manifest per environment** — keep a `nexus-providers.prod.yaml` and `nexus-providers.staging.yaml` and set `BROKER_BASE_URL` accordingly in each CI environment. |
| 230 | +5. **All mutations are audited** — every create, update, or delete applied by `nexus-cli` is recorded in the [Audit Log](../reference/audit-log.md). |
0 commit comments