Skip to content

Commit 1aa97f4

Browse files
committed
Add bulk import, session tools, and analysis
Introduce bulk host import, subnet-to-zone mappings, session export/import and lifecycle management, and a relationship analysis UI. public/index.html: add UI sections (Subnet Mappings, Bulk Import, Session Tools, Path Criteria, Analysis, Comparison), CSS for findings/controls, persistent state TTL (45 days) and save/load/clearState behavior, export/import helpers (JSON/CSV/PNG), parsing/merge logic for host lists, neighbour/ARP and DHCP leases, CIDR parsing and zone inference, protocol/port path criteria, improved rule matching, analysis findings generation, and accessibility for relationship entries. ARCHITECTURE.md: update roadmap/status and document implemented functions and TODOs. Add scripts/openwrt_export_hosts.sh: skeleton exporter for OpenWrt host data. These changes improve import workflows, make session handling robust against stale/corrupt storage, and add basic automated analysis and comparison features.
1 parent 54c530b commit 1aa97f4

3 files changed

Lines changed: 1321 additions & 86 deletions

File tree

ARCHITECTURE.md

Lines changed: 78 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ The example is useful for demonstrating the relationship views, but it should no
351351
| Simplified parser | Good for common UCI files, not a complete UCI interpreter |
352352
| Simplified decision engine | Useful for visual exploration, not a full firewall simulation |
353353
| Protocol and port fields are not evaluated | Per-service conclusions may be inaccurate |
354-
| Browser-local persistence | Saved state is per browser/profile and is not portable without a future import/export feature |
354+
| Browser-local persistence | Saved state is per browser/profile unless exported as JSON |
355355
| CDN dependency | Graph rendering depends on external script availability |
356356
| No automated tests | Behaviour is currently verified manually |
357357

@@ -373,8 +373,9 @@ Stored fields:
373373

374374
Relevant functions:
375375

376-
- `saveToLocalStorage()`.
377-
- `loadFromLocalStorage()`.
376+
- `saveState()`.
377+
- `loadState()`.
378+
- `clearExpiredState()`.
378379
- `readStoredState()`.
379380
- `normaliseSavedDevices()`.
380381
- `normaliseSavedTestPath()`.
@@ -415,13 +416,13 @@ Relevant functions and elements:
415416
- `#currentYear`.
416417
- `setCurrentYear()`.
417418

418-
## Future Enhancements
419+
## Implemented Future Enhancements
419420

420-
The following planned phases continue the roadmap sequence after implemented Phase A-C.
421+
The following phases continue the roadmap sequence after Phase A-C and are now implemented in `public/index.html`.
421422

422423
### Phase D: Local Storage Lifecycle Management
423424

424-
Status: planned.
425+
Status: implemented.
425426

426427
Objective: prevent stale browser state from living indefinitely while keeping the local-first workflow.
427428

@@ -434,19 +435,18 @@ Requirements:
434435
- Handle corrupted `localStorage` data gracefully.
435436
- Preserve backwards compatibility where possible for existing saved payloads.
436437

437-
Implementation notes:
438+
Implemented details:
438439

439-
- Keep `STORAGE_KEY` as the stable state namespace.
440-
- Introduce `STORAGE_TTL_DAYS = 45`.
441-
- Store `savedAt` or equivalent metadata in the persisted payload.
442-
- Implement `saveState()`.
443-
- Implement `loadState()`.
444-
- Implement `clearExpiredState()`.
445-
- Call `clearExpiredState()` during startup before applying saved state.
440+
- `STORAGE_KEY` remains the stable state namespace.
441+
- `STORAGE_TTL_DAYS = 45` defines expiry.
442+
- `savedAt` is stored in the persisted payload.
443+
- `saveState()` writes the timestamped state.
444+
- `loadState()` restores state and falls back to defaults.
445+
- `clearExpiredState()` silently removes expired or corrupted payloads on startup.
446446

447447
### Phase E: Graph Initial State Improvements
448448

449-
Status: planned.
449+
Status: implemented.
450450

451451
Objective: improve first-load user experience by preventing automatic path highlighting.
452452

@@ -458,15 +458,16 @@ Requirements:
458458
- No path should be highlighted until the user explicitly clicks a graph node.
459459
- No path should be highlighted until the user explicitly clicks a relationship entry.
460460

461-
Implementation notes:
461+
Implemented details:
462462

463-
- Separate path-result rendering from graph path highlighting.
464-
- Track whether the user has explicitly requested a path highlight.
465-
- Keep automatic path re-evaluation for text results, but defer graph highlighting until user action.
463+
- Path-result rendering is separated from graph path highlighting.
464+
- `graphPathHighlightRequested` tracks explicit path-highlighting intent.
465+
- Automatic re-renders update text results without selecting graph elements.
466+
- Graph highlighting is triggered only by "Test Path", graph node clicks, or relationship-card clicks.
466467

467468
### Phase F: Bulk Host Import
468469

469-
Status: planned.
470+
Status: implemented.
470471

471472
Objective: allow users to populate devices from existing network inventories instead of manually adding hosts one at a time.
472473

