Skip to content

Commit 017ef45

Browse files
jrx-codeclaude
andcommitted
fix: v0.20.3 — preserve settings on upgrade, trim changelog
init_from_env() now only seeds settings.json for keys not yet saved (checks _load_raw() instead of load()). Previously env vars from addon config overwrote web UI settings on every restart. CHANGELOG.md trimmed to show only the latest version for HA Supervisor panel. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 68736f3 commit 017ef45

3 files changed

Lines changed: 18 additions & 179 deletions

File tree

ha-sandbox/CHANGELOG.md

Lines changed: 4 additions & 168 deletions
Original file line numberDiff line numberDiff line change
@@ -1,172 +1,8 @@
11
# Changelog
22

3-
## [0.13.0] - 2026-03-10
4-
5-
### Added
6-
- **PDF export**`/api/report/{id}/pdf` endpoint + PDF button in UI; uses fpdf2 with DejaVu Unicode font (Alpine) and Helvetica fallback
7-
8-
### Changed
9-
- **AI model** — default switched from gemma3:12b to qwen2.5-coder:14b (4/4 category coverage, 0/10 on malicious code vs 2/10, 9/10 on safe code vs 5/10)
10-
- **AI prompt rewrite** — single-step Ollama call (was 2-step losing context), system prompt now used for Ollama (was missing), explicit "do not repeat static findings" instruction
11-
- **AI deduplication** — AI findings that duplicate static findings (same category+file) are filtered before report; eliminates duplicate noise
12-
- **AI confidence** — improved from 50% to 95% on benchmark test case
13-
14-
### Fixed
15-
- **Findings display bug** — HTML in `code` field (e.g. `innerHTML = '<div...'`) was parsed as real DOM elements, hiding subsequent findings; all report fields now HTML-escaped before rendering
16-
- **XSS hardening**`ai_summary`, `description`, `code`, `file`, `category` escaped via `esc()` helper; `onclick` handlers use `JSON.stringify()` instead of manual backtick escaping
17-
- **HTML export** — same HTML-escape fix applied to standalone HTML export
18-
19-
## [0.12.2] - 2026-03-10
3+
## [0.20.3] - 2026-03-10
204

