This commit is contained in:
eric
2026-05-19 09:19:52 +00:00
parent 585bcd9500
commit b617555360
30 changed files with 477 additions and 207 deletions

View File

@@ -113,7 +113,6 @@ def render(count: int) -> str:
' - "./external-extensions:/usr/share/chromium/extensions:ro"',
' - "./external-extensions:/usr/share/chromium-browser/extensions:ro"',
' - "./tampermonkey-seed:/etc/neko/tampermonkey-seed:ro"',
' - "./youtube-auto-dismiss-extension:/etc/neko/youtube-auto-dismiss-extension:ro"',
' - "./provisioning:/var/www/provisioning:ro"',
' - "./browser-launch.sh:/etc/neko/browser-launch.sh:ro"',
f" - {q(f'./{supervisor_conf}:/etc/neko/supervisord/{supervisor_conf}:ro')}",

View File

@@ -333,6 +333,70 @@ def verify_neko(checks: list[dict[str, Any]], env: dict[str, str], *, timeout: f
detail=(out or err2).strip(),
hint="Make services/neko/browser-launch.sh executable and restart Neko.",
)
code, out, err2 = docker_exec(
name,
"if [ \"${NEKO_MEMBER_PROVIDER:-}\" = multiuser ] "
"&& [ -n \"${NEKO_MEMBER_MULTIUSER_ADMIN_PASSWORD:-}\" ] "
"&& [ -n \"${NEKO_MEMBER_MULTIUSER_USER_PASSWORD:-}\" ]; then "
"printf 'provider=%s admin_password=set user_password=set\\n' \"$NEKO_MEMBER_PROVIDER\"; "
"else echo 'NEKO member env invalid'; exit 1; fi",
timeout=timeout,
)
check(
checks,
f"neko_{idx}_multiuser_admin",
f"{name} multiuser admin enabled",
code == 0,
detail=(out or err2).strip(),
hint="Neko must run with multiuser provider and a non-empty admin password.",
)
code, out, err2 = docker_exec(
name,
"awk '$5==\"/home/neko/.config/google-chrome\" || $5==\"/home/neko/.config/chromium\" {print $5}' "
"/proc/self/mountinfo | sort -u",
timeout=timeout,
)
mounted_profiles = {line.strip() for line in out.splitlines() if line.strip()}
check(
checks,
f"neko_{idx}_persistent_profile",
f"{name} persistent browser profile",
code == 0
and {
"/home/neko/.config/google-chrome",
"/home/neko/.config/chromium",
}.issubset(mounted_profiles),
detail=out.strip() or err2.strip() or "profile mounts missing",
hint="Neko profile directories must be bind-mounted so Google login, Tampermonkey, and channel state survive restarts.",
)
code, out, err2 = docker_exec(
name,
"python3 - <<'PY'\n"
"import json\n"
"from pathlib import Path\n"
"for path in (Path('/home/neko/.config/google-chrome/Default/Preferences'), Path('/home/neko/.config/chromium/Default/Preferences'), Path('/home/neko/.config/google-chrome/Local State'), Path('/home/neko/.config/chromium/Local State')):\n"
" if not path.exists():\n"
" continue\n"
" try:\n"
" data = json.loads(path.read_text(encoding='utf-8'))\n"
" except Exception:\n"
" continue\n"
" if data.get('extensions', {}).get('ui', {}).get('developer_mode') is True:\n"
" print(f'{path}: developer_mode=true')\n"
" raise SystemExit(0)\n"
"print('Developer mode preference not found')\n"
"raise SystemExit(1)\n"
"PY",
timeout=timeout,
)
check(
checks,
f"neko_{idx}_developer_mode",
f"{name} Chrome developer mode",
code == 0,
detail=(out or err2).strip(),
hint="browser-launch.sh must set extensions.ui.developer_mode in Preferences/Local State before Chrome starts.",
)
code, out, err2 = docker_exec(
name,
"find /etc/chromium/policies/managed /etc/chromium-browser/policies/managed /etc/opt/chrome/policies/managed "
@@ -379,22 +443,89 @@ def verify_neko(checks: list[dict[str, Any]], env: dict[str, str], *, timeout: f
detail="payload contains YouTube Studio Auto Dismiss" if code == 0 else (err2 or out).strip(),
hint="Regenerate services/neko/provisioning/tampermonkey-provisioning.json and restart Neko.",
)
code, out, err2 = docker_exec(
name,
"python3 - <<'PY'\n"
"import json\n"
"from pathlib import Path\n"
"ext = 'dhdgffkkebhmkfjojejmpbldmpobfkfo'\n"
"for base in ('/home/neko/.config/google-chrome/Default', '/home/neko/.config/chromium/Default'):\n"
" path = Path(base) / 'Preferences'\n"
" if not path.exists():\n"
" continue\n"
" try:\n"
" data = json.loads(path.read_text(encoding='utf-8'))\n"
" except Exception:\n"
" continue\n"
" state = data.get('extensions', {}).get('settings', {}).get(ext, {})\n"
" if state:\n"
" path_value = str(state.get('path') or '')\n"
" enabled = (\n"
" state.get('state') == 1\n"
" and not state.get('disable_reasons')\n"
" and state.get('from_webstore') is True\n"
" and not path_value.startswith('/')\n"
" and state.get('location') != 8\n"
" )\n"
" print(\n"
" f\"{base}: state={state.get('state')} disable_reasons={state.get('disable_reasons')} \"\n"
" f\"from_webstore={state.get('from_webstore')} location={state.get('location')} path={path_value}\"\n"
" )\n"
" raise SystemExit(0 if enabled else 1)\n"
"print('Tampermonkey preference not found')\n"
"raise SystemExit(1)\n"
"PY",
timeout=timeout,
)
check(
checks,
f"neko_{idx}_tm_enabled",
f"{name} Tampermonkey enabled",
code == 0,
detail=(out or err2).strip(),
hint="Tampermonkey must be a normal enabled extension, not an unpacked forced-disabled extension.",
)
code, out, err2 = docker_exec(
name,
"python3 - <<'PY'\n"
"import os\n"
"skip = {os.getpid(), os.getppid()}\n"
"bad = [b'--load-' + b'extension=', b'youtube-auto-' + b'dismiss-extension']\n"
"for name in os.listdir('/proc'):\n"
" if not name.isdigit() or int(name) in skip:\n"
" continue\n"
" try:\n"
" cmdline = open(f'/proc/{name}/cmdline', 'rb').read()\n"
" except OSError:\n"
" continue\n"
" if any(marker in cmdline for marker in bad):\n"
" print(cmdline.replace(b'\\0', b' ').decode('utf-8', errors='replace'))\n"
" raise SystemExit(1)\n"
"print('no standalone youtube extension')\n"
"PY",
timeout=timeout,
)
check(
checks,
f"neko_{idx}_no_standalone_youtube_extension",
f"{name} no standalone YouTube extension",
code == 0,
detail=(out or err2).strip(),
hint="The YouTube Studio Auto Dismiss automation must live inside Tampermonkey, not as a separate --load-extension.",
)
code, out, err2 = docker_exec(
name,
"for base in /home/neko/.config/google-chrome/Default /home/neko/.config/chromium/Default; do "
"for area in 'Local Extension Settings' 'Managed Extension Settings'; do "
"dir=\"$base/$area/dhdgffkkebhmkfjojejmpbldmpobfkfo\"; "
"if [ -d \"$dir\" ] && grep -R -a -l 'YouTube Studio Auto Dismiss' \"$dir\" 2>/dev/null | head -1; then exit 0; fi; "
"done; done; "
"for cmd in /proc/[0-9]*/cmdline; do "
"tr '\\0' '\\n' <\"$cmd\" 2>/dev/null | grep -q -- '--load-extension=.*youtube-auto-dismiss-extension' && echo '--load-extension youtube-auto-dismiss-extension' && exit 0; "
"done; exit 1",
"done; done; exit 1",
timeout=timeout,
)
check(
checks,
f"neko_{idx}_tm_storage",
f"{name} Tampermonkey script imported",
f"{name} Tampermonkey YouTube script imported",
code == 0 and bool(out.strip()),
required=True,
detail=out.strip() or err2.strip() or "not found",