Skip to content

Commit 31619f9

Browse files
author
Peter Wagstaff
committed
Merge branch 'format-improvement' into 'main'
Format improvement See merge request sl5tf/control-overlays-selector!1
2 parents 8146d6f + ea62b31 commit 31619f9

2 files changed

Lines changed: 141 additions & 3 deletions

File tree

CLAUDE.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
This is a web application for viewing and managing security control overlays based on NIST SP 800-53 controls. It's designed for security professionals working with frontier AI development, displaying NIST controls with various security overlays including SL5 (Security Level 5), FedRAMP, CNSSI 1253, and others.
8+
9+
## Architecture
10+
11+
- **Frontend**: Single-page application using vanilla JavaScript embedded in `index.html` (no build process)
12+
- **Data Pipeline**: Python scripts extract data from PDF overlays → JSON files → JavaScript web app
13+
- **Hosting**: GitLab Pages (https://gitlab.com/sl5tf/control-overlays-selector)
14+
15+
## Common Development Commands
16+
17+
### Python Data Extraction
18+
```bash
19+
# Extract overlay data from PDFs (requires PyMuPDF/fitz)
20+
python sl5_overlay/extract_sl5_overlay.py sl5_overlay/sl5_overlay.pdf
21+
python cnssi_1253/extract_cnssi_1253.py cnssi_1253/cnssi_1253_overlay.pdf
22+
python classified_information/extract_classified_information_overlay.py classified_information/classified_information_overlay.pdf
23+
24+
# Debug specific pages
25+
python sl5_overlay/extract_sl5_overlay.py sl5_overlay/sl5_overlay.pdf --debug-page 10
26+
27+
# Merge CNSSI data
28+
python cnssi_1253/cnssi_merger.py
29+
30+
# Sort NIST controls naturally
31+
python nist_catalog/nist_sorter.py input.json output.json
32+
```
33+
34+
### Development
35+
- No build process - edit `index.html` directly
36+
- No package manager - pure vanilla JavaScript
37+
- Deploy by pushing to GitLab (configured in `.gitlab-ci.yml`)
38+
39+
## Code Structure
40+
41+
### Frontend (`index.html`)
42+
- **Data Loading**: `loadData()` fetches all JSON files
43+
- **Rendering**: `renderControls()` displays filtered controls
44+
- **State**: Global variables store control data and overlay states
45+
- **Events**: Toggle overlays, search, filter by family, expand/collapse controls
46+
47+
### Data Pipeline
48+
Each overlay directory contains:
49+
- PDF source document
50+
- Python extractor script (`extract_*.py`)
51+
- Generated JSON data file
52+
- Common pattern: PDF → Python extractor → JSON → Web app
53+
54+
### Key Data Structures
55+
```javascript
56+
// Control format
57+
{
58+
"id": "AC-1",
59+
"text": "Control description...",
60+
"family": "Access Control",
61+
"enhancements": [...],
62+
"discussion": "..."
63+
}
64+
65+
// Overlay format varies by type
66+
// SL5: {"selected": true/false, "attributes": {...}}
67+
// CNSSI: {"control_text": "", "defined_value": "", "selected": true/false}
68+
```
69+
70+
## Important Patterns
71+
72+
1. **Control ID Format**: `[A-Z]{2}-\d{1,2}` (base) or `[A-Z]{2}-\d{1,2}\(\d+\)` (enhancement)
73+
2. **Overlay Toggle Logic**: Each overlay can be enabled/disabled, affecting control visibility
74+
3. **Enhancement Display**: Controls with enhancements have expandable sections
75+
4. **Modal System**: Click control IDs to preview in modal
76+
5. **Natural Sorting**: Controls sorted as AC-1, AC-2, ..., AC-10 (not lexically)
77+
78+
## Adding New Overlays
79+
80+
1. Create directory for new overlay
81+
2. Add PDF source document
82+
3. Create Python extractor following existing patterns (see `sl5_overlay/extract_sl5_overlay.py` as template)
83+
4. Generate JSON data
84+
5. Add overlay loading in `loadData()` function
85+
6. Add toggle UI in overlay panel
86+
7. Update `getOverlayInfo()` to handle new overlay format
87+
88+
## Testing
89+
90+
No automated tests exist. Manual testing process:
91+
1. Run Python extractors on PDFs
92+
2. Verify JSON output structure
93+
3. Load in browser and test filtering/toggling
94+
4. Check control display and enhancements
95+
5. Test search functionality
96+
97+
## Dependencies
98+
99+
- **Python**: PyMuPDF (fitz) for PDF extraction
100+
- **JavaScript**: None (vanilla JS only)
101+
- **Deployment**: GitLab Pages via CI/CD

index.html

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,10 @@
264264
color: #374151;
265265
text-align: left;
266266
}
267+
.control-text div {
268+
line-height: 1.6;
269+
margin-bottom: 0.25em;
270+
}
267271
.control-discussion {
268272
background: #f9fafb;
269273
padding: 1rem;
@@ -571,6 +575,10 @@
571575
color: #4b5563;
572576
margin-bottom: 1rem;
573577
}
578+
.modal-control-text div {
579+
line-height: 1.6;
580+
margin-bottom: 0.25em;
581+
}
574582
.modal-overlays {
575583
margin-bottom: 1rem;
576584
}
@@ -869,6 +877,35 @@ <h2 class="toggles-title">Additional Security Assumptions</h2>
869877
attachSearchListeners();
870878
}
871879

