feat(kasmvnc): Chrome CDP visible pour Playwright MCP

- modules/nixos/kasmvnc-chrome-cdp.nix : lance un Chromium dans le desktop KasmVNC avec --remote-debugging-port=9222, profil persistant /home/marc/chrome-cdp-profile
- Le MCP Playwright s'y attache (--cdp-endpoint http://127.0.0.1:9222) : les actions d'automatisation se font dans CETTE fenetre, donc visibles en direct sur le bureau distant (8443 en LAN, kasm.marcpartensky.com)
- CDP reste sur 127.0.0.1 : un port CDP joignable donne le controle total du navigateur par quiconque l'atteint, donc jamais au LAN ni via Pangolin
- newt : healthcheck HTTP sur le vhost local 8288 (KasmVNC repond 200 sur "/" avec disableBasicAuth) ; sans lui la cible sortait du load-balancer
This commit is contained in:
Hermes Agent
2026-10-17 16:56:10 -04:00
parent 50df23c53c
commit 8294a123a6
3 changed files with 140 additions and 0 deletions
+91
View File
@@ -0,0 +1,91 @@
# Module KasmVNC Chrome CDP : lance Chromium avec le Chrome DevTools Protocol
# (remote debugging) dans la session Plasma de KasmVNC, pour Playwright MCP.
#
# POURQUOI un module separe et pas du code inline dans le profil : un module NixOS
# ne doit PAS lire `config.<ses propres options>` dans son `let` au niveau racine
# (ca part en « infinite recursion »). La forme correcte est options + `config =
# mkIf cfg.enable { ... }`, comme ici.
{ config, lib, pkgs, ... }:
let
cfg = config.services.kasmvnc.chrome-cdp;
kasmUser = config.services.kasmvnc.user;
browserPkg = if cfg.browser == "google-chrome" then pkgs.google-chrome else pkgs.chromium;
browserBin = if cfg.browser == "google-chrome" then "google-chrome-stable" else "chromium";
# NixOS ne connait PAS users.users.<u>.xdg.autostart (c'est du home-manager, et
# le home de marc n'est pas gere par cette nixosConfiguration) : on ecrit le
# .desktop via tmpfiles, pointant sur un lanceur.
chromeCdpLauncher = pkgs.writeShellScript "chrome-cdp-launch" ''
exec ${browserPkg}/bin/${browserBin} \
--remote-debugging-port=${toString cfg.port} \
--remote-debugging-address=${cfg.bindAddress} \
--user-data-dir=${cfg.profileDir} \
${lib.concatStringsSep " " cfg.extraFlags} \
about:blank
'';
chromeCdpDesktop = pkgs.writeText "chrome-cdp.desktop" ''
[Desktop Entry]
Type=Application
Name=Chrome CDP
Comment=Chrome with Chrome DevTools Protocol for Playwright MCP
Exec=${chromeCdpLauncher}
Terminal=false
Categories=Network;WebBrowser;
OnlyShowIn=KDE;
'';
in {
options.services.kasmvnc.chrome-cdp = {
enable = lib.mkEnableOption "Chrome/Chromium avec CDP dans la session KasmVNC";
browser = lib.mkOption {
type = lib.types.enum [ "chromium" "google-chrome" ];
default = "chromium";
description = "Navigateur a installer et lancer";
};
port = lib.mkOption {
type = lib.types.port;
default = 9222;
description = "Port de debug CDP";
};
bindAddress = lib.mkOption {
type = lib.types.str;
default = "127.0.0.1";
description = "Adresse d'ecoute CDP (loopback par defaut : jamais au LAN)";
};
profileDir = lib.mkOption {
type = lib.types.str;
default = "/home/${kasmUser}/chrome-cdp-profile";
description = "Repertoire de profil Chrome persistant";
};
extraFlags = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = "Flags Chrome supplementaires";
};
openFirewall = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Ouvrir le port CDP au firewall (deconseille : CDP = controle total)";
};
exposePublic = lib.mkOption {
type = lib.types.bool;
default = false;
description = "Exposer CDP via Pangolin (SSO requis)";
};
publicDomain = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
description = "Domaine public CDP";
};
};
config = lib.mkIf cfg.enable {
services.kasmvnc.extraPackages = [ browserPkg ];
systemd.tmpfiles.rules = [
"d ${cfg.profileDir} 0700 ${kasmUser} users - -"
"d /home/${kasmUser}/.config/autostart 0755 ${kasmUser} users - -"
"L+ /home/${kasmUser}/.config/autostart/chrome-cdp.desktop - - - - ${chromeCdpDesktop}"
];
networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.port ];
};
}
+48
View File
@@ -8,6 +8,7 @@
# Client WireGuard vers le VPS (voir la section WIREGUARD CLIENT en bas).
wgClientEnable = false;
in {
imports = [
../../hosts/tower/disko.nix
../../hosts/laptop/hardware-configuration.nix
@@ -140,6 +141,34 @@ in {
disableBasicAuth = true;
};
# ========================================================================
# KASMVNC CHROME CDP - Chrome/Chromium avec remote debugging pour Playwright MCP
# ========================================================================
# But : VOIR en direct ce que fait l'automatisation. Un Chromium visible tourne
# dans le desktop Kasm (affichable sur 8443 en LAN et kasm.marcpartensky.com en
# Internet), et le MCP s'y attache via --cdp-endpoint http://127.0.0.1:9222 :
# toutes les actions Playwright se font alors dans CETTE fenetre.
# CDP en loopback uniquement (un port CDP joignable = controle total du
# navigateur par quiconque l'atteint, donc jamais au LAN ni sur Internet).
services.kasmvnc.chrome-cdp = {
enable = true;
browser = "chromium";
port = 9222;
bindAddress = "127.0.0.1";
profileDir = "/home/marc/chrome-cdp-profile";
extraFlags = [
"--no-first-run"
"--no-default-browser-check"
"--disable-background-networking"
"--disable-translate"
"--password-store=basic"
"--disable-component-extensions-with-background-pages"
"--disable-features=IsolateOrigins,site-per-process"
];
openFirewall = false;
exposePublic = false;
};
# /home/marc/.kasmpasswd : fichier au format kasmvncpasswd. Attention,
# kasmvncpasswd n'a PAS d'option -f et refuse de tourner sans terminal
# (« getpassword error: Inappropriate ioctl for device ») ; il lit le mot de
@@ -250,6 +279,25 @@ in {
hostname = "127.0.0.1";
port = 8288;
method = "http";
# Healthcheck sur le vhost nginx local (8288 -> https KasmVNC 8443).
# KasmVNC repond 200 text/html sur "/" (desactiveBasicAuth) : mesure
# du 11/10/2026 sur http://127.0.0.1:8288/ -> 200. Meme schema que
# noVNC/winnie dans services/newt (schema ancien : proxy-resources +
# protocol, valide par ce Pangolin).
healthcheck = {
enabled = true;
hostname = "127.0.0.1";
port = 8288;
path = "/";
scheme = "http";
mode = "http";
method = "GET";
interval = 30;
unhealthy-interval = 30;
timeout = 5;
healthy-threshold = 1;
unhealthy-threshold = 3;
};
}
];
};
+1
View File
@@ -76,6 +76,7 @@
../modules/nixos/vault-rustguac
../modules/nixos/rustguac
../modules/nixos/kasmvnc
../modules/nixos/kasmvnc-chrome-cdp.nix
../modules/nixos/rustdesk
../modules/nixos/nginx/rustguac
../modules/nixos/nginx/kasmvnc