aura-security 0.4.7 → 0.4.9

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/dist/cli.js CHANGED
@@ -24,7 +24,7 @@ import { existsSync, writeFileSync, mkdirSync } from 'fs';
24
24
  import { join, resolve, basename } from 'path';
25
25
  import { spawnSync } from 'child_process';
26
26
  const AURA_URL = process.env.AURA_URL ?? 'http://127.0.0.1:3000';
27
- const VERSION = '0.4.7';
27
+ const VERSION = '0.4.8';
28
28
  // ANSI colors for terminal output
29
29
  const colors = {
30
30
  reset: '\x1b[0m',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aura-security",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "description": "Deterministic security auditing engine with optional AI advisory layer. Run as CLI, CI step, or service. AI does not make enforcement decisions.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,970 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Documentation - aurasecurity</title>
7
+ <meta name="description" content="Learn how to use aurasecurity's 3D visualization and understand the SLOP protocol.">
8
+ <link rel="preconnect" href="https://fonts.googleapis.com">
9
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
+ <link href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
11
+ <style>
12
+ * {
13
+ margin: 0;
14
+ padding: 0;
15
+ box-sizing: border-box;
16
+ }
17
+
18
+ :root {
19
+ --bg: #030712;
20
+ --bg-elevated: #0f172a;
21
+ --bg-card: rgba(15, 23, 42, 0.6);
22
+ --border: rgba(148, 163, 184, 0.1);
23
+ --text: #f8fafc;
24
+ --text-secondary: #94a3b8;
25
+ --text-muted: #64748b;
26
+ --primary: #06b6d4;
27
+ --primary-glow: rgba(6, 182, 212, 0.4);
28
+ --secondary: #8b5cf6;
29
+ --critical: #ef4444;
30
+ --high: #f97316;
31
+ --medium: #f59e0b;
32
+ --low: #22c55e;
33
+ --success: #10b981;
34
+ }
35
+
36
+ body {
37
+ font-family: 'Inter', sans-serif;
38
+ background: var(--bg);
39
+ color: var(--text);
40
+ line-height: 1.7;
41
+ }
42
+
43
+ h1, h2, h3, h4 {
44
+ font-family: 'Space Grotesk', sans-serif;
45
+ }
46
+
47
+ code {
48
+ font-family: 'JetBrains Mono', monospace;
49
+ background: rgba(6, 182, 212, 0.1);
50
+ padding: 2px 6px;
51
+ border-radius: 4px;
52
+ font-size: 0.875em;
53
+ }
54
+
55
+ a {
56
+ color: var(--primary);
57
+ text-decoration: none;
58
+ }
59
+
60
+ a:hover {
61
+ text-decoration: underline;
62
+ }
63
+
64
+ /* Navigation */
65
+ nav {
66
+ position: fixed;
67
+ top: 0;
68
+ left: 0;
69
+ right: 0;
70
+ z-index: 100;
71
+ padding: 1rem 2rem;
72
+ background: rgba(3, 7, 18, 0.95);
73
+ backdrop-filter: blur(20px);
74
+ border-bottom: 1px solid var(--border);
75
+ }
76
+
77
+ .nav-inner {
78
+ max-width: 1200px;
79
+ margin: 0 auto;
80
+ display: flex;
81
+ justify-content: space-between;
82
+ align-items: center;
83
+ }
84
+
85
+ .logo {
86
+ display: flex;
87
+ align-items: center;
88
+ gap: 0.75rem;
89
+ text-decoration: none;
90
+ color: var(--text);
91
+ font-family: 'Space Grotesk', sans-serif;
92
+ font-weight: 700;
93
+ font-size: 1.25rem;
94
+ }
95
+
96
+ .logo-mark {
97
+ width: 36px;
98
+ height: 36px;
99
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
100
+ border-radius: 10px;
101
+ display: flex;
102
+ align-items: center;
103
+ justify-content: center;
104
+ font-size: 1.25rem;
105
+ }
106
+
107
+ .nav-links {
108
+ display: flex;
109
+ gap: 1.5rem;
110
+ align-items: center;
111
+ }
112
+
113
+ .nav-links a {
114
+ color: var(--text-secondary);
115
+ font-size: 0.875rem;
116
+ font-weight: 500;
117
+ }
118
+
119
+ .nav-links a:hover {
120
+ color: var(--text);
121
+ text-decoration: none;
122
+ }
123
+
124
+ /* Main Content */
125
+ main {
126
+ max-width: 1200px;
127
+ margin: 0 auto;
128
+ padding: 8rem 2rem 4rem;
129
+ }
130
+
131
+ .hero {
132
+ text-align: center;
133
+ margin-bottom: 4rem;
134
+ }
135
+
136
+ .hero h1 {
137
+ font-size: 3rem;
138
+ font-weight: 700;
139
+ margin-bottom: 1rem;
140
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
141
+ -webkit-background-clip: text;
142
+ -webkit-text-fill-color: transparent;
143
+ background-clip: text;
144
+ }
145
+
146
+ .hero p {
147
+ font-size: 1.25rem;
148
+ color: var(--text-secondary);
149
+ max-width: 600px;
150
+ margin: 0 auto;
151
+ }
152
+
153
+ /* Table of Contents */
154
+ .toc {
155
+ background: var(--bg-card);
156
+ border: 1px solid var(--border);
157
+ border-radius: 16px;
158
+ padding: 2rem;
159
+ margin-bottom: 3rem;
160
+ }
161
+
162
+ .toc h3 {
163
+ font-size: 1rem;
164
+ text-transform: uppercase;
165
+ letter-spacing: 0.1em;
166
+ color: var(--text-muted);
167
+ margin-bottom: 1rem;
168
+ }
169
+
170
+ .toc ul {
171
+ list-style: none;
172
+ display: grid;
173
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
174
+ gap: 0.5rem;
175
+ }
176
+
177
+ .toc a {
178
+ display: flex;
179
+ align-items: center;
180
+ gap: 0.5rem;
181
+ padding: 0.5rem;
182
+ border-radius: 8px;
183
+ transition: background 0.2s;
184
+ }
185
+
186
+ .toc a:hover {
187
+ background: rgba(6, 182, 212, 0.1);
188
+ text-decoration: none;
189
+ }
190
+
191
+ /* Sections */
192
+ section {
193
+ margin-bottom: 4rem;
194
+ }
195
+
196
+ section h2 {
197
+ font-size: 2rem;
198
+ font-weight: 700;
199
+ margin-bottom: 1.5rem;
200
+ padding-bottom: 0.75rem;
201
+ border-bottom: 2px solid var(--border);
202
+ }
203
+
204
+ section h3 {
205
+ font-size: 1.5rem;
206
+ font-weight: 600;
207
+ margin: 2rem 0 1rem;
208
+ color: var(--primary);
209
+ }
210
+
211
+ section h4 {
212
+ font-size: 1.125rem;
213
+ font-weight: 600;
214
+ margin: 1.5rem 0 0.75rem;
215
+ }
216
+
217
+ section p {
218
+ margin-bottom: 1rem;
219
+ color: var(--text-secondary);
220
+ }
221
+
222
+ /* SLOP Grid */
223
+ .slop-grid {
224
+ display: grid;
225
+ grid-template-columns: repeat(4, 1fr);
226
+ gap: 1.5rem;
227
+ margin: 2rem 0;
228
+ }
229
+
230
+ .slop-card {
231
+ background: var(--bg-card);
232
+ border: 1px solid var(--border);
233
+ border-radius: 16px;
234
+ padding: 1.5rem;
235
+ text-align: center;
236
+ }
237
+
238
+ .slop-letter {
239
+ font-family: 'Space Grotesk', sans-serif;
240
+ font-size: 3rem;
241
+ font-weight: 700;
242
+ background: linear-gradient(135deg, var(--primary), var(--secondary));
243
+ -webkit-background-clip: text;
244
+ -webkit-text-fill-color: transparent;
245
+ background-clip: text;
246
+ }
247
+
248
+ .slop-word {
249
+ font-weight: 600;
250
+ margin: 0.5rem 0;
251
+ }
252
+
253
+ .slop-desc {
254
+ font-size: 0.875rem;
255
+ color: var(--text-secondary);
256
+ }
257
+
258
+ /* Visual Guide */
259
+ .visual-guide {
260
+ display: grid;
261
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
262
+ gap: 1.5rem;
263
+ margin: 2rem 0;
264
+ }
265
+
266
+ .guide-card {
267
+ background: var(--bg-card);
268
+ border: 1px solid var(--border);
269
+ border-radius: 16px;
270
+ padding: 1.5rem;
271
+ }
272
+
273
+ .guide-card h4 {
274
+ margin-top: 0;
275
+ display: flex;
276
+ align-items: center;
277
+ gap: 0.75rem;
278
+ }
279
+
280
+ .guide-icon {
281
+ width: 40px;
282
+ height: 40px;
283
+ border-radius: 10px;
284
+ display: flex;
285
+ align-items: center;
286
+ justify-content: center;
287
+ font-size: 1.25rem;
288
+ }
289
+
290
+ /* Severity Colors */
291
+ .severity-grid {
292
+ display: grid;
293
+ grid-template-columns: repeat(4, 1fr);
294
+ gap: 1rem;
295
+ margin: 2rem 0;
296
+ }
297
+
298
+ .severity-card {
299
+ padding: 1.5rem;
300
+ border-radius: 12px;
301
+ text-align: center;
302
+ }
303
+
304
+ .severity-card.critical {
305
+ background: rgba(239, 68, 68, 0.15);
306
+ border: 1px solid rgba(239, 68, 68, 0.3);
307
+ }
308
+
309
+ .severity-card.high {
310
+ background: rgba(249, 115, 22, 0.15);
311
+ border: 1px solid rgba(249, 115, 22, 0.3);
312
+ }
313
+
314
+ .severity-card.medium {
315
+ background: rgba(245, 158, 11, 0.15);
316
+ border: 1px solid rgba(245, 158, 11, 0.3);
317
+ }
318
+
319
+ .severity-card.low {
320
+ background: rgba(34, 197, 94, 0.15);
321
+ border: 1px solid rgba(34, 197, 94, 0.3);
322
+ }
323
+
324
+ .severity-indicator {
325
+ width: 24px;
326
+ height: 24px;
327
+ border-radius: 50%;
328
+ margin: 0 auto 0.75rem;
329
+ }
330
+
331
+ .severity-card.critical .severity-indicator { background: var(--critical); box-shadow: 0 0 20px var(--critical); }
332
+ .severity-card.high .severity-indicator { background: var(--high); box-shadow: 0 0 20px var(--high); }
333
+ .severity-card.medium .severity-indicator { background: var(--medium); box-shadow: 0 0 20px var(--medium); }
334
+ .severity-card.low .severity-indicator { background: var(--low); box-shadow: 0 0 20px var(--low); }
335
+
336
+ .severity-card h5 {
337
+ font-size: 1rem;
338
+ font-weight: 600;
339
+ margin-bottom: 0.25rem;
340
+ }
341
+
342
+ .severity-card.critical h5 { color: var(--critical); }
343
+ .severity-card.high h5 { color: var(--high); }
344
+ .severity-card.medium h5 { color: var(--medium); }
345
+ .severity-card.low h5 { color: var(--low); }
346
+
347
+ .severity-card p {
348
+ font-size: 0.8125rem;
349
+ margin: 0;
350
+ }
351
+
352
+ /* Comparison */
353
+ .comparison {
354
+ display: grid;
355
+ grid-template-columns: 1fr 1fr;
356
+ gap: 2rem;
357
+ margin: 2rem 0;
358
+ }
359
+
360
+ .comparison-card {
361
+ background: var(--bg-card);
362
+ border-radius: 16px;
363
+ overflow: hidden;
364
+ }
365
+
366
+ .comparison-header {
367
+ padding: 1.25rem 1.5rem;
368
+ display: flex;
369
+ align-items: center;
370
+ gap: 0.75rem;
371
+ font-weight: 600;
372
+ }
373
+
374
+ .comparison-card.bad .comparison-header {
375
+ background: rgba(239, 68, 68, 0.15);
376
+ border-bottom: 2px solid var(--critical);
377
+ color: var(--critical);
378
+ }
379
+
380
+ .comparison-card.good .comparison-header {
381
+ background: rgba(34, 197, 94, 0.15);
382
+ border-bottom: 2px solid var(--success);
383
+ color: var(--success);
384
+ }
385
+
386
+ .comparison-body {
387
+ padding: 1.5rem;
388
+ }
389
+
390
+ .comparison-stat {
391
+ display: flex;
392
+ justify-content: space-between;
393
+ padding: 0.75rem 0;
394
+ border-bottom: 1px solid var(--border);
395
+ }
396
+
397
+ .comparison-stat:last-child {
398
+ border-bottom: none;
399
+ }
400
+
401
+ .stat-label {
402
+ color: var(--text-secondary);
403
+ }
404
+
405
+ .stat-value {
406
+ font-weight: 600;
407
+ font-family: 'JetBrains Mono', monospace;
408
+ }
409
+
410
+ .stat-value.critical { color: var(--critical); }
411
+ .stat-value.high { color: var(--high); }
412
+ .stat-value.medium { color: var(--medium); }
413
+ .stat-value.low { color: var(--low); }
414
+ .stat-value.clean { color: var(--success); }
415
+
416
+ /* Finding Examples */
417
+ .finding-example {
418
+ background: var(--bg-elevated);
419
+ border: 1px solid var(--border);
420
+ border-radius: 12px;
421
+ margin: 1rem 0;
422
+ overflow: hidden;
423
+ }
424
+
425
+ .finding-header {
426
+ display: flex;
427
+ justify-content: space-between;
428
+ align-items: center;
429
+ padding: 0.75rem 1rem;
430
+ background: rgba(0, 0, 0, 0.3);
431
+ border-bottom: 1px solid var(--border);
432
+ }
433
+
434
+ .finding-type {
435
+ font-size: 0.75rem;
436
+ font-weight: 600;
437
+ text-transform: uppercase;
438
+ letter-spacing: 0.05em;
439
+ }
440
+
441
+ .finding-severity {
442
+ font-size: 0.6875rem;
443
+ font-weight: 700;
444
+ padding: 0.25rem 0.5rem;
445
+ border-radius: 4px;
446
+ text-transform: uppercase;
447
+ }
448
+
449
+ .finding-severity.critical { background: var(--critical); color: white; }
450
+ .finding-severity.high { background: var(--high); color: white; }
451
+ .finding-severity.medium { background: var(--medium); color: black; }
452
+ .finding-severity.low { background: var(--low); color: black; }
453
+
454
+ .finding-body {
455
+ padding: 1rem;
456
+ }
457
+
458
+ .finding-file {
459
+ font-family: 'JetBrains Mono', monospace;
460
+ font-size: 0.8125rem;
461
+ color: var(--primary);
462
+ margin-bottom: 0.5rem;
463
+ }
464
+
465
+ .finding-message {
466
+ font-size: 0.875rem;
467
+ color: var(--text-secondary);
468
+ }
469
+
470
+ /* Info Boxes */
471
+ .info-box {
472
+ background: rgba(6, 182, 212, 0.1);
473
+ border: 1px solid rgba(6, 182, 212, 0.3);
474
+ border-radius: 12px;
475
+ padding: 1.25rem;
476
+ margin: 1.5rem 0;
477
+ }
478
+
479
+ .info-box h5 {
480
+ color: var(--primary);
481
+ font-size: 0.875rem;
482
+ font-weight: 600;
483
+ margin-bottom: 0.5rem;
484
+ display: flex;
485
+ align-items: center;
486
+ gap: 0.5rem;
487
+ }
488
+
489
+ .info-box p {
490
+ margin: 0;
491
+ font-size: 0.9375rem;
492
+ }
493
+
494
+ .warning-box {
495
+ background: rgba(245, 158, 11, 0.1);
496
+ border: 1px solid rgba(245, 158, 11, 0.3);
497
+ }
498
+
499
+ .warning-box h5 {
500
+ color: var(--medium);
501
+ }
502
+
503
+ /* Code Block */
504
+ .code-block {
505
+ background: rgba(0, 0, 0, 0.4);
506
+ border: 1px solid var(--border);
507
+ border-radius: 12px;
508
+ padding: 1rem 1.25rem;
509
+ font-family: 'JetBrains Mono', monospace;
510
+ font-size: 0.875rem;
511
+ overflow-x: auto;
512
+ margin: 1rem 0;
513
+ }
514
+
515
+ .code-block .prompt {
516
+ color: var(--primary);
517
+ user-select: none;
518
+ }
519
+
520
+ /* Footer */
521
+ footer {
522
+ padding: 3rem 2rem;
523
+ border-top: 1px solid var(--border);
524
+ text-align: center;
525
+ }
526
+
527
+ .footer-links {
528
+ display: flex;
529
+ justify-content: center;
530
+ gap: 2rem;
531
+ margin-bottom: 1rem;
532
+ }
533
+
534
+ .footer-links a {
535
+ color: var(--text-secondary);
536
+ font-size: 0.875rem;
537
+ }
538
+
539
+ .footer-copy {
540
+ color: var(--text-muted);
541
+ font-size: 0.8125rem;
542
+ }
543
+
544
+ /* Responsive */
545
+ @media (max-width: 1024px) {
546
+ .slop-grid {
547
+ grid-template-columns: repeat(2, 1fr);
548
+ }
549
+ .severity-grid {
550
+ grid-template-columns: repeat(2, 1fr);
551
+ }
552
+ }
553
+
554
+ @media (max-width: 768px) {
555
+ .comparison {
556
+ grid-template-columns: 1fr;
557
+ }
558
+ .slop-grid {
559
+ grid-template-columns: 1fr;
560
+ }
561
+ .severity-grid {
562
+ grid-template-columns: 1fr;
563
+ }
564
+ .hero h1 {
565
+ font-size: 2rem;
566
+ }
567
+ main {
568
+ padding: 6rem 1rem 2rem;
569
+ }
570
+ }
571
+ </style>
572
+ </head>
573
+ <body>
574
+ <!-- Navigation -->
575
+ <nav>
576
+ <div class="nav-inner">
577
+ <a href="https://aurasecurity.io" class="logo">
578
+ <div class="logo-mark">&#128737;</div>
579
+ aurasecurity
580
+ </a>
581
+ <div class="nav-links">
582
+ <a href="https://aurasecurity.io">Home</a>
583
+ <a href="https://app.aurasecurity.io/app">Dashboard</a>
584
+ <a href="https://github.com/aurasecurityio/aura-security" target="_blank">GitHub</a>
585
+ </div>
586
+ </div>
587
+ </nav>
588
+
589
+ <main>
590
+ <!-- Hero -->
591
+ <div class="hero">
592
+ <h1>Documentation</h1>
593
+ <p>Learn how to read scan results, understand the visualization, and interpret security findings.</p>
594
+ </div>
595
+
596
+ <!-- Table of Contents -->
597
+ <div class="toc">
598
+ <h3>Contents</h3>
599
+ <ul>
600
+ <li><a href="#slop-protocol">&#128640; The SLOP Protocol</a></li>
601
+ <li><a href="#visual-guide">&#127912; Visual Guide</a></li>
602
+ <li><a href="#severity-levels">&#128680; Severity Levels</a></li>
603
+ <li><a href="#finding-types">&#128269; Finding Types</a></li>
604
+ <li><a href="#good-vs-bad">&#9989; Good vs Bad Examples</a></li>
605
+ <li><a href="#interpreting-results">&#128200; Interpreting Results</a></li>
606
+ </ul>
607
+ </div>
608
+
609
+ <!-- SLOP Protocol -->
610
+ <section id="slop-protocol">
611
+ <h2>The SLOP Protocol</h2>
612
+ <p>SLOP (Segmentation, Labeling, Organization, Parallelism) is the architecture that powers aurasecurity's multi-scanner orchestration and visualization.</p>
613
+
614
+ <div class="slop-grid">
615
+ <div class="slop-card">
616
+ <div class="slop-letter">S</div>
617
+ <div class="slop-word">Segmentation</div>
618
+ <p class="slop-desc">Each scanner runs in isolation. Gitleaks can't corrupt Trivy's output. One tool failing doesn't break the pipeline.</p>
619
+ </div>
620
+ <div class="slop-card">
621
+ <div class="slop-letter">L</div>
622
+ <div class="slop-word">Labeling</div>
623
+ <p class="slop-desc">Every finding is tagged with its source tool, file path, and line number. Full transparency on where results came from.</p>
624
+ </div>
625
+ <div class="slop-card">
626
+ <div class="slop-letter">O</div>
627
+ <div class="slop-word">Organization</div>
628
+ <p class="slop-desc">Findings are deduplicated, categorized by severity, and organized into actionable groups. Clean, structured output.</p>
629
+ </div>
630
+ <div class="slop-card">
631
+ <div class="slop-letter">P</div>
632
+ <div class="slop-word">Parallelism</div>
633
+ <p class="slop-desc">All scanners run simultaneously. 8 tools don't mean 8x the wait time. Results stream in real-time.</p>
634
+ </div>
635
+ </div>
636
+
637
+ <div class="info-box">
638
+ <h5>&#128161; Why SLOP Matters</h5>
639
+ <p>Traditional security tools give you a wall of text. SLOP transforms raw scanner output into structured, navigable data that can be visualized in 3D, exported to any format, and integrated into your CI/CD pipeline.</p>
640
+ </div>
641
+ </section>
642
+
643
+ <!-- Visual Guide -->
644
+ <section id="visual-guide">
645
+ <h2>Visual Guide</h2>
646
+ <p>The 3D dashboard represents your security posture as an interactive scene. Here's what each element means:</p>
647
+
648
+ <div class="visual-guide">
649
+ <div class="guide-card">
650
+ <h4>
651
+ <div class="guide-icon" style="background: linear-gradient(135deg, #06b6d4, #8b5cf6);">&#128737;</div>
652
+ Central Hub
653
+ </h4>
654
+ <p>The glowing hexagonal shield at the center represents the Security Auditor - the orchestration engine that coordinates all scanners and aggregates results.</p>
655
+ </div>
656
+
657
+ <div class="guide-card">
658
+ <h4>
659
+ <div class="guide-icon" style="background: #22c55e;">&#9632;</div>
660
+ Green Nodes
661
+ </h4>
662
+ <p>Clean modules or repos with no findings. These components passed all security checks. The goal is to have all nodes green.</p>
663
+ </div>
664
+
665
+ <div class="guide-card">
666
+ <h4>
667
+ <div class="guide-icon" style="background: #f59e0b;">&#9632;</div>
668
+ Yellow/Orange Nodes
669
+ </h4>
670
+ <p>Modules with medium or high severity findings. These require attention but aren't critical. Review and prioritize fixes.</p>
671
+ </div>
672
+
673
+ <div class="guide-card">
674
+ <h4>
675
+ <div class="guide-icon" style="background: #ef4444;">&#9632;</div>
676
+ Red Nodes
677
+ </h4>
678
+ <p>Critical security issues detected. These require immediate attention - exposed secrets, critical CVEs, or severe misconfigurations.</p>
679
+ </div>
680
+
681
+ <div class="guide-card">
682
+ <h4>
683
+ <div class="guide-icon" style="background: linear-gradient(90deg, #06b6d4, #8b5cf6); height: 4px; width: 40px; border-radius: 2px;"></div>
684
+ Connection Lines
685
+ </h4>
686
+ <p>Lines between nodes show relationships - data flow, dependencies, or audit connections. Thicker lines indicate stronger coupling.</p>
687
+ </div>
688
+
689
+ <div class="guide-card">
690
+ <h4>
691
+ <div class="guide-icon" style="background: rgba(6, 182, 212, 0.3); border: 2px solid #06b6d4;">&#9711;</div>
692
+ Orbital Rings
693
+ </h4>
694
+ <p>Circular paths show scanning progress and module groupings. Nodes orbit the hub based on their scan status and category.</p>
695
+ </div>
696
+ </div>
697
+
698
+ <h3>Navigation</h3>
699
+ <ul style="color: var(--text-secondary); margin-left: 1.5rem;">
700
+ <li><strong>Click</strong> a node to select it and view details</li>
701
+ <li><strong>Drag</strong> to rotate the scene</li>
702
+ <li><strong>Scroll</strong> to zoom in/out</li>
703
+ <li><strong>Hover</strong> over nodes to see tooltips</li>
704
+ </ul>
705
+ </section>
706
+
707
+ <!-- Severity Levels -->
708
+ <section id="severity-levels">
709
+ <h2>Severity Levels</h2>
710
+ <p>Findings are categorized by severity to help you prioritize remediation efforts:</p>
711
+
712
+ <div class="severity-grid">
713
+ <div class="severity-card critical">
714
+ <div class="severity-indicator"></div>
715
+ <h5>Critical</h5>
716
+ <p>Immediate action required. Exposed secrets, critical CVEs with known exploits, or severe misconfigurations that could lead to full compromise.</p>
717
+ </div>
718
+
719
+ <div class="severity-card high">
720
+ <div class="severity-indicator"></div>
721
+ <h5>High</h5>
722
+ <p>Address soon. API keys, high-severity vulnerabilities, or security issues that could be exploited with some effort.</p>
723
+ </div>
724
+
725
+ <div class="severity-card medium">
726
+ <div class="severity-indicator"></div>
727
+ <h5>Medium</h5>
728
+ <p>Plan to fix. Deprecated dependencies, missing security headers, or issues that increase attack surface.</p>
729
+ </div>
730
+
731
+ <div class="severity-card low">
732
+ <div class="severity-indicator"></div>
733
+ <h5>Low</h5>
734
+ <p>Best practice improvements. Code style, minor optimizations, or informational findings that improve security posture.</p>
735
+ </div>
736
+ </div>
737
+
738
+ <div class="info-box warning-box">
739
+ <h5>&#9888;&#65039; Exit Codes</h5>
740
+ <p>By default, <code>aura-security scan</code> exits with code 2 for critical findings and code 1 for high findings. Use <code>--fail-on medium</code> to fail on medium+ or <code>--no-fail</code> to always exit 0.</p>
741
+ </div>
742
+ </section>
743
+
744
+ <!-- Finding Types -->
745
+ <section id="finding-types">
746
+ <h2>Finding Types</h2>
747
+ <p>aurasecurity detects multiple categories of security issues:</p>
748
+
749
+ <h4>&#128273; Secrets & Credentials</h4>
750
+ <p>Exposed API keys, passwords, tokens, private keys, and other sensitive credentials in your codebase. Detected by Gitleaks.</p>
751
+ <div class="finding-example">
752
+ <div class="finding-header">
753
+ <span class="finding-type">Private Key</span>
754
+ <span class="finding-severity critical">Critical</span>
755
+ </div>
756
+ <div class="finding-body">
757
+ <div class="finding-file">lib/insecurity.ts:23</div>
758
+ <div class="finding-message">Identified a Private Key, which may compromise cryptographic security and sensitive data encryption.</div>
759
+ </div>
760
+ </div>
761
+
762
+ <h4>&#128230; Dependency Vulnerabilities</h4>
763
+ <p>Known CVEs in your project dependencies. Detected by Grype, Trivy, and language-specific tools (npm audit, pip-audit, etc.).</p>
764
+ <div class="finding-example">
765
+ <div class="finding-header">
766
+ <span class="finding-type">CVE-2024-XXXXX</span>
767
+ <span class="finding-severity high">High</span>
768
+ </div>
769
+ <div class="finding-body">
770
+ <div class="finding-file">package.json (lodash@4.17.20)</div>
771
+ <div class="finding-message">Prototype pollution vulnerability allowing arbitrary code execution.</div>
772
+ </div>
773
+ </div>
774
+
775
+ <h4>&#128027; Code Issues (SAST)</h4>
776
+ <p>Static analysis findings like SQL injection, XSS, insecure deserialization. Detected by Semgrep.</p>
777
+
778
+ <h4>&#9729;&#65039; Infrastructure as Code</h4>
779
+ <p>Misconfigurations in Terraform, CloudFormation, Kubernetes manifests. Detected by Checkov.</p>
780
+
781
+ <h4>&#128051; Dockerfile Issues</h4>
782
+ <p>Best practice violations in Dockerfiles - unpinned versions, running as root, missing security directives. Detected by Hadolint.</p>
783
+ <div class="finding-example">
784
+ <div class="finding-header">
785
+ <span class="finding-type">DL3006</span>
786
+ <span class="finding-severity medium">Medium</span>
787
+ </div>
788
+ <div class="finding-body">
789
+ <div class="finding-file">Dockerfile:22</div>
790
+ <div class="finding-message">Always tag the version of an image explicitly.</div>
791
+ </div>
792
+ </div>
793
+ </section>
794
+
795
+ <!-- Good vs Bad Examples -->
796
+ <section id="good-vs-bad">
797
+ <h2>Good vs Bad: Real Examples</h2>
798
+ <p>Here's what secure and insecure repositories look like when scanned with aurasecurity:</p>
799
+
800
+ <div class="comparison">
801
+ <div class="comparison-card bad">
802
+ <div class="comparison-header">
803
+ <span>&#10060;</span>
804
+ <span>juice-shop (Intentionally Vulnerable)</span>
805
+ </div>
806
+ <div class="comparison-body">
807
+ <p style="font-size: 0.875rem; margin-bottom: 1rem;">OWASP Juice Shop - an intentionally insecure application for security training.</p>
808
+ <div class="comparison-stat">
809
+ <span class="stat-label">Scan Time</span>
810
+ <span class="stat-value">93.30s</span>
811
+ </div>
812
+ <div class="comparison-stat">
813
+ <span class="stat-label">Critical Findings</span>
814
+ <span class="stat-value critical">1 (Private Key)</span>
815
+ </div>
816
+ <div class="comparison-stat">
817
+ <span class="stat-label">High Findings</span>
818
+ <span class="stat-value high">4 (API Keys)</span>
819
+ </div>
820
+ <div class="comparison-stat">
821
+ <span class="stat-label">Medium Findings</span>
822
+ <span class="stat-value medium">4 (Dockerfile)</span>
823
+ </div>
824
+ <div class="comparison-stat">
825
+ <span class="stat-label">Low Findings</span>
826
+ <span class="stat-value low">11 (Dockerfile)</span>
827
+ </div>
828
+ <div class="comparison-stat">
829
+ <span class="stat-label">Total Issues</span>
830
+ <span class="stat-value critical">20</span>
831
+ </div>
832
+ </div>
833
+ </div>
834
+
835
+ <div class="comparison-card good">
836
+ <div class="comparison-header">
837
+ <span>&#9989;</span>
838
+ <span>get-shit-done (Clean)</span>
839
+ </div>
840
+ <div class="comparison-body">
841
+ <p style="font-size: 0.875rem; margin-bottom: 1rem;">A simple productivity tool with no security findings.</p>
842
+ <div class="comparison-stat">
843
+ <span class="stat-label">Scan Time</span>
844
+ <span class="stat-value">2.87s</span>
845
+ </div>
846
+ <div class="comparison-stat">
847
+ <span class="stat-label">Critical Findings</span>
848
+ <span class="stat-value clean">0</span>
849
+ </div>
850
+ <div class="comparison-stat">
851
+ <span class="stat-label">High Findings</span>
852
+ <span class="stat-value clean">0</span>
853
+ </div>
854
+ <div class="comparison-stat">
855
+ <span class="stat-label">Medium Findings</span>
856
+ <span class="stat-value clean">0</span>
857
+ </div>
858
+ <div class="comparison-stat">
859
+ <span class="stat-label">Low Findings</span>
860
+ <span class="stat-value clean">0</span>
861
+ </div>
862
+ <div class="comparison-stat">
863
+ <span class="stat-label">Total Issues</span>
864
+ <span class="stat-value clean">0 &#127881;</span>
865
+ </div>
866
+ </div>
867
+ </div>
868
+ </div>
869
+
870
+ <h3>What Made juice-shop Fail?</h3>
871
+ <p>Here are the actual findings from the scan:</p>
872
+
873
+ <div class="finding-example">
874
+ <div class="finding-header">
875
+ <span class="finding-type">Private Key Exposed</span>
876
+ <span class="finding-severity critical">Critical</span>
877
+ </div>
878
+ <div class="finding-body">
879
+ <div class="finding-file">lib/insecurity.ts:23</div>
880
+ <div class="finding-message">Hardcoded private key found in source code. This could compromise all cryptographic operations.</div>
881
+ </div>
882
+ </div>
883
+
884
+ <div class="finding-example">
885
+ <div class="finding-header">
886
+ <span class="finding-type">Generic API Key</span>
887
+ <span class="finding-severity high">High</span>
888
+ </div>
889
+ <div class="finding-body">
890
+ <div class="finding-file">data/static/users.yml:88</div>
891
+ <div class="finding-message">API key detected in configuration file. Could expose access to various services.</div>
892
+ </div>
893
+ </div>
894
+
895
+ <div class="finding-example">
896
+ <div class="finding-header">
897
+ <span class="finding-type">Generic API Key</span>
898
+ <span class="finding-severity high">High</span>
899
+ </div>
900
+ <div class="finding-body">
901
+ <div class="finding-file">routes/login.ts:65</div>
902
+ <div class="finding-message">Hardcoded API key in authentication route. Credentials should be loaded from environment variables.</div>
903
+ </div>
904
+ </div>
905
+
906
+ <div class="info-box">
907
+ <h5>&#128161; Key Takeaway</h5>
908
+ <p>A clean scan doesn't mean "no vulnerabilities exist" - it means "no <em>known</em> vulnerabilities were detected by the scanners." Always combine automated scanning with manual security review for critical applications.</p>
909
+ </div>
910
+ </section>
911
+
912
+ <!-- Interpreting Results -->
913
+ <section id="interpreting-results">
914
+ <h2>Interpreting Results</h2>
915
+
916
+ <h3>When You See Critical Findings</h3>
917
+ <ol style="color: var(--text-secondary); margin-left: 1.5rem;">
918
+ <li><strong>Stop and assess</strong> - Don't deploy code with critical findings</li>
919
+ <li><strong>Check if it's a false positive</strong> - Test files, examples, and documentation may trigger detections</li>
920
+ <li><strong>Rotate compromised credentials immediately</strong> - If real secrets are exposed, assume they're compromised</li>
921
+ <li><strong>Fix at the source</strong> - Use environment variables, secret managers, or .gitignore</li>
922
+ </ol>
923
+
924
+ <h3>When You See High/Medium Findings</h3>
925
+ <ol style="color: var(--text-secondary); margin-left: 1.5rem;">
926
+ <li><strong>Prioritize by exploitability</strong> - A CVE with a public exploit is more urgent than a theoretical issue</li>
927
+ <li><strong>Check your dependencies</strong> - Often the fix is just updating a package version</li>
928
+ <li><strong>Document accepted risks</strong> - Some findings may be acceptable in your context</li>
929
+ </ol>
930
+
931
+ <h3>Using the CLI Output</h3>
932
+ <div class="code-block">
933
+ <span class="prompt">$</span> aura-security scan . --format summary
934
+
935
+ <span style="color: var(--success);">&#10003;</span> Scan completed in 12.34s
936
+
937
+ <span style="color: var(--critical);">CRITICAL: 0</span> <span style="color: var(--high);">HIGH: 2</span> <span style="color: var(--medium);">MEDIUM: 5</span> <span style="color: var(--low);">LOW: 8</span>
938
+
939
+ Tools: gitleaks, grype, trivy, hadolint
940
+ </div>
941
+
942
+ <h3>CI/CD Integration</h3>
943
+ <p>Use exit codes to gate your pipeline:</p>
944
+ <div class="code-block">
945
+ <span class="prompt">$</span> aura-security scan . --fail-on high
946
+ <span style="color: var(--text-muted);"># Exits 1 if high+ findings detected</span>
947
+
948
+ <span class="prompt">$</span> aura-security scan . --fail-on critical
949
+ <span style="color: var(--text-muted);"># Only fails on critical (default)</span>
950
+
951
+ <span class="prompt">$</span> aura-security scan . --no-fail
952
+ <span style="color: var(--text-muted);"># Always exits 0, for informational scans</span>
953
+ </div>
954
+ </section>
955
+ </main>
956
+
957
+ <!-- Footer -->
958
+ <footer>
959
+ <div class="footer-links">
960
+ <a href="https://aurasecurity.io">Home</a>
961
+ <a href="https://app.aurasecurity.io/app">Dashboard</a>
962
+ <a href="https://github.com/aurasecurityio/aura-security">GitHub</a>
963
+ <a href="https://www.npmjs.com/package/aura-security">npm</a>
964
+ <a href="https://x.com/aiaurasecurity">X</a>
965
+ <a href="https://www.linkedin.com/in/shubham-vashist/">LinkedIn</a>
966
+ </div>
967
+ <p class="footer-copy">&copy; 2026 aurasecurity &middot; MIT License</p>
968
+ </footer>
969
+ </body>
970
+ </html>
@@ -436,6 +436,13 @@
436
436
  overflow-y: auto;
437
437
  }
