matthewspring commited on
Commit
de6c4b6
·
verified ·
1 Parent(s): c535da0

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +1049 -1172
index.html CHANGED
@@ -1,1180 +1,1057 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
3
-
4
  <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <meta http-equiv="X-UA-Compatible" content="IE=edge">
8
- <meta name="description" content="Hardened Gemma 3 LLM Container Security Dashboard - Critical Fixes Applied">
9
- <title>Gemma 3 Hardened Container Dashboard - Critical Fixes v2.0</title>
10
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
11
- <style>
12
- :root {
13
- --primary: #1a1a2e;
14
- --secondary: #16213e;
15
- --accent: #0f3460;
16
- --highlight: #e94560;
17
- --success: #00d9a0;
18
- --warning: #ffc107;
19
- --danger: #dc3545;
20
- --info: #17a2b8;
21
- --light: #f8f9fa;
22
- --dark: #0a0a0f;
23
- --purple: #9b59b6;
24
- --orange: #e67e22;
25
- --fixed: #2ecc71;
26
- --shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
27
- --radius: 12px;
28
- --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
29
- }
30
-
31
- * {
32
- margin: 0;
33
- padding: 0;
34
- box-sizing: border-box;
35
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
36
- }
37
-
38
- body {
39
- background: linear-gradient(135deg, var(--dark) 0%, var(--primary) 50%, var(--secondary) 100%);
40
- color: var(--light);
41
- line-height: 1.6;
42
- min-height: 100vh;
43
- display: flex;
44
- flex-direction: column;
45
- }
46
-
47
- /* Header Styles */
48
- header {
49
- background: linear-gradient(135deg, rgba(26, 26, 46, 0.95) 0%, rgba(22, 33, 62, 0.95) 100%);
50
- backdrop-filter: blur(10px);
51
- color: white;
52
- padding: 1rem 2rem;
53
- box-shadow: var(--shadow);
54
- position: sticky;
55
- top: 0;
56
- z-index: 1000;
57
- border-bottom: 1px solid rgba(233, 69, 96, 0.3);
58
- }
59
-
60
- .header-content {
61
- display: flex;
62
- justify-content: space-between;
63
- align-items: center;
64
- max-width: 1800px;
65
- margin: 0 auto;
66
- width: 100%;
67
- flex-wrap: wrap;
68
- gap: 1rem;
69
- }
70
-
71
- .logo-container {
72
- display: flex;
73
- align-items: center;
74
- gap: 1rem;
75
- flex-wrap: wrap;
76
- }
77
-
78
- .logo {
79
- font-size: 1.5rem;
80
- font-weight: 700;
81
- display: flex;
82
- align-items: center;
83
- gap: 0.8rem;
84
- text-decoration: none;
85
- color: white;
86
- }
87
-
88
- .logo-icon {
89
- background: linear-gradient(135deg, var(--highlight), #ff6b6b);
90
- padding: 0.6rem;
91
- border-radius: 50%;
92
- display: flex;
93
- align-items: center;
94
- justify-content: center;
95
- box-shadow: 0 0 20px rgba(233, 69, 96, 0.4);
96
- }
97
-
98
- .model-badge {
99
- background: linear-gradient(135deg, var(--accent), var(--secondary));
100
- padding: 0.3rem 0.8rem;
101
- border-radius: 20px;
102
- font-size: 0.7rem;
103
- font-weight: 600;
104
- border: 1px solid rgba(233, 69, 96, 0.5);
105
- color: var(--highlight);
106
- }
107
-
108
- .version-badge {
109
- background: linear-gradient(135deg, var(--fixed), #27ae60);
110
- padding: 0.3rem 0.8rem;
111
- border-radius: 20px;
112
- font-size: 0.7rem;
113
- font-weight: 600;
114
- color: white;
115
- display: flex;
116
- align-items: center;
117
- gap: 0.3rem;
118
- }
119
-
120
- .fixes-badge {
121
- background: linear-gradient(135deg, var(--danger), #c0392b);
122
- padding: 0.3rem 0.8rem;
123
- border-radius: 20px;
124
- font-size: 0.7rem;
125
- font-weight: 600;
126
- color: white;
127
- animation: pulse-badge 2s infinite;
128
- }
129
-
130
- @keyframes pulse-badge {
131
- 0%, 100% { opacity: 1; }
132
- 50% { opacity: 0.7; }
133
- }
134
-
135
- .built-with {
136
- font-size: 0.85rem;
137
- opacity: 0.9;
138
- display: flex;
139
- align-items: center;
140
- gap: 0.5rem;
141
- }
142
-
143
- .built-with a {
144
- color: var(--highlight);
145
- text-decoration: none;
146
- font-weight: 500;
147
- transition: var(--transition);
148
- }
149
-
150
- .built-with a:hover {
151
- text-decoration: underline;
152
- text-shadow: 0 0 10px rgba(233, 69, 96, 0.5);
153
- }
154
-
155
- /* Navigation */
156
- nav ul {
157
- display: flex;
158
- list-style: none;
159
- gap: 0.5rem;
160
- flex-wrap: wrap;
161
- }
162
-
163
- nav a {
164
- color: white;
165
- text-decoration: none;
166
- padding: 0.5rem 1rem;
167
- border-radius: var(--radius);
168
- transition: var(--transition);
169
- font-weight: 500;
170
- font-size: 0.85rem;
171
- position: relative;
172
- }
173
-
174
- nav a:hover {
175
- background: rgba(233, 69, 96, 0.2);
176
- }
177
-
178
- /* Main Content */
179
- main {
180
- flex: 1;
181
- max-width: 1800px;
182
- margin: 2rem auto;
183
- padding: 0 1.5rem;
184
- width: 100%;
185
- }
186
-
187
- /* Critical Fixes Banner */
188
- .critical-fixes-banner {
189
- background: linear-gradient(135deg, rgba(220, 53, 69, 0.2) 0%, rgba(192, 57, 43, 0.2) 100%);
190
- border: 2px solid var(--danger);
191
- border-radius: var(--radius);
192
- padding: 1.5rem;
193
- margin-bottom: 2rem;
194
- position: relative;
195
- overflow: hidden;
196
- }
197
-
198
- .critical-fixes-banner::before {
199
- content: '';
200
- position: absolute;
201
- top: 0;
202
- left: 0;
203
- width: 100%;
204
- height: 4px;
205
- background: linear-gradient(90deg, var(--danger), var(--warning), var(--fixed));
206
- }
207
-
208
- .banner-header {
209
- display: flex;
210
- align-items: center;
211
- gap: 1rem;
212
- margin-bottom: 1rem;
213
- }
214
-
215
- .banner-icon {
216
- width: 50px;
217
- height: 50px;
218
- background: var(--danger);
219
- border-radius: 50%;
220
- display: flex;
221
- align-items: center;
222
- justify-content: center;
223
- font-size: 1.5rem;
224
- color: white;
225
- animation: pulse 2s infinite;
226
- }
227
-
228
- .banner-title {
229
- font-size: 1.4rem;
230
- font-weight: 700;
231
- color: var(--danger);
232
- }
233
-
234
- .banner-subtitle {
235
- color: rgba(255, 255, 255, 0.8);
236
- font-size: 0.9rem;
237
- }
238
-
239
- .fixes-summary {
240
- display: grid;
241
- grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
242
- gap: 1rem;
243
- margin-top: 1rem;
244
- }
245
-
246
- .fix-item {
247
- background: rgba(0, 0, 0, 0.3);
248
- border-radius: 8px;
249
- padding: 1rem;
250
- display: flex;
251
- align-items: flex-start;
252
- gap: 0.8rem;
253
- }
254
-
255
- .fix-status {
256
- width: 24px;
257
- height: 24px;
258
- border-radius: 50%;
259
- display: flex;
260
- align-items: center;
261
- justify-content: center;
262
- font-size: 0.75rem;
263
- flex-shrink: 0;
264
- }
265
-
266
- .fix-status.fixed {
267
- background: var(--fixed);
268
- color: white;
269
- }
270
-
271
- .fix-status.critical {
272
- background: var(--danger);
273
- color: white;
274
- }
275
-
276
- .fix-content h4 {
277
- color: var(--light);
278
- font-size: 0.9rem;
279
- margin-bottom: 0.3rem;
280
- }
281
-
282
- .fix-content p {
283
- color: rgba(255, 255, 255, 0.7);
284
- font-size: 0.8rem;
285
- }
286
-
287
- /* Section Title */
288
- .section-title-main {
289
- font-size: 1.6rem;
290
- margin-bottom: 1.5rem;
291
- color: var(--light);
292
- display: flex;
293
- align-items: center;
294
- gap: 0.8rem;
295
- }
296
-
297
- .section-title-main i {
298
- color: var(--highlight);
299
- }
300
-
301
- /* Flaw Analysis Section */
302
- .flaw-analysis {
303
- background: linear-gradient(135deg, rgba(26, 26, 46, 0.95) 0%, rgba(22, 33, 62, 0.95) 100%);
304
- border-radius: var(--radius);
305
- padding: 2rem;
306
- margin-bottom: 2rem;
307
- border: 1px solid rgba(220, 53, 69, 0.3);
308
- }
309
-
310
- .flaw-card {
311
- background: rgba(0, 0, 0, 0.3);
312
- border-radius: 8px;
313
- margin-bottom: 1.5rem;
314
- overflow: hidden;
315
- border: 1px solid rgba(255, 255, 255, 0.1);
316
- }
317
-
318
- .flaw-header {
319
- background: rgba(220, 53, 69, 0.2);
320
- padding: 1rem 1.5rem;
321
- display: flex;
322
- align-items: center;
323
- justify-content: space-between;
324
- border-bottom: 1px solid rgba(220, 53, 69, 0.3);
325
- flex-wrap: wrap;
326
- gap: 0.5rem;
327
- }
328
-
329
- .flaw-header.fixed {
330
- background: rgba(46, 204, 113, 0.2);
331
- border-bottom-color: rgba(46, 204, 113, 0.3);
332
- }
333
-
334
- .flaw-title {
335
- display: flex;
336
- align-items: center;
337
- gap: 0.8rem;
338
- font-weight: 600;
339
- color: var(--light);
340
- }
341
-
342
- .flaw-title i {
343
- color: var(--danger);
344
- }
345
-
346
- .flaw-header.fixed .flaw-title i {
347
- color: var(--fixed);
348
- }
349
-
350
- .flaw-severity {
351
- padding: 0.3rem 0.8rem;
352
- border-radius: 20px;
353
- font-size: 0.7rem;
354
- font-weight: 600;
355
- text-transform: uppercase;
356
- }
357
-
358
- .severity-critical {
359
- background: var(--danger);
360
- color: white;
361
- }
362
-
363
- .severity-fixed {
364
- background: var(--fixed);
365
- color: white;
366
- }
367
-
368
- .flaw-body {
369
- padding: 1.5rem;
370
- }
371
-
372
- .flaw-section {
373
- margin-bottom: 1.5rem;
374
- }
375
-
376
- .flaw-section:last-child {
377
- margin-bottom: 0;
378
- }
379
-
380
- .flaw-section-title {
381
- font-size: 0.9rem;
382
- font-weight: 600;
383
- color: var(--highlight);
384
- margin-bottom: 0.5rem;
385
- display: flex;
386
- align-items: center;
387
- gap: 0.5rem;
388
- }
389
-
390
- .flaw-section-content {
391
- color: rgba(255, 255, 255, 0.8);
392
- font-size: 0.85rem;
393
- line-height: 1.7;
394
- }
395
-
396
- .comparison-grid {
397
- display: grid;
398
- grid-template-columns: 1fr 1fr;
399
- gap: 1rem;
400
- margin-top: 1rem;
401
- }
402
-
403
- @media (max-width: 768px) {
404
- .comparison-grid {
405
- grid-template-columns: 1fr;
406
- }
407
- }
408
-
409
- .comparison-box {
410
- background: rgba(0, 0, 0, 0.3);
411
- border-radius: 8px;
412
- padding: 1rem;
413
- border: 1px solid rgba(255, 255, 255, 0.1);
414
- }
415
-
416
- .comparison-box.before {
417
- border-color: rgba(220, 53, 69, 0.5);
418
- }
419
-
420
- .comparison-box.after {
421
- border-color: rgba(46, 204, 113, 0.5);
422
- }
423
-
424
- .comparison-label {
425
- font-size: 0.75rem;
426
- font-weight: 600;
427
- text-transform: uppercase;
428
- margin-bottom: 0.5rem;
429
- display: flex;
430
- align-items: center;
431
- gap: 0.3rem;
432
- }
433
-
434
- .comparison-box.before .comparison-label {
435
- color: var(--danger);
436
- }
437
-
438
- .comparison-box.after .comparison-label {
439
- color: var(--fixed);
440
- }
441
-
442
- /* Code Block */
443
- .code-block {
444
- background: rgba(0, 0, 0, 0.5);
445
- border-radius: 8px;
446
- padding: 1rem;
447
- font-family: 'Fira Code', 'Courier New', monospace;
448
- font-size: 0.75rem;
449
- overflow-x: auto;
450
- border: 1px solid rgba(255, 255, 255, 0.1);
451
- margin: 0.5rem 0;
452
- white-space: pre-wrap;
453
- word-break: break-all;
454
- line-height: 1.6;
455
- }
456
-
457
- .code-block .comment {
458
- color: #6a9955;
459
- }
460
-
461
- .code-block .keyword {
462
- color: #569cd6;
463
- }
464
-
465
- .code-block .string {
466
- color: #ce9178;
467
- }
468
-
469
- .code-block .function {
470
- color: #dcdcaa;
471
- }
472
-
473
- .code-block .class {
474
- color: #4ec9b0;
475
- }
476
-
477
- .code-block .decorator {
478
- color: #c586c0;
479
- }
480
-
481
- .code-block .number {
482
- color: #b5cea8;
483
- }
484
-
485
- .code-block .error {
486
- color: #f44747;
487
- text-decoration: line-through;
488
- }
489
-
490
- .code-block .correct {
491
- color: #4ec9b0;
492
- }
493
-
494
- .code-block .highlight-line {
495
- background: rgba(233, 69, 96, 0.2);
496
- display: block;
497
- margin: 0 -1rem;
498
- padding: 0 1rem;
499
- }
500
-
501
- .code-block .fixed-line {
502
- background: rgba(46, 204, 113, 0.2);
503
- display: block;
504
- margin: 0 -1rem;
505
- padding: 0 1rem;
506
- }
507
-
508
- /* Dashboard Grid */
509
- .dashboard-grid {
510
- display: grid;
511
- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
512
- gap: 1.5rem;
513
- margin-bottom: 2rem;
514
- }
515
-
516
- /* Card Styles */
517
- .card {
518
- background: linear-gradient(135deg, rgba(26, 26, 46, 0.9) 0%, rgba(22, 33, 62, 0.9) 100%);
519
- backdrop-filter: blur(10px);
520
- border-radius: var(--radius);
521
- box-shadow: var(--shadow);
522
- padding: 1.5rem;
523
- transition: var(--transition);
524
- position: relative;
525
- overflow: hidden;
526
- display: flex;
527
- flex-direction: column;
528
- border: 1px solid rgba(255, 255, 255, 0.1);
529
- }
530
-
531
- .card:hover {
532
- transform: translateY(-5px);
533
- box-shadow: 0 8px 30px rgba(233, 69, 96, 0.2);
534
- border-color: rgba(233, 69, 96, 0.3);
535
- }
536
-
537
- .card::before {
538
- content: '';
539
- position: absolute;
540
- top: 0;
541
- left: 0;
542
- width: 100%;
543
- height: 3px;
544
- background: linear-gradient(90deg, var(--highlight), var(--success));
545
- }
546
-
547
- .card.fixed::before {
548
- background: linear-gradient(90deg, var(--fixed), #27ae60);
549
- }
550
-
551
- .card.critical::before {
552
- background: linear-gradient(90deg, var(--danger), var(--warning));
553
- }
554
-
555
- .card-badge {
556
- position: absolute;
557
- top: 1rem;
558
- right: 1rem;
559
- padding: 0.2rem 0.6rem;
560
- border-radius: 12px;
561
- font-size: 0.65rem;
562
- font-weight: 600;
563
- text-transform: uppercase;
564
- }
565
-
566
- .badge-fixed {
567
- background: var(--fixed);
568
- color: white;
569
- }
570
-
571
- .badge-critical {
572
- background: var(--danger);
573
- color: white;
574
- }
575
-
576
- .card-icon {
577
- width: 48px;
578
- height: 48px;
579
- border-radius: 50%;
580
- display: flex;
581
- align-items: center;
582
- justify-content: center;
583
- font-size: 1.3rem;
584
- margin-bottom: 1rem;
585
- background: linear-gradient(135deg, var(--highlight), #ff6b6b);
586
- color: white;
587
- box-shadow: 0 4px 15px rgba(233, 69, 96, 0.3);
588
- }
589
-
590
- .card-icon.green {
591
- background: linear-gradient(135deg, var(--fixed), #27ae60);
592
- }
593
-
594
- .card-icon.blue {
595
- background: linear-gradient(135deg, var(--info), #138496);
596
- }
597
-
598
- .card-icon.orange {
599
- background: linear-gradient(135deg, var(--orange), #d35400);
600
- }
601
-
602
- .card-title {
603
- font-size: 1.1rem;
604
- margin-bottom: 0.6rem;
605
- color: var(--light);
606
- font-weight: 600;
607
- }
608
-
609
- .card-description {
610
- color: rgba(255, 255, 255, 0.7);
611
- margin-bottom: 1rem;
612
- flex: 1;
613
- font-size: 0.85rem;
614
- }
615
-
616
- .card-status {
617
- display: flex;
618
- align-items: center;
619
- gap: 0.5rem;
620
- margin-top: auto;
621
- }
622
-
623
- .status-indicator {
624
- width: 10px;
625
- height: 10px;
626
- border-radius: 50%;
627
- background: var(--success);
628
- box-shadow: 0 0 10px rgba(0, 217, 160, 0.5);
629
- animation: pulse 2s infinite;
630
- }
631
-
632
- @keyframes pulse {
633
- 0%, 100% { opacity: 1; }
634
- 50% { opacity: 0.6; }
635
- }
636
-
637
- .status-text {
638
- font-size: 0.85rem;
639
- font-weight: 500;
640
- }
641
-
642
- /* Script Section */
643
- .script-section {
644
- background: linear-gradient(135deg, rgba(26, 26, 46, 0.95) 0%, rgba(22, 33, 62, 0.95) 100%);
645
- border-radius: var(--radius);
646
- padding: 1.5rem;
647
- margin-bottom: 2rem;
648
- border: 1px solid rgba(255, 255, 255, 0.1);
649
- }
650
-
651
- .script-header {
652
- display: flex;
653
- justify-content: space-between;
654
- align-items: center;
655
- margin-bottom: 1rem;
656
- flex-wrap: wrap;
657
- gap: 1rem;
658
- }
659
-
660
- .script-title {
661
- font-size: 1.2rem;
662
- color: var(--light);
663
- display: flex;
664
- align-items: center;
665
- gap: 0.5rem;
666
- }
667
-
668
- .script-title i {
669
- color: var(--highlight);
670
- }
671
-
672
- .script-container {
673
- background: rgba(0, 0, 0, 0.5);
674
- border-radius: 8px;
675
- overflow: hidden;
676
- border: 1px solid rgba(255, 255, 255, 0.1);
677
- }
678
-
679
- .script-tabs {
680
- display: flex;
681
- background: rgba(0, 0, 0, 0.3);
682
- border-bottom: 1px solid rgba(255, 255, 255, 0.1);
683
- overflow-x: auto;
684
- }
685
-
686
- .script-tab {
687
- padding: 0.8rem 1.2rem;
688
- background: none;
689
- border: none;
690
- color: rgba(255, 255, 255, 0.7);
691
- cursor: pointer;
692
- transition: var(--transition);
693
- font-size: 0.8rem;
694
- border-bottom: 2px solid transparent;
695
- white-space: nowrap;
696
- }
697
-
698
- .script-tab:hover {
699
- color: var(--light);
700
- background: rgba(255, 255, 255, 0.05);
701
- }
702
-
703
- .script-tab.active {
704
- color: var(--highlight);
705
- border-bottom-color: var(--highlight);
706
- background: rgba(233, 69, 96, 0.1);
707
- }
708
-
709
- .script-content {
710
- padding: 1rem;
711
- max-height: 600px;
712
- overflow-y: auto;
713
- }
714
-
715
- .script-content pre {
716
- margin: 0;
717
- font-family: 'Fira Code', 'Courier New', monospace;
718
- font-size: 0.72rem;
719
- line-height: 1.5;
720
- color: #d4d4d4;
721
- }
722
-
723
- /* Buttons */
724
- .btn {
725
- padding: 0.5rem 1rem;
726
- border-radius: 8px;
727
- text-decoration: none;
728
- font-weight: 500;
729
- transition: var(--transition);
730
- border: none;
731
- cursor: pointer;
732
- display: inline-flex;
733
- align-items: center;
734
- gap: 0.5rem;
735
- font-size: 0.85rem;
736
- }
737
-
738
- .btn-primary {
739
- background: linear-gradient(135deg, var(--highlight), #ff6b6b);
740
- color: white;
741
- }
742
-
743
- .btn-primary:hover {
744
- transform: translateY(-2px);
745
- box-shadow: 0 4px 15px rgba(233, 69, 96, 0.4);
746
- }
747
-
748
- .btn-success {
749
- background: linear-gradient(135deg, var(--fixed), #27ae60);
750
- color: white;
751
- }
752
-
753
- .btn-success:hover {
754
- transform: translateY(-2px);
755
- box-shadow: 0 4px 15px rgba(46, 204, 113, 0.4);
756
- }
757
-
758
- .btn-secondary {
759
- background: rgba(255, 255, 255, 0.1);
760
- color: var(--light);
761
- border: 1px solid rgba(255, 255, 255, 0.2);
762
- }
763
-
764
- .btn-secondary:hover {
765
- background: rgba(255, 255, 255, 0.2);
766
- }
767
-
768
- /* Alert Box */
769
- .alert {
770
- padding: 1rem 1.2rem;
771
- border-radius: 8px;
772
- margin-bottom: 1rem;
773
- display: flex;
774
- align-items: flex-start;
775
- gap: 0.8rem;
776
- }
777
-
778
- .alert-success {
779
- background: rgba(46, 204, 113, 0.15);
780
- border: 1px solid rgba(46, 204, 113, 0.3);
781
- color: var(--fixed);
782
- }
783
-
784
- .alert-danger {
785
- background: rgba(220, 53, 69, 0.15);
786
- border: 1px solid rgba(220, 53, 69, 0.3);
787
- color: var(--danger);
788
- }
789
-
790
- .alert-warning {
791
- background: rgba(255, 193, 7, 0.15);
792
- border: 1px solid rgba(255, 193, 7, 0.3);
793
- color: var(--warning);
794
- }
795
-
796
- .alert-info {
797
- background: rgba(23, 162, 184, 0.15);
798
- border: 1px solid rgba(23, 162, 184, 0.3);
799
- color: var(--info);
800
- }
801
-
802
- .alert i {
803
- font-size: 1.2rem;
804
- margin-top: 0.1rem;
805
- }
806
-
807
- .alert-content {
808
- flex: 1;
809
- }
810
-
811
- .alert-title {
812
- font-weight: 600;
813
- margin-bottom: 0.3rem;
814
- }
815
-
816
- .alert-text {
817
- font-size: 0.85rem;
818
- opacity: 0.9;
819
- }
820
-
821
- /* Security Score */
822
- .security-score-container {
823
- background: linear-gradient(135deg, rgba(26, 26, 46, 0.95) 0%, rgba(22, 33, 62, 0.95) 100%);
824
- border-radius: var(--radius);
825
- padding: 2rem;
826
- margin-bottom: 2rem;
827
- border: 1px solid rgba(46, 204, 113, 0.3);
828
- display: grid;
829
- grid-template-columns: auto 1fr;
830
- gap: 2rem;
831
- align-items: center;
832
- }
833
-
834
- @media (max-width: 768px) {
835
- .security-score-container {
836
- grid-template-columns: 1fr;
837
- text-align: center;
838
- }
839
- }
840
-
841
- .score-circle {
842
- width: 140px;
843
- height: 140px;
844
- border-radius: 50%;
845
- background: conic-gradient(var(--fixed) 0deg, var(--fixed) 342deg, rgba(255, 255, 255, 0.1) 342deg);
846
- display: flex;
847
- align-items: center;
848
- justify-content: center;
849
- position: relative;
850
- margin: 0 auto;
851
- }
852
-
853
- .score-circle::before {
854
- content: '';
855
- position: absolute;
856
- width: 110px;
857
- height: 110px;
858
- background: var(--primary);
859
- border-radius: 50%;
860
- }
861
-
862
- .score-value {
863
- position: relative;
864
- z-index: 1;
865
- font-size: 2.2rem;
866
- font-weight: 700;
867
- color: var(--fixed);
868
- }
869
-
870
- .score-details {
871
- flex: 1;
872
- }
873
-
874
- .score-title {
875
- font-size: 1.4rem;
876
- margin-bottom: 0.5rem;
877
- color: var(--light);
878
- }
879
-
880
- .score-subtitle {
881
- color: rgba(255, 255, 255, 0.7);
882
- margin-bottom: 1rem;
883
- font-size: 0.9rem;
884
- }
885
-
886
- .score-breakdown {
887
- display: grid;
888
- grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
889
- gap: 0.8rem;
890
- }
891
-
892
- .score-item {
893
- background: rgba(255, 255, 255, 0.05);
894
- padding: 0.6rem;
895
- border-radius: 8px;
896
- text-align: center;
897
- }
898
-
899
- .score-item-value {
900
- font-size: 1.2rem;
901
- font-weight: 600;
902
- color: var(--fixed);
903
- }
904
-
905
- .score-item-label {
906
- font-size: 0.7rem;
907
- color: rgba(255, 255, 255, 0.6);
908
- text-transform: uppercase;
909
- }
910
-
911
- /* Checklist */
912
- .checklist {
913
- list-style: none;
914
- padding: 0;
915
- }
916
-
917
- .checklist-item {
918
- display: flex;
919
- align-items: flex-start;
920
- gap: 0.8rem;
921
- padding: 0.8rem;
922
- background: rgba(255, 255, 255, 0.03);
923
- border-radius: 8px;
924
- margin-bottom: 0.5rem;
925
- transition: var(--transition);
926
- }
927
-
928
- .checklist-item:hover {
929
- background: rgba(255, 255, 255, 0.06);
930
- }
931
-
932
- .checklist-icon {
933
- width: 24px;
934
- height: 24px;
935
- border-radius: 50%;
936
- display: flex;
937
- align-items: center;
938
- justify-content: center;
939
- font-size: 0.7rem;
940
- flex-shrink: 0;
941
- }
942
-
943
- .checklist-icon.done {
944
- background: var(--fixed);
945
- color: white;
946
- }
947
-
948
- .checklist-icon.fixed {
949
- background: var(--info);
950
- color: white;
951
- }
952
-
953
- .checklist-content {
954
- flex: 1;
955
- }
956
-
957
- .checklist-title {
958
- font-weight: 600;
959
- color: var(--light);
960
- font-size: 0.85rem;
961
- margin-bottom: 0.2rem;
962
- }
963
-
964
- .checklist-description {
965
- color: rgba(255, 255, 255, 0.6);
966
- font-size: 0.75rem;
967
- }
968
-
969
- /* Footer */
970
- footer {
971
- background: linear-gradient(135deg, rgba(26, 26, 46, 0.98) 0%, rgba(22, 33, 62, 0.98) 100%);
972
- padding: 2rem;
973
- text-align: center;
974
- border-top: 1px solid rgba(255, 255, 255, 0.1);
975
- }
976
-
977
- .footer-content {
978
- max-width: 1200px;
979
- margin: 0 auto;
980
- }
981
-
982
- .footer-text {
983
- color: rgba(255, 255, 255, 0.7);
984
- font-size: 0.85rem;
985
- margin-bottom: 0.5rem;
986
- }
987
-
988
- .footer-links {
989
- display: flex;
990
- justify-content: center;
991
- gap: 1.5rem;
992
- flex-wrap: wrap;
993
- }
994
-
995
- .footer-links a {
996
- color: var(--highlight);
997
- text-decoration: none;
998
- font-size: 0.85rem;
999
- transition: var(--transition);
1000
- }
1001
-
1002
- .footer-links a:hover {
1003
- text-decoration: underline;
1004
- }
1005
-
1006
- /* Responsive */
1007
- @media (max-width: 768px) {
1008
- header {
1009
- padding: 1rem;
1010
- }
1011
-
1012
- .header-content {
1013
- flex-direction: column;
1014
- align-items: flex-start;
1015
- }
1016
-
1017
- .logo {
1018
- font-size: 1.2rem;
1019
- }
1020
-
1021
- nav ul {
1022
- width: 100%;
1023
- justify-content: flex-start;
1024
- }
1025
-
1026
- main {
1027
- padding: 0 1rem;
1028
- }
1029
-
1030
- .section-title-main {
1031
- font-size: 1.3rem;
1032
- }
1033
-
1034
- .dashboard-grid {
1035
- grid-template-columns: 1fr;
1036
- }
1037
- }
1038
-
1039
- /* Copy Button */
1040
- .copy-btn {
1041
- position: absolute;
1042
- top: 0.5rem;
1043
- right: 0.5rem;
1044
- background: rgba(255, 255, 255, 0.1);
1045
- border: none;
1046
- color: rgba(255, 255, 255, 0.7);
1047
- padding: 0.4rem 0.6rem;
1048
- border-radius: 4px;
1049
- cursor: pointer;
1050
- font-size: 0.7rem;
1051
- transition: var(--transition);
1052
- }
1053
-
1054
- .copy-btn:hover {
1055
- background: rgba(255, 255, 255, 0.2);
1056
- color: var(--light);
1057
- }
1058
-
1059
- .copy-btn.copied {
1060
- background: var(--fixed);
1061
- color: white;
1062
- }
1063
-
1064
- /* Entropy Visualization */
1065
- .entropy-visual {
1066
- display: flex;
1067
- gap: 2px;
1068
- margin: 1rem 0;
1069
- flex-wrap: wrap;
1070
- }
1071
-
1072
- .entropy-block {
1073
- width: 8px;
1074
- height: 20px;
1075
- border-radius: 2px;
1076
- transition: var(--transition);
1077
- }
1078
-
1079
- .entropy-block.high {
1080
- background: var(--fixed);
1081
- }
1082
-
1083
- .entropy-block.medium {
1084
- background: var(--warning);
1085
- }
1086
-
1087
- .entropy-block.low {
1088
- background: var(--danger);
1089
- }
1090
- </style>
1091
  </head>
1092
-
1093
  <body>
1094
- <header>
1095
- <div class="header-content">
1096
- <div class="logo-container">
1097
- <a href="#" class="logo">
1098
- <span class="logo-icon"><i class="fas fa-shield-halved"></i></span>
1099
- Gemma 3 Hardened Container
1100
- </a>
1101
- <span class="model-badge">gemma-3-12b-it-abliterated-v2.q4_k_m.gguf</span>
1102
- <span class="version-badge"><i class="fas fa-wrench"></i> v2.0 - Critical Fixes</span>
1103
- <span class="fixes-badge"><i class="fas fa-bug"></i> 3 Flaws Resolved</span>
1104
- </div>
1105
- <div class="built-with">
1106
- <span>Built with</span>
1107
- <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a>
1108
- </div>
1109
- </div>
1110
- <nav>
1111
- <ul>
1112
- <li><a href="#fixes"><i class="fas fa-tools"></i> Critical Fixes</a></li>
1113
- <li><a href="#implementation"><i class="fas fa-code"></i> Implementation</a></li>
1114
- <li><a href="#scripts"><i class="fas fa-terminal"></i> Scripts</a></li>
1115
- <li><a href="#verification"><i class="fas fa-check-double"></i> Verification</a></li>
1116
- </ul>
1117
- </nav>
1118
- </header>
1119
-
1120
- <main>
1121
- <!-- Critical Fixes Banner -->
1122
- <section class="critical-fixes-banner" id="fixes">
1123
- <div class="banner-header">
1124
- <div class="banner-icon">
1125
- <i class="fas fa-exclamation-triangle"></i>
1126
- </div>
1127
- <div>
1128
- <h2 class="banner-title">Critical Implementation Flaws - RESOLVED</h2>
1129
- <p class="banner-subtitle">All identified security and functionality issues have been addressed in this version</p>
1130
  </div>
1131
- </div>
1132
- <div class="fixes-summary">
1133
- <div class="fix-item">
1134
- <div class="fix-status fixed"><i class="fas fa-check"></i></div>
1135
- <div class="fix-content">
1136
- <h4>Logging Paradox (DoS Fix)</h4>
1137
- <p>Removed FileHandler, now using stdout/stderr with Docker log driver</p>
1138
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1139
  </div>
1140
- <div class="fix-item">
1141
- <div class="fix-status fixed"><i class="fas fa-check"></i></div>
1142
- <div class="fix-content">
1143
- <h4>Remount Fallacy Removed</h4>
1144
- <p>Eliminated privileged mount command that would fail without CAP_SYS_ADMIN</p>
1145
- </div>
1146
- </div>
1147
- <div class="fix-item">
1148
- <div class="fix-status fixed"><i class="fas fa-check"></i></div>
1149
- <div class="fix-content">
1150
- <h4>Entropy Source Hardened</h4>
1151
- <p>Added hardware RNG verification and /dev/random blocking for crypto operations</p>
1152
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1153
  </div>
1154
- </div>
1155
- </section>
1156
-
1157
- <!-- Security Score -->
1158
- <section class="security-score-container">
1159
- <div class="score-circle">
1160
- <span class="score-value">95%</span>
1161
- </div>
1162
- <div class="score-details">
1163
- <h2 class="score-title">Security Posture Score - Post-Fix</h2>
1164
- <p class="score-subtitle">All critical implementation flaws resolved. Container now production-ready.</p>
1165
- <div class="score-breakdown">
1166
- <div class="score-item">
1167
- <div class="score-item-value">✓</div>
1168
- <div class="score-item-label">Logging Fixed</div>
1169
- </div>
1170
- <div class="score-item">
1171
- <div class="score-item-value">✓</div>
1172
- <div class="score-item-label">RO Filesystem</div>
1173
- </div>
1174
- <div class="score-item">
1175
- <div class="score-item-value">✓</div>
1176
- <div class="score-item-label">Entropy Secure</div>
1177
- </div>
1178
- <div class="score-item">
1179
- <div class="score-item-value">✓</div>
1180
- <div class="score
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Gemma 3 Hardened Container - Ubuntu Scripts</title>
7
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
8
+ <style>
9
+ :root {
10
+ --primary: #1a1a2e;
11
+ --secondary: #16213e;
12
+ --accent: #0f3460;
13
+ --highlight: #e94560;
14
+ --success: #00d9a0;
15
+ --warning: #ffc107;
16
+ --danger: #dc3545;
17
+ --info: #17a2b8;
18
+ --light: #f8f9fa;
19
+ --dark: #0a0a0f;
20
+ --fixed: #2ecc71;
21
+ --ubuntu: #E95420;
22
+ --shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
23
+ --radius: 12px;
24
+ --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
25
+ }
26
+
27
+ * {
28
+ margin: 0;
29
+ padding: 0;
30
+ box-sizing: border-box;
31
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
32
+ }
33
+
34
+ body {
35
+ background: linear-gradient(135deg, var(--dark) 0%, var(--primary) 50%, var(--secondary) 100%);
36
+ color: var(--light);
37
+ line-height: 1.6;
38
+ min-height: 100vh;
39
+ }
40
+
41
+ header {
42
+ background: linear-gradient(135deg, rgba(233, 84, 32, 0.9) 0%, rgba(26, 26, 46, 0.95) 100%);
43
+ padding: 1.5rem 2rem;
44
+ border-bottom: 3px solid var(--ubuntu);
45
+ }
46
+
47
+ .header-content {
48
+ max-width: 1400px;
49
+ margin: 0 auto;
50
+ display: flex;
51
+ justify-content: space-between;
52
+ align-items: center;
53
+ flex-wrap: wrap;
54
+ gap: 1rem;
55
+ }
56
+
57
+ .logo {
58
+ display: flex;
59
+ align-items: center;
60
+ gap: 1rem;
61
+ text-decoration: none;
62
+ color: white;
63
+ }
64
+
65
+ .logo-icon {
66
+ width: 50px;
67
+ height: 50px;
68
+ background: white;
69
+ border-radius: 50%;
70
+ display: flex;
71
+ align-items: center;
72
+ justify-content: center;
73
+ }
74
+
75
+ .logo-icon i {
76
+ font-size: 1.5rem;
77
+ color: var(--ubuntu);
78
+ }
79
+
80
+ .logo-text h1 {
81
+ font-size: 1.4rem;
82
+ font-weight: 700;
83
+ }
84
+
85
+ .logo-text span {
86
+ font-size: 0.8rem;
87
+ opacity: 0.9;
88
+ }
89
+
90
+ .built-with {
91
+ font-size: 0.9rem;
92
+ }
93
+
94
+ .built-with a {
95
+ color: var(--warning);
96
+ text-decoration: none;
97
+ font-weight: 600;
98
+ }
99
+
100
+ .built-with a:hover {
101
+ text-decoration: underline;
102
+ }
103
+
104
+ main {
105
+ max-width: 1400px;
106
+ margin: 2rem auto;
107
+ padding: 0 1.5rem;
108
+ }
109
+
110
+ .intro-section {
111
+ background: linear-gradient(135deg, rgba(233, 84, 32, 0.15) 0%, rgba(26, 26, 46, 0.9) 100%);
112
+ border: 1px solid var(--ubuntu);
113
+ border-radius: var(--radius);
114
+ padding: 2rem;
115
+ margin-bottom: 2rem;
116
+ }
117
+
118
+ .intro-header {
119
+ display: flex;
120
+ align-items: center;
121
+ gap: 1rem;
122
+ margin-bottom: 1.5rem;
123
+ }
124
+
125
+ .intro-icon {
126
+ width: 60px;
127
+ height: 60px;
128
+ background: var(--ubuntu);
129
+ border-radius: 50%;
130
+ display: flex;
131
+ align-items: center;
132
+ justify-content: center;
133
+ font-size: 1.8rem;
134
+ }
135
+
136
+ .intro-title {
137
+ font-size: 1.6rem;
138
+ color: var(--light);
139
+ }
140
+
141
+ .intro-subtitle {
142
+ color: rgba(255,255,255,0.7);
143
+ font-size: 0.95rem;
144
+ }
145
+
146
+ .quick-start {
147
+ background: rgba(0,0,0,0.4);
148
+ border-radius: 8px;
149
+ padding: 1.5rem;
150
+ margin-top: 1.5rem;
151
+ }
152
+
153
+ .quick-start h3 {
154
+ color: var(--success);
155
+ margin-bottom: 1rem;
156
+ display: flex;
157
+ align-items: center;
158
+ gap: 0.5rem;
159
+ }
160
+
161
+ .quick-start-code {
162
+ background: rgba(0,0,0,0.5);
163
+ border-radius: 6px;
164
+ padding: 1rem;
165
+ font-family: 'Fira Code', 'Courier New', monospace;
166
+ font-size: 0.85rem;
167
+ overflow-x: auto;
168
+ }
169
+
170
+ .quick-start-code .comment {
171
+ color: #6a9955;
172
+ }
173
+
174
+ .quick-start-code .command {
175
+ color: #dcdcaa;
176
+ }
177
+
178
+ .scripts-grid {
179
+ display: grid;
180
+ grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
181
+ gap: 1.5rem;
182
+ margin-bottom: 2rem;
183
+ }
184
+
185
+ .script-card {
186
+ background: linear-gradient(135deg, rgba(26, 26, 46, 0.95) 0%, rgba(22, 33, 62, 0.95) 100%);
187
+ border-radius: var(--radius);
188
+ border: 1px solid rgba(255,255,255,0.1);
189
+ overflow: hidden;
190
+ transition: var(--transition);
191
+ }
192
+
193
+ .script-card:hover {
194
+ border-color: var(--ubuntu);
195
+ transform: translateY(-3px);
196
+ box-shadow: 0 10px 30px rgba(233, 84, 32, 0.2);
197
+ }
198
+
199
+ .script-card-header {
200
+ background: linear-gradient(135deg, var(--ubuntu), #c0392b);
201
+ padding: 1.2rem 1.5rem;
202
+ display: flex;
203
+ align-items: center;
204
+ justify-content: space-between;
205
+ }
206
+
207
+ .script-card-title {
208
+ display: flex;
209
+ align-items: center;
210
+ gap: 0.8rem;
211
+ font-weight: 600;
212
+ font-size: 1rem;
213
+ }
214
+
215
+ .script-card-title i {
216
+ font-size: 1.2rem;
217
+ }
218
+
219
+ .script-badge {
220
+ background: rgba(255,255,255,0.2);
221
+ padding: 0.3rem 0.8rem;
222
+ border-radius: 20px;
223
+ font-size: 0.7rem;
224
+ font-weight: 600;
225
+ }
226
+
227
+ .script-card-body {
228
+ padding: 1.5rem;
229
+ }
230
+
231
+ .script-description {
232
+ color: rgba(255,255,255,0.8);
233
+ font-size: 0.9rem;
234
+ margin-bottom: 1rem;
235
+ line-height: 1.6;
236
+ }
237
+
238
+ .script-features {
239
+ list-style: none;
240
+ margin-bottom: 1.5rem;
241
+ }
242
+
243
+ .script-features li {
244
+ display: flex;
245
+ align-items: center;
246
+ gap: 0.6rem;
247
+ padding: 0.4rem 0;
248
+ font-size: 0.85rem;
249
+ color: rgba(255,255,255,0.7);
250
+ }
251
+
252
+ .script-features li i {
253
+ color: var(--success);
254
+ font-size: 0.8rem;
255
+ }
256
+
257
+ .script-actions {
258
+ display: flex;
259
+ gap: 0.8rem;
260
+ flex-wrap: wrap;
261
+ }
262
+
263
+ .btn {
264
+ padding: 0.6rem 1.2rem;
265
+ border-radius: 8px;
266
+ border: none;
267
+ cursor: pointer;
268
+ font-weight: 600;
269
+ font-size: 0.85rem;
270
+ display: inline-flex;
271
+ align-items: center;
272
+ gap: 0.5rem;
273
+ transition: var(--transition);
274
+ text-decoration: none;
275
+ }
276
+
277
+ .btn-primary {
278
+ background: var(--ubuntu);
279
+ color: white;
280
+ }
281
+
282
+ .btn-primary:hover {
283
+ background: #c0392b;
284
+ transform: translateY(-2px);
285
+ }
286
+
287
+ .btn-secondary {
288
+ background: rgba(255,255,255,0.1);
289
+ color: var(--light);
290
+ border: 1px solid rgba(255,255,255,0.2);
291
+ }
292
+
293
+ .btn-secondary:hover {
294
+ background: rgba(255,255,255,0.2);
295
+ }
296
+
297
+ .full-script-section {
298
+ background: linear-gradient(135deg, rgba(26, 26, 46, 0.95) 0%, rgba(22, 33, 62, 0.95) 100%);
299
+ border-radius: var(--radius);
300
+ margin-bottom: 2rem;
301
+ border: 1px solid rgba(255,255,255,0.1);
302
+ overflow: hidden;
303
+ }
304
+
305
+ .script-section-header {
306
+ background: rgba(0,0,0,0.3);
307
+ padding: 1rem 1.5rem;
308
+ display: flex;
309
+ justify-content: space-between;
310
+ align-items: center;
311
+ border-bottom: 1px solid rgba(255,255,255,0.1);
312
+ flex-wrap: wrap;
313
+ gap: 1rem;
314
+ }
315
+
316
+ .script-section-title {
317
+ display: flex;
318
+ align-items: center;
319
+ gap: 0.8rem;
320
+ font-size: 1.1rem;
321
+ font-weight: 600;
322
+ }
323
+
324
+ .script-section-title i {
325
+ color: var(--ubuntu);
326
+ }
327
+
328
+ .script-tabs {
329
+ display: flex;
330
+ background: rgba(0,0,0,0.2);
331
+ border-bottom: 1px solid rgba(255,255,255,0.1);
332
+ overflow-x: auto;
333
+ }
334
+
335
+ .script-tab {
336
+ padding: 0.8rem 1.5rem;
337
+ background: none;
338
+ border: none;
339
+ color: rgba(255,255,255,0.6);
340
+ cursor: pointer;
341
+ font-size: 0.85rem;
342
+ border-bottom: 2px solid transparent;
343
+ transition: var(--transition);
344
+ white-space: nowrap;
345
+ }
346
+
347
+ .script-tab:hover {
348
+ color: var(--light);
349
+ background: rgba(255,255,255,0.05);
350
+ }
351
+
352
+ .script-tab.active {
353
+ color: var(--ubuntu);
354
+ border-bottom-color: var(--ubuntu);
355
+ background: rgba(233, 84, 32, 0.1);
356
+ }
357
+
358
+ .script-content {
359
+ display: none;
360
+ position: relative;
361
+ }
362
+
363
+ .script-content.active {
364
+ display: block;
365
+ }
366
+
367
+ .script-code {
368
+ background: #1e1e1e;
369
+ padding: 1.5rem;
370
+ max-height: 600px;
371
+ overflow: auto;
372
+ font-family: 'Fira Code', 'Courier New', monospace;
373
+ font-size: 0.78rem;
374
+ line-height: 1.6;
375
+ }
376
+
377
+ .script-code pre {
378
+ margin: 0;
379
+ white-space: pre;
380
+ }
381
+
382
+ .copy-btn {
383
+ position: absolute;
384
+ top: 1rem;
385
+ right: 1rem;
386
+ background: var(--ubuntu);
387
+ color: white;
388
+ border: none;
389
+ padding: 0.5rem 1rem;
390
+ border-radius: 6px;
391
+ cursor: pointer;
392
+ font-size: 0.8rem;
393
+ display: flex;
394
+ align-items: center;
395
+ gap: 0.4rem;
396
+ transition: var(--transition);
397
+ z-index: 10;
398
+ }
399
+
400
+ .copy-btn:hover {
401
+ background: #c0392b;
402
+ }
403
+
404
+ .copy-btn.copied {
405
+ background: var(--success);
406
+ }
407
+
408
+ /* Syntax highlighting */
409
+ .sh-comment { color: #6a9955; }
410
+ .sh-string { color: #ce9178; }
411
+ .sh-keyword { color: #569cd6; }
412
+ .sh-function { color: #dcdcaa; }
413
+ .sh-variable { color: #9cdcfe; }
414
+ .sh-command { color: #4ec9b0; }
415
+ .sh-flag { color: #c586c0; }
416
+ .sh-number { color: #b5cea8; }
417
+ .sh-operator { color: #d4d4d4; }
418
+
419
+ .alert {
420
+ padding: 1rem 1.5rem;
421
+ border-radius: 8px;
422
+ margin-bottom: 1.5rem;
423
+ display: flex;
424
+ align-items: flex-start;
425
+ gap: 1rem;
426
+ }
427
+
428
+ .alert-warning {
429
+ background: rgba(255, 193, 7, 0.15);
430
+ border: 1px solid rgba(255, 193, 7, 0.4);
431
+ }
432
+
433
+ .alert-warning i {
434
+ color: var(--warning);
435
+ font-size: 1.3rem;
436
+ }
437
+
438
+ .alert-info {
439
+ background: rgba(23, 162, 184, 0.15);
440
+ border: 1px solid rgba(23, 162, 184, 0.4);
441
+ }
442
+
443
+ .alert-info i {
444
+ color: var(--info);
445
+ font-size: 1.3rem;
446
+ }
447
+
448
+ .alert-content h4 {
449
+ margin-bottom: 0.3rem;
450
+ color: var(--light);
451
+ }
452
+
453
+ .alert-content p {
454
+ font-size: 0.9rem;
455
+ color: rgba(255,255,255,0.8);
456
+ }
457
+
458
+ footer {
459
+ background: rgba(0,0,0,0.5);
460
+ padding: 2rem;
461
+ text-align: center;
462
+ border-top: 1px solid rgba(255,255,255,0.1);
463
+ }
464
+
465
+ .footer-text {
466
+ color: rgba(255,255,255,0.6);
467
+ font-size: 0.9rem;
468
+ }
469
+
470
+ .footer-text a {
471
+ color: var(--ubuntu);
472
+ text-decoration: none;
473
+ }
474
+
475
+ .footer-text a:hover {
476
+ text-decoration: underline;
477
+ }
478
+
479
+ @media (max-width: 768px) {
480
+ .header-content {
481
+ flex-direction: column;
482
+ text-align: center;
483
+ }
484
+
485
+ .scripts-grid {
486
+ grid-template-columns: 1fr;
487
+ }
488
+
489
+ .script-code {
490
+ font-size: 0.7rem;
491
+ }
492
+ }
493
+ </style>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
494
  </head>
 
495
  <body>
496
+ <header>
497
+ <div class="header-content">
498
+ <a href="#" class="logo">
499
+ <div class="logo-icon">
500
+ <i class="fab fa-ubuntu"></i>
501
+ </div>
502
+ <div class="logo-text">
503
+ <h1>Gemma 3 Hardened Container</h1>
504
+ <span>Ubuntu Shell Scripts - Production Ready</span>
505
+ </div>
506
+ </a>
507
+ <div class="built-with">
508
+ Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a>
509
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
510
  </div>
511
+ </header>
512
+
513
+ <main>
514
+ <!-- Introduction -->
515
+ <section class="intro-section">
516
+ <div class="intro-header">
517
+ <div class="intro-icon">
518
+ <i class="fas fa-terminal"></i>
519
+ </div>
520
+ <div>
521
+ <h2 class="intro-title">Ubuntu Shell Scripts for Hardened LLM Container</h2>
522
+ <p class="intro-subtitle">Complete deployment scripts with all critical fixes applied - ready to run on Ubuntu 20.04+</p>
523
+ </div>
524
+ </div>
525
+
526
+ <div class="quick-start">
527
+ <h3><i class="fas fa-rocket"></i> Quick Start</h3>
528
+ <div class="quick-start-code">
529
+ <pre><span class="comment"># 1. Download and make executable</span>
530
+ <span class="command">chmod +x</span> gemma3-setup.sh gemma3-entrypoint.sh gemma3-verify.sh
531
+
532
+ <span class="comment"># 2. Run the setup script (requires sudo)</span>
533
+ <span class="command">sudo ./gemma3-setup.sh</span>
534
+
535
+ <span class="comment"># 3. Build and run the container</span>
536
+ <span class="command">docker build -t</span> gemma3-hardened .
537
+ <span class="command">docker run -d --name</span> gemma3 <span class="command">-p</span> 8080:8080 gemma3-hardened
538
+
539
+ <span class="comment"># 4. Verify security posture</span>
540
+ <span class="command">./gemma3-verify.sh</span></pre>
541
+ </div>
542
+ </div>
543
+ </section>
544
+
545
+ <!-- Alerts -->
546
+ <div class="alert alert-warning">
547
+ <i class="fas fa-exclamation-triangle"></i>
548
+ <div class="alert-content">
549
+ <h4>Prerequisites Required</h4>
550
+ <p>These scripts require Ubuntu 20.04+, Docker 20.10+, and sudo privileges. Ensure you have at least 16GB RAM for the 12B model.</p>
551
+ </div>
552
  </div>
553
+
554
+ <!-- Script Cards -->
555
+ <div class="scripts-grid">
556
+ <div class="script-card">
557
+ <div class="script-card-header">
558
+ <div class="script-card-title">
559
+ <i class="fas fa-cogs"></i>
560
+ gemma3-setup.sh
561
+ </div>
562
+ <span class="script-badge">Main Setup</span>
563
+ </div>
564
+ <div class="script-card-body">
565
+ <p class="script-description">
566
+ Complete system setup script that configures the host, builds the Docker image, and applies all security hardening.
567
+ </p>
568
+ <ul class="script-features">
569
+ <li><i class="fas fa-check"></i> Installs Docker and dependencies</li>
570
+ <li><i class="fas fa-check"></i> Creates non-root user (UID 1000)</li>
571
+ <li><i class="fas fa-check"></i> Generates Dockerfile with security</li>
572
+ <li><i class="fas fa-check"></i> Configures seccomp and AppArmor</li>
573
+ <li><i class="fas fa-check"></i> Sets up proper logging to stdout</li>
574
+ </ul>
575
+ <div class="script-actions">
576
+ <button class="btn btn-primary" onclick="scrollToScript('setup')">
577
+ <i class="fas fa-eye"></i> View Script
578
+ </button>
579
+ <button class="btn btn-secondary" onclick="downloadScript('setup')">
580
+ <i class="fas fa-download"></i> Download
581
+ </button>
582
+ </div>
583
+ </div>
584
+ </div>
585
+
586
+ <div class="script-card">
587
+ <div class="script-card-header">
588
+ <div class="script-card-title">
589
+ <i class="fas fa-play-circle"></i>
590
+ gemma3-entrypoint.sh
591
+ </div>
592
+ <span class="script-badge">Container Entry</span>
593
+ </div>
594
+ <div class="script-card-body">
595
+ <p class="script-description">
596
+ Container entrypoint script with proper entropy verification, health checks, and stdout-based logging.
597
+ </p>
598
+ <ul class="script-features">
599
+ <li><i class="fas fa-check"></i> Hardware RNG verification</li>
600
+ <li><i class="fas fa-check"></i> Entropy pool monitoring</li>
601
+ <li><i class="fas fa-check"></i> Stdout/stderr logging only</li>
602
+ <li><i class="fas fa-check"></i> Graceful shutdown handling</li>
603
+ <li><i class="fas fa-check"></i> Health check endpoints</li>
604
+ </ul>
605
+ <div class="script-actions">
606
+ <button class="btn btn-primary" onclick="scrollToScript('entrypoint')">
607
+ <i class="fas fa-eye"></i> View Script
608
+ </button>
609
+ <button class="btn btn-secondary" onclick="downloadScript('entrypoint')">
610
+ <i class="fas fa-download"></i> Download
611
+ </button>
612
+ </div>
613
+ </div>
614
+ </div>
615
+
616
+ <div class="script-card">
617
+ <div class="script-card-header">
618
+ <div class="script-card-title">
619
+ <i class="fas fa-shield-alt"></i>
620
+ gemma3-verify.sh
621
+ </div>
622
+ <span class="script-badge">Security Audit</span>
623
+ </div>
624
+ <div class="script-card-body">
625
+ <p class="script-description">
626
+ Comprehensive verification script that audits the container's security posture and generates a report.
627
+ </p>
628
+ <ul class="script-features">
629
+ <li><i class="fas fa-check"></i> Filesystem permissions check</li>
630
+ <li><i class="fas fa-check"></i> Capability verification</li>
631
+ <li><i class="fas fa-check"></i> Seccomp profile validation</li>
632
+ <li><i class="fas fa-check"></i> Network isolation test</li>
633
+ <li><i class="fas fa-check"></i> Entropy source audit</li>
634
+ </ul>
635
+ <div class="script-actions">
636
+ <button class="btn btn-primary" onclick="scrollToScript('verify')">
637
+ <i class="fas fa-eye"></i> View Script
638
+ </button>
639
+ <button class="btn btn-secondary" onclick="downloadScript('verify')">
640
+ <i class="fas fa-download"></i> Download
641
+ </button>
642
+ </div>
643
+ </div>
644
+ </div>
645
  </div>
646
+
647
+ <!-- Full Scripts Section -->
648
+ <section class="full-script-section" id="scripts">
649
+ <div class="script-section-header">
650
+ <div class="script-section-title">
651
+ <i class="fas fa-file-code"></i>
652
+ Complete Shell Scripts
653
+ </div>
654
+ <button class="btn btn-primary" onclick="downloadAllScripts()">
655
+ <i class="fas fa-download"></i> Download All Scripts
656
+ </button>
657
+ </div>
658
+
659
+ <div class="script-tabs">
660
+ <button class="script-tab active" data-tab="setup" onclick="switchTab('setup')">
661
+ <i class="fas fa-cogs"></i> gemma3-setup.sh
662
+ </button>
663
+ <button class="script-tab" data-tab="entrypoint" onclick="switchTab('entrypoint')">
664
+ <i class="fas fa-play-circle"></i> gemma3-entrypoint.sh
665
+ </button>
666
+ <button class="script-tab" data-tab="verify" onclick="switchTab('verify')">
667
+ <i class="fas fa-shield-alt"></i> gemma3-verify.sh
668
+ </button>
669
+ <button class="script-tab" data-tab="dockerfile" onclick="switchTab('dockerfile')">
670
+ <i class="fab fa-docker"></i> Dockerfile
671
+ </button>
672
+ <button class="script-tab" data-tab="seccomp" onclick="switchTab('seccomp')">
673
+ <i class="fas fa-lock"></i> seccomp.json
674
+ </button>
675
+ </div>
676
+
677
+ <!-- Setup Script -->
678
+ <div class="script-content active" id="tab-setup">
679
+ <button class="copy-btn" onclick="copyScript('setup')">
680
+ <i class="fas fa-copy"></i> Copy
681
+ </button>
682
+ <div class="script-code">
683
+ <pre id="script-setup">#!/bin/bash
684
+ #===============================================================================
685
+ # Gemma 3 Hardened Container Setup Script
686
+ # Version: 2.0 - Critical Fixes Applied
687
+ # Target: Ubuntu 20.04+ / Debian 11+
688
+ #===============================================================================
689
+
690
+ set -euo pipefail
691
+ IFS=$'\n\t'
692
+
693
+ # Colors for output
694
+ RED='\033[0;31m'
695
+ GREEN='\033[0;32m'
696
+ YELLOW='\033[1;33m'
697
+ BLUE='\033[0;34m'
698
+ NC='\033[0m' # No Color
699
+
700
+ # Configuration
701
+ readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
702
+ readonly MODEL_NAME="gemma-3-12b-it-abliterated-v2.q4_k_m.gguf"
703
+ readonly CONTAINER_USER="llmuser"
704
+ readonly CONTAINER_UID=1000
705
+ readonly CONTAINER_GID=1000
706
+ readonly IMAGE_NAME="gemma3-hardened"
707
+ readonly CONTAINER_NAME="gemma3"
708
+
709
+ # Logging functions - stdout only (FIX #1: No file logging)
710
+ log_info() {
711
+ echo -e "${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $*"
712
+ }
713
+
714
+ log_success() {
715
+ echo -e "${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $*"
716
+ }
717
+
718
+ log_warn() {
719
+ echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $*" >&2
720
+ }
721
+
722
+ log_error() {
723
+ echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $*" >&2
724
+ }
725
+
726
+ # Check if running as root
727
+ check_root() {
728
+ if [[ $EUID -ne 0 ]]; then
729
+ log_error "This script must be run as root (use sudo)"
730
+ exit 1
731
+ fi
732
+ }
733
+
734
+ # Check system requirements
735
+ check_requirements() {
736
+ log_info "Checking system requirements..."
737
+
738
+ # Check Ubuntu/Debian
739
+ if ! grep -qE "(Ubuntu|Debian)" /etc/os-release 2>/dev/null; then
740
+ log_warn "This script is designed for Ubuntu/Debian. Proceeding anyway..."
741
+ fi
742
+
743
+ # Check available memory
744
+ local total_mem=$(free -g | awk '/^Mem:/{print $2}')
745
+ if [[ $total_mem -lt 16 ]]; then
746
+ log_warn "Less than 16GB RAM detected. The 12B model may not run optimally."
747
+ fi
748
+
749
+ # Check disk space
750
+ local free_space=$(df -BG "${SCRIPT_DIR}" | awk 'NR==2 {print $4}' | tr -d 'G')
751
+ if [[ $free_space -lt 20 ]]; then
752
+ log_error "Insufficient disk space. Need at least 20GB free."
753
+ exit 1
754
+ fi
755
+
756
+ log_success "System requirements check passed"
757
+ }
758
+
759
+ # Install Docker if not present
760
+ install_docker() {
761
+ if command -v docker &>/dev/null; then
762
+ log_info "Docker is already installed: $(docker --version)"
763
+ return 0
764
+ fi
765
+
766
+ log_info "Installing Docker..."
767
+
768
+ # Remove old versions
769
+ apt-get remove -y docker docker-engine docker.io containerd runc 2>/dev/null || true
770
+
771
+ # Install prerequisites
772
+ apt-get update
773
+ apt-get install -y \
774
+ apt-transport-https \
775
+ ca-certificates \
776
+ curl \
777
+ gnupg \
778
+ lsb-release
779
+
780
+ # Add Docker GPG key
781
+ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
782
+
783
+ # Add Docker repository
784
+ echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
785
+
786
+ # Install Docker
787
+ apt-get update
788
+ apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
789
+
790
+ # Start and enable Docker
791
+ systemctl start docker
792
+ systemctl enable docker
793
+
794
+ log_success "Docker installed successfully"
795
+ }
796
+
797
+ # Install additional security tools
798
+ install_security_tools() {
799
+ log_info "Installing security tools..."
800
+
801
+ apt-get install -y \
802
+ rng-tools \
803
+ haveged \
804
+ apparmor \
805
+ apparmor-utils \
806
+ auditd
807
+
808
+ # Enable and start haveged for entropy
809
+ systemctl enable haveged
810
+ systemctl start haveged
811
+
812
+ log_success "Security tools installed"
813
+ }
814
+
815
+ # Create project directory structure
816
+ create_directories() {
817
+ log_info "Creating project directories..."
818
+
819
+ local project_dir="${SCRIPT_DIR}/gemma3-hardened"
820
+ mkdir -p "${project_dir}"/{config,scripts,models}
821
+
822
+ echo "${project_dir}"
823
+ }
824
+
825
+ # Generate Dockerfile
826
+ generate_dockerfile() {
827
+ local project_dir="$1"
828
+
829
+ log_info "Generating Dockerfile..."
830
+
831
+ cat > "${project_dir}/Dockerfile" << 'DOCKERFILE'
832
+ #===============================================================================
833
+ # Gemma 3 Hardened Container Dockerfile
834
+ # Security Level: Production Hardened
835
+ # Critical Fixes Applied: Logging, Filesystem, Entropy
836
+ #===============================================================================
837
+
838
+ FROM python:3.11-slim-bookworm AS builder
839
+
840
+ # Build arguments
841
+ ARG LLAMA_CPP_VERSION=b2354
842
+
843
+ # Install build dependencies
844
+ RUN apt-get update && apt-get install -y --no-install-recommends \
845
+ build-essential \
846
+ cmake \
847
+ git \
848
+ && rm -rf /var/lib/apt/lists/*
849
+
850
+ # Build llama.cpp
851
+ WORKDIR /build
852
+ RUN git clone --depth 1 --branch ${LLAMA_CPP_VERSION} https://github.com/ggerganov/llama.cpp.git && \
853
+ cd llama.cpp && \
854
+ mkdir build && cd build && \
855
+ cmake .. -DLLAMA_BUILD_SERVER=ON -DCMAKE_BUILD_TYPE=Release && \
856
+ cmake --build . --config Release -j$(nproc) && \
857
+ cp bin/llama-server /llama-server
858
+
859
+ #===============================================================================
860
+ # Production Stage
861
+ #===============================================================================
862
+ FROM python:3.11-slim-bookworm
863
+
864
+ # Security: Create non-root user with specific UID/GID
865
+ RUN groupadd -g 1000 llmuser && \
866
+ useradd -u 1000 -g 1000 -m -s /bin/bash llmuser
867
+
868
+ # Install minimal runtime dependencies
869
+ RUN apt-get update && apt-get install -y --no-install-recommends \
870
+ libgomp1 \
871
+ curl \
872
+ ca-certificates \
873
+ && rm -rf /var/lib/apt/lists/* \
874
+ && apt-get clean \
875
+ && rm -rf /var/cache/apt/archives/*
876
+
877
+ # Copy llama-server from builder
878
+ COPY --from=builder /llama-server /usr/local/bin/llama-server
879
+ RUN chmod 755 /usr/local/bin/llama-server
880
+
881
+ # Create application directories
882
+ RUN mkdir -p /app/models /app/config /tmp/llm-cache && \
883
+ chown -R llmuser:llmuser /app /tmp/llm-cache
884
+
885
+ # Copy entrypoint script
886
+ COPY --chown=llmuser:llmuser scripts/entrypoint.sh /app/entrypoint.sh
887
+ RUN chmod 755 /app/entrypoint.sh
888
+
889
+ # Set working directory
890
+ WORKDIR /app
891
+
892
+ # Switch to non-root user
893
+ USER llmuser
894
+
895
+ # Environment variables
896
+ ENV LLAMA_ARG_HOST=0.0.0.0 \
897
+ LLAMA_ARG_PORT=8080 \
898
+ LLAMA_ARG_CTX_SIZE=4096 \
899
+ LLAMA_ARG_N_GPU_LAYERS=0 \
900
+ PYTHONUNBUFFERED=1 \
901
+ HOME=/home/llmuser
902
+
903
+ # Health check
904
+ HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
905
+ CMD curl -f http://localhost:8080/health || exit 1
906
+
907
+ # Expose port
908
+ EXPOSE 8080
909
+
910
+ # Entrypoint
911
+ ENTRYPOINT ["/app/entrypoint.sh"]
912
+ DOCKERFILE
913
+
914
+ log_success "Dockerfile generated"
915
+ }
916
+
917
+ # Generate entrypoint script
918
+ generate_entrypoint() {
919
+ local project_dir="$1"
920
+
921
+ log_info "Generating entrypoint script..."
922
+
923
+ mkdir -p "${project_dir}/scripts"
924
+
925
+ cat > "${project_dir}/scripts/entrypoint.sh" << 'ENTRYPOINT'
926
+ #!/bin/bash
927
+ #===============================================================================
928
+ # Gemma 3 Container Entrypoint Script
929
+ # FIX #1: Logging to stdout/stderr only (no file writes on read-only fs)
930
+ # FIX #3: Proper entropy verification with hardware RNG check
931
+ #===============================================================================
932
+
933
+ set -euo pipefail
934
+
935
+ # Logging functions - stdout/stderr only
936
+ log_info() {
937
+ echo "[INFO] $(date -u '+%Y-%m-%dT%H:%M:%SZ') - $*"
938
+ }
939
+
940
+ log_warn() {
941
+ echo "[WARN] $(date -u '+%Y-%m-%dT%H:%M:%SZ') - $*" >&2
942
+ }
943
+
944
+ log_error() {
945
+ echo "[ERROR] $(date -u '+%Y-%m-%dT%H:%M:%SZ') - $*" >&2
946
+ }
947
+
948
+ # FIX #3: Enhanced entropy verification
949
+ verify_entropy() {
950
+ log_info "Verifying entropy sources..."
951
+
952
+ # Check entropy pool size
953
+ local entropy_avail=$(cat /proc/sys/kernel/random/entropy_avail 2>/dev/null || echo "0")
954
+ local min_entropy=256
955
+
956
+ if [[ $entropy_avail -lt $min_entropy ]]; then
957
+ log_warn "Low entropy detected: ${entropy_avail} bits (minimum: ${min_entropy})"
958
+ log_warn "Waiting for entropy pool to fill..."
959
+
960
+ # Wait for entropy with timeout
961
+ local timeout=30
962
+ local waited=0
963
+ while [[ $entropy_avail -lt $min_entropy && $waited -lt $timeout ]]; do
964
+ sleep 1
965
+ entropy_avail=$(cat /proc/sys/kernel/random/entropy_avail 2>/dev/null || echo "0")
966
+ ((waited++))
967
+ done
968
+
969
+ if [[ $entropy_avail -lt $min_entropy ]]; then
970
+ log_error "Insufficient entropy after ${timeout}s. This may affect cryptographic operations."
971
+ log_error "Consider adding --device /dev/hwrng:/dev/hwrng to docker run"
972
+ fi
973
+ fi
974
+
975
+ log_info "Entropy available: ${entropy_avail} bits"
976
+
977
+ # Check for hardware RNG
978
+ if [[ -c /dev/hwrng ]]; then
979
+ log_info "Hardware RNG detected and available"
980
+ else
981
+ log_warn "No hardware RNG available - using software entropy only"
982
+ fi
983
+
984
+ # Verify /dev/urandom is accessible
985
+ if ! dd if=/dev/urandom bs=32 count=1 2>/dev/null | od -An -tx1 >/dev/null; then
986
+ log_error "/dev/urandom is not accessible!"
987
+ exit 1
988
+ fi
989
+
990
+ log_info "Entropy verification complete"
991
+ }
992
+
993
+ # Verify read-only filesystem (FIX #2: Removed invalid remount command)
994
+ verify_filesystem() {
995
+ log_info "Verifying filesystem permissions..."
996
+
997
+ # Check if root filesystem is read-only by attempting to write
998
+ if touch /.ro_test 2>/dev/null; then
999
+ rm -f /.ro_test
1000
+ log_warn "Root filesystem is writable - container may not be properly hardened"
1001
+ else
1002
+ log_info "Root filesystem is read-only (expected)"
1003
+ fi
1004
+
1005
+ # Verify tmpfs mounts are available for necessary writes
1006
+ if [[ -w /tmp ]]; then
1007
+ log_info "/tmp is writable (tmpfs)"
1008
+ else
1009
+ log_error "/tmp is not writable - container cannot function"
1010
+ exit 1
1011
+ fi
1012
+ }
1013
+
1014
+ # Signal handlers for graceful shutdown
1015
+ cleanup() {
1016
+ log_info "Received shutdown signal, cleaning up..."
1017
+
1018
+ # Kill llama-server gracefully
1019
+ if [[ -n "${LLAMA_PID:-}" ]]; then
1020
+ kill -TERM "$LLAMA_PID" 2>/dev/null || true
1021
+ wait "$LLAMA_PID" 2>/dev/null || true
1022
+ fi
1023
+
1024
+ log_info "Shutdown complete"
1025
+ exit 0
1026
+ }
1027
+
1028
+ trap cleanup SIGTERM SIGINT SIGQUIT
1029
+
1030
+ # Main execution
1031
+ main() {
1032
+ log_info "Starting Gemma 3 Hardened Container"
1033
+ log_info "User: $(id)"
1034
+ log_info "Working directory: $(pwd)"
1035
+
1036
+ # Run security verifications
1037
+ verify_entropy
1038
+ verify_filesystem
1039
+
1040
+ # Find model file
1041
+ MODEL_PATH="${MODEL_PATH:-/app/models/gemma-3-12b-it-abliterated-v2.q4_k_m.gguf}"
1042
+
1043
+ if [[ ! -f "$MODEL_PATH" ]]; then
1044
+ log_error "Model file not found: $MODEL_PATH"
1045
+ log_error "Please mount the model file to /app/models/"
1046
+ exit 1
1047
+ fi
1048
+
1049
+ log_info "Model found: $MODEL_PATH"
1050
+ log_info "Model size: $(du -h "$MODEL_PATH" | cut -f1)"
1051
+
1052
+ # Start llama-server
1053
+ log_info "Starting llama-server..."
1054
+
1055
+ exec /usr/local/bin/llama-server \
1056
+ --model "$MODEL_PATH" \
1057
+ --host "${LLAMA_ARG_HOST:-