**Test status:** Core pure-logic modules are covered (config, leak_detect, validator timing, chain_map, browser persona). No automated tests touch `service.py`, `firewall.py`, `gost_util.py`, `sysproxy.py`, or `app.py`.
**Top 5 P0 production blockers**
1.**No CI/CD** — nothing runs tests or build on push/tag (`requirements.txt:1-4`, no `.github/workflows` / `.gitea/workflows`).
2.**No code signing** — release `.exe` is unsigned (`ProxyChainManager.spec:70-71`).
3.**Secrets at rest in plaintext** — proxy credentials and signup passwords in `%LOCALAPPDATA%\ProxyChainManager\` JSON (`config.py:364-368`, `signup_prep.py:295-296`).
4.**GOST binary integrity not verified** — runtime download with zip magic check only, no SHA256/signature pin (`gost_util.py:17-65`).
5.**Kill-switch recovery gap** — outbound BLOCK can persist if process dies mid-run; no standalone recovery tool documented (`firewall.py:142-156`, `service.py:136-143`).
| I-1 | **No CI/CD pipeline** (no GitHub/Gitea workflow YAML in repo) | Regressions ship silently; no reproducible build gate | Add workflow: `pip install -r requirements.txt`, `unittest discover`, optional `pyinstaller` on tag | **P0** |
| I-2 | **No automated test gate on PR/merge** | CONTRIBUTING.md says “run tests” but nothing enforces it (`CONTRIBUTING.md:9`) | Fail CI if `python -m unittest discover -s tests` fails | **P0** |
| I-3 | **No dependency lockfile** (`requirements.txt` uses `>=` only) | Non-reproducible builds across machines/time | Generate `requirements.lock` or pin exact versions in release branch | **P1** |
| I-4 | **PyInstaller not pinned** — installed ad hoc in `scripts/setup_and_build.ps1:39` | Release binaries differ per builder Python/PyInstaller version | Pin `pyinstaller==x.y.z` in dev requirements; record in release notes | **P1** |
| I-5 | **No release automation** — `docs/RELEASE_PROCESS.md` is manual checklist only | SHA256/commit attachment steps are skipped in practice | Script: build → hash → attach to Gitea release with commit SHA | **P1** |
| I-6 | **No pre-commit / secret scanning** | Risk of committing proxy creds or signup JSON from dev machines | `gitleaks` or similar in CI + pre-commit | **P1** |
| I-7 | **No documented required env vars** — `MAINTENANCE.md:22` asks for them but none exist | Operators cannot configure corporate proxy, custom data dir, etc. | Document optional `LOCALAPPDATA` override pattern or explicit env contract | **P2** |
| I-8 | **Stewardship checklists are templates only** — all items unchecked in `docs/SECURITY_REVIEW.md`, `docs/PROVENANCE_CHECKLIST.md` | Release gate in docs is never enforced | Complete checklists per release or automate in CI | **P1** |
### Reliability
| # | What's missing | Why it matters for prod | Suggested fix | Priority |
| R-5 | **`update_settings()` while service thread running** — no lock around `_settings` (`service.py:112-114`, `349+`) | Race: health interval / pool refresh reads half-written settings | `threading.Lock` on settings read/write or restart service on save | **P1** |
| R-6 | **No offline / degraded mode** — empty pool sleeps 60s and retries (`service.py:402` area) | Air-gapped or CDN-down hosts spin with no cached pool | Persist last-good pool snapshot; UI banner “offline, using cache” | **P1** |
| R-7 | **ChainService thread is daemon** (`service.py:131-133`) | Process exit can abort mid-teardown (proxy/firewall left dirty) | Non-daemon thread + bounded shutdown protocol | **P1** |
| R-9 | **Global `ThreadPoolExecutor`s never shut down** (`service.py:64`, `pool_ops.py:15`) | Interpreter shutdown warnings; resource leaks in long-running tray sessions | `shutdown(wait=False)` on app exit | **P2** |
| R-10 | **No GOST process watchdog** — if GOST dies, behavior depends on loop branch | Silent proxy outage until next health check | Detect `proc.poll()`; restart or rotate immediately | **P1** |
| R-11 | **Logon scheduled task runs LIMITED** (`windows_task.py:47-48`) | Auto-start cannot engage kill-switch / MAC / HKLM fixes that need Admin | Document “task ≠ full enforcement”; optional elevated task with warning | **P1** |
| R-12 | **No backup/restore for operator data** | Reinstall or profile wipe loses chains and signup vault | Export/import ZIP of `%LOCALAPPDATA%\ProxyChainManager\` | **P2** |
| S-1 | **Plaintext `settings.json`** with embedded proxy auth (`config.py:364-368`, `asdict` stores URLs) | Disk theft = credential leak | DPAPI-encrypt sensitive fields or Windows credential locker | **P0** |
| S-2 | **Plaintext signup vault** — `signup_draft.json`, `signup_accounts.json` (`signup_prep.py:252-296`) | Passwords/emails readable by any local user/process | Encrypt at rest; redact in logs (partially done for proxy URLs only) | **P0** |
| S-3 | **No TLS/certificate pinning for feed URLs** (`fetcher.py:11-18`) | MITM on jsdivr/GitHub could inject malicious proxy list | Pin certs or use signed offline bundle for sources | **P2** |
| S-4 | **Broad Defender exclusion** on entire GOST folder (`gost_util.py:23-39`) | AV blind spot if folder is poisoned | Exclude only `gost.exe`; verify hash before exclusion | **P1** |
| S-5 | **`ip_check_url` and custom `sources` not URL-validated** (`config.py:338-340`) | Hand-edited JSON could point health checks at internal/metadata endpoints | Allowlist HTTPS hosts; block RFC1918/link-local in validator | **P1** |
| S-6 | **Kill-switch default ON** (`config.py:186`) without mandatory recovery docs in README | Bricked network for non-technical operators | README “emergency disengage” + startup orphan detection | **P0** |
| S-7 | **Always-elevated PyInstaller build** (`ProxyChainManager.spec:72``uac_admin=True`) | Every launch prompts UAC; users may habit-click; not least-privilege | Split “Operator” vs “Enforcer” binaries or manifest optional elevation | **P1** |
| O-1 | **`proxy_chain_manager.log` has no rotation** (`app.py:91-98`) — unlike `gost.log` (`gost_util.py:98-105`) | Long sessions fill disk | `RotatingFileHandler` or size cap like GOST | **P1** |
| O-2 | **No crash reporting** (WER hook, Sentry, minidump) | Field failures are invisible to maintainer | Opt-in crash telemetry with redaction | **P1** |
| O-3 | **Unstructured text logs only** | Hard to query in SIEM | Optional JSON log format for file handler | **P2** |
| O-4 | **No metrics** (Prometheus/windows perf counters) | Cannot alert on pool size, rotation rate, leak count | Export counters via named pipe or local HTTP if needed | **P2** |
| O-5 | **No external health endpoint** | Expected for server apps; desktop app has tray only — gap if headless automation desired | Document N/A for GUI; optional `127.0.0.1:status` for scripting | **P2** |
| O-6 | **Broad `except Exception: pass` in Defender helper** (`gost_util.py:38-39`) | Silent failure to exclude → GOST quarantined with no UI clue | Log warning + surface in Live tab | **P1** |
| D-2 | **No SHA256 publish step in build script** — required by `docs/RELEASE_PROCESS.md:10` but `setup_and_build.ps1` only copies exe | Users cannot verify download integrity | Emit `ProxyChainManager.exe.sha256` in `dist/` | **P1** |
| D-3 | **UPX compression enabled** (`ProxyChainManager.spec:66-67`) | AV false positives on packed binaries | Disable UPX for release builds | **P1** |
| D-4 | **GOST not shipped in installer** — downloaded on first run (`gost_util.py:42-65`) | First-run requires internet; air-gap fails | Bundle pinned `gost.exe` in installer or optional offline pack | **P1** |
| D-5 | **No MSI/Inno installer** — only raw exe + Desktop copy (`setup_and_build.ps1:55-58`) | No uninstaller, no Start Menu integration, no upgrade path | Wrap in signed installer with upgrade code | **P2** |
| D-6 | **No in-app auto-update channel** | Security patches require manual git pull / rebuild | Check release API + signed delta or full exe | **P1** |
| D-7 | **Version `1.0.0` static** (`__init__.py:3`) — not embedded in Windows file properties | Support cannot map exe → commit | PyInstaller `version` resource from git tag | **P1** |
| DOC-2 | **README omits production realities** — no mention of: unsigned exe, first-run GOST download, Defender exclusion, kill-switch recovery (`README.md:69-114`) | Operators misconfigure or panic when network dies | Add “Production deployment” section | **P1** |
| DOC-3 | **README test claim understates gaps** — “Covers config… smoke paths” (`README.md:124`) but no service/firewall/GUI tests | False confidence in release quality | Align README with actual test matrix | **P1** |
| DOC-4 | **`CHANGELOG.md` Unreleased empty** (`CHANGELOG.md:5-7`) | No user-visible record between tags | Require changelog entry in PR template | **P1** |
| DOC-5 | **No `THIRD_PARTY_NOTICES.md`** for GOST, CustomTkinter, Pystray, Proxifly data | License compliance for binary distribution | Generate notices from `pip licenses` + GOST MIT | **P1** |
| DOC-6 | **No operator runbook** (kill-switch stuck, proxy leak, pool empty) | MTTR high in field | `docs/RUNBOOK.md` with netsh recovery steps | **P0** |
| DOC-7 | **“Mission-grade” / “fail closed” marketing without SLOs** (`README.md:5-12`) | Enterprise buyers expect defined behavior | Add limitations: public proxy quality, VPN requirement, admin scope | **P2** |
| DOC-8 | **`docs/MAINTENANCE.md` rate-limit note** (`MAINTENANCE.md:23`) not reflected in product | Release gate incomplete | Implement S-9 or remove claim | **P1** |
### Testing
| # | What's missing | Why it matters for prod | Suggested fix | Priority |
| OP-3 | **Kill-switch skipped silently when non-admin** (`service.py:328-330`) | User believes they are “fail closed” but are not | Prominent banner when not admin + kill-switch ON | **P1** |
| OP-5 | **No first-run wizard** (GOST download, VPN check, admin recommendation) | High abandonment on first failure | Step-through: VPN → Admin → Test pool | **P1** |
| OP-6 | **Close button minimizes to tray only** (`app.py:2888`) — good for daemon, bad if user expects quit | Document; tray “Exit” must disengage FW | Already in tray; add tooltip on X | **P2** |
| OP-7 | **README says “Accept UAC” but spec forces `uac_admin`** (`README.md:131`, `ProxyChainManager.spec:72`) | Confusing for non-admin workflows | Document two launch modes | **P1** |
| OP-8 | **No visible “version / build commit” in UI** | Support tickets lack context | Show `__version__` + git SHA in About | **P1** |
| OP-9 | **Pool refresh hammers external CDNs** (default 1800s, 3 sources) | Operator IP banned from jsdivr | Backoff; custom mirror field | **P1** |
| OP-10 | **Ban tester / leak audit results not persisted** | Cannot trend ban rate over sessions | Optional CSV export | **P2** |
1.**Wrong Chrome/Edge WebRTC policy key/value** — `fingerprint.py:21,177` writes DWORD `2` which is `default_public_and_private_interfaces`, NOT `disable_non_proxied_udp` (DWORD `3`). Modern Chrome also requires REG_SZ `WebRtcIPHandling = disable_non_proxied_udp`. Audits treat `2` as success → false green.
2.**`BrowserSession.stop()` kills ALL Firefox on the machine** — `browser_launcher.py:297-305` runs `taskkill /F /IM firefox.exe` with no PID scope. Operator loses unrelated browser sessions.
3.**Credentials plaintext at rest** — `config.py:19-22`, `signup_prep.py:252-325` store proxy auth + signup passwords in JSON. `cryptography==48.0.0` is in requirements but unused.
4.**Preflight race condition** — `app.py:2001-2009` uses fixed `root.after(200, _final)` which can report "All passed" before async network checks finish.
5.**Preflight IP compare is exact-match only** — ignores the VPN-aware `/16` logic used in production leak detection (`leak_detect.py:24-38`).
6.**HTTPS CONNECT failure doesn't stop chain** — `service.py:573-580` logs warning only; chain stays "healthy" and system proxy remains set.
7.**Pinned manual chain never validates hops at runtime** — dead chain retries every 10s forever (`service.py:393-403`).
8.**`emergency_disengage()` runs on ALL exits** — even if kill-switch never engaged; can mask other apps' firewall state (`service.py:105`, `firewall.py:165-177`).
9.**Signup extension runs on all URLs** — `signup_extension/manifest.json:13-19` uses `<all_urls>`.
10.**Account auto-saved before signup completes** — password saved on browser launch before user registers (`app.py:2147-2174`).
11.**GOST exe not re-hashed on reuse** — zip is verified but extracted `gost.exe` on disk is not re-checked (`gost_util.py:61-64`).
12.**`asyncio.run()` from worker threads** — `app.py:1860-1863` nested event loop risk if caller context changes.
---
## README Claims vs Implementation
## 1. Critical Bugs
| README claim | Status | Evidence |
|--------------|--------|----------|
| “Self-healing… rotate on failure, repeat forever” | **Partial** | Rotation exists (`service.py` main loop); no GOST watchdog (R-10) |
missing.append(f"{name}: no WebRTC policy keys present")
exceptOSError:
continue# key not present at all — browser not installed or not policy-managed
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.