averecion-lite 1.5.2 → 1.6.1
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/dashboard/dash.css +219 -123
- package/dashboard/dash.js +98 -69
- package/dashboard/index.html +62 -61
- package/dist/log-watcher.d.ts +1 -0
- package/dist/log-watcher.d.ts.map +1 -1
- package/dist/log-watcher.js +88 -7
- package/dist/src/threat-assessment.d.ts.map +1 -1
- package/dist/src/threat-assessment.js +9 -4
- package/package.json +1 -1
package/dashboard/dash.css
CHANGED
|
@@ -443,46 +443,6 @@ body {
|
|
|
443
443
|
color: var(--text-muted);
|
|
444
444
|
}
|
|
445
445
|
|
|
446
|
-
.safety-grid {
|
|
447
|
-
display: grid;
|
|
448
|
-
gap: 0.75rem;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
.safety-item {
|
|
452
|
-
display: flex;
|
|
453
|
-
align-items: center;
|
|
454
|
-
gap: 0.75rem;
|
|
455
|
-
padding: 1rem;
|
|
456
|
-
background: var(--bg-card);
|
|
457
|
-
border-radius: 12px;
|
|
458
|
-
border: 1px solid var(--border);
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
.safety-item.pass {
|
|
462
|
-
border-color: rgba(34, 197, 94, 0.3);
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
.safety-item.fail {
|
|
466
|
-
border-color: rgba(239, 68, 68, 0.3);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
.check-icon {
|
|
470
|
-
width: 24px;
|
|
471
|
-
height: 24px;
|
|
472
|
-
border-radius: 50%;
|
|
473
|
-
display: flex;
|
|
474
|
-
align-items: center;
|
|
475
|
-
justify-content: center;
|
|
476
|
-
font-size: 0.8rem;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
.safety-item.pass .check-icon {
|
|
480
|
-
background: var(--success);
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
.safety-item.fail .check-icon {
|
|
484
|
-
background: var(--danger);
|
|
485
|
-
}
|
|
486
446
|
|
|
487
447
|
.activity-list {
|
|
488
448
|
background: var(--bg-card);
|
|
@@ -606,75 +566,251 @@ body {
|
|
|
606
566
|
cursor: help;
|
|
607
567
|
}
|
|
608
568
|
|
|
609
|
-
.protection-section {
|
|
569
|
+
.protection-safety-section {
|
|
610
570
|
margin-bottom: 1.5rem;
|
|
611
571
|
}
|
|
612
572
|
|
|
613
|
-
.protection-
|
|
573
|
+
.protection-safety-card {
|
|
614
574
|
background: var(--bg-card);
|
|
615
575
|
border-radius: 16px;
|
|
616
|
-
padding: 1.
|
|
576
|
+
padding: 1.25rem;
|
|
617
577
|
border: 1px solid var(--border);
|
|
618
578
|
}
|
|
619
579
|
|
|
620
|
-
.
|
|
580
|
+
.ps-header {
|
|
621
581
|
display: flex;
|
|
622
582
|
align-items: center;
|
|
623
|
-
gap:
|
|
583
|
+
gap: 0.75rem;
|
|
624
584
|
margin-bottom: 1rem;
|
|
585
|
+
padding-bottom: 0.75rem;
|
|
586
|
+
border-bottom: 1px solid var(--border);
|
|
625
587
|
}
|
|
626
588
|
|
|
627
|
-
.score
|
|
628
|
-
font-size:
|
|
589
|
+
.ps-score {
|
|
590
|
+
font-size: 1.75rem;
|
|
629
591
|
font-weight: 700;
|
|
630
592
|
color: var(--success);
|
|
631
593
|
}
|
|
632
594
|
|
|
633
|
-
.
|
|
595
|
+
.ps-label {
|
|
634
596
|
color: var(--text-secondary);
|
|
635
|
-
font-size:
|
|
597
|
+
font-size: 0.95rem;
|
|
636
598
|
}
|
|
637
599
|
|
|
638
|
-
.
|
|
639
|
-
display:
|
|
640
|
-
|
|
641
|
-
gap: 0.
|
|
600
|
+
.ps-checks {
|
|
601
|
+
display: flex;
|
|
602
|
+
flex-direction: column;
|
|
603
|
+
gap: 0.5rem;
|
|
642
604
|
}
|
|
643
605
|
|
|
644
|
-
.
|
|
606
|
+
.ps-check {
|
|
645
607
|
display: flex;
|
|
646
|
-
flex-direction: column;
|
|
647
608
|
align-items: center;
|
|
648
|
-
gap: 0.
|
|
649
|
-
padding:
|
|
609
|
+
gap: 0.75rem;
|
|
610
|
+
padding: 0.6rem 0.75rem;
|
|
650
611
|
background: var(--bg-dark);
|
|
651
|
-
border-radius:
|
|
652
|
-
border:
|
|
612
|
+
border-radius: 10px;
|
|
613
|
+
border: 1px solid var(--border);
|
|
653
614
|
cursor: help;
|
|
654
|
-
transition: border-color 0.2s
|
|
615
|
+
transition: border-color 0.2s;
|
|
655
616
|
}
|
|
656
617
|
|
|
657
|
-
.
|
|
658
|
-
border-color:
|
|
618
|
+
.ps-check.active {
|
|
619
|
+
border-color: rgba(34, 197, 94, 0.3);
|
|
659
620
|
}
|
|
660
621
|
|
|
661
|
-
.
|
|
662
|
-
border-color:
|
|
663
|
-
opacity: 0.
|
|
622
|
+
.ps-check.inactive {
|
|
623
|
+
border-color: rgba(239, 68, 68, 0.3);
|
|
624
|
+
opacity: 0.7;
|
|
664
625
|
}
|
|
665
626
|
|
|
666
|
-
.
|
|
667
|
-
|
|
627
|
+
.ps-check-icon {
|
|
628
|
+
font-size: 1.1rem;
|
|
668
629
|
}
|
|
669
630
|
|
|
670
|
-
.
|
|
671
|
-
|
|
631
|
+
.ps-check-label {
|
|
632
|
+
flex: 1;
|
|
633
|
+
font-size: 0.85rem;
|
|
634
|
+
color: var(--text-secondary);
|
|
672
635
|
}
|
|
673
636
|
|
|
674
|
-
.
|
|
675
|
-
font-size: 0.
|
|
637
|
+
.ps-check-status {
|
|
638
|
+
font-size: 0.8rem;
|
|
639
|
+
font-weight: 700;
|
|
640
|
+
color: var(--success);
|
|
641
|
+
width: 20px;
|
|
642
|
+
height: 20px;
|
|
643
|
+
border-radius: 50%;
|
|
644
|
+
background: rgba(34, 197, 94, 0.2);
|
|
645
|
+
display: flex;
|
|
646
|
+
align-items: center;
|
|
647
|
+
justify-content: center;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
.ps-check.inactive .ps-check-status {
|
|
651
|
+
color: var(--danger);
|
|
652
|
+
background: rgba(239, 68, 68, 0.2);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.header-scan-btn {
|
|
656
|
+
background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%);
|
|
657
|
+
border: none;
|
|
658
|
+
color: #fff;
|
|
659
|
+
padding: 0.5rem 1rem;
|
|
660
|
+
border-radius: 8px;
|
|
661
|
+
font-size: 0.85rem;
|
|
662
|
+
font-weight: 600;
|
|
663
|
+
cursor: pointer;
|
|
664
|
+
transition: all 0.2s;
|
|
665
|
+
box-shadow: 0 2px 10px rgba(124, 58, 237, 0.3);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
.header-scan-btn:hover {
|
|
669
|
+
transform: translateY(-1px);
|
|
670
|
+
box-shadow: 0 4px 15px rgba(124, 58, 237, 0.4);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
.section-accordion {
|
|
674
|
+
display: flex;
|
|
675
|
+
align-items: center;
|
|
676
|
+
justify-content: space-between;
|
|
677
|
+
width: 100%;
|
|
678
|
+
padding: 0.85rem 1rem;
|
|
679
|
+
background: var(--bg-card);
|
|
680
|
+
border: 1px solid var(--border);
|
|
681
|
+
border-radius: 12px;
|
|
676
682
|
color: var(--text-secondary);
|
|
683
|
+
font-size: 0.9rem;
|
|
684
|
+
font-weight: 500;
|
|
685
|
+
cursor: pointer;
|
|
686
|
+
transition: all 0.2s;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
.section-accordion:hover {
|
|
690
|
+
border-color: rgba(255, 255, 255, 0.15);
|
|
691
|
+
color: var(--text-primary);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
.accordion-arrow {
|
|
695
|
+
font-size: 0.7rem;
|
|
696
|
+
transition: transform 0.2s;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
.section-accordion.expanded .accordion-arrow {
|
|
700
|
+
transform: rotate(90deg);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.security-arch-grid.collapsed {
|
|
704
|
+
display: none;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.modal-overlay {
|
|
708
|
+
position: fixed;
|
|
709
|
+
top: 0;
|
|
710
|
+
left: 0;
|
|
711
|
+
right: 0;
|
|
712
|
+
bottom: 0;
|
|
713
|
+
background: rgba(0, 0, 0, 0.7);
|
|
714
|
+
backdrop-filter: blur(4px);
|
|
715
|
+
z-index: 2000;
|
|
716
|
+
display: flex;
|
|
717
|
+
align-items: center;
|
|
718
|
+
justify-content: center;
|
|
719
|
+
padding: 2rem;
|
|
720
|
+
animation: fadeIn 0.2s ease;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
.modal-overlay.hidden {
|
|
724
|
+
display: none;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
.modal-content {
|
|
728
|
+
background: var(--bg-dark);
|
|
729
|
+
border: 1px solid var(--border);
|
|
730
|
+
border-radius: 20px;
|
|
731
|
+
width: 100%;
|
|
732
|
+
max-width: 700px;
|
|
733
|
+
max-height: 85vh;
|
|
734
|
+
display: flex;
|
|
735
|
+
flex-direction: column;
|
|
736
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
.modal-header {
|
|
740
|
+
display: flex;
|
|
741
|
+
align-items: center;
|
|
742
|
+
justify-content: space-between;
|
|
743
|
+
padding: 1.25rem 1.5rem;
|
|
744
|
+
border-bottom: 1px solid var(--border);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
.modal-header h2 {
|
|
748
|
+
font-size: 1.2rem;
|
|
749
|
+
color: var(--text-primary);
|
|
750
|
+
margin: 0;
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
.modal-close {
|
|
754
|
+
background: none;
|
|
755
|
+
border: none;
|
|
756
|
+
color: var(--text-muted);
|
|
757
|
+
font-size: 1.75rem;
|
|
758
|
+
cursor: pointer;
|
|
759
|
+
padding: 0;
|
|
760
|
+
line-height: 1;
|
|
761
|
+
transition: color 0.2s;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
.modal-close:hover {
|
|
765
|
+
color: var(--text-primary);
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.modal-body {
|
|
769
|
+
padding: 1.5rem;
|
|
770
|
+
overflow-y: auto;
|
|
771
|
+
flex: 1;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.modal-scan-area {
|
|
677
775
|
text-align: center;
|
|
776
|
+
padding: 1rem 0;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
.modal-scan-desc {
|
|
780
|
+
color: var(--text-secondary);
|
|
781
|
+
font-size: 0.9rem;
|
|
782
|
+
margin-bottom: 1.25rem;
|
|
783
|
+
line-height: 1.5;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.modal-footer {
|
|
787
|
+
display: flex;
|
|
788
|
+
gap: 0.75rem;
|
|
789
|
+
padding: 1rem 1.5rem;
|
|
790
|
+
border-top: 1px solid var(--border);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
.modal-footer.hidden {
|
|
794
|
+
display: none;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
.modal-export-btn {
|
|
798
|
+
flex: 1;
|
|
799
|
+
padding: 0.65rem 1rem;
|
|
800
|
+
background: var(--bg-card);
|
|
801
|
+
border: 1px solid var(--border);
|
|
802
|
+
border-radius: 10px;
|
|
803
|
+
color: var(--text-secondary);
|
|
804
|
+
font-size: 0.85rem;
|
|
805
|
+
font-weight: 500;
|
|
806
|
+
cursor: pointer;
|
|
807
|
+
transition: all 0.2s;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
.modal-export-btn:hover {
|
|
811
|
+
border-color: rgba(124, 58, 237, 0.5);
|
|
812
|
+
color: var(--text-primary);
|
|
813
|
+
background: var(--bg-card-hover);
|
|
678
814
|
}
|
|
679
815
|
|
|
680
816
|
.activity-item.has-context {
|
|
@@ -936,8 +1072,14 @@ body {
|
|
|
936
1072
|
align-items: flex-start;
|
|
937
1073
|
}
|
|
938
1074
|
|
|
939
|
-
.
|
|
940
|
-
|
|
1075
|
+
.header-actions {
|
|
1076
|
+
flex-wrap: wrap;
|
|
1077
|
+
justify-content: center;
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
.modal-content {
|
|
1081
|
+
max-height: 90vh;
|
|
1082
|
+
margin: 1rem;
|
|
941
1083
|
}
|
|
942
1084
|
|
|
943
1085
|
.hero h1 {
|
|
@@ -1157,18 +1299,14 @@ body {
|
|
|
1157
1299
|
}
|
|
1158
1300
|
|
|
1159
1301
|
.security-arch-section {
|
|
1160
|
-
margin-
|
|
1302
|
+
margin-bottom: 1.5rem;
|
|
1161
1303
|
}
|
|
1162
1304
|
|
|
1163
1305
|
.security-arch-grid {
|
|
1164
1306
|
display: grid;
|
|
1165
|
-
grid-template-columns: repeat(2, 1fr);
|
|
1166
|
-
gap: 0.75rem;
|
|
1167
|
-
margin-top: 1rem;
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
.dash-col-right .security-arch-grid {
|
|
1171
1307
|
grid-template-columns: 1fr;
|
|
1308
|
+
gap: 0.5rem;
|
|
1309
|
+
margin-top: 0.5rem;
|
|
1172
1310
|
}
|
|
1173
1311
|
|
|
1174
1312
|
.arch-item {
|
|
@@ -1201,13 +1339,6 @@ body {
|
|
|
1201
1339
|
line-height: 1.5;
|
|
1202
1340
|
}
|
|
1203
1341
|
|
|
1204
|
-
.threat-section {
|
|
1205
|
-
margin-top: 2rem;
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
.threat-header {
|
|
1209
|
-
margin-top: 1rem;
|
|
1210
|
-
}
|
|
1211
1342
|
|
|
1212
1343
|
.threat-scan-btn {
|
|
1213
1344
|
background: linear-gradient(135deg, #7c3aed 0%, #a855f7 100%);
|
|
@@ -1298,48 +1429,13 @@ body {
|
|
|
1298
1429
|
.threat-summary-badge.low { background: rgba(96, 165, 250, 0.2); color: #60a5fa; }
|
|
1299
1430
|
.threat-summary-badge.passed { background: rgba(34, 197, 94, 0.2); color: var(--success); }
|
|
1300
1431
|
|
|
1301
|
-
.threat-findings-toggle {
|
|
1302
|
-
display: flex;
|
|
1303
|
-
align-items: center;
|
|
1304
|
-
gap: 0.5rem;
|
|
1305
|
-
margin-top: 0.75rem;
|
|
1306
|
-
padding: 0.5rem 0.75rem;
|
|
1307
|
-
background: var(--bg-card);
|
|
1308
|
-
border: 1px solid var(--border);
|
|
1309
|
-
border-radius: 8px;
|
|
1310
|
-
cursor: pointer;
|
|
1311
|
-
color: var(--text-secondary);
|
|
1312
|
-
font-size: 0.8rem;
|
|
1313
|
-
transition: all 0.2s;
|
|
1314
|
-
width: 100%;
|
|
1315
|
-
text-align: left;
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
.threat-findings-toggle:hover {
|
|
1319
|
-
border-color: var(--primary, #7c3aed);
|
|
1320
|
-
color: var(--text-primary);
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
.threat-findings-toggle .toggle-arrow {
|
|
1324
|
-
transition: transform 0.2s;
|
|
1325
|
-
font-size: 0.7rem;
|
|
1326
|
-
}
|
|
1327
|
-
|
|
1328
|
-
.threat-findings-toggle.expanded .toggle-arrow {
|
|
1329
|
-
transform: rotate(90deg);
|
|
1330
|
-
}
|
|
1331
|
-
|
|
1332
1432
|
.threat-findings {
|
|
1333
|
-
margin-top:
|
|
1433
|
+
margin-top: 1rem;
|
|
1334
1434
|
display: flex;
|
|
1335
1435
|
flex-direction: column;
|
|
1336
1436
|
gap: 0.5rem;
|
|
1337
1437
|
}
|
|
1338
1438
|
|
|
1339
|
-
.threat-findings.collapsed {
|
|
1340
|
-
display: none;
|
|
1341
|
-
}
|
|
1342
|
-
|
|
1343
1439
|
.threat-finding {
|
|
1344
1440
|
background: var(--bg-card);
|
|
1345
1441
|
border: 1px solid var(--border);
|
package/dashboard/dash.js
CHANGED
|
@@ -235,13 +235,6 @@
|
|
|
235
235
|
globalStatus.className = "status-badge protected";
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
const checkLocal = document.getElementById("check-local");
|
|
239
|
-
const checkSecret = document.getElementById("check-secret");
|
|
240
|
-
const checkInjection = document.getElementById("check-injection");
|
|
241
|
-
|
|
242
|
-
if (checkLocal) checkLocal.className = "safety-item " + (metrics.instance.dashboardLocalOnly ? "pass" : "fail");
|
|
243
|
-
if (checkSecret) checkSecret.className = "safety-item " + (metrics.instance.secretsEnvOnly ? "pass" : "fail");
|
|
244
|
-
if (checkInjection) checkInjection.className = "safety-item pass";
|
|
245
238
|
|
|
246
239
|
const activityList = document.getElementById("activity-list");
|
|
247
240
|
if (metrics.lastActions && metrics.lastActions.length > 0) {
|
|
@@ -397,42 +390,35 @@
|
|
|
397
390
|
|
|
398
391
|
function updateProtectionScore(metrics) {
|
|
399
392
|
let score = 0;
|
|
400
|
-
const
|
|
393
|
+
const checks = {
|
|
401
394
|
local: document.getElementById("bar-local"),
|
|
402
395
|
secret: document.getElementById("bar-secret"),
|
|
403
396
|
injection: document.getElementById("bar-injection"),
|
|
404
397
|
approval: document.getElementById("bar-approval")
|
|
405
398
|
};
|
|
399
|
+
const statusEls = {
|
|
400
|
+
local: document.getElementById("check-local"),
|
|
401
|
+
secret: document.getElementById("check-secret"),
|
|
402
|
+
injection: document.getElementById("check-injection")
|
|
403
|
+
};
|
|
406
404
|
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
bars.secret?.classList.add("active");
|
|
419
|
-
bars.secret?.classList.remove("inactive");
|
|
420
|
-
} else {
|
|
421
|
-
bars.secret?.classList.remove("active");
|
|
422
|
-
bars.secret?.classList.add("inactive");
|
|
405
|
+
function setCheck(key, active) {
|
|
406
|
+
if (active) {
|
|
407
|
+
score++;
|
|
408
|
+
checks[key]?.classList.add("active");
|
|
409
|
+
checks[key]?.classList.remove("inactive");
|
|
410
|
+
if (statusEls[key]) { statusEls[key].textContent = "✓"; }
|
|
411
|
+
} else {
|
|
412
|
+
checks[key]?.classList.remove("active");
|
|
413
|
+
checks[key]?.classList.add("inactive");
|
|
414
|
+
if (statusEls[key]) { statusEls[key].textContent = "✗"; }
|
|
415
|
+
}
|
|
423
416
|
}
|
|
424
417
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
score++;
|
|
430
|
-
bars.approval?.classList.add("active");
|
|
431
|
-
bars.approval?.classList.remove("inactive");
|
|
432
|
-
} else {
|
|
433
|
-
bars.approval?.classList.remove("active");
|
|
434
|
-
bars.approval?.classList.add("inactive");
|
|
435
|
-
}
|
|
418
|
+
setCheck("local", metrics.instance.dashboardLocalOnly);
|
|
419
|
+
setCheck("secret", metrics.instance.secretsEnvOnly);
|
|
420
|
+
setCheck("injection", true);
|
|
421
|
+
setCheck("approval", localStorage.getItem("protection_level") !== "relaxed");
|
|
436
422
|
|
|
437
423
|
const scoreEl = document.getElementById("score-value");
|
|
438
424
|
if (scoreEl) {
|
|
@@ -911,7 +897,8 @@
|
|
|
911
897
|
initProtectionToggle();
|
|
912
898
|
initNotificationToggle();
|
|
913
899
|
initResetButton();
|
|
914
|
-
|
|
900
|
+
initThreatModal();
|
|
901
|
+
initSecurityAccordion();
|
|
915
902
|
|
|
916
903
|
function initNotificationToggle() {
|
|
917
904
|
const btn = document.getElementById("btn-notifications");
|
|
@@ -949,15 +936,41 @@
|
|
|
949
936
|
});
|
|
950
937
|
}
|
|
951
938
|
|
|
952
|
-
|
|
953
|
-
|
|
939
|
+
let lastScanData = null;
|
|
940
|
+
|
|
941
|
+
function initThreatModal() {
|
|
942
|
+
const modal = document.getElementById("threat-modal");
|
|
943
|
+
const headerBtn = document.getElementById("btn-scan-header");
|
|
944
|
+
const closeBtn = document.getElementById("btn-modal-close");
|
|
945
|
+
const scanBtn = document.getElementById("btn-scan");
|
|
946
|
+
const exportJsonBtn = document.getElementById("btn-export-json");
|
|
947
|
+
const exportCopyBtn = document.getElementById("btn-export-copy");
|
|
948
|
+
if (!modal || !headerBtn) return;
|
|
949
|
+
|
|
950
|
+
headerBtn.addEventListener("click", () => {
|
|
951
|
+
modal.classList.remove("hidden");
|
|
952
|
+
});
|
|
953
|
+
|
|
954
|
+
closeBtn?.addEventListener("click", () => {
|
|
955
|
+
modal.classList.add("hidden");
|
|
956
|
+
});
|
|
957
|
+
|
|
958
|
+
modal.addEventListener("click", (e) => {
|
|
959
|
+
if (e.target === modal) modal.classList.add("hidden");
|
|
960
|
+
});
|
|
961
|
+
|
|
962
|
+
document.addEventListener("keydown", (e) => {
|
|
963
|
+
if (e.key === "Escape" && !modal.classList.contains("hidden")) {
|
|
964
|
+
modal.classList.add("hidden");
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
|
|
954
968
|
const scoreDisplay = document.getElementById("threat-score-display");
|
|
955
969
|
const findingsEl = document.getElementById("threat-findings");
|
|
956
|
-
if (!btn || !scoreDisplay || !findingsEl) return;
|
|
957
970
|
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
971
|
+
scanBtn?.addEventListener("click", async () => {
|
|
972
|
+
scanBtn.disabled = true;
|
|
973
|
+
scanBtn.textContent = "🔍 Scanning...";
|
|
961
974
|
|
|
962
975
|
try {
|
|
963
976
|
const headers = {};
|
|
@@ -965,13 +978,36 @@
|
|
|
965
978
|
const res = await fetch("/api/threat-assessment", { headers });
|
|
966
979
|
if (!res.ok) throw new Error("Scan failed");
|
|
967
980
|
const data = await res.json();
|
|
981
|
+
lastScanData = data;
|
|
968
982
|
renderThreatResults(data, scoreDisplay, findingsEl);
|
|
969
|
-
|
|
983
|
+
scanBtn.textContent = "🔍 Rescan";
|
|
984
|
+
document.getElementById("modal-export-footer")?.classList.remove("hidden");
|
|
970
985
|
} catch (err) {
|
|
971
|
-
|
|
986
|
+
scanBtn.textContent = "⚠️ Scan Failed — Retry";
|
|
972
987
|
console.error("Threat scan error:", err);
|
|
973
988
|
}
|
|
974
|
-
|
|
989
|
+
scanBtn.disabled = false;
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
exportJsonBtn?.addEventListener("click", () => {
|
|
993
|
+
if (!lastScanData) return;
|
|
994
|
+
const blob = new Blob([JSON.stringify(lastScanData, null, 2)], { type: "application/json" });
|
|
995
|
+
const url = URL.createObjectURL(blob);
|
|
996
|
+
const a = document.createElement("a");
|
|
997
|
+
a.href = url;
|
|
998
|
+
a.download = `clawguard-scan-${new Date().toISOString().slice(0, 10)}.json`;
|
|
999
|
+
a.click();
|
|
1000
|
+
URL.revokeObjectURL(url);
|
|
1001
|
+
});
|
|
1002
|
+
|
|
1003
|
+
exportCopyBtn?.addEventListener("click", () => {
|
|
1004
|
+
if (!lastScanData) return;
|
|
1005
|
+
const text = `Clawguard Security Scan - ${new Date().toLocaleDateString()}\nGrade: ${lastScanData.grade} | Score: ${lastScanData.score}/100\n\n` +
|
|
1006
|
+
lastScanData.findings.map(f => `[${f.passed ? "PASS" : f.severity.toUpperCase()}] ${f.title}: ${f.description}${!f.passed ? "\n → " + f.recommendation : ""}`).join("\n");
|
|
1007
|
+
navigator.clipboard.writeText(text).then(() => {
|
|
1008
|
+
exportCopyBtn.textContent = "✓ Copied!";
|
|
1009
|
+
setTimeout(() => { exportCopyBtn.textContent = "📋 Copy to Clipboard"; }, 2000);
|
|
1010
|
+
});
|
|
975
1011
|
});
|
|
976
1012
|
}
|
|
977
1013
|
|
|
@@ -997,30 +1033,6 @@
|
|
|
997
1033
|
const failed = data.findings.filter(f => !f.passed);
|
|
998
1034
|
const passed = data.findings.filter(f => f.passed);
|
|
999
1035
|
const sorted = [...failed, ...passed];
|
|
1000
|
-
const failCount = failed.length;
|
|
1001
|
-
|
|
1002
|
-
let existingToggle = document.querySelector(".threat-findings-toggle");
|
|
1003
|
-
if (!existingToggle) {
|
|
1004
|
-
existingToggle = document.createElement("button");
|
|
1005
|
-
existingToggle.className = "threat-findings-toggle";
|
|
1006
|
-
existingToggle.setAttribute("data-testid", "btn-findings-toggle");
|
|
1007
|
-
findingsEl.parentNode.insertBefore(existingToggle, findingsEl);
|
|
1008
|
-
existingToggle.addEventListener("click", () => {
|
|
1009
|
-
const isCollapsed = findingsEl.classList.contains("collapsed");
|
|
1010
|
-
if (isCollapsed) {
|
|
1011
|
-
findingsEl.classList.remove("collapsed");
|
|
1012
|
-
existingToggle.classList.add("expanded");
|
|
1013
|
-
} else {
|
|
1014
|
-
findingsEl.classList.add("collapsed");
|
|
1015
|
-
existingToggle.classList.remove("expanded");
|
|
1016
|
-
}
|
|
1017
|
-
existingToggle.querySelector(".toggle-label").textContent =
|
|
1018
|
-
findingsEl.classList.contains("collapsed") ? `Show ${data.findings.length} findings (${failCount} issues)` : "Hide findings";
|
|
1019
|
-
});
|
|
1020
|
-
}
|
|
1021
|
-
existingToggle.innerHTML = `<span class="toggle-arrow">▶</span> <span class="toggle-label">Show ${data.findings.length} findings (${failCount} issues)</span>`;
|
|
1022
|
-
findingsEl.classList.add("collapsed");
|
|
1023
|
-
existingToggle.classList.remove("expanded");
|
|
1024
1036
|
|
|
1025
1037
|
findingsEl.innerHTML = sorted.map(f => {
|
|
1026
1038
|
const sevIcon = f.passed ? "✓" : (f.severity === "critical" ? "!!" : f.severity === "high" ? "!" : f.severity === "medium" ? "~" : "·");
|
|
@@ -1038,6 +1050,23 @@
|
|
|
1038
1050
|
}).join("");
|
|
1039
1051
|
}
|
|
1040
1052
|
|
|
1053
|
+
function initSecurityAccordion() {
|
|
1054
|
+
const btn = document.getElementById("btn-toggle-security");
|
|
1055
|
+
const content = document.getElementById("security-arch-content");
|
|
1056
|
+
if (!btn || !content) return;
|
|
1057
|
+
|
|
1058
|
+
btn.addEventListener("click", () => {
|
|
1059
|
+
const isCollapsed = content.classList.contains("collapsed");
|
|
1060
|
+
if (isCollapsed) {
|
|
1061
|
+
content.classList.remove("collapsed");
|
|
1062
|
+
btn.classList.add("expanded");
|
|
1063
|
+
} else {
|
|
1064
|
+
content.classList.add("collapsed");
|
|
1065
|
+
btn.classList.remove("expanded");
|
|
1066
|
+
}
|
|
1067
|
+
});
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1041
1070
|
function initResetButton() {
|
|
1042
1071
|
const btn = document.getElementById("btn-reset");
|
|
1043
1072
|
if (!btn) return;
|
package/dashboard/index.html
CHANGED
|
@@ -106,6 +106,9 @@
|
|
|
106
106
|
</div>
|
|
107
107
|
</div>
|
|
108
108
|
<div class="header-actions">
|
|
109
|
+
<button id="btn-scan-header" class="header-scan-btn" data-testid="btn-scan-header" title="Run a full security scan">
|
|
110
|
+
🔍 Security Scan
|
|
111
|
+
</button>
|
|
109
112
|
<button id="btn-notifications" class="notification-toggle" data-testid="btn-notifications" title="Enable browser notifications">
|
|
110
113
|
🔔 Notifications
|
|
111
114
|
</button>
|
|
@@ -200,96 +203,66 @@
|
|
|
200
203
|
</div>
|
|
201
204
|
|
|
202
205
|
<div class="dash-col-right">
|
|
203
|
-
<section class="protection-section">
|
|
204
|
-
<div class="protection-
|
|
205
|
-
<div class="
|
|
206
|
-
<span class="score
|
|
207
|
-
<span class="
|
|
206
|
+
<section class="protection-safety-section">
|
|
207
|
+
<div class="protection-safety-card" data-testid="protection-score">
|
|
208
|
+
<div class="ps-header">
|
|
209
|
+
<span class="ps-score" id="score-value">4/4</span>
|
|
210
|
+
<span class="ps-label">Protection Active</span>
|
|
208
211
|
</div>
|
|
209
|
-
<div class="
|
|
210
|
-
<div class="
|
|
211
|
-
<span class="
|
|
212
|
-
<span class="
|
|
212
|
+
<div class="ps-checks">
|
|
213
|
+
<div class="ps-check active" id="bar-local" data-tooltip="Dashboard only accessible from your computer">
|
|
214
|
+
<span class="ps-check-icon">🏠</span>
|
|
215
|
+
<span class="ps-check-label">Local Only</span>
|
|
216
|
+
<span class="ps-check-status" id="check-local" data-testid="check-local">✓</span>
|
|
213
217
|
</div>
|
|
214
|
-
<div class="
|
|
215
|
-
<span class="
|
|
216
|
-
<span class="
|
|
218
|
+
<div class="ps-check active" id="bar-secret" data-tooltip="Your dashboard is protected by a secret key">
|
|
219
|
+
<span class="ps-check-icon">🔑</span>
|
|
220
|
+
<span class="ps-check-label">Secret Key</span>
|
|
221
|
+
<span class="ps-check-status" id="check-secret" data-testid="check-secret">✓</span>
|
|
217
222
|
</div>
|
|
218
|
-
<div class="
|
|
219
|
-
<span class="
|
|
220
|
-
<span class="
|
|
223
|
+
<div class="ps-check active" id="bar-injection" data-tooltip="Detecting prompt injection attempts in real-time">
|
|
224
|
+
<span class="ps-check-icon">🛡️</span>
|
|
225
|
+
<span class="ps-check-label">Injection Detection</span>
|
|
226
|
+
<span class="ps-check-status" id="check-injection" data-testid="check-injection">✓</span>
|
|
221
227
|
</div>
|
|
222
|
-
<div class="
|
|
223
|
-
<span class="
|
|
224
|
-
<span class="
|
|
228
|
+
<div class="ps-check active" id="bar-approval" data-tooltip="Real-time visibility into all agent activity">
|
|
229
|
+
<span class="ps-check-icon">👁️</span>
|
|
230
|
+
<span class="ps-check-label">Live Monitoring</span>
|
|
231
|
+
<span class="ps-check-status">✓</span>
|
|
225
232
|
</div>
|
|
226
233
|
</div>
|
|
227
234
|
</div>
|
|
228
235
|
</section>
|
|
229
236
|
|
|
230
|
-
<section class="safety-section">
|
|
231
|
-
<h2>Safety Checks</h2>
|
|
232
|
-
<div class="safety-grid">
|
|
233
|
-
<div class="safety-item pass" id="check-local" data-testid="check-local">
|
|
234
|
-
<span class="check-icon">✓</span>
|
|
235
|
-
<span>Dashboard is local-only</span>
|
|
236
|
-
<span class="legend-help" data-tooltip="Only you can see this dashboard - no remote access">?</span>
|
|
237
|
-
</div>
|
|
238
|
-
<div class="safety-item pass" id="check-secret" data-testid="check-secret">
|
|
239
|
-
<span class="check-icon">✓</span>
|
|
240
|
-
<span>Secret key protected</span>
|
|
241
|
-
<span class="legend-help" data-tooltip="Your dashboard is locked with a secret key">?</span>
|
|
242
|
-
</div>
|
|
243
|
-
<div class="safety-item pass" id="check-injection" data-testid="check-injection">
|
|
244
|
-
<span class="check-icon">✓</span>
|
|
245
|
-
<span>Prompt injection detection active</span>
|
|
246
|
-
<span class="legend-help" data-tooltip="Detecting hidden attack instructions in real-time">?</span>
|
|
247
|
-
</div>
|
|
248
|
-
</div>
|
|
249
|
-
</section>
|
|
250
|
-
|
|
251
237
|
<section class="security-arch-section">
|
|
252
|
-
<
|
|
253
|
-
|
|
238
|
+
<button class="section-accordion" id="btn-toggle-security" data-testid="btn-toggle-security">
|
|
239
|
+
<span>🔒 How Your Dashboard Stays Safe</span>
|
|
240
|
+
<span class="accordion-arrow">▶</span>
|
|
241
|
+
</button>
|
|
242
|
+
<div class="security-arch-grid collapsed" id="security-arch-content">
|
|
254
243
|
<div class="arch-item">
|
|
255
244
|
<div class="arch-icon">🔒</div>
|
|
256
245
|
<div class="arch-title">Local-Only Binding</div>
|
|
257
|
-
<div class="arch-desc">Dashboard listens on localhost only. No external network can reach it
|
|
246
|
+
<div class="arch-desc">Dashboard listens on localhost only. No external network can reach it.</div>
|
|
258
247
|
</div>
|
|
259
248
|
<div class="arch-item">
|
|
260
249
|
<div class="arch-icon">🔑</div>
|
|
261
250
|
<div class="arch-title">Secret Key Auth</div>
|
|
262
|
-
<div class="arch-desc">Every request requires a secret key your bot never sees
|
|
251
|
+
<div class="arch-desc">Every request requires a secret key your bot never sees.</div>
|
|
263
252
|
</div>
|
|
264
253
|
<div class="arch-item">
|
|
265
254
|
<div class="arch-icon">👁️</div>
|
|
266
255
|
<div class="arch-title">Passive Monitoring</div>
|
|
267
|
-
<div class="arch-desc">Clawguard only reads log files —
|
|
256
|
+
<div class="arch-desc">Clawguard only reads log files — never writes to the bot.</div>
|
|
268
257
|
</div>
|
|
269
258
|
<div class="arch-item">
|
|
270
259
|
<div class="arch-icon">🚫</div>
|
|
271
260
|
<div class="arch-title">No Write-Back Path</div>
|
|
272
|
-
<div class="arch-desc">
|
|
261
|
+
<div class="arch-desc">No API, socket, or channel from dashboard back to your bot.</div>
|
|
273
262
|
</div>
|
|
274
263
|
</div>
|
|
275
264
|
</section>
|
|
276
265
|
|
|
277
|
-
<section class="threat-section" id="threat-section">
|
|
278
|
-
<h2>Threat Assessment <span class="legend-help" data-tooltip="Holistic security scan of your server">?</span></h2>
|
|
279
|
-
<div class="threat-header" id="threat-header">
|
|
280
|
-
<button class="threat-scan-btn" id="btn-scan" data-testid="btn-scan">🔍 Run Security Scan</button>
|
|
281
|
-
<div class="threat-score-display hidden" id="threat-score-display">
|
|
282
|
-
<div class="threat-grade" id="threat-grade">-</div>
|
|
283
|
-
<div class="threat-score-info">
|
|
284
|
-
<span class="threat-score-value" id="threat-score-value">-/100</span>
|
|
285
|
-
<span class="threat-score-label">Security Score</span>
|
|
286
|
-
</div>
|
|
287
|
-
<div class="threat-summary" id="threat-summary"></div>
|
|
288
|
-
</div>
|
|
289
|
-
</div>
|
|
290
|
-
<div class="threat-findings collapsed" id="threat-findings" data-testid="threat-findings"></div>
|
|
291
|
-
</section>
|
|
292
|
-
|
|
293
266
|
<section class="control-section">
|
|
294
267
|
<h2>Protection Level</h2>
|
|
295
268
|
<div class="protection-toggle" data-testid="protection-toggle">
|
|
@@ -361,6 +334,34 @@
|
|
|
361
334
|
</div>
|
|
362
335
|
</div>
|
|
363
336
|
|
|
337
|
+
<div class="modal-overlay hidden" id="threat-modal" data-testid="threat-modal">
|
|
338
|
+
<div class="modal-content">
|
|
339
|
+
<div class="modal-header">
|
|
340
|
+
<h2>🔍 Threat Assessment</h2>
|
|
341
|
+
<button class="modal-close" id="btn-modal-close" data-testid="btn-modal-close">×</button>
|
|
342
|
+
</div>
|
|
343
|
+
<div class="modal-body">
|
|
344
|
+
<div class="modal-scan-area" id="modal-scan-area">
|
|
345
|
+
<p class="modal-scan-desc">Run a full security scan of your server environment. Checks processes, files, secrets, network, system, and bot-specific risks.</p>
|
|
346
|
+
<button class="threat-scan-btn" id="btn-scan" data-testid="btn-scan">🔍 Run Security Scan</button>
|
|
347
|
+
</div>
|
|
348
|
+
<div class="threat-score-display hidden" id="threat-score-display">
|
|
349
|
+
<div class="threat-grade" id="threat-grade">-</div>
|
|
350
|
+
<div class="threat-score-info">
|
|
351
|
+
<span class="threat-score-value" id="threat-score-value">-/100</span>
|
|
352
|
+
<span class="threat-score-label">Security Score</span>
|
|
353
|
+
</div>
|
|
354
|
+
<div class="threat-summary" id="threat-summary"></div>
|
|
355
|
+
</div>
|
|
356
|
+
<div class="threat-findings" id="threat-findings" data-testid="threat-findings"></div>
|
|
357
|
+
</div>
|
|
358
|
+
<div class="modal-footer hidden" id="modal-export-footer">
|
|
359
|
+
<button class="modal-export-btn" id="btn-export-json" data-testid="btn-export-json">📥 Download JSON</button>
|
|
360
|
+
<button class="modal-export-btn" id="btn-export-copy" data-testid="btn-export-copy">📋 Copy to Clipboard</button>
|
|
361
|
+
</div>
|
|
362
|
+
</div>
|
|
363
|
+
</div>
|
|
364
|
+
|
|
364
365
|
<div class="tooltip" id="tooltip"></div>
|
|
365
366
|
|
|
366
367
|
<script src="/static/dash.js"></script>
|
package/dist/log-watcher.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log-watcher.d.ts","sourceRoot":"","sources":["../log-watcher.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"log-watcher.d.ts","sourceRoot":"","sources":["../log-watcher.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAsDtC,qBAAa,UAAW,SAAQ,YAAY;IAC1C,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,UAAU,CAAgC;IAClD,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,mBAAmB,CAA6B;IACxD,OAAO,CAAC,qBAAqB,CAA+B;;IAY5D,KAAK,IAAI,IAAI;IAUb,IAAI,IAAI,IAAI;IAeZ,OAAO,CAAC,iBAAiB;IAsBzB,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,SAAS;IAuCjB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,YAAY;IA+BpB,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,YAAY;IAmMpB,OAAO,CAAC,kBAAkB;IA+D1B,OAAO,CAAC,eAAe;IAuCvB,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,eAAe;IAmCvB,OAAO,CAAC,aAAa;IAiBrB,OAAO,CAAC,gBAAgB;CAWzB;AAID,wBAAgB,eAAe,IAAI,UAAU,CAM5C;AAED,wBAAgB,cAAc,IAAI,IAAI,CAKrC;AAED,wBAAgB,aAAa,IAAI,UAAU,GAAG,IAAI,CAEjD"}
|
package/dist/log-watcher.js
CHANGED
|
@@ -29,9 +29,13 @@ exports.stopLogWatcher = stopLogWatcher;
|
|
|
29
29
|
exports.getLogWatcher = getLogWatcher;
|
|
30
30
|
const fs = __importStar(require("fs"));
|
|
31
31
|
const path = __importStar(require("path"));
|
|
32
|
+
const os = __importStar(require("os"));
|
|
32
33
|
const events_1 = require("events");
|
|
33
34
|
const storage_1 = require("./storage");
|
|
34
|
-
const
|
|
35
|
+
const CLAWDBOT_LOG_DIRS = [
|
|
36
|
+
path.join(os.homedir(), ".clawdbot", "logs"),
|
|
37
|
+
"/tmp/clawdbot",
|
|
38
|
+
];
|
|
35
39
|
const DANGEROUS_PATTERNS = [
|
|
36
40
|
{ pattern: /rm\s+-rf?\s+\//, reason: "Dangerous rm command (root delete)" },
|
|
37
41
|
{ pattern: /rm\s+-rf?\s+~/, reason: "Dangerous rm command (home delete)" },
|
|
@@ -80,7 +84,7 @@ class LogWatcher extends events_1.EventEmitter {
|
|
|
80
84
|
start() {
|
|
81
85
|
const logFile = this.getCurrentLogFile();
|
|
82
86
|
if (!logFile) {
|
|
83
|
-
console.log(
|
|
87
|
+
console.log(`[LogWatcher] No log files found in ${CLAWDBOT_LOG_DIRS.join(", ")} — polling every 5s...`);
|
|
84
88
|
this.pollInterval = setInterval(() => this.checkForLogFile(), 5000);
|
|
85
89
|
return;
|
|
86
90
|
}
|
|
@@ -101,11 +105,27 @@ class LogWatcher extends events_1.EventEmitter {
|
|
|
101
105
|
}
|
|
102
106
|
}
|
|
103
107
|
getCurrentLogFile() {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
108
|
+
for (const dir of CLAWDBOT_LOG_DIRS) {
|
|
109
|
+
if (!fs.existsSync(dir))
|
|
110
|
+
continue;
|
|
111
|
+
const commandsLog = path.join(dir, "commands.log");
|
|
112
|
+
if (fs.existsSync(commandsLog))
|
|
113
|
+
return commandsLog;
|
|
114
|
+
const today = new Date().toISOString().split("T")[0];
|
|
115
|
+
const dateLog = path.join(dir, `clawdbot-${today}.log`);
|
|
116
|
+
if (fs.existsSync(dateLog))
|
|
117
|
+
return dateLog;
|
|
118
|
+
try {
|
|
119
|
+
const files = fs.readdirSync(dir)
|
|
120
|
+
.filter(f => f.endsWith(".log"))
|
|
121
|
+
.map(f => ({ name: f, mtime: fs.statSync(path.join(dir, f)).mtimeMs }))
|
|
122
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
123
|
+
if (files.length > 0)
|
|
124
|
+
return path.join(dir, files[0].name);
|
|
125
|
+
}
|
|
126
|
+
catch { }
|
|
127
|
+
}
|
|
128
|
+
return null;
|
|
109
129
|
}
|
|
110
130
|
checkForLogFile() {
|
|
111
131
|
const logFile = this.getCurrentLogFile();
|
|
@@ -373,8 +393,69 @@ class LogWatcher extends events_1.EventEmitter {
|
|
|
373
393
|
return { subsystem, message, timestamp, logLevel, toolEvent };
|
|
374
394
|
}
|
|
375
395
|
catch {
|
|
396
|
+
return this.parsePlainTextLine(line);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
parsePlainTextLine(line) {
|
|
400
|
+
const trimmed = line.trim();
|
|
401
|
+
if (!trimmed || trimmed.length < 5)
|
|
376
402
|
return null;
|
|
403
|
+
const timestamp = new Date();
|
|
404
|
+
let toolEvent;
|
|
405
|
+
const timestampMatch = trimmed.match(/^\[?(\d{4}-\d{2}-\d{2}[T ]\d{2}:\d{2}:\d{2}[^\]]*)\]?\s*(.*)/);
|
|
406
|
+
const content = timestampMatch ? timestampMatch[2] : trimmed;
|
|
407
|
+
if (timestampMatch) {
|
|
408
|
+
try {
|
|
409
|
+
const d = new Date(timestampMatch[1]);
|
|
410
|
+
if (!isNaN(d.getTime()))
|
|
411
|
+
Object.assign(timestamp, { _parsed: d });
|
|
412
|
+
}
|
|
413
|
+
catch { }
|
|
414
|
+
}
|
|
415
|
+
const cmdMatch = content.match(/(?:command|cmd|exec|run|shell)\s*[=:]\s*(.+)/i);
|
|
416
|
+
if (cmdMatch) {
|
|
417
|
+
toolEvent = {
|
|
418
|
+
runId: `cmd-${Date.now()}`,
|
|
419
|
+
tool: "exec",
|
|
420
|
+
toolCallId: `cmd-${Date.now()}`,
|
|
421
|
+
phase: "start",
|
|
422
|
+
timestamp,
|
|
423
|
+
args: { command: cmdMatch[1].trim() },
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
const msgMatch = content.match(/(?:message|msg|body|text|input)\s*[=:]\s*(.+)/i);
|
|
427
|
+
if (!toolEvent && msgMatch) {
|
|
428
|
+
toolEvent = {
|
|
429
|
+
runId: `msg-${Date.now()}`,
|
|
430
|
+
tool: "whatsapp-inbound",
|
|
431
|
+
toolCallId: `msg-${Date.now()}`,
|
|
432
|
+
phase: "start",
|
|
433
|
+
timestamp,
|
|
434
|
+
args: { body: msgMatch[1].trim() },
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
const replyMatch = content.match(/(?:reply|response|answer|out)\s*[=:]\s*(.+)/i);
|
|
438
|
+
if (!toolEvent && replyMatch) {
|
|
439
|
+
toolEvent = {
|
|
440
|
+
runId: `reply-${Date.now()}`,
|
|
441
|
+
tool: "whatsapp-reply",
|
|
442
|
+
toolCallId: `reply-${Date.now()}`,
|
|
443
|
+
phase: "start",
|
|
444
|
+
timestamp,
|
|
445
|
+
args: { text: replyMatch[1].trim() },
|
|
446
|
+
};
|
|
447
|
+
}
|
|
448
|
+
if (!toolEvent && content.length > 3) {
|
|
449
|
+
toolEvent = {
|
|
450
|
+
runId: `log-${Date.now()}`,
|
|
451
|
+
tool: "agent-log",
|
|
452
|
+
toolCallId: `log-${Date.now()}`,
|
|
453
|
+
phase: "start",
|
|
454
|
+
timestamp,
|
|
455
|
+
args: { message: content },
|
|
456
|
+
};
|
|
377
457
|
}
|
|
458
|
+
return { message: content, timestamp, logLevel: "INFO", toolEvent };
|
|
378
459
|
}
|
|
379
460
|
extractToolArgs(json) {
|
|
380
461
|
const args = {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"threat-assessment.d.ts","sourceRoot":"","sources":["../../src/threat-assessment.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAC;IACzE,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;
|
|
1
|
+
{"version":3,"file":"threat-assessment.d.ts","sourceRoot":"","sources":["../../src/threat-assessment.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,GAAG,KAAK,CAAC;IACzE,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC1D,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,aAAa,EAAE,CAAC;IAC1B,OAAO,EAAE;QACP,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AAqeD,wBAAgB,mBAAmB,IAAI,gBAAgB,CAgDtD"}
|
|
@@ -29,7 +29,10 @@ const path = __importStar(require("path"));
|
|
|
29
29
|
const os = __importStar(require("os"));
|
|
30
30
|
const child_process_1 = require("child_process");
|
|
31
31
|
const CLAWGUARD_DIR = path.join(os.homedir(), ".clawguard");
|
|
32
|
-
const
|
|
32
|
+
const CLAWDBOT_LOG_DIRS = [
|
|
33
|
+
path.join(os.homedir(), ".clawdbot", "logs"),
|
|
34
|
+
"/tmp/clawdbot",
|
|
35
|
+
];
|
|
33
36
|
const SEVERITY_PENALTIES = {
|
|
34
37
|
critical: 25,
|
|
35
38
|
high: 15,
|
|
@@ -445,14 +448,16 @@ function checkBotSecurity() {
|
|
|
445
448
|
let credentialLeak = false;
|
|
446
449
|
let leakDetail = "";
|
|
447
450
|
try {
|
|
448
|
-
|
|
449
|
-
|
|
451
|
+
for (const logDir of CLAWDBOT_LOG_DIRS) {
|
|
452
|
+
if (!fs.existsSync(logDir))
|
|
453
|
+
continue;
|
|
454
|
+
const logFiles = fs.readdirSync(logDir)
|
|
450
455
|
.filter(f => f.endsWith(".log"))
|
|
451
456
|
.sort()
|
|
452
457
|
.slice(-3);
|
|
453
458
|
for (const file of logFiles) {
|
|
454
459
|
try {
|
|
455
|
-
const filePath = path.join(
|
|
460
|
+
const filePath = path.join(logDir, file);
|
|
456
461
|
const stat = fs.statSync(filePath);
|
|
457
462
|
const readSize = Math.min(stat.size, 50000);
|
|
458
463
|
const fd = fs.openSync(filePath, "r");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "averecion-lite",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.1",
|
|
4
4
|
"description": "Real-time AI agent monitoring - watches logs, detects dangerous commands and prompt injection attempts",
|
|
5
5
|
"author": "Averecion <hello@averecion.com>",
|
|
6
6
|
"homepage": "https://github.com/averecion/clawguard#readme",
|