Une cible = une instance Android, donc une interface et ses propres fichiers : c'est la
seule isolation franche du trafic par appli, et elle ne demande aucun root.
- waydroid : capture sur le bridge waydroid0.
- avd : alimentee par le -tcpdump de l'emulateur, qui sort par la pile reseau de l'hote.
- rotation de 10 min, 72 fichiers conserves (12 h), digest d'hotes par cible.
Pas de root : CAP_NET_RAW et CAP_NET_ADMIN en capacites ambiantes, donc NoNewPrivileges
reste a false (systemd refuse la combinaison). Utilisateur statique et non DynamicUser,
plusieurs unites partageant le meme arbre d'etat. marc et hermes sont ajoutes au groupe
pour lire les captures sans root.
Verifie sur tower : tcpdump a l'ecoute sur waydroid0, deux jeux de pcaps distincts, digests
ecrits par les timers (avd : connectivitycheck.gstatic.com ; waydroid : play.googleapis.com).
Les lignes du sélecteur de modèle SANS suffixe [1m] (claude-opus-5-5, claude-opus-5, claude-sonnet-5) passent par le provider natif anthropic, pas par claude-subscription-directsdk. Sans le paquet python anthropic dans le venv scellé, une session ouverte sur une de ces lignes meurt en agent_init_failed : "The 'anthropic' package is required for the Anthropic provider" (lazy installs désactivés par le packaging nix).
Auth du provider natif : aucune clé API à poser, agent/anthropic_credentials.py prend l'OAuth de l'abonnement dans ~/.claude/.credentials.json (refresh et réécriture gérés par Hermes), ou un grant Hermes via hermes auth add anthropic --type oauth.
Les lignes AVEC [1m] (provider claude-subscription-directsdk, CLI claude) ne changent pas. Supprime aussi la ligne commentée devenue doublon : extraDependencyGroups n'est défini qu'une fois.
Token créé dans Gitea (compte mazex, son compte SSO Zitadel). Débloque le serveur MCP gitea (GITEA_ACCESS_TOKEN_FILE) et les opérations git/API sur git.marcpartensky.com, dont le miroir des repos GitHub.
MCP stdio lancé par hermes-agent sur tower ; parle au Mac en ssh (alias
maclan puis mac, clé hermes). Tools : status (winnie-doctor + révisions),
sync, doctor_fix, xcode_fix (3 opérations root via la règle sudo
NOPASSWD xcode-select/xcodebuild/xcrun), runtime_install et les builds
(arrière-plan, suivi par log_tail) : ios_init, ios_build_sim,
macos_build.
Vérifié : pycodestyle/pyflakes, build de la dérivation, sonde stdio
(tools/list + appels réels sur le Mac), éval du toplevel avant commit.
L'ancien câblage ne pouvait pas marcher : client_id littéral "gitea"
(impossible, Zitadel génère les client_id) et oneshot qui échouait à chaque
boot sur --enabled (flag inexistant en Gitea 1.27.x), avalé par `|| true`.
- App Zitadel "Gitea" (projet marcpartensky) : appId 396570385799184684,
clientId 396570385799250220, type Web, redirect
https://git.marcpartensky.com/user/oauth2/zitadel/callback
- oneshot gitea-oidc-init : add-or-update (id de login_source via psql),
secret lu depuis sops à chaque exécution, idempotent même en dérive
- [openid] d'app.ini : OpenID 2.0 legacy, désactivé (sans rapport avec OIDC,
échouait en "rel=openid2.provider not found" avec une URL Zitadel)
- [oauth2_client] : ENABLE_AUTO_REGISTRATION, USERNAME=email,
ACCOUNT_LINKING=login (page de liaison unique pour le compte local marc)
- ressource Pangolin : auth.sso-enabled=false (auth Gitea seule, une seule
couche, clients git/API à token non bloqués par un redirect SSO)
- secrets/gitea-oidc.yml : vrai oidc_client_secret (chiffré, clé tower)
hermes@tower, connecté en ssh sur marc@mac, doit lancer les rares
opérations root du toolchain Xcode sans mot de passe : bascule de
xcode-select, acceptation de la licence, runtime du simulateur.
Fragment sudoers.d dédié (security.sudo.extraConfig est déjà posé par le
bloc terminfo de nix-darwin), scopé aux trois shims
/usr/bin/{xcode-select,xcodebuild,xcrun} ; le reste du sudo de marc reste
inchangé. Vérifié : visudo parsed OK, éval du fragment et du toplevel.
Le premier bootstrap avait laisse un layout Garage a zero noeud (quorum de 0, inapplicable) : purge unique de meta/data avant le demarrage du service, winnie-bucket reprovisionne bucket, cle et s3.env. L'ingest passe de Type=oneshot a Type=exec pour que RuntimeMaxSec s'applique, et S3_ENV_FILE force le redemarrage du backend quand Garage est provisionne apres son premier demarrage.
postgresql.service est Type=notify : sans after et requires, le oneshot qui pose le mot de passe de la base partait en parallele et mourait sur « connection to server on socket /run/postgresql/.s.PGSQL.5432 failed » (boots du 22/10 20:29 et du 23/10 09:37).
enabled=false, send=false et offer_version=2 ecrits dans config.yaml : la question de partage des stats ne revient plus a chaque session (le defaut ne compte pas comme reponse) et rien n'est collecte.
Deux agents separes au niveau OS (utilisateurs anna et yves, HERMES_HOME dedie, tmpfiles + ExecStartPre qui recree le squelette du home en mode managed), outils dangereux desactives et /api/pty comme /api/files bloques par nginx. Exposes en hermes-anna et hermes-yves.marcpartensky.com ; identifiants hors store nix sous /var/lib/hermes/guests.
services/hermes-pocket devient services/hermes-mobile : le backend de l'appli F-Droid sert le profil default (meme historique, memoire, skills et modele que le gateway Matrix et le dashboard) au lieu du profil isole pocket, en gardant la porte d'auth native (mobile-serve.env). Le nom de ressource Pangolin reste hermes-pocket : le renommer recreerait une ressource sur un domaine deja pris.
ExitOnForwardFailure=yes sur l'autossh du Mac : un forward rate (port deja pris, sshd pas encore pret au boot) ne laisse plus une session inutile, launchd reessaie. La cle du Mac (marc@Air-de-Marc) est autorisee sur tower et sur le deck : ssh tower et ssh deck passent par rack en ProxyJump.
mk8dx selectionne le dump de base (Title ID 0100152000022000, sinon un fichier hors update/DLC, sinon le premier .nsp/.xci) au lieu du MK8DX.xci code en dur : Eden applique seul l'update pose a cote du jeu, mais lancer le NSP d'update comme s'il etait le jeu echoue. La tuile Gaming Mode passe par ce script.
tower fait routeur pour son LAN : ip_forward et NAT wg1 -> wlan0 (sortie avec l'IP LAN 192.168.1.44), et le pair tower cote VPS declare desormais 192.168.1.0/24 dans ses allowedIPs. Le Steam Deck et le reste du LAN deviennent joignables depuis rack sans dependre d'un forward de la box.
Timer de 5 minutes qui remet 100.89.128.1/24 et la route du 100.89.128.0/24 sur wg0, et reinsere l'exception iptables INPUT pour 100.89.128.0/24 : tailscaled jette cette source recue sur une interface autre que tailscale0, ce qui avait coupe le tunnel Pangolin 6h40 le 23/10. Complement de gerbil-wg0-ensure.nix, qui ne couvre que le demarrage de gerbil.
Le controleur headscale du VPS passe en mode durci : flotte DERP de Tailscale retiree (derp.urls vide), DERP embarque sur le VPS (region 900, verify_clients) et STUN en UDP 3478 ; route Traefik headscale.marcpartensky.com -> 127.0.0.1:8090. Cote clients, services/tailscale remplace l'ancien secret tailscale/auth_key (absent) par headscale/preauth_key, coupe l'envoi de logs vers Tailscale Inc (disableUpstreamLogging) et est importe sur tower, le deck et anywhere.
secrets/switch-keys.yml (prod.keys d'Eden sur le deck, posees dans le home de marc) et secrets/headscale.yml (preauth_key reutilisable, consommee par services/tailscale sur tower, le deck et le VPS). Regles de creation sops associees dans .sops.yaml.
Le Mac expose deja son sshd (services.openssh dans profiles/macos) et son
tunnel inverse autossh (rack:2223), il manquait les alias cote marc.
- maclan = marc@192.168.1.48 (LAN, IP DHCP)
- mac = marc@localhost:2223 via rack (tunnel inverse, hors LAN)
Verifie en construisant le fichier genere (hm_.sshconfig) : les deux entrees
sortent avec le bon HostName/Port/ProxyJump.
L'app se build sur le Mac en trois commandes, le toolchain restant dans le
devShell du flake winnie (jamais installé sur le Mac) :
cd ~/git/nixos && just mac # déploie ce setup
winnie-sync # attrape ~/git/winnie depuis tower (rsync ssh)
winnie-ios # simulateur ; npm ci + tauri ios init au besoin
- modules/home-mac/winnie : winnie-doctor [--fix], winnie-sync [--delete],
winnie-shell, winnie-front, winnie-macos, winnie-build-macos, winnie-ios,
winnie-build-ios, winnie-verify. Scripts en writeShellApplication (shellcheck
au build) ; scripts.nix est séparé du module pour être constructible depuis
tower avec les pkgs linux et testable sans Mac.
- profiles/macos : flakes + trusted-users dans nix.conf, et
system.activationScripts.winnie-xcode (xcode-select -s, licence Xcode,
-runFirstLaunch) pour que seule l'installation App Store reste manuelle.
- Embarque aussi le setup SSH entrant du Mac (sshd, clé hermes@tower, tunnel
inverse autossh) qui était déjà dans l'arbre de travail.
Vérifié depuis tower : nix eval du darwinConfigurations.macos (toplevel et
home-manager-generation) + build des scripts en x86_64-linux (shellcheck) et
rsync de bout en bout depuis le dépôt de tower.
Paquets yggdrasil + tor et deux launchd.daemons (tor SOCKS 127.0.0.1:9050,
yggdrasil sur /etc/yggdrasil.conf) pour faire entrer le Mac dans le mesh.
/etc/yggdrasil.conf (mot de passe partagé) reste hors du store, à créer
une fois à la main ; le torrc ne contient aucun secret.
Module services/ygg-mesh : Yggdrasil en réseau privé (mot de passe partagé,
clés publiques épinglées), liens Tor via une instance tor dédiée (onion
service par machine) et lien direct multicast prioritaire sur le LAN.
Chaque machine garde une adresse IPv6 stable et un nom <host>.ygg.
Secret dans secrets/ygg-mesh.yml (règle .sops.yaml dédiée) ; config rendue
à chaud au démarrage (ExecStartPre + credential systemd), le mot de passe
ne touche jamais le store. Identités et clés dans la table `nodes`.
onedark.transparent couvre tous les groupes du theme, pas seulement
Normal ; les highlights Lualine sont nettoyes apres ColorScheme et
les ~ de fin de buffer deviennent des espaces.
stalwart-mcp (Rust) parle JMAP au Stalwart du VPS, patche pour l'URL
API et l'envoi depuis l'identite marc. Mot de passe dedie dans
secrets/stalwart-mcp.yml ; importe par tower seulement, pour eviter
le conflit de cle sops avec services/stalwart sur anywhere.
Le mineur ne tourne que 01:00-09:00, plus en semaine 09:00-18:00
quand un evenement du calendrier sg est actif. Le wallet vient de
secrets/monero.yml via LoadCredential (plus dans la ligne de
commande) ; meme planning sur le Deck.
Le forward de box 77.207.176.170:42070 est mort : tower devient pair
client du hub wg1 avec persistentKeepalive. L'alias ssh tower pointe
sur 10.100.0.3 et la cle root du VPS est autorisee sur tower. Cle
privee dans secrets/wireguard.yml (recipient tower).
Renomme stalwart_mail_pw2/pw3, spam_pw, noreply_pw, admin_pw, bob_pw
et acme_secret en stalwart_*_password / stalwart_acme_secret, un
fichier sops par usage.
66.108.44.154 passe en allowed-ip : l'auto-ban persiste en base et
bloquait le domicile sur 25/465/993.
meetup@marcpartensky.com partage la boite de marc.
Les blobs common.yml et anywhere.yml sont re-chiffres dans le meme
commit (renommage des cles Stalwart, rotation, postgres_crt/key).
secrets/zitadel-smtp.yml porte le mot de passe du compte d'envoi pour
le provisioning SMTP par API (v2 ignore la config runtime). Le PAT
admin est materialise en 0400 pour hermes et rotate.
dashboard.public_url engage auth_required : la racine ne sert plus le
token de session en clair derriere Pangolin. Le flux client passe par
/auth/password-login puis un ws-ticket a usage unique. nginx annonce
https et la sonde devient /api/status.
App Zitadel publique en PKCE (client_id 395733475048620332), claim
preferred_username limite a marc@marcpartensky.com, redirect explicite
car nginx reecrit le Host. SSO Pangolin coupe pour eviter le double
login.
DeepSeek v4.1 Flash devient le modele par defaut ; chaine de secours
DeepSeek puis Nemotron 3 Ultra gratuit ; le salon de Zoe (Matrix) y
passe aussi.
Beeper est declare dans les mcpServers avec le token lu depuis
l'environnement (plus de token en dur dans config.yaml) et l'URL LAN
pour etre cliquable depuis Hermes Desktop. Le timeout du MCP gitea
est complete.
anki-mcp : Anki sans bureau et addon AnkiMCP, HTTP MCP sur 3141,
connecte a la collection du serveur de sync.
mcp-lan-access republie sur l'adresse LAN de tower les endpoints
loopback (3141, 8710, 6060, 23373), firewall limite au Mac ; l'addon
Anki autorise ce Host (anti DNS-rebinding).
arr-mcp ne publie plus 6060 sur 0.0.0.0. Le module mcp-lan-access
est importe par services/default.nix avec anki-mcp, wise-mcp et
bank-mcp.
Input brut hermes-menagerie (github:ZakiChair/hermes-catppuccin),
module home-mac/hermes-skins qui installe les palettes dans
~/.hermes/skins, active dans la home de marc@macos.