@getaegis/cli 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -14
- package/dist/agent/agent.d.ts +98 -0
- package/dist/agent/agent.d.ts.map +1 -0
- package/dist/agent/agent.js +212 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/index.d.ts +3 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +2 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/cli/auth.d.ts +19 -0
- package/dist/cli/auth.d.ts.map +1 -0
- package/dist/cli/auth.js +44 -0
- package/dist/cli/auth.js.map +1 -0
- package/dist/cli/commands/agent.d.ts +6 -0
- package/dist/cli/commands/agent.d.ts.map +1 -0
- package/dist/cli/commands/agent.js +241 -0
- package/dist/cli/commands/agent.js.map +1 -0
- package/dist/cli/commands/config.d.ts +6 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +125 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/dashboard.d.ts +6 -0
- package/dist/cli/commands/dashboard.d.ts.map +1 -0
- package/dist/cli/commands/dashboard.js +195 -0
- package/dist/cli/commands/dashboard.js.map +1 -0
- package/dist/cli/commands/db.d.ts +6 -0
- package/dist/cli/commands/db.d.ts.map +1 -0
- package/dist/cli/commands/db.js +139 -0
- package/dist/cli/commands/db.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +6 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +39 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/gate.d.ts +6 -0
- package/dist/cli/commands/gate.d.ts.map +1 -0
- package/dist/cli/commands/gate.js +202 -0
- package/dist/cli/commands/gate.js.map +1 -0
- package/dist/cli/commands/init.d.ts +6 -0
- package/dist/cli/commands/init.d.ts.map +1 -0
- package/dist/cli/commands/init.js +175 -0
- package/dist/cli/commands/init.js.map +1 -0
- package/dist/cli/commands/key.d.ts +6 -0
- package/dist/cli/commands/key.d.ts.map +1 -0
- package/dist/cli/commands/key.js +49 -0
- package/dist/cli/commands/key.js.map +1 -0
- package/dist/cli/commands/ledger.d.ts +6 -0
- package/dist/cli/commands/ledger.d.ts.map +1 -0
- package/dist/cli/commands/ledger.js +140 -0
- package/dist/cli/commands/ledger.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +6 -0
- package/dist/cli/commands/mcp.d.ts.map +1 -0
- package/dist/cli/commands/mcp.js +224 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/policy.d.ts +6 -0
- package/dist/cli/commands/policy.d.ts.map +1 -0
- package/dist/cli/commands/policy.js +126 -0
- package/dist/cli/commands/policy.js.map +1 -0
- package/dist/cli/commands/user.d.ts +6 -0
- package/dist/cli/commands/user.d.ts.map +1 -0
- package/dist/cli/commands/user.js +150 -0
- package/dist/cli/commands/user.js.map +1 -0
- package/dist/cli/commands/vault-manager.d.ts +6 -0
- package/dist/cli/commands/vault-manager.d.ts.map +1 -0
- package/dist/cli/commands/vault-manager.js +240 -0
- package/dist/cli/commands/vault-manager.js.map +1 -0
- package/dist/cli/commands/vault.d.ts +6 -0
- package/dist/cli/commands/vault.d.ts.map +1 -0
- package/dist/cli/commands/vault.js +265 -0
- package/dist/cli/commands/vault.js.map +1 -0
- package/dist/cli/commands/webhook.d.ts +6 -0
- package/dist/cli/commands/webhook.d.ts.map +1 -0
- package/dist/cli/commands/webhook.js +151 -0
- package/dist/cli/commands/webhook.js.map +1 -0
- package/dist/cli/helpers.d.ts +12 -0
- package/dist/cli/helpers.d.ts.map +1 -0
- package/dist/cli/helpers.js +61 -0
- package/dist/cli/helpers.js.map +1 -0
- package/dist/cli/index.d.ts +19 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +19 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/validation.d.ts +37 -0
- package/dist/cli/validation.d.ts.map +1 -0
- package/dist/cli/validation.js +104 -0
- package/dist/cli/validation.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +37 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +120 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +401 -0
- package/dist/config.js.map +1 -0
- package/dist/dashboard/dashboard-server.d.ts +95 -0
- package/dist/dashboard/dashboard-server.d.ts.map +1 -0
- package/dist/dashboard/dashboard-server.js +329 -0
- package/dist/dashboard/dashboard-server.js.map +1 -0
- package/dist/dashboard/index.d.ts +3 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +2 -0
- package/dist/dashboard/index.js.map +1 -0
- package/dist/dashboard/public/assets/index-Cah0_BKk.js +148 -0
- package/dist/dashboard/public/assets/index-CpMruPNh.css +1 -0
- package/dist/dashboard/public/favicon.svg +6 -0
- package/dist/dashboard/public/index.html +14 -0
- package/dist/db.d.ts +27 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/db.js +209 -0
- package/dist/db.js.map +1 -0
- package/dist/doctor.d.ts +37 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js +216 -0
- package/dist/doctor.js.map +1 -0
- package/dist/gate/body-inspector.d.ts +31 -0
- package/dist/gate/body-inspector.d.ts.map +1 -0
- package/dist/gate/body-inspector.js +193 -0
- package/dist/gate/body-inspector.js.map +1 -0
- package/dist/gate/gate.d.ts +190 -0
- package/dist/gate/gate.d.ts.map +1 -0
- package/dist/gate/gate.js +1243 -0
- package/dist/gate/gate.js.map +1 -0
- package/dist/gate/index.d.ts +7 -0
- package/dist/gate/index.d.ts.map +1 -0
- package/dist/gate/index.js +4 -0
- package/dist/gate/index.js.map +1 -0
- package/dist/gate/rate-limiter.d.ts +59 -0
- package/dist/gate/rate-limiter.d.ts.map +1 -0
- package/dist/gate/rate-limiter.js +120 -0
- package/dist/gate/rate-limiter.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/key-storage/credential-manager-windows.d.ts +19 -0
- package/dist/key-storage/credential-manager-windows.d.ts.map +1 -0
- package/dist/key-storage/credential-manager-windows.js +87 -0
- package/dist/key-storage/credential-manager-windows.js.map +1 -0
- package/dist/key-storage/file-fallback.d.ts +21 -0
- package/dist/key-storage/file-fallback.d.ts.map +1 -0
- package/dist/key-storage/file-fallback.js +62 -0
- package/dist/key-storage/file-fallback.js.map +1 -0
- package/dist/key-storage/index.d.ts +6 -0
- package/dist/key-storage/index.d.ts.map +1 -0
- package/dist/key-storage/index.js +6 -0
- package/dist/key-storage/index.js.map +1 -0
- package/dist/key-storage/key-storage.d.ts +41 -0
- package/dist/key-storage/key-storage.d.ts.map +1 -0
- package/dist/key-storage/key-storage.js +70 -0
- package/dist/key-storage/key-storage.js.map +1 -0
- package/dist/key-storage/keychain-macos.d.ts +19 -0
- package/dist/key-storage/keychain-macos.d.ts.map +1 -0
- package/dist/key-storage/keychain-macos.js +51 -0
- package/dist/key-storage/keychain-macos.js.map +1 -0
- package/dist/key-storage/secret-service-linux.d.ts +19 -0
- package/dist/key-storage/secret-service-linux.d.ts.map +1 -0
- package/dist/key-storage/secret-service-linux.js +55 -0
- package/dist/key-storage/secret-service-linux.js.map +1 -0
- package/dist/ledger/index.d.ts +3 -0
- package/dist/ledger/index.d.ts.map +1 -0
- package/dist/ledger/index.js +2 -0
- package/dist/ledger/index.js.map +1 -0
- package/dist/ledger/ledger.d.ts +98 -0
- package/dist/ledger/ledger.d.ts.map +1 -0
- package/dist/ledger/ledger.js +145 -0
- package/dist/ledger/ledger.js.map +1 -0
- package/dist/logger/index.d.ts +3 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +2 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/logger/logger.d.ts +58 -0
- package/dist/logger/logger.d.ts.map +1 -0
- package/dist/logger/logger.js +201 -0
- package/dist/logger/logger.js.map +1 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +2 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/mcp-server.d.ts +130 -0
- package/dist/mcp/mcp-server.d.ts.map +1 -0
- package/dist/mcp/mcp-server.js +775 -0
- package/dist/mcp/mcp-server.js.map +1 -0
- package/dist/metrics/index.d.ts +3 -0
- package/dist/metrics/index.d.ts.map +1 -0
- package/dist/metrics/index.js +2 -0
- package/dist/metrics/index.js.map +1 -0
- package/dist/metrics/metrics.d.ts +88 -0
- package/dist/metrics/metrics.d.ts.map +1 -0
- package/dist/metrics/metrics.js +179 -0
- package/dist/metrics/metrics.js.map +1 -0
- package/dist/policy/index.d.ts +3 -0
- package/dist/policy/index.d.ts.map +1 -0
- package/dist/policy/index.js +2 -0
- package/dist/policy/index.js.map +1 -0
- package/dist/policy/policy.d.ts +119 -0
- package/dist/policy/policy.d.ts.map +1 -0
- package/dist/policy/policy.js +426 -0
- package/dist/policy/policy.js.map +1 -0
- package/dist/user/index.d.ts +3 -0
- package/dist/user/index.d.ts.map +1 -0
- package/dist/user/index.js +2 -0
- package/dist/user/index.js.map +1 -0
- package/dist/user/user.d.ts +102 -0
- package/dist/user/user.d.ts.map +1 -0
- package/dist/user/user.js +216 -0
- package/dist/user/user.js.map +1 -0
- package/dist/vault/crypto.d.ts +28 -0
- package/dist/vault/crypto.d.ts.map +1 -0
- package/dist/vault/crypto.js +44 -0
- package/dist/vault/crypto.js.map +1 -0
- package/dist/vault/index.d.ts +10 -0
- package/dist/vault/index.d.ts.map +1 -0
- package/dist/vault/index.js +6 -0
- package/dist/vault/index.js.map +1 -0
- package/dist/vault/seal.d.ts +68 -0
- package/dist/vault/seal.d.ts.map +1 -0
- package/dist/vault/seal.js +110 -0
- package/dist/vault/seal.js.map +1 -0
- package/dist/vault/shamir.d.ts +33 -0
- package/dist/vault/shamir.d.ts.map +1 -0
- package/dist/vault/shamir.js +174 -0
- package/dist/vault/shamir.js.map +1 -0
- package/dist/vault/vault-manager.d.ts +62 -0
- package/dist/vault/vault-manager.d.ts.map +1 -0
- package/dist/vault/vault-manager.js +151 -0
- package/dist/vault/vault-manager.js.map +1 -0
- package/dist/vault/vault.d.ts +104 -0
- package/dist/vault/vault.d.ts.map +1 -0
- package/dist/vault/vault.js +259 -0
- package/dist/vault/vault.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +18 -0
- package/dist/version.js.map +1 -0
- package/dist/webhook/index.d.ts +3 -0
- package/dist/webhook/index.d.ts.map +1 -0
- package/dist/webhook/index.js +2 -0
- package/dist/webhook/index.js.map +1 -0
- package/dist/webhook/webhook.d.ts +114 -0
- package/dist/webhook/webhook.d.ts.map +1 -0
- package/dist/webhook/webhook.js +269 -0
- package/dist/webhook/webhook.js.map +1 -0
- package/package.json +12 -6
package/README.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Aegis
|
|
2
2
|
|
|
3
|
+
[](https://github.com/getaegis/aegis/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@getaegis/cli)
|
|
5
|
+
[](https://ghcr.io/getaegis/aegis)
|
|
6
|
+
[](LICENSE)
|
|
7
|
+
|
|
3
8
|
**Credential isolation for AI agents.**
|
|
4
9
|
|
|
5
10
|
Aegis sits between your AI agent and the APIs it calls. The agent never sees, stores, or transmits real credentials — Aegis injects them at the network boundary.
|
|
@@ -41,17 +46,30 @@ Aegis solves all four. Your agent makes HTTP calls through a local proxy. Aegis
|
|
|
41
46
|
npm install -g @getaegis/cli
|
|
42
47
|
|
|
43
48
|
# Initialize — generates master key, config file, and encrypted vault
|
|
49
|
+
aegis init
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
By default, `aegis init` stores the master key in your OS keychain (macOS Keychain, Windows Credential Manager, or Linux Secret Service). If no keychain is available, it falls back to a file at `.aegis/.master-key` (mode 0600).
|
|
53
|
+
|
|
54
|
+
Alternative storage modes:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# Store in .env file (for CI/headless environments)
|
|
58
|
+
aegis init --env-file
|
|
59
|
+
|
|
60
|
+
# Store in aegis.config.yaml (convenient for local dev, not recommended for production)
|
|
44
61
|
aegis init --write-secrets
|
|
62
|
+
|
|
63
|
+
# Check where your master key is stored
|
|
64
|
+
aegis key where
|
|
45
65
|
```
|
|
46
66
|
|
|
47
|
-
|
|
67
|
+
If you use `--env-file` or need to set the key manually:
|
|
48
68
|
|
|
49
69
|
```bash
|
|
50
70
|
export AEGIS_MASTER_KEY=<key from init>
|
|
51
71
|
```
|
|
52
72
|
|
|
53
|
-
With `--write-secrets`, the key is saved to `aegis.config.yaml` automatically (convenient for local dev, not recommended for production).
|
|
54
|
-
|
|
55
73
|
```bash
|
|
56
74
|
# Add a credential
|
|
57
75
|
aegis vault add \
|
|
@@ -90,6 +108,7 @@ curl http://localhost:3100/slack/api/auth.test \
|
|
|
90
108
|
| **RBAC** | Admin, operator, viewer roles with 16 granular permissions |
|
|
91
109
|
| **Multi-Vault** | Separate vaults for dev/staging/prod with isolated encryption keys |
|
|
92
110
|
| **Shamir's Secret Sharing** | M-of-N key splitting for team master key management |
|
|
111
|
+
| **Cross-Platform Key Storage** | OS keychain by default (macOS Keychain, Windows Credential Manager, Linux Secret Service) with file fallback |
|
|
93
112
|
| **TLS Support** | Optional HTTPS on Gate with cert/key configuration |
|
|
94
113
|
| **Configuration File** | `aegis.config.yaml` with env var overrides and CLI flag overrides |
|
|
95
114
|
|
|
@@ -116,7 +135,7 @@ The MCP server replicates the full Gate security pipeline: domain guard, agent a
|
|
|
116
135
|
|
|
117
136
|
## Agent Identity & Scoping
|
|
118
137
|
|
|
119
|
-
|
|
138
|
+
Agent authentication is **on by default**. Every request through Gate must include a valid `X-Aegis-Agent` header. Requests without a token get a helpful 401 error with instructions to create an agent.
|
|
120
139
|
|
|
121
140
|
```bash
|
|
122
141
|
# Register an agent — token is printed once, save it
|
|
@@ -128,13 +147,16 @@ aegis agent grant --agent "research-bot" --credential "slack-bot"
|
|
|
128
147
|
# Set per-agent rate limits
|
|
129
148
|
aegis agent set-rate-limit --agent "research-bot" --limit 50/min
|
|
130
149
|
|
|
131
|
-
# Start Gate
|
|
132
|
-
aegis gate
|
|
150
|
+
# Start Gate (agent auth is on by default)
|
|
151
|
+
aegis gate
|
|
133
152
|
|
|
134
153
|
# Agent must include its token in every request
|
|
135
154
|
curl http://localhost:3100/slack/api/auth.test \
|
|
136
155
|
-H "X-Target-Host: api.slack.com" \
|
|
137
156
|
-H "X-Aegis-Agent: aegis_a1b2c3d4..."
|
|
157
|
+
|
|
158
|
+
# To disable agent auth (not recommended):
|
|
159
|
+
aegis gate --no-agent-auth
|
|
138
160
|
```
|
|
139
161
|
|
|
140
162
|
Tokens are SHA-256 hashed for storage — they cannot be recovered, only regenerated:
|
|
@@ -204,7 +226,8 @@ aegis vault add \
|
|
|
204
226
|
| `--ttl <days>` | *(none)* | Credential expires after this many days |
|
|
205
227
|
| `--rate-limit` | *(none)* | Rate limit: `100/min`, `1000/hour`, `10/sec` |
|
|
206
228
|
| `--body-inspection` | `block` | Scan outbound bodies for credential patterns: `off`, `warn`, `block` |
|
|
207
|
-
| `--header-name` | — | Custom header name (
|
|
229
|
+
| `--header-name` | — | Custom header name (for `--auth-type header`) |
|
|
230
|
+
| `--query-param` | `key` | Query parameter name (for `--auth-type query`) |
|
|
208
231
|
|
|
209
232
|
Update any field later:
|
|
210
233
|
|
|
@@ -221,7 +244,7 @@ Aegis supports four credential injection methods:
|
|
|
221
244
|
| `bearer` | `--auth-type bearer` (default) | `Authorization: Bearer <secret>` |
|
|
222
245
|
| `header` | `--auth-type header --header-name X-API-Key` | `X-API-Key: <secret>` |
|
|
223
246
|
| `basic` | `--auth-type basic` | `Authorization: Basic <base64(secret)>` |
|
|
224
|
-
| `query` | `--auth-type query` | Appends `?
|
|
247
|
+
| `query` | `--auth-type query --query-param api_key` | Appends `?api_key=<secret>` to the URL |
|
|
225
248
|
|
|
226
249
|
## Configuration
|
|
227
250
|
|
|
@@ -463,13 +486,15 @@ Runs diagnostics on your Aegis installation:
|
|
|
463
486
|
- Config file validation
|
|
464
487
|
- Database accessibility and schema
|
|
465
488
|
- Master key correctness (test decrypt)
|
|
489
|
+
- Key storage backend (keychain type and status)
|
|
466
490
|
- Expired or expiring-soon credentials
|
|
467
491
|
|
|
468
492
|
Returns pass/warn/fail for each check.
|
|
469
493
|
|
|
470
494
|
## Security Model
|
|
471
495
|
|
|
472
|
-
- **Encryption at rest** — AES-256-GCM with PBKDF2 key derivation (
|
|
496
|
+
- **Encryption at rest** — AES-256-GCM with PBKDF2 key derivation (210,000 iterations, SHA-512, random per-deployment salt)
|
|
497
|
+
- **Cross-platform key storage** — master key stored in OS keychain by default (macOS Keychain, Windows Credential Manager, Linux Secret Service). File fallback for CI/headless
|
|
473
498
|
- **Domain guard** — enforced on every outbound request. No bypass, no override. Wildcards supported (`*.slack.com`)
|
|
474
499
|
- **Credential scopes** — `read` (GET/HEAD/OPTIONS), `write` (POST/PUT/PATCH/DELETE), `*` (all). Enforced at the Gate before any request is forwarded
|
|
475
500
|
- **Header stripping** — agent-supplied `Authorization`, `X-API-Key`, `Proxy-Authorization` headers are removed before injection
|
|
@@ -479,13 +504,13 @@ Returns pass/warn/fail for each check.
|
|
|
479
504
|
- **TLS support** — optional HTTPS on Gate (`aegis gate --tls --cert <path> --key <path>`)
|
|
480
505
|
- **Graceful shutdown** — drains in-flight requests on SIGINT/SIGTERM
|
|
481
506
|
|
|
482
|
-
See [SECURITY_ARCHITECTURE.md](docs/SECURITY_ARCHITECTURE.md) for the full security design
|
|
507
|
+
See [SECURITY_ARCHITECTURE.md](docs/SECURITY_ARCHITECTURE.md) for the full security design and trust boundaries, and [THREAT_MODEL.md](docs/THREAT_MODEL.md) for the STRIDE threat analysis.
|
|
483
508
|
|
|
484
509
|
## CLI Reference
|
|
485
510
|
|
|
486
511
|
```
|
|
487
512
|
aegis init [--write-secrets] Initialize Aegis (master key + config)
|
|
488
|
-
aegis gate [--port] [--tls] [--
|
|
513
|
+
aegis gate [--port] [--tls] [--no-agent-auth] [--policies-dir] [--policy-mode]
|
|
489
514
|
Start the HTTP proxy
|
|
490
515
|
aegis dashboard [--port] [--gate-port] Start the web dashboard + Gate
|
|
491
516
|
|
|
@@ -547,8 +572,12 @@ aegis user regenerate-token --name <name> Regenerate user token
|
|
|
547
572
|
aegis mcp serve [--transport] [--port] Start the MCP server
|
|
548
573
|
aegis mcp config <claude|cursor|vscode> Generate MCP host config
|
|
549
574
|
|
|
575
|
+
aegis db backup [--output <path>] Backup the vault database
|
|
576
|
+
aegis db restore --input <path> [--force] Restore from a backup
|
|
577
|
+
|
|
550
578
|
aegis config validate Validate config file
|
|
551
579
|
aegis config show Show resolved configuration
|
|
580
|
+
aegis key where Show where the master key is stored
|
|
552
581
|
aegis doctor Health check diagnostics
|
|
553
582
|
```
|
|
554
583
|
|
|
@@ -556,7 +585,7 @@ aegis doctor Health check diagnostics
|
|
|
556
585
|
|
|
557
586
|
| Error | Cause | Fix |
|
|
558
587
|
|-------|-------|-----|
|
|
559
|
-
| `AEGIS_MASTER_KEY is not set` | No master key in config or
|
|
588
|
+
| `AEGIS_MASTER_KEY is not set` | No master key in config, env, or keychain | Run `aegis key where` to check storage, or `export AEGIS_MASTER_KEY=<key>` |
|
|
560
589
|
| `Invalid master key` | Wrong key for this vault | Check `AEGIS_MASTER_KEY` matches the key from `aegis init` |
|
|
561
590
|
| `Port 3100 is already in use` | Another process on that port | Use `aegis gate --port 3200` or stop the other process |
|
|
562
591
|
| `Database file is corrupted` | SQLite file damaged | Back up `.aegis/` and re-run `aegis init` |
|
|
@@ -585,8 +614,8 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for code style, PR process, and architect
|
|
|
585
614
|
|-------|------------|
|
|
586
615
|
| Language | TypeScript (ES2022, native ESM) |
|
|
587
616
|
| Runtime | Node.js ≥ 20 |
|
|
588
|
-
| Database | SQLite via better-sqlite3 (WAL mode) |
|
|
589
|
-
| Encryption | AES-256-GCM, PBKDF2 |
|
|
617
|
+
| Database | SQLite via better-sqlite3-multiple-ciphers (WAL mode, ChaCha20-Poly1305 encryption at rest) |
|
|
618
|
+
| Encryption | AES-256-GCM (field-level), ChaCha20-Poly1305 (full-database), PBKDF2 |
|
|
590
619
|
| Logging | pino (structured JSON, field-level redaction) |
|
|
591
620
|
| Metrics | prom-client (Prometheus) |
|
|
592
621
|
| CLI | Commander.js |
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type Database from 'better-sqlite3-multiple-ciphers';
|
|
2
|
+
export interface Agent {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
tokenPrefix: string;
|
|
6
|
+
rateLimit?: string;
|
|
7
|
+
createdAt: string;
|
|
8
|
+
updatedAt: string;
|
|
9
|
+
}
|
|
10
|
+
export interface AgentWithToken extends Agent {
|
|
11
|
+
token: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Agent Registry — manages agent identities and their credential access grants.
|
|
15
|
+
*
|
|
16
|
+
* Agents are identified by tokens (UUID v4 + HMAC suffix). Tokens are:
|
|
17
|
+
* - Hashed (SHA-256) for fast lookup during request validation — hash-only, no recovery
|
|
18
|
+
* - Prefixed (first 12 chars) for safe display in logs and audit entries
|
|
19
|
+
*
|
|
20
|
+
* Security: Tokens are never stored in recoverable form. If a token is lost,
|
|
21
|
+
* use regenerateToken() to issue a new one (same pattern as GitHub/Stripe key rotation).
|
|
22
|
+
*/
|
|
23
|
+
export declare class AgentRegistry {
|
|
24
|
+
private db;
|
|
25
|
+
private derivedKey;
|
|
26
|
+
constructor(db: Database.Database, derivedKey: Buffer);
|
|
27
|
+
/**
|
|
28
|
+
* Register a new agent. Returns the agent with its token (shown once).
|
|
29
|
+
*
|
|
30
|
+
* Token format: aegis_{uuid}_{hmac_prefix}
|
|
31
|
+
* The HMAC is derived from the UUID using the master key, making tokens
|
|
32
|
+
* verifiable as Aegis-generated.
|
|
33
|
+
*/
|
|
34
|
+
add(params: {
|
|
35
|
+
name: string;
|
|
36
|
+
rateLimit?: string;
|
|
37
|
+
}): AgentWithToken;
|
|
38
|
+
/**
|
|
39
|
+
* List all registered agents (without tokens).
|
|
40
|
+
*/
|
|
41
|
+
list(): Agent[];
|
|
42
|
+
/**
|
|
43
|
+
* Get an agent by name (without token).
|
|
44
|
+
*/
|
|
45
|
+
getByName(name: string): Agent | null;
|
|
46
|
+
/**
|
|
47
|
+
* Validate an agent token. Returns the agent if the token is valid, null otherwise.
|
|
48
|
+
*
|
|
49
|
+
* Uses SHA-256 hash comparison for constant-time-safe lookup.
|
|
50
|
+
*/
|
|
51
|
+
validateToken(token: string): Agent | null;
|
|
52
|
+
/**
|
|
53
|
+
* Remove an agent by name. Also removes all credential grants.
|
|
54
|
+
*/
|
|
55
|
+
remove(name: string): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Regenerate an agent's token. Issues a new token, invalidates the old one.
|
|
58
|
+
*
|
|
59
|
+
* The agent keeps its identity (id, name), credential grants, and rate limits.
|
|
60
|
+
* Only the token changes. This follows the same pattern as GitHub personal
|
|
61
|
+
* access token rotation or Stripe API key rolling.
|
|
62
|
+
*
|
|
63
|
+
* Returns the agent with the new token (shown once), or null if not found.
|
|
64
|
+
*/
|
|
65
|
+
regenerateToken(name: string): AgentWithToken | null;
|
|
66
|
+
/**
|
|
67
|
+
* Grant an agent access to a credential.
|
|
68
|
+
*/
|
|
69
|
+
grant(params: {
|
|
70
|
+
agentName: string;
|
|
71
|
+
credentialId: string;
|
|
72
|
+
}): void;
|
|
73
|
+
/**
|
|
74
|
+
* Revoke an agent's access to a credential.
|
|
75
|
+
*/
|
|
76
|
+
revoke(params: {
|
|
77
|
+
agentName: string;
|
|
78
|
+
credentialId: string;
|
|
79
|
+
}): boolean;
|
|
80
|
+
/**
|
|
81
|
+
* Check if an agent has access to a specific credential.
|
|
82
|
+
*/
|
|
83
|
+
hasAccess(agentId: string, credentialId: string): boolean;
|
|
84
|
+
/**
|
|
85
|
+
* List all credential IDs an agent has access to.
|
|
86
|
+
*/
|
|
87
|
+
listGrants(agentName: string): string[];
|
|
88
|
+
/**
|
|
89
|
+
* Set or update an agent's rate limit for a specific service.
|
|
90
|
+
* This is stored as a general rate limit on the agent record.
|
|
91
|
+
*/
|
|
92
|
+
setRateLimit(params: {
|
|
93
|
+
agentName: string;
|
|
94
|
+
rateLimit: string | null;
|
|
95
|
+
}): Agent;
|
|
96
|
+
private rowToAgent;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/agent/agent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,QAAQ,MAAM,iCAAiC,CAAC;AAI5D,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAe,SAAQ,KAAK;IAC3C,KAAK,EAAE,MAAM,CAAC;CACf;AAcD;;;;;;;;;GASG;AACH,qBAAa,aAAa;IAItB,OAAO,CAAC,EAAE;IAHZ,OAAO,CAAC,UAAU,CAAS;gBAGjB,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAC7B,UAAU,EAAE,MAAM;IAKpB;;;;;;OAMG;IACH,GAAG,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,cAAc;IAkCjE;;OAEG;IACH,IAAI,IAAI,KAAK,EAAE;IAQf;;OAEG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI;IAOrC;;;;OAIG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI;IAS1C;;OAEG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAS7B;;;;;;;;OAQG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAkCpD;;OAEG;IACH,KAAK,CAAC,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAoBhE;;OAEG;IACH,MAAM,CAAC,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO;IAapE;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO;IAQzD;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE;IAevC;;;OAGG;IACH,YAAY,CAAC,MAAM,EAAE;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,KAAK;IAmB5E,OAAO,CAAC,UAAU;CAUnB"}
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import * as crypto from 'node:crypto';
|
|
2
|
+
// ─── Agent Registry ──────────────────────────────────────────────
|
|
3
|
+
/**
|
|
4
|
+
* Agent Registry — manages agent identities and their credential access grants.
|
|
5
|
+
*
|
|
6
|
+
* Agents are identified by tokens (UUID v4 + HMAC suffix). Tokens are:
|
|
7
|
+
* - Hashed (SHA-256) for fast lookup during request validation — hash-only, no recovery
|
|
8
|
+
* - Prefixed (first 12 chars) for safe display in logs and audit entries
|
|
9
|
+
*
|
|
10
|
+
* Security: Tokens are never stored in recoverable form. If a token is lost,
|
|
11
|
+
* use regenerateToken() to issue a new one (same pattern as GitHub/Stripe key rotation).
|
|
12
|
+
*/
|
|
13
|
+
export class AgentRegistry {
|
|
14
|
+
db;
|
|
15
|
+
derivedKey;
|
|
16
|
+
constructor(db, derivedKey) {
|
|
17
|
+
this.db = db;
|
|
18
|
+
this.derivedKey = derivedKey;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Register a new agent. Returns the agent with its token (shown once).
|
|
22
|
+
*
|
|
23
|
+
* Token format: aegis_{uuid}_{hmac_prefix}
|
|
24
|
+
* The HMAC is derived from the UUID using the master key, making tokens
|
|
25
|
+
* verifiable as Aegis-generated.
|
|
26
|
+
*/
|
|
27
|
+
add(params) {
|
|
28
|
+
const id = crypto.randomUUID();
|
|
29
|
+
const uuid = crypto.randomUUID();
|
|
30
|
+
// Create HMAC of the UUID using the derived key for token integrity
|
|
31
|
+
const hmac = crypto
|
|
32
|
+
.createHmac('sha256', this.derivedKey)
|
|
33
|
+
.update(uuid)
|
|
34
|
+
.digest('hex')
|
|
35
|
+
.slice(0, 16);
|
|
36
|
+
const token = `aegis_${uuid}_${hmac}`;
|
|
37
|
+
// Hash the full token for fast lookup (hash-only — no recovery, only regeneration)
|
|
38
|
+
const tokenHash = crypto.createHash('sha256').update(token).digest('hex');
|
|
39
|
+
const tokenPrefix = token.slice(0, 12);
|
|
40
|
+
this.db
|
|
41
|
+
.prepare(`INSERT INTO agents (id, name, token_hash, token_prefix, rate_limit)
|
|
42
|
+
VALUES (?, ?, ?, ?, ?)`)
|
|
43
|
+
.run(id, params.name, tokenHash, tokenPrefix, params.rateLimit ?? null);
|
|
44
|
+
return {
|
|
45
|
+
id,
|
|
46
|
+
name: params.name,
|
|
47
|
+
tokenPrefix,
|
|
48
|
+
token,
|
|
49
|
+
rateLimit: params.rateLimit,
|
|
50
|
+
createdAt: new Date().toISOString(),
|
|
51
|
+
updatedAt: new Date().toISOString(),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* List all registered agents (without tokens).
|
|
56
|
+
*/
|
|
57
|
+
list() {
|
|
58
|
+
const rows = this.db
|
|
59
|
+
.prepare('SELECT * FROM agents ORDER BY created_at DESC')
|
|
60
|
+
.all();
|
|
61
|
+
return rows.map((row) => this.rowToAgent(row));
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Get an agent by name (without token).
|
|
65
|
+
*/
|
|
66
|
+
getByName(name) {
|
|
67
|
+
const row = this.db.prepare('SELECT * FROM agents WHERE name = ?').get(name);
|
|
68
|
+
return row ? this.rowToAgent(row) : null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Validate an agent token. Returns the agent if the token is valid, null otherwise.
|
|
72
|
+
*
|
|
73
|
+
* Uses SHA-256 hash comparison for constant-time-safe lookup.
|
|
74
|
+
*/
|
|
75
|
+
validateToken(token) {
|
|
76
|
+
const tokenHash = crypto.createHash('sha256').update(token).digest('hex');
|
|
77
|
+
const row = this.db.prepare('SELECT * FROM agents WHERE token_hash = ?').get(tokenHash);
|
|
78
|
+
return row ? this.rowToAgent(row) : null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Remove an agent by name. Also removes all credential grants.
|
|
82
|
+
*/
|
|
83
|
+
remove(name) {
|
|
84
|
+
const agent = this.getByName(name);
|
|
85
|
+
if (!agent)
|
|
86
|
+
return false;
|
|
87
|
+
// Foreign key CASCADE handles agent_credentials cleanup
|
|
88
|
+
const result = this.db.prepare('DELETE FROM agents WHERE name = ?').run(name);
|
|
89
|
+
return result.changes > 0;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Regenerate an agent's token. Issues a new token, invalidates the old one.
|
|
93
|
+
*
|
|
94
|
+
* The agent keeps its identity (id, name), credential grants, and rate limits.
|
|
95
|
+
* Only the token changes. This follows the same pattern as GitHub personal
|
|
96
|
+
* access token rotation or Stripe API key rolling.
|
|
97
|
+
*
|
|
98
|
+
* Returns the agent with the new token (shown once), or null if not found.
|
|
99
|
+
*/
|
|
100
|
+
regenerateToken(name) {
|
|
101
|
+
const agent = this.getByName(name);
|
|
102
|
+
if (!agent)
|
|
103
|
+
return null;
|
|
104
|
+
// Generate a new token with the same UUID+HMAC format
|
|
105
|
+
const uuid = crypto.randomUUID();
|
|
106
|
+
const hmac = crypto
|
|
107
|
+
.createHmac('sha256', this.derivedKey)
|
|
108
|
+
.update(uuid)
|
|
109
|
+
.digest('hex')
|
|
110
|
+
.slice(0, 16);
|
|
111
|
+
const token = `aegis_${uuid}_${hmac}`;
|
|
112
|
+
// Compute new hash and prefix
|
|
113
|
+
const tokenHash = crypto.createHash('sha256').update(token).digest('hex');
|
|
114
|
+
const tokenPrefix = token.slice(0, 12);
|
|
115
|
+
// Update only the token fields — identity, grants, and rate limits are preserved
|
|
116
|
+
this.db
|
|
117
|
+
.prepare(`UPDATE agents SET token_hash = ?, token_prefix = ?, updated_at = datetime('now') WHERE id = ?`)
|
|
118
|
+
.run(tokenHash, tokenPrefix, agent.id);
|
|
119
|
+
return {
|
|
120
|
+
...agent,
|
|
121
|
+
tokenPrefix,
|
|
122
|
+
token,
|
|
123
|
+
updatedAt: new Date().toISOString(),
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
// ─── Credential Grants ──────────────────────────────────────────
|
|
127
|
+
/**
|
|
128
|
+
* Grant an agent access to a credential.
|
|
129
|
+
*/
|
|
130
|
+
grant(params) {
|
|
131
|
+
const agent = this.getByName(params.agentName);
|
|
132
|
+
if (!agent) {
|
|
133
|
+
throw new Error(`No agent found with name "${params.agentName}"`);
|
|
134
|
+
}
|
|
135
|
+
// Check if already granted
|
|
136
|
+
const existing = this.db
|
|
137
|
+
.prepare('SELECT 1 FROM agent_credentials WHERE agent_id = ? AND credential_id = ?')
|
|
138
|
+
.get(agent.id, params.credentialId);
|
|
139
|
+
if (existing) {
|
|
140
|
+
return; // Already granted — idempotent
|
|
141
|
+
}
|
|
142
|
+
this.db
|
|
143
|
+
.prepare('INSERT INTO agent_credentials (agent_id, credential_id) VALUES (?, ?)')
|
|
144
|
+
.run(agent.id, params.credentialId);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Revoke an agent's access to a credential.
|
|
148
|
+
*/
|
|
149
|
+
revoke(params) {
|
|
150
|
+
const agent = this.getByName(params.agentName);
|
|
151
|
+
if (!agent) {
|
|
152
|
+
throw new Error(`No agent found with name "${params.agentName}"`);
|
|
153
|
+
}
|
|
154
|
+
const result = this.db
|
|
155
|
+
.prepare('DELETE FROM agent_credentials WHERE agent_id = ? AND credential_id = ?')
|
|
156
|
+
.run(agent.id, params.credentialId);
|
|
157
|
+
return result.changes > 0;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Check if an agent has access to a specific credential.
|
|
161
|
+
*/
|
|
162
|
+
hasAccess(agentId, credentialId) {
|
|
163
|
+
const row = this.db
|
|
164
|
+
.prepare('SELECT 1 FROM agent_credentials WHERE agent_id = ? AND credential_id = ?')
|
|
165
|
+
.get(agentId, credentialId);
|
|
166
|
+
return row !== undefined;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* List all credential IDs an agent has access to.
|
|
170
|
+
*/
|
|
171
|
+
listGrants(agentName) {
|
|
172
|
+
const agent = this.getByName(agentName);
|
|
173
|
+
if (!agent) {
|
|
174
|
+
throw new Error(`No agent found with name "${agentName}"`);
|
|
175
|
+
}
|
|
176
|
+
const rows = this.db
|
|
177
|
+
.prepare('SELECT credential_id FROM agent_credentials WHERE agent_id = ?')
|
|
178
|
+
.all(agent.id);
|
|
179
|
+
return rows.map((r) => r.credential_id);
|
|
180
|
+
}
|
|
181
|
+
// ─── Per-Agent Rate Limits ──────────────────────────────────────
|
|
182
|
+
/**
|
|
183
|
+
* Set or update an agent's rate limit for a specific service.
|
|
184
|
+
* This is stored as a general rate limit on the agent record.
|
|
185
|
+
*/
|
|
186
|
+
setRateLimit(params) {
|
|
187
|
+
const agent = this.getByName(params.agentName);
|
|
188
|
+
if (!agent) {
|
|
189
|
+
throw new Error(`No agent found with name "${params.agentName}"`);
|
|
190
|
+
}
|
|
191
|
+
this.db
|
|
192
|
+
.prepare("UPDATE agents SET rate_limit = ?, updated_at = datetime('now') WHERE id = ?")
|
|
193
|
+
.run(params.rateLimit, agent.id);
|
|
194
|
+
return {
|
|
195
|
+
...agent,
|
|
196
|
+
rateLimit: params.rateLimit ?? undefined,
|
|
197
|
+
updatedAt: new Date().toISOString(),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
// ─── Internal ───────────────────────────────────────────────────
|
|
201
|
+
rowToAgent(row) {
|
|
202
|
+
return {
|
|
203
|
+
id: row.id,
|
|
204
|
+
name: row.name,
|
|
205
|
+
tokenPrefix: row.token_prefix,
|
|
206
|
+
rateLimit: row.rate_limit ?? undefined,
|
|
207
|
+
createdAt: row.created_at,
|
|
208
|
+
updatedAt: row.updated_at,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=agent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.js","sourceRoot":"","sources":["../../src/agent/agent.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/agent/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RBAC enforcement helper for CLI commands.
|
|
3
|
+
*
|
|
4
|
+
* Authenticates the current user via AEGIS_USER_TOKEN and checks
|
|
5
|
+
* whether they have the required permission.
|
|
6
|
+
*/
|
|
7
|
+
import type { getDb } from '../db.js';
|
|
8
|
+
import type { Permission } from '../user/index.js';
|
|
9
|
+
/**
|
|
10
|
+
* Authenticate the current user via AEGIS_USER_TOKEN and check permission.
|
|
11
|
+
*
|
|
12
|
+
* Always enforced once users exist. If no users have been created yet
|
|
13
|
+
* (bootstrap mode), all commands are allowed — `aegis init` creates the
|
|
14
|
+
* first admin user.
|
|
15
|
+
*
|
|
16
|
+
* Returns true if allowed. Calls process.exit(1) if denied.
|
|
17
|
+
*/
|
|
18
|
+
export declare function requireUserAuth(db: ReturnType<typeof getDb>, derivedKey: Buffer, permission: Permission): boolean;
|
|
19
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/cli/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,UAAU,CAAC,OAAO,KAAK,CAAC,EAC5B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,UAAU,GACrB,OAAO,CA+BT"}
|
package/dist/cli/auth.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RBAC enforcement helper for CLI commands.
|
|
3
|
+
*
|
|
4
|
+
* Authenticates the current user via AEGIS_USER_TOKEN and checks
|
|
5
|
+
* whether they have the required permission.
|
|
6
|
+
*/
|
|
7
|
+
import { hasPermission, UserRegistry } from '../user/index.js';
|
|
8
|
+
/**
|
|
9
|
+
* Authenticate the current user via AEGIS_USER_TOKEN and check permission.
|
|
10
|
+
*
|
|
11
|
+
* Always enforced once users exist. If no users have been created yet
|
|
12
|
+
* (bootstrap mode), all commands are allowed — `aegis init` creates the
|
|
13
|
+
* first admin user.
|
|
14
|
+
*
|
|
15
|
+
* Returns true if allowed. Calls process.exit(1) if denied.
|
|
16
|
+
*/
|
|
17
|
+
export function requireUserAuth(db, derivedKey, permission) {
|
|
18
|
+
const registry = new UserRegistry(db, derivedKey);
|
|
19
|
+
// Bootstrap mode: no users exist yet — allow everything so init can create the first admin
|
|
20
|
+
if (registry.count() === 0)
|
|
21
|
+
return true;
|
|
22
|
+
const token = process.env.AEGIS_USER_TOKEN;
|
|
23
|
+
if (!token) {
|
|
24
|
+
console.error('\n✗ Authentication required. Set AEGIS_USER_TOKEN=<your-api-key>\n');
|
|
25
|
+
console.error(' Get an API key from your admin, or regenerate with:');
|
|
26
|
+
console.error(' aegis user regenerate-token --name <name>\n');
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
const user = registry.validateToken(token);
|
|
30
|
+
if (!user) {
|
|
31
|
+
console.error('\n✗ Invalid API key. Token not recognized.\n');
|
|
32
|
+
console.error(' Regenerate with: aegis user regenerate-token --name <name>\n');
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
if (!hasPermission(user.role, permission)) {
|
|
36
|
+
console.error(`\n✗ Permission denied. Role "${user.role}" does not have "${permission}".\n`);
|
|
37
|
+
console.error(` Required permission: ${permission}`);
|
|
38
|
+
console.error(` Your role: ${user.role}`);
|
|
39
|
+
console.error(` Contact an admin to upgrade your role.\n`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/cli/auth.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAE/D;;;;;;;;GAQG;AACH,MAAM,UAAU,eAAe,CAC7B,EAA4B,EAC5B,UAAkB,EAClB,UAAsB;IAEtB,MAAM,QAAQ,GAAG,IAAI,YAAY,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IAElD,2FAA2F;IAC3F,IAAI,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAExC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;IAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,oEAAoE,CAAC,CAAC;QACpF,OAAO,CAAC,KAAK,CAAC,uDAAuD,CAAC,CAAC;QACvE,OAAO,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAE3C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAC9D,OAAO,CAAC,KAAK,CAAC,gEAAgE,CAAC,CAAC;QAChF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,CAAC;QAC1C,OAAO,CAAC,KAAK,CAAC,gCAAgC,IAAI,CAAC,IAAI,oBAAoB,UAAU,MAAM,CAAC,CAAC;QAC7F,OAAO,CAAC,KAAK,CAAC,0BAA0B,UAAU,EAAE,CAAC,CAAC;QACtD,OAAO,CAAC,KAAK,CAAC,gBAAgB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3C,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QAC5D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/agent.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQzC,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqP/C"}
|