Sanitize codebase, reorganize docs, and add missing deploy files
Remove dead code identified in docs/SANITIZATION-REVIEW.md:
- app/blueprints/content_old.py and app/blueprints/playlist.py
- app/models/group.py, app/utils/nginx_config_reader.py
- orphaned templates (content_list, edit_content, upload_content,
player_page) and the related group/Template references
Result: 6 blueprints, 82 routes, no dead modules or orphan templates.
Add files that deploy.sh and docker-entrypoint.sh already require but
which were never tracked:
- https_manager.py (referenced by deploy.sh, migrate_network.sh,
docker-entrypoint.sh)
- Caddyfile.example (seeded by deploy.sh; its absence aborts deploy)
Relocate generated Graphify artifacts from graphify-out/ to
docs/graphify-out/ (110 files, no content change) and archive the
superseded docs under docs/.
Ignore hygiene:
- ignore ad-hoc .env backups (.env.bak*) — they contain live secrets
- keep the pre-sanitization snapshots (docs/legacy code/,
docs/old_code_documentation/) on disk but out of the repo
Fix .env.example: drop a duplicated config block, genericize the
hardcoded host IP, and document HOSTNAME_INTERNAL.
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
"""Verify every Caddyfile mode against the real `caddy validate` binary.
|
||||
|
||||
Also asserts the structural guarantees required for the deployment model:
|
||||
* ONE HTTP endpoint that answers regardless of Host header (catch-all :80)
|
||||
* explicit per-name HTTP blocks for both IP and hostname
|
||||
* HTTPS on 443 only when enabled, using the internal CA for intranet names
|
||||
|
||||
Run: PYTHONPATH=$(pwd) ./.venv/bin/python docs/tools/verify_caddyfile_modes.py
|
||||
"""
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from app.utils.caddy_manager import CaddyConfigGenerator as G
|
||||
|
||||
|
||||
class Cfg:
|
||||
def __init__(self, **kw):
|
||||
self.email = kw.get('email', 'admin@example.com')
|
||||
self.https_enabled = kw.get('https_enabled', False)
|
||||
self.domain = kw.get('domain', '')
|
||||
self.ip_address = kw.get('ip_address', '')
|
||||
self.hostname = kw.get('hostname', '')
|
||||
self.port = kw.get('port', 443)
|
||||
|
||||
|
||||
def validate(text):
|
||||
path = '/tmp/_caddyfile_check'
|
||||
open(path, 'w').write(text)
|
||||
r = subprocess.run(
|
||||
['docker', 'run', '--rm', '-v', f'{path}:/etc/caddy/Caddyfile:ro',
|
||||
'caddy:2-alpine', 'caddy', 'validate', '--config', '/etc/caddy/Caddyfile'],
|
||||
capture_output=True, text=True)
|
||||
return (r.returncode == 0 and 'Valid configuration' in (r.stdout + r.stderr),
|
||||
(r.stdout + r.stderr))
|
||||
|
||||
|
||||
CASES = [
|
||||
('1. Nothing configured -> HTTP only on :80',
|
||||
Cfg(), True, {}),
|
||||
('2. HTTPS on, IP only -> internal CA + HTTP fallback',
|
||||
Cfg(https_enabled=True, ip_address='192.168.0.152'), True,
|
||||
{'tls internal', 'http://192.168.0.152', 'https://192.168.0.152', ':80'}),
|
||||
('3. HTTPS on, IP + hostname -> both served',
|
||||
Cfg(https_enabled=True, ip_address='192.168.0.152', hostname='digiserver'),
|
||||
True,
|
||||
{'http://digiserver', 'https://digiserver', 'http://192.168.0.152'}),
|
||||
('4. HTTPS on, redirect-only -> 301 to published port',
|
||||
Cfg(https_enabled=True, ip_address='192.168.0.152'), False,
|
||||
{'redir https://192.168.0.152{uri} 301', ':80'}),
|
||||
('5. HTTPS on, public domain -> ACME (no tls internal)',
|
||||
Cfg(https_enabled=True, domain='example.com',
|
||||
ip_address='192.168.0.152'), True,
|
||||
{'https://example.com', 'tls internal'}),
|
||||
('6. HTTP only even though IP known (HTTPS disabled) -> :80 only',
|
||||
Cfg(https_enabled=False, ip_address='192.168.0.152'), True,
|
||||
{':80'}),
|
||||
]
|
||||
|
||||
failures = []
|
||||
for label, cfg, fallback, must_contain in CASES:
|
||||
text = G.generate_caddyfile(cfg, http_fallback=fallback)
|
||||
ok, raw = validate(text)
|
||||
|
||||
missing = sorted(s for s in must_contain if s not in text)
|
||||
if missing:
|
||||
ok = False
|
||||
|
||||
print(f'[{"OK " if ok else "FAIL"}] {label}')
|
||||
blocks = [ln.strip() for ln in text.splitlines()
|
||||
if ln.strip().startswith(('http://', 'https://', ':80'))]
|
||||
print(f' blocks: {blocks}')
|
||||
if missing:
|
||||
print(f' MISSING: {missing}')
|
||||
if not ok:
|
||||
failures.append(label)
|
||||
print(' ', raw.strip()[-400:])
|
||||
print()
|
||||
|
||||
# Extra guarantees that are easy to regress silently.
|
||||
text_https = G.generate_caddyfile(
|
||||
Cfg(https_enabled=True, ip_address='192.168.0.152', hostname='digiserver'),
|
||||
http_fallback=True)
|
||||
assert ':80 {' in text_https, 'catch-all :80 block missing'
|
||||
assert 'https://digiserver {' in text_https, 'hostname TLS block missing'
|
||||
assert text_https.count(':80 {') == 1, 'exactly one catch-all :80 expected'
|
||||
|
||||
text_http = G.generate_caddyfile(Cfg(https_enabled=False))
|
||||
assert 'https://' not in text_http, 'no TLS should be emitted when disabled'
|
||||
assert ':80 {' in text_http
|
||||
|
||||
print('Structural guarantees hold (catch-all :80, per-name blocks, TLS only when enabled)')
|
||||
|
||||
if failures:
|
||||
print(f'FAILED: {failures}')
|
||||
sys.exit(1)
|
||||
print('All Caddyfile modes are VALID')
|
||||
Reference in New Issue
Block a user