438
438
 
439
+ /* Mobile: hide details panel */
440
+ @media (max-width: 768px) {
441
+ #details-panel {
442
+ display: none;
443
+ }
444
+ }
445
+
439
446
  .selected-repo-header {
440
447
  display: none;
441
448
  padding: 12px;
@@ -421,6 +421,49 @@
421
421
  box-shadow: 0 0 30px #00ff88;
422
422
  }
423
423
 
424
+ /* Filter Toggles */
425
+ .filter-toggle {
426
+ display: flex;
427
+ align-items: center;
428
+ gap: 4px;
429
+ padding: 4px 8px;
430
+ background: rgba(0, 20, 10, 0.6);
431
+ border: 1px solid #00ff8844;
432
+ border-radius: 4px;
433
+ font-size: 10px;
434
+ cursor: pointer;
435
+ transition: all 0.2s;
436
+ user-select: none;
437
+ }
438
+
439
+ .filter-toggle input {
440
+ display: none;
441
+ }
442
+
443
+ .filter-toggle .filter-icon {
444
+ width: 14px;
445
+ height: 14px;
446
+ border-radius: 3px;
447
+ display: flex;
448
+ align-items: center;
449
+ justify-content: center;
450
+ font-size: 8px;
451
+ }
452
+
453
+ .filter-toggle.active {
454
+ border-color: #00ff88;
455
+ background: rgba(0, 255, 136, 0.1);
456
+ }
457
+
458
+ .filter-toggle:not(.active) {
459
+ opacity: 0.5;
460
+ border-color: #333;
461
+ }
462
+
463
+ .filter-toggle:hover {
464
+ border-color: #00ff88;
465
+ }
466
+
424
467
  /* Scrollbar */