@@ -503,13 +504,13 @@ Supported Linux neighbour table format:
503504
172.16.20.11 dev br-iot lladdr aa:bb:cc:dd:ee:00 STALE
504505
```
505506

506-
Implementation notes:
507+
Implemented details:
507508

508-
- Create `importBulkHosts()`.
509-
- Create `parseBulkHosts()`.
510-
- Create `parseHostLine()`.
511-
- Create `mergeDevices()`.
512-
- Report skipped or unrecognised lines without blocking valid imports.
509+
- `importBulkHosts()` imports the textarea content.
510+
- `parseBulkHosts()` parses host data line-by-line.
511+
- `parseHostLine()` handles host-list, neighbour/ARP, and DHCP lease formats.
512+
- `mergeDevices()` merges by IP without overwriting manually supplied names or zones.
513+
- Skipped and unresolved lines are reported in the import result panel.
513514

514515
Benefits:
515516

@@ -519,7 +520,7 @@ Benefits:
519520

520521
### Phase G: Zone Inference Engine
521522

522-
Status: planned.
523+
Status: partially implemented.
523524

524525
Objective: automatically assign firewall zones from subnet definitions when imported hosts do not include a zone.
525526

@@ -551,16 +552,25 @@ Expected inferred result:
551552
zone = iot
552553
```
553554

554-
Implementation notes:
555+
Implemented details:
555556

556-
- Add a subnet mapping input area.
557-
- Parse CIDR notation into comparable network ranges.
558-
- Apply inference during bulk import and device normalisation.
559-
- Surface unresolved hosts so the user can assign zones manually.
557+
- The `subnetMappings` textarea stores subnet-to-zone mappings.
558+
- `parseSubnetMappings()` parses CIDR mappings.
559+
- `inferZoneForIp()` assigns zones during import when a host line has no explicit zone.
560+
- Unresolved imported hosts are counted in the import result panel.
561+
562+
Todo:
563+
564+
- Supported Input Formats
565+
- 1. Manual Zone/Subnet Mapping (done)
566+
- 2. OpenWRT UCI Export (todo)
567+
- uci show firewall | grep "\.network="
568+
- uci show network | grep -E "\.(ipaddr|netmask|proto)="
569+
-
560570

561571
### Phase H: Network Discovery Importers
562572

563-
Status: planned.
573+
Status: partially implemented.
564574

565575
Objective: support importing host data directly from common network tooling output.
566576

@@ -571,16 +581,28 @@ Initial import targets:
571581
- OpenWrt `ip neighbour`.
572582
- OpenWrt `cat /tmp/dhcp.leases`, preferably because it includes hostnames.
573583

574-
Implementation notes:
584+
Implemented details:
585+
586+
- `parseNeighbourLine()` supports Linux/OpenWrt `ip neighbour` and common `arp -a` output.
587+
- `parseDhcpLeaseLine()` supports OpenWrt `/tmp/dhcp.leases`.
588+
- DHCP hostnames are preferred when present.
589+
- IP-only names are used when no hostname is available.
590+
- Skipped source lines are shown in the import result panel.
575591

576-
- Feed parsed importer output into the Phase F bulk host import path.
577-
- Prefer hostnames from DHCP lease data when available.
578-
- Fall back to IP-only device names when no hostname is present.
579-
- Preserve raw importer output for troubleshooting skipped lines.
592+
TODO:
593+
594+
- Better placeholder for different import methods
595+
- Support for `openwrt_export_hosts.sh` script
596+
- ip,hostname,zone,mac
597+
172.16.20.10,Alexa-Kitchen,iot,aa:bb:cc:dd:ee:ff
598+
172.16.20.11,Alexa-Bedroom,iot,aa:bb:cc:dd:ee:00
599+
172.16.30.25,Guest-Phone,guest,aa:bb:cc:dd:ee:11
600+
- ? button which points to the script
601+
-
580602

581603
### Phase I: Relationship Analysis Engine
582604

583-
Status: planned.
605+
Status: implemented.
584606

585607
Objective: move beyond visualisation and provide automated security analysis.
586608

@@ -595,41 +617,47 @@ Requirements:
595617
- Detect zones with unrestricted forwarding.
596618
- Detect device exceptions that bypass segmentation.
597619

598-
Implementation notes:
620+
Implemented details:
599621

600-
- Build analysis rules on top of `evaluateZonePath()` and `evaluateDevicePath()`.
601-
- Return findings with severity, affected source, affected destination, and reason.
602-
- Add a findings panel before recommending changes.
622+
- `buildAnalysisFindings()` builds findings on top of `evaluateZonePath()` and `evaluateDevicePath()`.
623+
- Findings include severity, title, and reason.
624+
- `renderAnalysisFindings()` renders the findings panel.
603625

604626
### Phase J: Rule Engine Accuracy
605627

606-
Status: planned.
628+
Status: implemented.
607629

608-
Improve decision accuracy before adding policy recommendations.
630+
Decision accuracy has been improved before adding policy recommendations.
609631

610-
Candidate improvements:
632+
Implemented improvements:
611633

612634
- Honour protocol matching.
613635
- Honour destination port matching.
614636
- Represent rule order more explicitly in explanations.
615637
- Distinguish `ACCEPT`, `REJECT`, and `DROP`.
616638
- Surface unsupported rule fields in the UI.
617-
- Consider zone `input` and `output` policies where relevant.
639+
- Keep zone `input` and `output` visible in zone cards while forwarding decisions remain based on zone forwardings and same-zone forward policy.
618640

619641
### Phase K: Import, Export, And Comparison
620642

621-
Status: planned.
643+
Status: Mostly.
622644

623-
Add workflows for longer-lived analysis.
645+
Workflows for longer-lived analysis are now available.
624646

625-
Candidate improvements:
647+
Implemented improvements:
626648

627649
- Export device mappings as JSON or CSV.
628650
- Import saved device mappings.
629651
- Export graph images.
630652
- Compare two firewall configs.
631653
- Show before/after impact for changed forwardings and rules.
632654

655+
Todo:
656+
657+
- Clear colour coding for Export Session
658+
- Clearer button for Import Session
659+
660+
633661
## Development Notes
634662

635663
The current implementation is intentionally simple:

0 commit comments

Comments
 (0)