215
### Fixed
22-
- **Ingress double-slash**`GET //` from Supervisor proxy now redirects to `/` (was returning 404)
23-
- **Startup race condition** — retry loop waits for Supervisor API before reading config (fixes "Unable to access the API, forbidden" on fresh install)
24-
- **MQTT graceful fallback** — no more error when MQTT service not configured in Supervisor
25-
26-
## [0.12.1] - 2026-03-10
27-
28-
### Fixed
29-
- **AppArmor install error** — removed custom `apparmor.txt` profile that caused `Can't load profile` / `exit status 1` on HAOS (AppArmor 3.1.2); Supervisor now uses default Docker AppArmor profile
30-
- Reproduced and verified on fresh HAOS 14.2 KVM VM
31-
32-
## [0.12.0] - 2026-03-09
33-
34-
### Improved (Actionable Finding Descriptions)
35-
- **JS scanner** — all descriptions rewritten: eval→JSON.parse, innerHTML→textContent/DOMPurify, fetch→verify URL, localStorage→check stored data
36-
- **Python scanner** — subprocess, pickle, exec, os.system, requests descriptions now include specific remediation
37-
- **HA scanner** — services.call, bus.fire, auth access, dynamic entity descriptions include attack scenarios
38-
- **Pattern**: "What was detected → Why it's risky → What to do" across all scanners
39-
- No new tests needed (descriptions only, 265 tests still passing)
40-
41-
## [0.11.0] - 2026-03-09
42-
43-
### Added (Dependency Scanner Enhancement — 3/5 → 5/5)
44-
- **npm/package.json scanning** — parse dependencies + devDependencies, query OSV.dev with ecosystem=npm
45-
- **requirements.txt auto-discovery** — find and scan all `requirements*.txt` files in repo
46-
- **pyproject.toml parsing** — extract `[project.dependencies]` for CVE checking
47-
- **Known malicious package detection** — 30+ PyPI + 25+ npm typosquatting/supply chain packages (CRITICAL severity)
48-
- **OSV.dev batch query**`/v1/querybatch` for efficient bulk CVE lookup (100 per batch)
49-
- **Repo-wide dependency scan**`check_cve_repo()` discovers all dep files automatically
50-
- **Pipeline integration** — Phase 1c scans repo deps in addition to manifest requirements
51-
- 21 new tests (265 total)
52-
53-
## [0.10.0] - 2026-03-09
54-
55-
### Added (YAML Scanner Enhancement — 2/5 → 4/5)
56-
- **Structural YAML parsing** via `yaml.safe_load()` — analyzes parsed tree, not just regex
57-
- **Automation flow injection detection**`service_template`, dynamic `service` with templates, template values in `data` flowing to `shell_command`
58-
- **Nested action scanning** — follows `choose/sequence/then/else/default` structures
59-
- **rest_command HTTP detection** — flags `rest_command` and `rest` using HTTP (not HTTPS)
60-
- **!include path validation** — detects template paths, absolute paths, parent traversal (`..`)
61-
- **Secrets in comments** — finds password/token/api_key values accidentally left in YAML comments
62-
- **Per-file finding cap** — max 3 per category per file (consistent with Python/JS/HA scanners)
63-
- **Standalone automation list support** — scans list-at-root automation files
64-
- 22 new tests (244 total)
65-
66-
## [0.9.0] - 2026-03-09
67-
68-
### Improved (batch scan on 50 HACS repos)
69-
- **Noise reduction**: findings cut by 90%+ on large repos (e.g. 804→13 for waste_collection_schedule)
70-
- `re.compile()` no longer flagged as code injection (only bare `compile()`)
71-
- `compile()` severity reduced from HIGH to MEDIUM (legitimate use common)
72-
- Per-file finding cap: max 3 findings per category per file
73-
- Network import aggregation: max 5 kept + summary for repos with many modules
74-
- `parse_info` aggregated: 1 per repo instead of 1 per file (412→1 for large cards)
75-
- Removed noisy `appendChild` detection (LOW value, extreme volume)
76-
- Vendor/third-party JS files skipped (docsify, prism, marked, etc.)
77-
- `docs/` directory excluded from JS scanning
78-
- 8 new tests for noise reduction (222 total)
79-
80-
## [0.8.0] - 2026-03-09
81-
82-
### Added
83-
- **Code Learning** — 4-module learning pipeline:
84-
- L.1 Pattern Fingerprinting — extract structural fingerprints (imports, HA APIs, network domains, file types)
85-
- L.2 Baseline / Norm Database — statistical profiling from scan history, deviation detection (z-score > 2σ)
86-
- L.3 Whitelist / False Positives — "Ignoruj" button in UI, pattern-based whitelist with category+file matching
87-
- L.4 Reputation Score — track safety score trends across versions with ↑/↓/→ trend indicators
88-
- Reputation display in report modal (scan count, average score, trend)
89-
- CSV/HTML export buttons in report modal
90-
- REST API endpoints: `/api/whitelist` (CRUD), `/api/reputation` (per-domain + all)
91-
- 25 new tests covering all learning modules (208 total)
92-
93-
### Changed
94-
- Scan pipeline now filters whitelisted findings before report generation
95-
- Fingerprint and reputation data recorded automatically after each scan
96-
97-
## [0.7.0] - 2026-03-09
98-
99-
### Added
100-
- JavaScript AST parser using esprima with regex fallback for ES2020+
101-
- Python taint tracking — data flow analysis from user input to dangerous sinks
102-
- HA API pattern validator — detects risky hass.services, event bus, auth access
103-
- Batch scanning with SQLite-backed queue and progress tracking
104-
- Report export: CSV and standalone HTML (print/PDF ready)
105-
- Finding deduplication with category aliases and severity merge
106-
- Structured AI prompting with scoring rubric, few-shot examples, confidence scores
107-
108-
## [0.6.0] - 2026-03-09
109-
110-
### Added
111-
- YAML/Jinja2 scanner (shell_command, hardcoded secrets, unsafe HTTP, injection)
112-
- CVE database lookup via OSV.dev for dependency scanning
113-
- SQLite job persistence (survives restarts)
114-
- MQTT scans_total counter (persisted across restarts)
115-
116-
### Fixed
117-
- MQTT TLS connection with proper certificate verification
118-
119-
## [0.5.1] - 2026-03-07
120-
121-
### Fixed
122-
- Active scans no longer stay visible after completion
123-
- Failed scans show red badge instead of spinner
124-
125-
### Added
126-
- Version tag visible in UI header (both pages)
127-
- Findings sorted by severity in report details (critical → info)
128-
129-
## [0.5.0] - 2026-03-07
130-
131-
### Changed
132-
- Converted to HA Add-on format (config.yaml, run.sh, build.yaml)
133-
- Dockerfile uses HA base images (Alpine + Python 3.13)
134-
- Version sourced from config.yaml (single source of truth)
135-
- Added HA Ingress support (X-Ingress-Path, SSO)
136-
- MQTT auto-detects Supervisor MQTT service
137-
- HA token auto-injected via Supervisor API
138-
- Data stored in /share/ha-sandbox/
139-
140-
## [0.4.0] - 2026-03-06
141-
142-
### Added
143-
- Settings page with dual AI provider support (Ollama/Public API)
144-
- Clear Results button on dashboard
145-
- Centralized version constant
146-
- Test suite (87 tests) covering all phases
147-
148-
### Fixed
149-
- 3 production bugs found via test suite
150-
151-
## [0.3.0] - 2026-03-06
152-
153-
### Changed
154-
- UI theme switched from dark blue to Nord color palette
155-
156-
## [0.2.0] - 2026-03-06
157-
158-
### Added
159-
- MQTT auto-discovery for Home Assistant
160-
- Static analysis for JavaScript/TypeScript
161-
- AI review via Ollama with code context
162-
- Report generation with JSON persistence
163-
- Installed HACS component listing via WebSocket
164-
165-
## [0.1.0] - 2026-03-06
166-
167-
### Added
168-
- Initial release
169-
- Repository cloning and manifest parsing
170-
- Static Python analysis (AST-based)
171-
- FastAPI web dashboard
172-
- Background scan pipeline
6+
- **Settings preserved on upgrade** — env vars from addon config now only seed settings.json on first start; web UI settings survive restarts and upgrades
7+
- **OpenRouter 401 Forbidden** — addon config API key (set in HA UI) synced to settings.json on first start
8+
- **Changelog** — now shows only latest version (was showing full history)

