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

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. index.html +1037 -1043
index.html CHANGED
@@ -1,1057 +1,1051 @@
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:-
 
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
+ <title>Gemma 3 Hardened Container - Ubuntu Scripts v2.1</title>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <style>
10
+ :root {
11
+ --primary: #1a1a2e;
12
+ --secondary: #16213e;
13
+ --accent: #0f3460;
14
+ --highlight: #e94560;
15
+ --success: #00d9a0;
16
+ --warning: #ffc107;
17
+ --danger: #dc3545;
18
+ --info: #17a2b8;
19
+ --light: #f8f9fa;
20
+ --dark: #0a0a0f;
21
+ --fixed: #2ecc71;
22
+ --ubuntu: #E95420;
23
+ --shadow: 0 4px 20px rgba(143, 37, 37, 0.3);
24
+ --radius: 12px;
25
+ --transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
26
+ }
27
+
28
+ * {
29
+ margin: 0;
30
+ padding: 0;
31
+ box-sizing: border-box;
32
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
33
+ }
34
+
35
+ body {
36
+ background: linear-gradient(135deg, var(--dark) 0%, var(--primary) 50%, var(--secondary) 100%);
37
+ color: var(--light);
38
+ line-height: 1.6;
39
+ min-height: 100vh;
40
+ }
41
+
42
+ header {
43
+ background: linear-gradient(135deg, rgba(233, 84, 32, 0.9) 0%, rgba(26, 26, 46, 0.95) 100%);
44
+ padding: 1.5rem 2rem;
45
+ border-bottom: 3px solid var(--ubuntu);
46
+ position: sticky;
47
+ top: 0;
48
+ z-index: 100;
49
+ }
50
+
51
+ .header-content {
52
+ max-width: 1400px;
53
+ margin: 0 auto;
54
+ display: flex;
55
+ justify-content: space-between;
56
+ align-items: center;
57
+ flex-wrap: wrap;
58
+ gap: 1rem;
59
+ }
60
+
61
+ .logo {
62
+ display: flex;
63
+ align-items: center;
64
+ gap: 1rem;
65
+ text-decoration: none;
66
+ color: white;
67
+ }
68
+
69
+ .logo-icon {
70
+ width: 50px;
71
+ height: 50px;
72
+ background: white;
73
+ border-radius: 50%;
74
+ display: flex;
75
+ align-items: center;
76
+ justify-content: center;
77
+ }
78
+
79
+ .logo-icon i {
80
+ font-size: 1.5rem;
81
+ color: var(--ubuntu);
82
+ }
83
+
84
+ .logo-text h1 {
85
+ font-size: 1.4rem;
86
+ font-weight: 700;
87
+ }
88
+
89
+ .logo-text span {
90
+ font-size: 0.8rem;
91
+ opacity: 0.9;
92
+ }
93
+
94
+ .built-with {
95
+ font-size: 0.9rem;
96
+ }
97
+
98
+ .built-with a {
99
+ color: var(--warning);
100
+ text-decoration: none;
101
+ font-weight: 600;
102
+ }
103
+
104
+ .built-with a:hover {
105
+ text-decoration: underline;
106
+ }
107
+
108
+ main {
109
+ max-width: 1400px;
110
+ margin: 2rem auto;
111
+ padding: 0 1.5rem;
112
+ }
113
+
114
+ .intro-section {
115
+ background: linear-gradient(135deg, rgba(233, 84, 32, 0.15) 0%, rgba(26, 26, 46, 0.9) 100%);
116
+ border: 1px solid var(--ubuntu);
117
+ border-radius: var(--radius);
118
+ padding: 2rem;
119
+ margin-bottom: 2rem;
120
+ }
121
+
122
+ .intro-header {
123
+ display: flex;
124
+ align-items: center;
125
+ gap: 1rem;
126
+ margin-bottom: 1.5rem;
127
+ }
128
+
129
+ .intro-icon {
130
+ width: 60px;
131
+ height: 60px;
132
+ background: var(--ubuntu);
133
+ border-radius: 50%;
134
+ display: flex;
135
+ align-items: center;
136
+ justify-content: center;
137
+ font-size: 1.8rem;
138
+ }
139
+
140
+ .intro-title {
141
+ font-size: 1.6rem;
142
+ color: var(--light);
143
+ }
144
+
145
+ .intro-subtitle {
146
+ color: rgba(255, 255, 255, 0.7);
147
+ font-size: 0.95rem;
148
+ }
149
+
150
+ .version-badge {
151
+ display: inline-block;
152
+ background: var(--success);
153
+ color: var(--dark);
154
+ padding: 0.3rem 0.8rem;
155
+ border-radius: 20px;
156
+ font-size: 0.75rem;
157
+ font-weight: 700;
158
+ margin-left: 0.5rem;
159
+ }
160
+
161
+ .quick-start {
162
+ background: rgba(0, 0, 0, 0.4);
163
+ border-radius: 8px;
164
+ padding: 1.5rem;
165
+ margin-top: 1.5rem;
166
+ }
167
+
168
+ .quick-start h3 {
169
+ color: var(--success);
170
+ margin-bottom: 1rem;
171
+ display: flex;
172
+ align-items: center;
173
+ gap: 0.5rem;
174
+ }
175
+
176
+ .quick-start-code {
177
+ background: rgba(0, 0, 0, 0.5);
178
+ border-radius: 6px;
179
+ padding: 1rem;
180
+ font-family: 'Fira Code', 'Courier New', monospace;
181
+ font-size: 0.85rem;
182
+ overflow-x: auto;
183
+ }
184
+
185
+ .quick-start-code .comment {
186
+ color: #6a9955;
187
+ }
188
+
189
+ .quick-start-code .command {
190
+ color: #dcdcaa;
191
+ }
192
+
193
+ .security-phases {
194
+ display: grid;
195
+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
196
+ gap: 1.5rem;
197
+ margin-bottom: 2rem;
198
+ }
199
+
200
+ .phase-card {
201
+ background: linear-gradient(135deg, rgba(26, 26, 46, 0.95) 0%, rgba(22, 33, 62, 0.95) 100%);
202
+ border-radius: var(--radius);
203
+ border: 1px solid rgba(255, 255, 255, 0.1);
204
+ overflow: hidden;
205
+ transition: var(--transition);
206
+ }
207
+
208
+ .phase-card:hover {
209
+ border-color: var(--success);
210
+ transform: translateY(-3px);
211
+ box-shadow: 0 10px 30px rgba(0, 217, 160, 0.2);
212
+ }
213
+
214
+ .phase-card-header {
215
+ padding: 1.2rem 1.5rem;
216
+ display: flex;
217
+ align-items: center;
218
+ gap: 1rem;
219
+ }
220
+
221
+ .phase-card-header.build {
222
+ background: linear-gradient(135deg, #3498db, #2980b9);
223
+ }
224
+
225
+ .phase-card-header.deploy {
226
+ background: linear-gradient(135deg, #9b59b6, #8e44ad);
227
+ }
228
+
229
+ .phase-card-header.runtime {
230
+ background: linear-gradient(135deg, #e74c3c, #c0392b);
231
+ }
232
+
233
+ .phase-icon {
234
+ width: 45px;
235
+ height: 45px;
236
+ background: rgba(255, 255, 255, 0.2);
237
+ border-radius: 50%;
238
+ display: flex;
239
+ align-items: center;
240
+ justify-content: center;
241
+ font-size: 1.3rem;
242
+ }
243
+
244
+ .phase-title h3 {
245
+ font-size: 1rem;
246
+ font-weight: 600;
247
+ }
248
+
249
+ .phase-title span {
250
+ font-size: 0.75rem;
251
+ opacity: 0.9;
252
+ }
253
+
254
+ .phase-card-body {
255
+ padding: 1.5rem;
256
+ }
257
+
258
+ .phase-description {
259
+ color: rgba(255, 255, 255, 0.8);
260
+ font-size: 0.9rem;
261
+ margin-bottom: 1rem;
262
+ line-height: 1.6;
263
+ }
264
+
265
+ .phase-tools {
266
+ display: flex;
267
+ flex-wrap: wrap;
268
+ gap: 0.5rem;
269
+ }
270
+
271
+ .tool-badge {
272
+ background: rgba(255, 255, 255, 0.1);
273
+ border: 1px solid rgba(255, 255, 255, 0.2);
274
+ padding: 0.3rem 0.7rem;
275
+ border-radius: 20px;
276
+ font-size: 0.75rem;
277
+ color: var(--light);
278
+ }
279
+
280
+ .scripts-grid {
281
+ display: grid;
282
+ grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
283
+ gap: 1.5rem;
284
+ margin-bottom: 2rem;
285
+ }
286
+
287
+ .script-card {
288
+ background: linear-gradient(135deg, rgba(26, 26, 46, 0.95) 0%, rgba(22, 33, 62, 0.95) 100%);
289
+ border-radius: var(--radius);
290
+ border: 1px solid rgba(255, 255, 255, 0.1);
291
+ overflow: hidden;
292
+ transition: var(--transition);
293
+ }
294
+
295
+ .script-card:hover {
296
+ border-color: var(--ubuntu);
297
+ transform: translateY(-3px);
298
+ box-shadow: 0 10px 30px rgba(233, 84, 32, 0.2);
299
+ }
300
+
301
+ .script-card-header {
302
+ background: linear-gradient(135deg, var(--ubuntu), #c0392b);
303
+ padding: 1.2rem 1.5rem;
304
+ display: flex;
305
+ align-items: center;
306
+ justify-content: space-between;
307
+ }
308
+
309
+ .script-card-title {
310
+ display: flex;
311
+ align-items: center;
312
+ gap: 0.8rem;
313
+ font-weight: 600;
314
+ font-size: 1rem;
315
+ }
316
+
317
+ .script-card-title i {
318
+ font-size: 1.2rem;
319
+ }
320
+
321
+ .script-badge {
322
+ background: rgba(255, 255, 255, 0.2);
323
+ padding: 0.3rem 0.8rem;
324
+ border-radius: 20px;
325
+ font-size: 0.7rem;
326
+ font-weight: 600;
327
+ }
328
+
329
+ .script-card-body {
330
+ padding: 1.5rem;
331
+ }
332
+
333
+ .script-description {
334
+ color: rgba(255, 255, 255, 0.8);
335
+ font-size: 0.9rem;
336
+ margin-bottom: 1rem;
337
+ line-height: 1.6;
338
+ }
339
+
340
+ .script-features {
341
+ list-style: none;
342
+ margin-bottom: 1.5rem;
343
+ }
344
+
345
+ .script-features li {
346
+ display: flex;
347
+ align-items: center;
348
+ gap: 0.6rem;
349
+ padding: 0.4rem 0;
350
+ font-size: 0.85rem;
351
+ color: rgba(255, 255, 255, 0.7);
352
+ }
353
+
354
+ .script-features li i {
355
+ color: var(--success);
356
+ font-size: 0.8rem;
357
+ }
358
+
359
+ .script-features li i.new-feature {
360
+ color: var(--warning);
361
+ }
362
+
363
+ .script-actions {
364
+ display: flex;
365
+ gap: 0.8rem;
366
+ flex-wrap: wrap;
367
+ }
368
+
369
+ .btn {
370
+ padding: 0.6rem 1.2rem;
371
+ border-radius: 8px;
372
+ border: none;
373
+ cursor: pointer;
374
+ font-weight: 600;
375
+ font-size: 0.85rem;
376
+ display: inline-flex;
377
+ align-items: center;
378
+ gap: 0.5rem;
379
+ transition: var(--transition);
380
+ text-decoration: none;
381
+ }
382
+
383
+ .btn-primary {
384
+ background: var(--ubuntu);
385
+ color: white;
386
+ }
387
+
388
+ .btn-primary:hover {
389
+ background: #c0392b;
390
+ transform: translateY(-2px);
391
+ }
392
+
393
+ .btn-secondary {
394
+ background: rgba(255, 255, 255, 0.1);
395
+ color: var(--light);
396
+ border: 1px solid rgba(255, 255, 255, 0.2);
397
+ }
398
+
399
+ .btn-secondary:hover {
400
+ background: rgba(255, 255, 255, 0.2);
401
+ }
402
+
403
+ .full-script-section {
404
+ background: linear-gradient(135deg, rgba(26, 26, 46, 0.95) 0%, rgba(22, 33, 62, 0.95) 100%);
405
+ border-radius: var(--radius);
406
+ margin-bottom: 2rem;
407
+ border: 1px solid rgba(255, 255, 255, 0.1);
408
+ overflow: hidden;
409
+ }
410
+
411
+ .script-section-header {
412
+ background: rgba(0, 0, 0, 0.3);
413
+ padding: 1rem 1.5rem;
414
+ display: flex;
415
+ justify-content: space-between;
416
+ align-items: center;
417
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
418
+ flex-wrap: wrap;
419
+ gap: 1rem;
420
+ }
421
+
422
+ .script-section-title {
423
+ display: flex;
424
+ align-items: center;
425
+ gap: 0.8rem;
426
+ font-size: 1.1rem;
427
+ font-weight: 600;
428
+ }
429
+
430
+ .script-section-title i {
431
+ color: var(--ubuntu);
432
+ }
433
+
434
+ .script-tabs {
435
+ display: flex;
436
+ background: rgba(0, 0, 0, 0.2);
437
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
438
+ overflow-x: auto;
439
+ }
440
+
441
+ .script-tab {
442
+ padding: 0.8rem 1.5rem;
443
+ background: none;
444
+ border: none;
445
+ color: rgba(255, 255, 255, 0.6);
446
+ cursor: pointer;
447
+ font-size: 0.85rem;
448
+ border-bottom: 2px solid transparent;
449
+ transition: var(--transition);
450
+ white-space: nowrap;
451
+ display: flex;
452
+ align-items: center;
453
+ gap: 0.5rem;
454
+ }
455
+
456
+ .script-tab:hover {
457
+ color: var(--light);
458
+ background: rgba(255, 255, 255, 0.05);
459
+ }
460
+
461
+ .script-tab.active {
462
+ color: var(--ubuntu);
463
+ border-bottom-color: var(--ubuntu);
464
+ background: rgba(233, 84, 32, 0.1);
465
+ }
466
+
467
+ .script-content {
468
+ display: none;
469
+ position: relative;
470
+ }
471
+
472
+ .script-content.active {
473
+ display: block;
474
+ }
475
+
476
+ .script-code {
477
+ background: #1e1e1e;
478
+ padding: 1.5rem;
479
+ max-height: 700px;
480
+ overflow: auto;
481
+ font-family: 'Fira Code', 'Courier New', monospace;
482
+ font-size: 0.78rem;
483
+ line-height: 1.6;
484
+ }
485
+
486
+ .script-code pre {
487
+ margin: 0;
488
+ white-space: pre;
489
+ }
490
+
491
+ .copy-btn {
492
+ position: absolute;
493
+ top: 1rem;
494
+ right: 1rem;
495
+ background: var(--ubuntu);
496
+ color: white;
497
+ border: none;
498
+ padding: 0.5rem 1rem;
499
+ border-radius: 6px;
500
+ cursor: pointer;
501
+ font-size: 0.8rem;
502
+ display: flex;
503
+ align-items: center;
504
+ gap: 0.4rem;
505
+ transition: var(--transition);
506
+ z-index: 10;
507
+ }
508
+
509
+ .copy-btn:hover {
510
+ background: #c0392b;
511
+ }
512
+
513
+ .copy-btn.copied {
514
+ background: var(--success);
515
+ }
516
+
517
+ /* Syntax highlighting */
518
+ .sh-comment {
519
+ color: #6a9955;
520
+ }
521
+
522
+ .sh-string {
523
+ color: #ce9178;
524
+ }
525
+
526
+ .sh-keyword {
527
+ color: #569cd6;
528
+ }
529
+
530
+ .sh-function {
531
+ color: #dcdcaa;
532
+ }
533
+
534
+ .sh-variable {
535
+ color: #9cdcfe;
536
+ }
537
+
538
+ .sh-command {
539
+ color: #4ec9b0;
540
+ }
541
+
542
+ .sh-flag {
543
+ color: #c586c0;
544
+ }
545
+
546
+ .sh-number {
547
+ color: #b5cea8;
548
+ }
549
+
550
+ .sh-operator {
551
+ color: #d4d4d4;
552
+ }
553
+
554
+ .alert {
555
+ padding: 1rem 1.5rem;
556
+ border-radius: 8px;
557
+ margin-bottom: 1.5rem;
558
+ display: flex;
559
+ align-items: flex-start;
560
+ gap: 1rem;
561
+ }
562
+
563
+ .alert-warning {
564
+ background: rgba(255, 193, 7, 0.15);
565
+ border: 1px solid rgba(255, 193, 7, 0.4);
566
+ }
567
+
568
+ .alert-warning i {
569
+ color: var(--warning);
570
+ font-size: 1.3rem;
571
+ }
572
+
573
+ .alert-info {
574
+ background: rgba(23, 162, 184, 0.15);
575
+ border: 1px solid rgba(23, 162, 184, 0.4);
576
+ }
577
+
578
+ .alert-info i {
579
+ color: var(--info);
580
+ font-size: 1.3rem;
581
+ }
582
+
583
+ .alert-success {
584
+ background: rgba(0, 217, 160, 0.15);
585
+ border: 1px solid rgba(0, 217, 160, 0.4);
586
+ }
587
+
588
+ .alert-success i {
589
+ color: var(--success);
590
+ font-size: 1.3rem;
591
+ }
592
+
593
+ .alert-content h4 {
594
+ margin-bottom: 0.3rem;
595
+ color: var(--light);
596
+ }
597
+
598
+ .alert-content p {
599
+ font-size: 0.9rem;
600
+ color: rgba(255, 255, 255, 0.8);
601
+ }
602
+
603
+ .fixes-list {
604
+ background: rgba(0, 0, 0, 0.3);
605
+ border-radius: 8px;
606
+ padding: 1.5rem;
607
+ margin-top: 1.5rem;
608
+ }
609
+
610
+ .fixes-list h3 {
611
+ color: var(--success);
612
+ margin-bottom: 1rem;
613
+ display: flex;
614
+ align-items: center;
615
+ gap: 0.5rem;
616
+ }
617
+
618
+ .fix-item {
619
+ display: flex;
620
+ align-items: flex-start;
621
+ gap: 1rem;
622
+ padding: 0.8rem 0;
623
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
624
+ }
625
+
626
+ .fix-item:last-child {
627
+ border-bottom: none;
628
+ }
629
+
630
+ .fix-icon {
631
+ width: 30px;
632
+ height: 30px;
633
+ background: var(--success);
634
+ border-radius: 50%;
635
+ display: flex;
636
+ align-items: center;
637
+ justify-content: center;
638
+ flex-shrink: 0;
639
+ }
640
+
641
+ .fix-icon i {
642
+ color: white;
643
+ font-size: 0.8rem;
644
+ }
645
+
646
+ .fix-content h4 {
647
+ font-size: 0.95rem;
648
+ color: var(--light);
649
+ margin-bottom: 0.3rem;
650
+ }
651
+
652
+ .fix-content p {
653
+ font-size: 0.85rem;
654
+ color: rgba(255, 255, 255, 0.7);
655
+ }
656
+
657
+ footer {
658
+ background: rgba(0, 0, 0, 0.5);
659
+ padding: 2rem;
660
+ text-align: center;
661
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
662
+ }
663
+
664
+ .footer-text {
665
+ color: rgba(255, 255, 255, 0.6);
666
+ font-size: 0.9rem;
667
+ }
668
+
669
+ .footer-text a {
670
+ color: var(--ubuntu);
671
+ text-decoration: none;
672
+ }
673
+
674
+ .footer-text a:hover {
675
+ text-decoration: underline;
676
+ }
677
+
678
+ @media (max-width: 768px) {
679
+ .header-content {
680
+ flex-direction: column;
681
+ text-align: center;
682
+ }
683
+
684
+ .scripts-grid {
685
+ grid-template-columns: 1fr;
686
+ }
687
+
688
+ .security-phases {
689
+ grid-template-columns: 1fr;
690
+ }
691
+
692
+ .script-code {
693
+ font-size: 0.7rem;
694
+ }
695
+
696
+ .script-tabs {
697
+ flex-wrap: nowrap;
698
+ }
699
+ }
700
+ </style>
701
  </head>
702
+
703
  <body>
704
+ <header>
705
+ <div class="header-content">
706
+ <a href="#" class="logo">
707
+ <div class="logo-icon">
708
+ <i class="fab fa-ubuntu"></i>
709
+ </div>
710
+ <div class="logo-text">
711
+ <h1>Gemma 3 Hardened Container <span class="version-badge">v2.1</span></h1>
712
+ <span>Ubuntu Shell Scripts - Production Ready with Full Security Pipeline</span>
713
+ </div>
714
+ </a>
715
+ <div class="built-with">
716
+ Built with <a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">anycoder</a>
717
+ </div>
718
+ </div>
719
+ </header>
720
+
721
+ <main>
722
+ <!-- Introduction -->
723
+ <section class="intro-section">
724
+ <div class="intro-header">
725
+ <div class="intro-icon">
726
+ <i class="fas fa-terminal"></i>
727
+ </div>
728
+ <div>
729
+ <h2 class="intro-title">Ubuntu Shell Scripts for Hardened LLM Container</h2>
730
+ <p class="intro-subtitle">Complete deployment scripts with all critical fixes + Build, Deploy & Runtime security phases</p>
731
+ </div>
732
+ </div>
733
+
734
+ <div class="fixes-list">
735
+ <h3><i class="fas fa-wrench"></i> Critical Fixes Applied in v2.1</h3>
736
+ <div class="fix-item">
737
+ <div class="fix-icon"><i class="fas fa-check"></i></div>
738
+ <div class="fix-content">
739
+ <h4>FIX #1: exec for Signal Handling</h4>
740
+ <p>Using <code>exec /usr/local/bin/llama-server</code> ensures the LLM server replaces the shell process (PID 1), receiving Docker's SIGTERM directly for proper graceful shutdown.</p>
741
+ </div>
742
+ </div>
743
+ <div class="fix-item">
744
+ <div class="fix-icon"><i class="fas fa-check"></i></div>
745
+ <div class="fix-content">
746
+ <h4>FIX #2: Build Phase - Vulnerability Scanning</h4>
747
+ <p>Integrated Trivy scanner in CI/CD pipeline to scan container image layers for CVEs before pushing to registry.</p>
748
+ </div>
749
+ </div>
750
+ <div class="fix-item">
751
+ <div class="fix-icon"><i class="fas fa-check"></i></div>
752
+ <div class="fix-content">
753
+ <h4>FIX #3: Deploy Phase - Policy Enforcement</h4>
754
+ <p>Kyverno policies for Kubernetes admission control - enforcing non-root, resource limits, and network isolation.</p>
755
+ </div>
756
  </div>
757
+ <div class="fix-item">
758
+ <div class="fix-icon"><i class="fas fa-check"></i></div>
759
+ <div class="fix-content">
760
+ <h4>FIX #4: Runtime Phase - Active Protection</h4>
761
+ <p>Falco rules for real-time syscall monitoring and anomaly detection with automatic threat response.</p>
762
+ </div>
763
+ </div>
764
+ </div>
765
+
766
+ <div class="quick-start">
767
+ <h3><i class="fas fa-rocket"></i> Quick Start</h3>
768
+ <div class="quick-start-code">
769
+ <pre><span class="comment"># 1. Download and make executable</span>
770
+ <span class="command">chmod +x</span> gemma3-*.sh
 
 
 
 
 
 
771
 
772
  <span class="comment"># 2. Run the setup script (requires sudo)</span>
773
  <span class="command">sudo ./gemma3-setup.sh</span>
774
 
775
+ <span class="comment"># 3. Build with vulnerability scanning</span>
776
+ <span class="command">./gemma3-build-scan.sh</span>
777
+
778
+ <span class="comment"># 4. Deploy with policy enforcement (Kubernetes)</span>
779
+ <span class="command">kubectl apply -f</span> kyverno-policies.yaml
780
+ <span class="command">kubectl apply -f</span> gemma3-deployment.yaml
781
+
782
+ <span class="comment"># 5. Enable runtime protection</span>
783
+ <span class="command">./gemma3-runtime-protect.sh</span>
784
 
785
+ <span class="comment"># 6. Verify security posture</span>
786
  <span class="command">./gemma3-verify.sh</span></pre>
 
 
 
 
 
 
 
 
 
 
 
787
  </div>
788
+ </div>
789
+ </section>
790
+
791
+ <!-- Security Phases -->
792
+ <h2 style="color: var(--light); margin-bottom: 1.5rem; display: flex; align-items: center; gap: 0.8rem;">
793
+ <i class="fas fa-shield-alt" style="color: var(--success);"></i>
794
+ Three-Phase Security Architecture
795
+ </h2>
796
+
797
+ <div class="security-phases">
798
+ <div class="phase-card">
799
+ <div class="phase-card-header build">
800
+ <div class="phase-icon">
801
+ <i class="fas fa-hammer"></i>
802
+ </div>
803
+ <div class="phase-title">
804
+ <h3>Build Phase</h3>
805
+ <span>Vulnerability Scanning</span>
806
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
807
  </div>
808
+ <div class="phase-card-body">
809
+ <p class="phase-description">
810
+ Integrated into CI/CD, tools scan container image layers for known CVEs. This prevents vulnerable code from reaching the registry.
811
+ </p>
812
+ <div class="phase-tools">
813
+ <span class="tool-badge"><i class="fas fa-search"></i> Trivy</span>
814
+ <span class="tool-badge"><i class="fas fa-shield-virus"></i> Clair</span>
815
+ <span class="tool-badge"><i class="fas fa-bug"></i> Grype</span>
816
+ <span class="tool-badge"><i class="fab fa-docker"></i> Docker Scout</span>
817
+ </div>
818
+ </div>
819
+ </div>
820
+
821
+ <div class="phase-card">
822
+ <div class="phase-card-header deploy">
823
+ <div class="phase-icon">
824
+ <i class="fas fa-gavel"></i>
825
+ </div>
826
+ <div class="phase-title">
827
+ <h3>Deploy Phase</h3>
828
+ <span>Policy Enforcement</span>
829
+ </div>
830
+ </div>
831
+ <div class="phase-card-body">
832
+ <p class="phase-description">
833
+ Kubernetes Admission Controllers check manifests against security policies before pods start (non-root, resource limits, network isolation).
834
+ </p>
835
+ <div class="phase-tools">
836
+ <span class="tool-badge"><i class="fas fa-clipboard-check"></i> Kyverno</span>
837
+ <span class="tool-badge"><i class="fas fa-balance-scale"></i> OPA Gatekeeper</span>
838
+ <span class="tool-badge"><i class="fas fa-lock"></i> Pod Security</span>
839
+ </div>
840
+ </div>
841
+ </div>
842
+
843
+ <div class="phase-card">
844
+ <div class="phase-card-header runtime">
845
+ <div class="phase-icon">
846
+ <i class="fas fa-eye"></i>
847
+ </div>
848
+ <div class="phase-title">
849
+ <h3>Runtime Phase</h3>
850
+ <span>Active Protection</span>
851
+ </div>
852
+ </div>
853
+ <div class="phase-card-body">
854
+ <p class="phase-description">
855
+ Real-time monitoring of syscalls, file access, and network activity. Detects and blocks anomalous behavior based on behavioral profiles.
856
+ </p>
857
+ <div class="phase-tools">
858
+ <span class="tool-badge"><i class="fas fa-crow"></i> Falco</span>
859
+ <span class="tool-badge"><i class="fas fa-spider"></i> Sysdig</span>
860
+ <span class="tool-badge"><i class="fas fa-network-wired"></i> Cilium</span>
861
+ </div>
862
+ </div>
863
+ </div>
864
+ </div>
865
+
866
+ <!-- Alerts -->
867
+ <div class="alert alert-success">
868
+ <i class="fas fa-check-circle"></i>
869
+ <div class="alert-content">
870
+ <h4>Signal Handling Fixed</h4>
871
+ <p>The entrypoint now uses <code>exec</code> to replace the shell with llama-server, ensuring proper SIGTERM delivery for graceful shutdown of GPU resources.</p>
872
+ </div>
873
+ </div>
874
+
875
+ <div class="alert alert-warning">
876
+ <i class="fas fa-exclamation-triangle"></i>
877
+ <div class="alert-content">
878
+ <h4>Prerequisites Required</h4>
879
+ <p>These scripts require Ubuntu 20.04+, Docker 20.10+, and sudo privileges. For Kubernetes features: kubectl, helm, and cluster admin access.</p>
880
+ </div>
881
+ </div>
882
+
883
+ <!-- Script Cards -->
884
+ <div class="scripts-grid">
885
+ <div class="script-card">
886
+ <div class="script-card-header">
887
+ <div class="script-card-title">
888
+ <i class="fas fa-cogs"></i>
889
+ gemma3-setup.sh
890
+ </div>
891
+ <span class="script-badge">Main Setup</span>
892
+ </div>
893
+ <div class="script-card-body">
894
+ <p class="script-description">
895
+ Complete system setup script that configures the host, builds the Docker image, and applies all security hardening.
896
+ </p>
897
+ <ul class="script-features">
898
+ <li><i class="fas fa-check"></i> Installs Docker and dependencies</li>
899
+ <li><i class="fas fa-check"></i> Creates non-root user (UID 1000)</li>
900
+ <li><i class="fas fa-check"></i> Generates Dockerfile with security</li>
901
+ <li><i class="fas fa-check"></i> Configures seccomp and AppArmor</li>
902
+ <li><i class="fas fa-check"></i> Sets up proper logging to stdout</li>
903
+ </ul>
904
+ <div class="script-actions">
905
+ <button class="btn btn-primary" onclick="scrollToScript('setup')">
906
+ <i class="fas fa-eye"></i> View Script
907
+ </button>
908
+ <button class="btn btn-secondary" onclick="downloadScript('setup')">
909
+ <i class="fas fa-download"></i> Download
910
+ </button>
911
+ </div>
912
+ </div>
913
+ </div>
914
+
915
+ <div class="script-card">
916
+ <div class="script-card-header">
917
+ <div class="script-card-title">
918
+ <i class="fas fa-play-circle"></i>
919
+ gemma3-entrypoint.sh
920
+ </div>
921
+ <span class="script-badge">Container Entry</span>
922
+ </div>
923
+ <div class="script-card-body">
924
+ <p class="script-description">
925
+ Container entrypoint with exec-based process replacement for proper signal handling and graceful shutdown.
926
+ </p>
927
+ <ul class="script-features">
928
+ <li><i class="fas fa-star new-feature"></i> <strong>exec</strong> for PID 1 signal handling</li>
929
+ <li><i class="fas fa-check"></i> Hardware RNG verification</li>
930
+ <li><i class="fas fa-check"></i> Entropy pool monitoring</li>
931
+ <li><i class="fas fa-check"></i> Stdout/stderr logging only</li>
932
+ <li><i class="fas fa-check"></i> Graceful SIGTERM handling</li>
933
+ </ul>
934
+ <div class="script-actions">
935
+ <button class="btn btn-primary" onclick="scrollToScript('entrypoint')">
936
+ <i class="fas fa-eye"></i> View Script
937
+ </button>
938
+ <button class="btn btn-secondary" onclick="downloadScript('entrypoint')">
939
+ <i class="fas fa-download"></i> Download
940
+ </button>
941
+ </div>
942
+ </div>
943
+ </div>
944
+
945
+ <div class="script-card">
946
+ <div class="script-card-header" style="background: linear-gradient(135deg, #3498db, #2980b9);">
947
+ <div class="script-card-title">
948
+ <i class="fas fa-search"></i>
949
+ gemma3-build-scan.sh
950
+ </div>
951
+ <span class="script-badge">NEW: Build Phase</span>
952
+ </div>
953
+ <div class="script-card-body">
954
+ <p class="script-description">
955
+ CI/CD integration script for vulnerability scanning with Trivy before pushing images to registry.
956
+ </p>
957
+ <ul class="script-features">
958
+ <li><i class="fas fa-star new-feature"></i> Trivy vulnerability scanner</li>
959
+ <li><i class="fas fa-star new-feature"></i> CVE severity thresholds</li>
960
+ <li><i class="fas fa-star new-feature"></i> SBOM generation</li>
961
+ <li><i class="fas fa-star new-feature"></i> Registry push gates</li>
962
+ <li><i class="fas fa-star new-feature"></i> JSON/SARIF reports</li>
963
+ </ul>
964
+ <div class="script-actions">
965
+ <button class="btn btn-primary" onclick="scrollToScript('build')">
966
+ <i class="fas fa-eye"></i> View Script
967
+ </button>
968
+ <button class="btn btn-secondary" onclick="downloadScript('build')">
969
+ <i class="fas fa-download"></i> Download
970
+ </button>
971
+ </div>
972
+ </div>
973
+ </div>
974
+
975
+ <div class="script-card">
976
+ <div class="script-card-header" style="background: linear-gradient(135deg, #9b59b6, #8e44ad);">
977
+ <div class="script-card-title">
978
+ <i class="fas fa-gavel"></i>
979
+ kyverno-policies.yaml
980
+ </div>
981
+ <span class="script-badge">NEW: Deploy Phase</span>
982
+ </div>
983
+ <div class="script-card-body">
984
+ <p class="script-description">
985
+ Kubernetes admission controller policies for enforcing security requirements at deployment time.
986
+ </p>
987
+ <ul class="script-features">
988
+ <li><i class="fas fa-star new-feature"></i> Non-root enforcement</li>
989
+ <li><i class="fas fa-star new-feature"></i> Resource limits required</li>
990
+ <li><i class="fas fa-star new-feature"></i> Read-only root filesystem</li>
991
+ <li><i class="fas fa-star new-feature"></i> Host namespace blocking</li>
992
+ <li><i class="fas fa-star new-feature"></i> Privileged container denial</li>
993
+ </ul>
994
+ <div class="script-actions">
995
+ <button class="btn btn-primary" onclick="scrollToScript('kyverno')">
996
+ <i class="fas fa-eye"></i> View Policy
997
+ </button>
998
+ <button class="btn btn-secondary" onclick="downloadScript('kyverno')">
999
+ <i class="fas fa-download"></i> Download
1000
+ </button>
1001
+ </div>
1002
+ </div>
1003
+ </div>
1004
+
1005
+ <div class="script-card">
1006
+ <div class="script-card-header" style="background: linear-gradient(135deg, #e74c3c, #c0392b);">
1007
+ <div class="script-card-title">
1008
+ <i class="fas fa-crow"></i>
1009
+ gemma3-runtime-protect.sh
1010
+ </div>
1011
+ <span class="script-badge">NEW: Runtime Phase</span>
1012
+ </div>
1013
+ <div class="script-card-body">
1014
+ <p class="script-description">
1015
+ Falco-based runtime security with custom rules for LLM container behavioral monitoring.
1016
+ </p>
1017
+ <ul class="script-features">
1018
+ <li><i class="fas fa-star new-feature"></i> Syscall monitoring</li>
1019
+ <li><i class="fas fa-star new-feature"></i> File access detection</li>
1020
+ <li><i class="fas fa-star new-feature"></i> Network anomaly alerts</li>
1021
+ <li><i class="fas fa-star new-feature"></i> Shell spawn detection</li>
1022
+ <li><i class="fas fa-star new-feature"></i> Automatic threat response</li>
1023
+ </ul>
1024
+ <div class="script-actions">
1025
+ <button class="btn btn-primary" onclick="scrollToScript('runtime')">
1026
+ <i class="fas fa-eye"></i> View Script
1027
+ </button>
1028
+ <button class="btn btn-secondary" onclick="downloadScript('runtime')">
1029
+ <i class="fas fa-download"></i> Download
1030
+ </button>
1031
+ </div>
1032
+ </div>
1033
+ </div>
1034
+
1035
+ <div class="script-card">
1036
+ <div class="script-card-header">
1037
+ <div class="script-card-title">
1038
+ <i class="fas fa-shield-alt"></i>
1039
+ gemma3-verify.sh
1040
+ </div>
1041
+ <span class="script-badge">Security Audit</span>
1042
+ </div>
1043
+ <div class="script-card-body">
1044
+ <p class="script-description">
1045
+ Comprehensive verification script that audits all three security phases and generates a compliance report.
1046
+ </p>
1047
+ <ul class="script-features">
1048
+ <li><i class="fas fa-check"></i> Filesystem permissions check</li>
1049
+ <li><i class="fas fa-check"></i> Capability verification</li>
1050
+ <li><i class="fas fa-check"></i> Seccomp profile validation</li>
1051
+ <li><i