425
468
  ::-webkit-scrollbar { width: 6px; }
426
469
  ::-webkit-scrollbar-track { background: #0a0a0f; }
@@ -615,6 +658,32 @@
615
658
 
616
659
  <div class="panel">
617
660
  <div class="panel-title">Security Findings</div>
661
+ <!-- Filter Toggles -->
662
+ <div id="findingsFilter" style="margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid #00ff8833;">
663
+ <div style="font-size: 9px; color: #666; margin-bottom: 6px; text-transform: uppercase; letter-spacing: 1px;">Filter by Type:</div>
664
+ <div style="display: flex; flex-wrap: wrap; gap: 6px;">
665
+ <label class="filter-toggle active" data-filter="secrets">
666
+ <input type="checkbox" checked onchange="toggleFilter('secrets', this.checked)">
667
+ <span class="filter-icon" style="background: #ff0088;">🔑</span>
668
+ <span>Secrets</span>
669
+ </label>
670
+ <label class="filter-toggle active" data-filter="cves">
671
+ <input type="checkbox" checked onchange="toggleFilter('cves', this.checked)">
672
+ <span class="filter-icon" style="background: #ff4400;">📦</span>
673
+ <span>CVEs</span>
674
+ </label>
675
+ <label class="filter-toggle active" data-filter="dockerfile">
676
+ <input type="checkbox" checked onchange="toggleFilter('dockerfile', this.checked)">
677
+ <span class="filter-icon" style="background: #00aaff;">🐳</span>
678
+ <span>Docker</span>
679
+ </label>
680
+ <label class="filter-toggle active" data-filter="sast">
681
+ <input type="checkbox" checked onchange="toggleFilter('sast', this.checked)">
682
+ <span class="filter-icon" style="background: #ffaa00;">🔬</span>
683
+ <span>SAST</span>
684
+ </label>
685
+ </div>
686
+ </div>
618
687
  <div id="findingsList">
619
688
  <p style="color: #666; font-size: 11px;">No findings yet. Run an audit to detect issues.</p>
620
689
  </div>
@@ -625,6 +694,34 @@
625
694
  <div class="panel-title">Settings <span id="settingsStatus" style="color: #666; font-size: 10px;"></span></div>
626
695
  <button class="btn secondary" style="width: 100%;" onclick="openSettingsModal()">Configure Integrations</button>
627
696
  </div>
697
+
698
+ <!-- Badge Generator Panel -->
699
+ <div class="panel">
700
+ <div class="panel-title">Badge Generator</div>
701
+ <p style="font-size: 10px; color: #666; margin-bottom: 8px;">Generate shields for your README</p>
702
+ <div id="badgePreview" style="margin-bottom: 10px; text-align: center; padding: 10px; background: rgba(0,0,0,0.3); border-radius: 4px;">
703
+ <img id="badgeImg" src="https://img.shields.io/badge/security-scanning-00ff88?style=flat-square&logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik0xMiAxTDMgNXY2YzAgNS41NSAzLjg0IDEwLjc0IDkgMTIgNS4xNi0xLjI2IDktNi40NSA5LTEyVjVsLTktNHoiLz48L3N2Zz4=" alt="security badge" style="height: 20px;">
704
+ </div>
705
+ <div style="margin-bottom: 8px;">
706
+ <select id="badgeStyle" style="width: 100%; padding: 6px; background: rgba(0,20,10,0.8); border: 1px solid #00ff88; color: #00ff88; font-size: 11px;" onchange="updateBadgePreview()">
707
+ <option value="flat-square">Flat Square</option>
708
+ <option value="flat">Flat</option>
709
+ <option value="plastic">Plastic</option>
710
+ <option value="for-the-badge">For The Badge</option>
711
+ </select>
712
+ </div>
713
+ <div style="margin-bottom: 8px;">
714
+ <select id="badgeType" style="width: 100%; padding: 6px; background: rgba(0,20,10,0.8); border: 1px solid #00ff88; color: #00ff88; font-size: 11px;" onchange="updateBadgePreview()">
715
+ <option value="status">Scan Status</option>
716
+ <option value="critical">Critical Count</option>
717
+ <option value="total">Total Findings</option>
718
+ </select>
719
+ </div>
720
+ <div id="badgeMarkdown" style="background: rgba(0,0,0,0.4); padding: 8px; border-radius: 4px; font-family: monospace; font-size: 9px; color: #00ff88; word-break: break-all; margin-bottom: 8px; max-height: 60px; overflow-y: auto;">
721
+ ![aurasecurity](https://img.shields.io/badge/security-scanning-00ff88?style=flat-square)
722
+ </div>
723
+ <button class="btn secondary" style="width: 100%; font-size: 10px;" onclick="copyBadgeMarkdown()">📋 Copy Markdown</button>
724
+ </div>
628
725
  </div>
629
726
 
630
727
  <!-- Settings Modal -->
@@ -951,6 +1048,71 @@
951
1048
  blocked: 0xff0044
952
1049
  };
953
1050
 
1051
+ // ========== FINDINGS FILTER STATE ==========
1052
+ const findingsFilter = {
1053
+ secrets: true,
1054
+ cves: true,
1055
+ dockerfile: true,
1056
+ sast: true
1057
+ };
1058
+
1059
+ // Toggle filter and re-render findings
1060
+ window.toggleFilter = function(filterType, enabled) {
1061
+ findingsFilter[filterType] = enabled;
1062
+ const toggle = document.querySelector(`.filter-toggle[data-filter="${filterType}"]`);
1063
+ if (toggle) {
1064
+ toggle.classList.toggle('active', enabled);
1065
+ }
1066
+ // Re-render with current findings
1067
+ if (typeof renderFindingsList === 'function') {
1068
+ renderFindingsList(currentFindings);
1069
+ }
1070
+ // Also re-render scan findings if we have them
1071
+ if (typeof renderScanFindings === 'function' && currentScanFindings) {
1072
+ renderScanFindings(currentScanFindings);
1073
+ }
1074
+ };
1075
+
1076
+ // Determine finding type from finding data
1077
+ function getFindingType(finding) {
1078
+ // Check payload for audit events
1079
+ if (finding.payload) {
1080
+ const claim = (finding.payload.claim || '').toLowerCase();
1081
+ const assets = (finding.payload.affected_assets || []).join(' ').toLowerCase();
1082
+
1083
+ if (claim.includes('secret') || claim.includes('credential') || claim.includes('key') || claim.includes('password') || assets.includes('secrets')) {
1084
+ return 'secrets';
1085
+ }
1086
+ if (claim.includes('vulnerability') || claim.includes('cve') || claim.includes('package') || claim.includes('dependency')) {
1087
+ return 'cves';
1088
+ }
1089
+ if (claim.includes('docker') || claim.includes('container') || claim.includes('dockerfile')) {
1090
+ return 'dockerfile';
1091
+ }
1092
+ if (claim.includes('injection') || claim.includes('xss') || claim.includes('sast') || claim.includes('code')) {
1093
+ return 'sast';
1094
+ }
1095
+ }
1096
+ // Check direct finding type
1097
+ if (finding.type) {
1098
+ const type = finding.type.toLowerCase();
1099
+ if (type.includes('secret') || type.includes('key') || type.includes('credential')) return 'secrets';
1100
+ if (type.includes('vuln') || type.includes('cve') || type.includes('package')) return 'cves';
1101
+ if (type.includes('docker') || type.includes('hadolint')) return 'dockerfile';
1102
+ if (type.includes('sast') || type.includes('semgrep')) return 'sast';
1103
+ }
1104
+ return 'sast'; // Default to SAST for unknown types
1105
+ }
1106
+
1107
+ // Check if finding passes current filters
1108
+ function findingPassesFilter(finding) {
1109
+ const type = getFindingType(finding);
1110
+ return findingsFilter[type] === true;
1111
+ }
1112
+
1113
+ // Store current scan findings for filtering
1114
+ let currentScanFindings = null;
1115
+
954
1116
  // Clear the map - remove all modules and connections to start fresh
955
1117
  function clearMap() {
956
1118
  console.log('Clearing map for fresh scan...');
@@ -1375,11 +1537,24 @@
1375
1537
  return;
1376
1538
  }
1377
1539
 
1378
- container.innerHTML = findings.map(f => `
1379
- <div class="finding ${f.payload.severity}">
1540
+ // Apply filters
1541
+ const filteredFindings = findings.filter(f => findingPassesFilter(f));
1542
+
1543
+ if (filteredFindings.length === 0) {
1544
+ container.innerHTML = '<p style="color: #666; font-size: 11px;">No findings match current filters. Adjust filters above.</p>';
1545
+ return;
1546
+ }
1547
+
1548
+ container.innerHTML = filteredFindings.map(f => {
1549
+ const findingType = getFindingType(f);
1550
+ const typeIcons = { secrets: '🔑', cves: '📦', dockerfile: '🐳', sast: '🔬' };
1551
+ const typeIcon = typeIcons[findingType] || '⚠️';
1552
+
1553
+ return `
1554
+ <div class="finding ${f.payload.severity}" data-type="${findingType}">
1380
1555
  <div class="finding-header">
1381
1556
  <span class="severity-badge ${f.payload.severity}">${f.payload.severity.toUpperCase()}</span>
1382
- <span class="finding-module">${f.payload.affected_assets[0] || 'system'}</span>
1557
+ <span class="finding-module">${typeIcon} ${f.payload.affected_assets[0] || 'system'}</span>
1383
1558
  </div>
1384
1559
  <div class="finding-claim">${f.payload.claim}</div>
1385
1560
  <div class="finding-details">
@@ -1389,7 +1564,7 @@
1389
1564
  <strong>Confidence:</strong> ${(f.payload.confidence * 100).toFixed(0)}%
1390
1565
  </div>
1391
1566
  </div>
1392
- `).join('');
1567
+ `}).join('');
1393
1568
  }
