@oculum/cli 1.0.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/LICENSE +21 -0
- package/README.md +425 -0
- package/dist/commands/auth.d.ts +11 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +156 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/scan.d.ts +23 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +323 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/watch.d.ts +10 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +231 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +47624 -0
- package/dist/index.js.map +1 -0
- package/dist/utils/api.d.ts +42 -0
- package/dist/utils/api.d.ts.map +1 -0
- package/dist/utils/api.js +120 -0
- package/dist/utils/api.js.map +1 -0
- package/dist/utils/config.d.ts +50 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +91 -0
- package/dist/utils/config.js.map +1 -0
- package/package.json +67 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Felix Westin
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
# Oculum CLI
|
|
2
|
+
|
|
3
|
+
AI-native security scanner for detecting vulnerabilities in AI-generated code, BYOK patterns, and modern web applications.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@oculum/cli)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- 🤖 **AI-Native Security**: Specialized detection for AI-era risks (BYOK patterns, agent tools, AI-generated code)
|
|
11
|
+
- ⚡ **Multiple Scan Depths**: Choose between cheap (fast), validated (AI-verified), or deep (comprehensive) scans
|
|
12
|
+
- 🎯 **Low False Positives**: AI validation reduces noise by ~70%
|
|
13
|
+
- 📊 **Multiple Output Formats**: Terminal, JSON, SARIF, or Markdown
|
|
14
|
+
- 🔄 **Incremental Scanning**: Scan only changed files for faster CI/CD
|
|
15
|
+
- 🎨 **Interactive TUI**: Beautiful terminal UI for exploring findings
|
|
16
|
+
- 🔐 **Secure Authentication**: Device flow authentication with GitHub
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g @oculum/cli
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or use with npx (no installation required):
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx @oculum/cli scan .
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick Start
|
|
31
|
+
|
|
32
|
+
### 1. Authenticate
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
oculum login
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This will open a browser window for GitHub authentication. Follow the prompts to complete the login.
|
|
39
|
+
|
|
40
|
+
### 2. Run Your First Scan
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Quick scan (fast, local-only)
|
|
44
|
+
oculum scan .
|
|
45
|
+
|
|
46
|
+
# Validated scan (AI-verified, recommended)
|
|
47
|
+
oculum scan . --mode validated
|
|
48
|
+
|
|
49
|
+
# Deep scan (comprehensive analysis)
|
|
50
|
+
oculum scan . --mode deep
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3. Explore Results Interactively
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
oculum ui
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Commands
|
|
60
|
+
|
|
61
|
+
### `oculum scan [path]`
|
|
62
|
+
|
|
63
|
+
Scan a directory or file for security vulnerabilities.
|
|
64
|
+
|
|
65
|
+
**Options:**
|
|
66
|
+
|
|
67
|
+
- `-d, --depth <mode>` - Scan depth: `cheap`, `validated`, or `deep` (default: `cheap`)
|
|
68
|
+
- `-f, --format <format>` - Output format: `terminal`, `json`, `sarif`, or `markdown` (default: `terminal`)
|
|
69
|
+
- `-o, --output <file>` - Write output to file instead of stdout
|
|
70
|
+
- `--incremental` - Only scan files changed since last commit (git required)
|
|
71
|
+
- `--config <path>` - Path to config file (default: `oculum.config.json`)
|
|
72
|
+
|
|
73
|
+
**Examples:**
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# Scan current directory with validated mode
|
|
77
|
+
oculum scan . --mode validated
|
|
78
|
+
|
|
79
|
+
# Scan specific file with JSON output
|
|
80
|
+
oculum scan src/api/auth.ts --format json
|
|
81
|
+
|
|
82
|
+
# Incremental scan for CI/CD
|
|
83
|
+
oculum scan . --incremental --mode validated
|
|
84
|
+
|
|
85
|
+
# Save results to file
|
|
86
|
+
oculum scan . --output results.sarif --format sarif
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### `oculum ui`
|
|
90
|
+
|
|
91
|
+
Launch interactive terminal UI for scanning and exploring results.
|
|
92
|
+
|
|
93
|
+
**Features:**
|
|
94
|
+
- Visual file tree navigation
|
|
95
|
+
- Real-time scan progress
|
|
96
|
+
- Interactive findings explorer
|
|
97
|
+
- Severity filtering
|
|
98
|
+
- Code snippet preview
|
|
99
|
+
|
|
100
|
+
### `oculum login`
|
|
101
|
+
|
|
102
|
+
Authenticate with Oculum API using GitHub device flow.
|
|
103
|
+
|
|
104
|
+
**Process:**
|
|
105
|
+
1. CLI displays a URL and code
|
|
106
|
+
2. Open URL in browser
|
|
107
|
+
3. Enter code and authorize with GitHub
|
|
108
|
+
4. CLI automatically completes authentication
|
|
109
|
+
|
|
110
|
+
### `oculum status`
|
|
111
|
+
|
|
112
|
+
Check authentication status and current tier.
|
|
113
|
+
|
|
114
|
+
**Output:**
|
|
115
|
+
- Logged in status
|
|
116
|
+
- Email address
|
|
117
|
+
- Current tier (free/pro)
|
|
118
|
+
- API key status
|
|
119
|
+
|
|
120
|
+
### `oculum logout`
|
|
121
|
+
|
|
122
|
+
Remove stored credentials and log out.
|
|
123
|
+
|
|
124
|
+
## Scan Depth Modes
|
|
125
|
+
|
|
126
|
+
### Cheap (Free)
|
|
127
|
+
|
|
128
|
+
- **Speed**: Very fast (~5-10s for 100 files)
|
|
129
|
+
- **Cost**: Free, runs locally
|
|
130
|
+
- **Detection**: Pattern-based detection (Layer 1 + Layer 2)
|
|
131
|
+
- **Use Case**: Quick checks, pre-commit hooks, local development
|
|
132
|
+
|
|
133
|
+
### Validated (Pro)
|
|
134
|
+
|
|
135
|
+
- **Speed**: Moderate (~30-60s for 100 files)
|
|
136
|
+
- **Cost**: Paid, requires API key
|
|
137
|
+
- **Detection**: Pattern + AI validation (reduces false positives by ~70%)
|
|
138
|
+
- **Use Case**: PR checks, CI/CD pipelines, production code
|
|
139
|
+
|
|
140
|
+
### Deep (Pro)
|
|
141
|
+
|
|
142
|
+
- **Speed**: Slower (~2-5min for 100 files)
|
|
143
|
+
- **Cost**: Higher cost, requires API key
|
|
144
|
+
- **Detection**: Full semantic analysis with project context
|
|
145
|
+
- **Use Case**: Security audits, critical code paths, compliance
|
|
146
|
+
|
|
147
|
+
## Configuration File
|
|
148
|
+
|
|
149
|
+
Create `oculum.config.json` in your project root:
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"depth": "validated",
|
|
154
|
+
"format": "terminal",
|
|
155
|
+
"ignore": [
|
|
156
|
+
"**/node_modules/**",
|
|
157
|
+
"**/dist/**",
|
|
158
|
+
"**/*.test.ts"
|
|
159
|
+
],
|
|
160
|
+
"include": [
|
|
161
|
+
"src/**/*.ts",
|
|
162
|
+
"src/**/*.js"
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Options:**
|
|
168
|
+
|
|
169
|
+
- `depth` - Default scan depth (`cheap`, `validated`, `deep`)
|
|
170
|
+
- `format` - Default output format (`terminal`, `json`, `sarif`, `markdown`)
|
|
171
|
+
- `ignore` - Glob patterns to exclude from scanning
|
|
172
|
+
- `include` - Glob patterns to include in scanning (overrides ignore)
|
|
173
|
+
|
|
174
|
+
## Output Formats
|
|
175
|
+
|
|
176
|
+
### Terminal (Default)
|
|
177
|
+
|
|
178
|
+
Human-readable output with colors and formatting:
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
════════════════════════════════════════════════════════════
|
|
182
|
+
OCULUM SECURITY SCAN RESULTS
|
|
183
|
+
════════════════════════════════════════════════════════════
|
|
184
|
+
|
|
185
|
+
🔴 2 critical issues found
|
|
186
|
+
|
|
187
|
+
🔑 Secrets & Credentials (1 critical)
|
|
188
|
+
────────────────────────────────────────────────────────────
|
|
189
|
+
🔴 CRITICAL Hardcoded API key detected
|
|
190
|
+
src/config.ts:12
|
|
191
|
+
API key appears to be hardcoded in source code.
|
|
192
|
+
💡 Move to environment variables: process.env.API_KEY
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### JSON
|
|
196
|
+
|
|
197
|
+
Machine-readable JSON for programmatic processing:
|
|
198
|
+
|
|
199
|
+
```json
|
|
200
|
+
{
|
|
201
|
+
"summary": {
|
|
202
|
+
"totalIssues": 2,
|
|
203
|
+
"critical": 2,
|
|
204
|
+
"high": 0,
|
|
205
|
+
"medium": 0,
|
|
206
|
+
"low": 0
|
|
207
|
+
},
|
|
208
|
+
"findings": [...]
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### SARIF
|
|
213
|
+
|
|
214
|
+
GitHub Security tab compatible format:
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
oculum scan . --format sarif --output results.sarif
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Upload to GitHub:
|
|
221
|
+
```yaml
|
|
222
|
+
- uses: github/codeql-action/upload-sarif@v2
|
|
223
|
+
with:
|
|
224
|
+
sarif_file: results.sarif
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Markdown
|
|
228
|
+
|
|
229
|
+
Documentation-friendly format:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
oculum scan . --format markdown --output SECURITY.md
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## What Oculum Detects
|
|
236
|
+
|
|
237
|
+
### AI-Era Risks
|
|
238
|
+
|
|
239
|
+
- **BYOK Patterns**: Bring-your-own-key usage, storage, and logging
|
|
240
|
+
- **Agent Tools**: Over-permissive tool definitions, unsafe tool execution
|
|
241
|
+
- **AI-Generated Code**: Common patterns from AI coding assistants
|
|
242
|
+
- **Prompt Injection**: User input in AI prompts without sanitization
|
|
243
|
+
|
|
244
|
+
### Traditional Security
|
|
245
|
+
|
|
246
|
+
- **Secrets**: Hardcoded API keys, tokens, credentials
|
|
247
|
+
- **Injection**: SQL injection, command injection, XSS
|
|
248
|
+
- **Authentication**: Missing auth checks, weak session handling
|
|
249
|
+
- **Data Exposure**: Sensitive data in logs, error messages, responses
|
|
250
|
+
- **Dangerous Functions**: `eval`, `exec`, unsafe deserialization
|
|
251
|
+
|
|
252
|
+
### Configuration Issues
|
|
253
|
+
|
|
254
|
+
- **Docker**: Running as root, hardcoded secrets in Dockerfiles
|
|
255
|
+
- **CORS**: Permissive origins, credential exposure
|
|
256
|
+
- **Environment**: Committed `.env` files, hardcoded configs
|
|
257
|
+
|
|
258
|
+
## CI/CD Integration
|
|
259
|
+
|
|
260
|
+
### GitHub Actions
|
|
261
|
+
|
|
262
|
+
```yaml
|
|
263
|
+
name: Security Scan
|
|
264
|
+
on: [pull_request]
|
|
265
|
+
|
|
266
|
+
jobs:
|
|
267
|
+
scan:
|
|
268
|
+
runs-on: ubuntu-latest
|
|
269
|
+
steps:
|
|
270
|
+
- uses: actions/checkout@v3
|
|
271
|
+
|
|
272
|
+
- name: Install Oculum
|
|
273
|
+
run: npm install -g @oculum/cli
|
|
274
|
+
|
|
275
|
+
- name: Authenticate
|
|
276
|
+
run: echo "${{ secrets.OCULUM_API_KEY }}" | oculum login --stdin
|
|
277
|
+
|
|
278
|
+
- name: Scan
|
|
279
|
+
run: oculum scan . --mode validated --format sarif --output results.sarif
|
|
280
|
+
|
|
281
|
+
- name: Upload SARIF
|
|
282
|
+
uses: github/codeql-action/upload-sarif@v2
|
|
283
|
+
with:
|
|
284
|
+
sarif_file: results.sarif
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### GitLab CI
|
|
288
|
+
|
|
289
|
+
```yaml
|
|
290
|
+
security_scan:
|
|
291
|
+
stage: test
|
|
292
|
+
script:
|
|
293
|
+
- npm install -g @oculum/cli
|
|
294
|
+
- echo "$OCULUM_API_KEY" | oculum login --stdin
|
|
295
|
+
- oculum scan . --mode validated --format json --output results.json
|
|
296
|
+
artifacts:
|
|
297
|
+
reports:
|
|
298
|
+
codequality: results.json
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## Troubleshooting
|
|
302
|
+
|
|
303
|
+
### Authentication Issues
|
|
304
|
+
|
|
305
|
+
**Problem**: `Login failed: APIError`
|
|
306
|
+
|
|
307
|
+
**Solution**:
|
|
308
|
+
1. Check your internet connection
|
|
309
|
+
2. Verify API endpoint is accessible: `curl https://oculum-api.vercel.app/api/v1/auth/device`
|
|
310
|
+
3. Try logging out and back in: `oculum logout && oculum login`
|
|
311
|
+
|
|
312
|
+
### Scan Failures
|
|
313
|
+
|
|
314
|
+
**Problem**: `Scan failed: quota exceeded`
|
|
315
|
+
|
|
316
|
+
**Solution**:
|
|
317
|
+
- Check your usage: `oculum status`
|
|
318
|
+
- Upgrade to Pro tier for higher limits
|
|
319
|
+
- Use `--mode cheap` for unlimited local scans
|
|
320
|
+
|
|
321
|
+
**Problem**: Too many files being scanned
|
|
322
|
+
|
|
323
|
+
**Solution**:
|
|
324
|
+
- Add ignore patterns to `oculum.config.json`
|
|
325
|
+
- Use `.gitignore` patterns (automatically respected)
|
|
326
|
+
- Scan specific directories: `oculum scan src/`
|
|
327
|
+
|
|
328
|
+
### Performance Issues
|
|
329
|
+
|
|
330
|
+
**Problem**: Scans are slow
|
|
331
|
+
|
|
332
|
+
**Solution**:
|
|
333
|
+
- Use `--mode cheap` for faster local scans
|
|
334
|
+
- Enable incremental scanning: `--incremental`
|
|
335
|
+
- Reduce scope with ignore patterns
|
|
336
|
+
- Scan only changed files in CI/CD
|
|
337
|
+
|
|
338
|
+
## API Key Management
|
|
339
|
+
|
|
340
|
+
### Getting an API Key
|
|
341
|
+
|
|
342
|
+
1. Sign up at https://oculum-api.vercel.app
|
|
343
|
+
2. Navigate to Dashboard → API Keys
|
|
344
|
+
3. Click "Create New Key"
|
|
345
|
+
4. Copy the key (shown only once)
|
|
346
|
+
5. Use with CLI: `oculum login --api-key YOUR_KEY`
|
|
347
|
+
|
|
348
|
+
### Storing API Keys Securely
|
|
349
|
+
|
|
350
|
+
**Local Development:**
|
|
351
|
+
```bash
|
|
352
|
+
# Store in config (recommended)
|
|
353
|
+
oculum login
|
|
354
|
+
|
|
355
|
+
# Or use environment variable
|
|
356
|
+
export OCULUM_API_KEY="your-key-here"
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
**CI/CD:**
|
|
360
|
+
- Store as encrypted secret in your CI/CD platform
|
|
361
|
+
- Never commit API keys to version control
|
|
362
|
+
- Rotate keys regularly
|
|
363
|
+
|
|
364
|
+
## Pricing
|
|
365
|
+
|
|
366
|
+
### Free Tier
|
|
367
|
+
- ✅ Unlimited cheap (local) scans
|
|
368
|
+
- ✅ Basic CLI access
|
|
369
|
+
- ✅ All output formats
|
|
370
|
+
- ❌ No validated/deep scans
|
|
371
|
+
|
|
372
|
+
### Pro Tier
|
|
373
|
+
- ✅ Everything in Free
|
|
374
|
+
- ✅ Validated scans (AI-verified)
|
|
375
|
+
- ✅ Deep scans (semantic analysis)
|
|
376
|
+
- ✅ API access
|
|
377
|
+
- ✅ Priority support
|
|
378
|
+
|
|
379
|
+
[View detailed pricing →](https://oculum-api.vercel.app/pricing)
|
|
380
|
+
|
|
381
|
+
## Examples
|
|
382
|
+
|
|
383
|
+
### Pre-commit Hook
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
#!/bin/bash
|
|
387
|
+
# .git/hooks/pre-commit
|
|
388
|
+
|
|
389
|
+
oculum scan . --mode cheap --format terminal
|
|
390
|
+
if [ $? -ne 0 ]; then
|
|
391
|
+
echo "Security issues found. Commit blocked."
|
|
392
|
+
exit 1
|
|
393
|
+
fi
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
### Watch Mode (Development)
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
# Scan on file changes
|
|
400
|
+
oculum watch src/ --mode cheap
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Scan Specific File Types
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
# Only TypeScript files
|
|
407
|
+
oculum scan . --include "**/*.ts" --include "**/*.tsx"
|
|
408
|
+
|
|
409
|
+
# Exclude tests
|
|
410
|
+
oculum scan . --ignore "**/*.test.ts" --ignore "**/*.spec.ts"
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
## Support
|
|
414
|
+
|
|
415
|
+
- 📧 Email: felix.lwestin@gmail.com
|
|
416
|
+
- 🐛 Issues: [GitHub Issues](https://github.com/flexipie/oculum/issues)
|
|
417
|
+
- 📚 Docs: [Documentation](https://oculum-api.vercel.app/docs)
|
|
418
|
+
|
|
419
|
+
## License
|
|
420
|
+
|
|
421
|
+
MIT © Felix Westin
|
|
422
|
+
|
|
423
|
+
---
|
|
424
|
+
|
|
425
|
+
**Made with ❤️ for developers building with AI**
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth Commands
|
|
3
|
+
* Handle login, logout, and status
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
/**
|
|
7
|
+
* Auth command group
|
|
8
|
+
*/
|
|
9
|
+
export declare const authCommand: Command;
|
|
10
|
+
export declare const loginCommand: Command;
|
|
11
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAiJnC;;GAEG;AACH,eAAO,MAAM,WAAW,SACe,CAAA;AA+BvC,eAAO,MAAM,YAAY,SAGT,CAAA"}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Auth Commands
|
|
4
|
+
* Handle login, logout, and status
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.loginCommand = exports.authCommand = void 0;
|
|
11
|
+
const commander_1 = require("commander");
|
|
12
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
13
|
+
const ora_1 = __importDefault(require("ora"));
|
|
14
|
+
const config_js_1 = require("../utils/config.js");
|
|
15
|
+
const api_js_1 = require("../utils/api.js");
|
|
16
|
+
/**
|
|
17
|
+
* Login command
|
|
18
|
+
*/
|
|
19
|
+
async function login(options) {
|
|
20
|
+
const spinner = (0, ora_1.default)();
|
|
21
|
+
// If API key provided directly, verify and store it
|
|
22
|
+
if (options.apiKey) {
|
|
23
|
+
spinner.start('Verifying API key...');
|
|
24
|
+
const result = await (0, api_js_1.verifyApiKey)(options.apiKey);
|
|
25
|
+
if (!result.valid) {
|
|
26
|
+
spinner.fail('Invalid API key');
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
(0, config_js_1.setAuthCredentials)(options.apiKey, result.email, result.tier);
|
|
30
|
+
spinner.succeed('Logged in successfully!');
|
|
31
|
+
console.log(chalk_1.default.dim(` Email: ${result.email}`));
|
|
32
|
+
console.log(chalk_1.default.dim(` Tier: ${result.tier}`));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Otherwise, use device flow
|
|
36
|
+
try {
|
|
37
|
+
spinner.start('Initiating login...');
|
|
38
|
+
const { authUrl, deviceCode } = await (0, api_js_1.initiateLogin)();
|
|
39
|
+
spinner.stop();
|
|
40
|
+
console.log('\nTo complete login:');
|
|
41
|
+
console.log(chalk_1.default.cyan(`\n 1. Open this URL in your browser:\n ${authUrl}`));
|
|
42
|
+
console.log(chalk_1.default.dim(`\n 2. Enter the code: ${chalk_1.default.bold(deviceCode)}`));
|
|
43
|
+
console.log(chalk_1.default.dim('\n Waiting for authorization...'));
|
|
44
|
+
// Poll for completion
|
|
45
|
+
spinner.start('Waiting for browser authorization...');
|
|
46
|
+
const maxAttempts = 60; // 5 minutes with 5s interval
|
|
47
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
48
|
+
await new Promise(resolve => setTimeout(resolve, 5000));
|
|
49
|
+
const result = await (0, api_js_1.pollForLogin)(deviceCode);
|
|
50
|
+
if (result.complete) {
|
|
51
|
+
(0, config_js_1.setAuthCredentials)(result.apiKey, result.email, result.tier);
|
|
52
|
+
spinner.succeed('Logged in successfully!');
|
|
53
|
+
console.log(chalk_1.default.dim(` Email: ${result.email}`));
|
|
54
|
+
console.log(chalk_1.default.dim(` Tier: ${result.tier}`));
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
spinner.fail('Login timed out. Please try again.');
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
spinner.fail(`Login failed: ${err}`);
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Logout command
|
|
68
|
+
*/
|
|
69
|
+
function logout() {
|
|
70
|
+
if (!(0, config_js_1.isAuthenticated)()) {
|
|
71
|
+
console.log(chalk_1.default.yellow('Not logged in.'));
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
(0, config_js_1.clearAuth)();
|
|
75
|
+
console.log(chalk_1.default.green('Logged out successfully.'));
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Status command
|
|
79
|
+
*/
|
|
80
|
+
async function status() {
|
|
81
|
+
const config = (0, config_js_1.getConfig)();
|
|
82
|
+
console.log('\n' + chalk_1.default.bold('Oculum CLI Status'));
|
|
83
|
+
console.log(chalk_1.default.dim('─'.repeat(40)));
|
|
84
|
+
if (!(0, config_js_1.isAuthenticated)()) {
|
|
85
|
+
console.log(chalk_1.default.yellow('\nNot logged in.'));
|
|
86
|
+
console.log(chalk_1.default.dim('\nRun `oculum login` to authenticate.'));
|
|
87
|
+
console.log(chalk_1.default.dim('Free tier allows cheap (local) scans only.'));
|
|
88
|
+
console.log(chalk_1.default.dim('Paid tiers unlock AI-powered validated and deep scans.\n'));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Verify the stored key is still valid
|
|
92
|
+
const spinner = (0, ora_1.default)('Verifying credentials...').start();
|
|
93
|
+
const result = await (0, api_js_1.verifyApiKey)(config.apiKey);
|
|
94
|
+
if (!result.valid) {
|
|
95
|
+
spinner.fail('Stored credentials are invalid or expired.');
|
|
96
|
+
console.log(chalk_1.default.dim('Run `oculum login` to re-authenticate.'));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
spinner.succeed('Authenticated');
|
|
100
|
+
console.log(chalk_1.default.dim(` Email: ${result.email || config.email}`));
|
|
101
|
+
console.log(chalk_1.default.dim(` Tier: ${result.tier || config.tier}`));
|
|
102
|
+
// Show tier capabilities
|
|
103
|
+
console.log('\n' + chalk_1.default.bold('Available Scan Depths:'));
|
|
104
|
+
const tier = result.tier || config.tier || 'free';
|
|
105
|
+
console.log(chalk_1.default.green(' cheap - Fast pattern matching (always available)'));
|
|
106
|
+
if (tier === 'pro' || tier === 'enterprise') {
|
|
107
|
+
console.log(chalk_1.default.green(' validated - AI-powered validation'));
|
|
108
|
+
console.log(chalk_1.default.green(' deep - Full AI semantic analysis'));
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
console.log(chalk_1.default.dim(' validated - AI-powered validation (requires Pro)'));
|
|
112
|
+
console.log(chalk_1.default.dim(' deep - Full AI semantic analysis (requires Pro)'));
|
|
113
|
+
}
|
|
114
|
+
console.log('');
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Upgrade command (opens billing portal)
|
|
118
|
+
*/
|
|
119
|
+
function upgrade() {
|
|
120
|
+
console.log(chalk_1.default.cyan('\nTo upgrade your subscription, visit:'));
|
|
121
|
+
console.log(chalk_1.default.bold(' https://oculum.dev/billing\n'));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Auth command group
|
|
125
|
+
*/
|
|
126
|
+
exports.authCommand = new commander_1.Command('auth')
|
|
127
|
+
.description('Manage authentication');
|
|
128
|
+
// Login subcommand
|
|
129
|
+
exports.authCommand
|
|
130
|
+
.command('login')
|
|
131
|
+
.description('Log in to Oculum')
|
|
132
|
+
.option('-k, --api-key <key>', 'API key (skip browser auth)')
|
|
133
|
+
.action(login);
|
|
134
|
+
// Logout subcommand
|
|
135
|
+
exports.authCommand
|
|
136
|
+
.command('logout')
|
|
137
|
+
.description('Log out from Oculum')
|
|
138
|
+
.action(logout);
|
|
139
|
+
// Status subcommand
|
|
140
|
+
exports.authCommand
|
|
141
|
+
.command('status')
|
|
142
|
+
.description('Show current authentication status')
|
|
143
|
+
.action(status);
|
|
144
|
+
// Upgrade subcommand
|
|
145
|
+
exports.authCommand
|
|
146
|
+
.command('upgrade')
|
|
147
|
+
.description('Upgrade your subscription')
|
|
148
|
+
.action(upgrade);
|
|
149
|
+
// Default: show status
|
|
150
|
+
exports.authCommand.action(status);
|
|
151
|
+
// Also export standalone login command for convenience
|
|
152
|
+
exports.loginCommand = new commander_1.Command('login')
|
|
153
|
+
.description('Log in to Oculum')
|
|
154
|
+
.option('-k, --api-key <key>', 'API key (skip browser auth)')
|
|
155
|
+
.action(login);
|
|
156
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scan Command
|
|
3
|
+
* Main scanning functionality for the CLI
|
|
4
|
+
*/
|
|
5
|
+
import { Command } from 'commander';
|
|
6
|
+
export interface ScanOptions {
|
|
7
|
+
depth: 'cheap' | 'validated' | 'deep';
|
|
8
|
+
format: 'terminal' | 'json' | 'sarif' | 'markdown';
|
|
9
|
+
failOn: 'critical' | 'high' | 'medium' | 'low' | 'none';
|
|
10
|
+
color?: boolean;
|
|
11
|
+
incremental?: boolean;
|
|
12
|
+
diff?: string;
|
|
13
|
+
output?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Main scan function
|
|
17
|
+
*/
|
|
18
|
+
export declare function runScan(targetPath: string, options: ScanOptions): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Scan command definition
|
|
21
|
+
*/
|
|
22
|
+
export declare const scanCommand: Command;
|
|
23
|
+
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAwBnC,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,OAAO,GAAG,WAAW,GAAG,MAAM,CAAA;IACrC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,CAAA;IAClD,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAA;IACvD,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAuND;;GAEG;AACH,wBAAsB,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA0GrF;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,SAUN,CAAA"}
|