ha-sandbox/app/settings.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -111,24 +111,27 @@ def _apply_to_runtime(data: dict) -> None:
111111

112112

113113
def init_from_env() -> None:
114-
"""On startup, merge env vars into saved settings (env takes precedence for secrets).
114+
"""On startup, seed settings.json from env vars (only for keys not yet saved).
115115
116116
The HA addon config UI sets options that run.sh exports as SANDBOX_* env vars.
117-
These must be synced into settings.json so that settings.load() returns them.
118-
Without this, _get_ai_config() would return empty defaults and API calls fail (401).
117+
On first start these seed settings.json so _get_ai_config() picks them up.
118+
On subsequent restarts/upgrades, saved values (from web UI settings page)
119+
are preserved — env vars never overwrite existing settings.
119120
"""
120121
import os
121-
data = load()
122+
raw = _load_raw() # only what's explicitly saved (no defaults)
123+
data = {**DEFAULTS, **raw}
124+
122125
env_token = os.environ.get("HA_TOKEN", "")
123-
if env_token and not data.get("ha_token"):
126+
if env_token and not raw.get("ha_token"):
124127
data["ha_token"] = env_token
125128
env_mqtt_pass = os.environ.get("MQTT_PASS", "")
126-
if env_mqtt_pass and not data.get("mqtt_pass"):
129+
if env_mqtt_pass and not raw.get("mqtt_pass"):
127130
data["mqtt_pass"] = env_mqtt_pass
128131

129-
# Sync addon config options (SANDBOX_* env vars from run.sh) into settings.json.
130-
# Env takes precedence over saved settings for these fields, because the user
131-
# sets them in the HA addon config UI and expects them to take effect immediately.
132+
# Seed addon config options into settings.json on first start.
133+
# Only set values not already saved — this way web UI settings
134+
# (written to settings.json via /api/settings) survive restarts.
132135
env_map = {
133136
"SANDBOX_AI_PROVIDER": "ai_provider",
134137
"SANDBOX_PUBLIC_PROVIDER": "public_provider",
@@ -140,7 +143,7 @@ def init_from_env() -> None:
140143
}
141144
for env_var, setting_key in env_map.items():
142145
val = os.environ.get(env_var, "")
143-
if val:
146+
if val and setting_key not in raw:
144147
data[setting_key] = val
145148

146149
save(data)

ha-sandbox/config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: "HA Security Sandbox"
2-
version: "0.20.2"
2+
version: "0.20.3"
33
slug: ha_security_sandbox
44
description: "Security scanner for Home Assistant custom components — static analysis + AI review"
55
url: "https://github.com/jrx-code/ha-security-sandbox"

0 commit comments

Comments
 (0)