1394
1569
 
1395
1570
  function updateStats(findings) {
@@ -1961,6 +2136,83 @@
1961
2136
  setTimeout(() => toast.remove(), 4000);
1962
2137
  }
1963
2138
 
2139
+ // ========== BADGE GENERATOR ==========
2140
+ window.updateBadgePreview = function() {
2141
+ const style = document.getElementById('badgeStyle').value;
2142
+ const type = document.getElementById('badgeType').value;
2143
+
2144
+ // Get current stats
2145
+ const critical = parseInt(document.getElementById('statCritical').textContent) || 0;
2146
+ const high = parseInt(document.getElementById('statHigh').textContent) || 0;
2147
+ const medium = parseInt(document.getElementById('statMedium').textContent) || 0;
2148
+ const low = parseInt(document.getElementById('statLow').textContent) || 0;
2149
+ const total = critical + high + medium + low;
2150
+
2151
+ let label, message, color;
2152
+
2153
+ if (type === 'status') {
2154
+ label = 'security';
2155
+ if (critical > 0) {
2156
+ message = 'critical';
2157
+ color = 'ff0044';
2158
+ } else if (high > 0) {
2159
+ message = 'issues found';
2160
+ color = 'ff4400';
2161
+ } else if (total > 0) {
2162
+ message = 'warnings';
2163
+ color = 'ffaa00';
2164
+ } else {
2165
+ message = 'passing';
2166
+ color = '00ff88';
2167
+ }
2168
+ } else if (type === 'critical') {
2169
+ label = 'critical';
2170
+ message = critical.toString();
2171
+ color = critical > 0 ? 'ff0044' : '00ff88';
2172
+ } else {
2173
+ label = 'findings';
2174
+ message = total.toString();
2175
+ color = total > 5 ? 'ff4400' : total > 0 ? 'ffaa00' : '00ff88';
2176
+ }
2177
+
2178
+ // Shield logo as base64
2179
+ const logo = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0id2hpdGUiIGQ9Ik0xMiAxTDMgNXY2YzAgNS41NSAzLjg0IDEwLjc0IDkgMTIgNS4xNi0xLjI2IDktNi40NSA5LTEyVjVsLTktNHoiLz48L3N2Zz4=';
2180
+
2181
+ const badgeUrl = `https://img.shields.io/badge/${encodeURIComponent(label)}-${encodeURIComponent(message)}-${color}?style=${style}&logo=${encodeURIComponent(logo)}`;
2182
+ const markdown = `[![aurasecurity](${badgeUrl})](https://aurasecurity.io)`;
2183
+
2184
+ document.getElementById('badgeImg').src = badgeUrl;
2185
+ document.getElementById('badgeMarkdown').textContent = markdown;
2186
+ };
2187
+
2188
+ window.copyBadgeMarkdown = function() {
2189
+ const markdown = document.getElementById('badgeMarkdown').textContent;
2190
+ navigator.clipboard.writeText(markdown).then(() => {
2191
+ showToast('Badge markdown copied!');
2192
+ }).catch(() => {
2193
+ showToast('Failed to copy', true);
2194
+ });
2195
+ };
2196
+
2197
+ // Update badge when stats change
2198
+ const originalUpdateStats = function() {};
2199
+ const statsObserver = new MutationObserver(() => {
2200
+ if (typeof updateBadgePreview === 'function') {
2201
+ updateBadgePreview();
2202
+ }
2203
+ });
2204
+
2205
+ // Start observing stats after DOM is ready
2206
+ setTimeout(() => {
2207
+ const statElements = ['statCritical', 'statHigh', 'statMedium', 'statLow'];
2208
+ statElements.forEach(id => {
2209
+ const el = document.getElementById(id);
2210
+ if (el) statsObserver.observe(el, { childList: true, characterData: true, subtree: true });
2211
+ });
2212
+ // Initial badge update
2213
+ if (typeof updateBadgePreview === 'function') updateBadgePreview();
2214
+ }, 1000);
2215
+
1964
2216
  function onWindowResize() {
1965
2217
  camera.aspect = window.innerWidth / window.innerHeight;
1966
2218
  camera.updateProjectionMatrix();
@@ -1496,6 +1496,7 @@
1496
1496
  <a href="#install" class="nav-link">Install</a>
1497
1497
  <a href="#features" class="nav-link">Outcomes</a>
1498
1498
  <a href="#architecture" class="nav-link">How it Works</a>
1499
+ <a href="/docs.html" class="nav-link">Docs</a>
1499
1500
  <a href="https://github.com/aurasecurityio/aura-security" target="_blank" class="nav-link">GitHub</a>
1500
1501
  <a href="https://app.aurasecurity.io/app" class="btn btn-primary">Open Dashboard</a>
1501
1502
  </div>
@@ -1512,11 +1513,11 @@
1512
1513
  aurasecurity turns code changes into verifiable security events using real scanners, reproducible output, and structured findings — no black boxes.
1513
1514
  </p>
1514
1515
  <div class="hero-actions">
1515
- <a href="#install" class="btn btn-primary">
1516
+ <a href="https://app.aurasecurity.io/app" class="btn btn-primary">
1516
1517
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
1517
1518
  <path d="M5 12h14M12 5l7 7-7 7"/>
1518
1519
  </svg>
1519
- Run your first audit
1520
+ Open Dashboard
1520
1521
  </a>
1521
1522
  <a href="https://github.com/aurasecurityio/aura-security#example-output" target="_blank" class="btn btn-ghost">
1522
1523
  <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -1905,6 +1906,9 @@
1905
1906
  <a href="https://www.npmjs.com/package/aura-security" target="_blank">npm</a>
1906
1907
  <a href="https://pypi.org/project/aura-security/" target="_blank">PyPI</a>
1907
1908
  <a href="https://app.aurasecurity.io/app">Dashboard</a>
1909
+ <a href="/docs.html">Docs</a>
1910
+ <a href="https://x.com/aiaurasecurity" target="_blank">X</a>
1911
+ <a href="https://www.linkedin.com/in/shubham-vashist/" target="_blank">LinkedIn</a>
1908
1912
  </div>
1909
1913
  </div>
1910
1914
  <div class="footer-right">