880+
// --------------------
881+
// Helper Functions
882+
// --------------------
883+
function formatControlText(text) {
884+
if (!text) return '';
885+
886+
// Split by newlines and process each line
887+
const lines = text.split('\n');
888+
const formattedLines = lines.map(line => {
889+
// Check for different indentation patterns
890+
if (line.match(/^\([a-z]\)/)) {
891+
// Lines starting with (a), (b), etc. - deepest level
892+
return `<div style="margin-left: 3em;">${line}</div>`;
893+
} else if (line.match(/^\d+\./)) {
894+
// Lines starting with 1., 2., etc. - middle level
895+
return `<div style="margin-left: 1.5em;">${line}</div>`;
896+
} else if (line.match(/^[a-z]\./)) {
897+
// Lines starting with a., b., etc. - top level
898+
return `<div style="margin-top: 0.5em;">${line}</div>`;
899+
} else if (line.trim() !== '') {
900+
// Other non-empty lines (continuation of previous line)
901+
return `<div style="margin-left: 1.5em;">${line}</div>`;
902+
}
903+
return '';
904+
});
905+
906+
return formattedLines.join('');
907+
}
908+
872909
// --------------------
873910
// Main Render Function
874911
// --------------------
@@ -957,7 +994,7 @@ <h2 class="toggles-title">Additional Security Assumptions</h2>
957994
</div>
958995
</div>
959996
<div class="control-details" id="details-${control.id}">
960-
<div class="control-text"><strong>Control Text:</strong><br>${control.text}</div>
997+
<div class="control-text"><strong>Control Text:</strong><br>${formatControlText(control.text)}</div>
961998
${control.discussion ? `
962999
<div class="control-discussion">
9631000
<div class="discussion-title">Discussion:</div>
@@ -1120,7 +1157,7 @@ <h3 class="overlays-title">Overlays</h3>
11201157
<div class="modal-control-name">${targetControl.name}</div>
11211158
<div class="modal-control-text">
11221159
<strong>Control Text:</strong><br>
1123-
${targetControl.text}
1160+
${formatControlText(targetControl.text)}
11241161
</div>
11251162
${overlays.length > 0 ? `
11261163
<div class="modal-overlays">
@@ -1593,7 +1630,7 @@ <h3 class="overlays-title">Overlays</h3>
15931630
</div>
15941631
</div>
15951632
<div class="control-details" id="details-${enhancementId}">
1596-
<div class="control-text"><strong>Enhancement Text:</strong><br>${enhancement.text}</div>
1633+
<div class="control-text"><strong>Enhancement Text:</strong><br>${formatControlText(enhancement.text)}</div>
15971634
${enhancement.discussion ? `
15981635
<div class="control-discussion">
15991636
<div class="discussion-title">Discussion:</div>

0 commit comments

Comments
 (0)