Commit Diff


commit - 4c05a15cfa439f1fcc11e58ce8844d9fcf35c0c9
commit + 6dcb1bb76873ac8f62376401c4124d0c56ace04e
blob - /dev/null
blob + 58eb2e043e09c04d1151664c005a9d48d1570337 (mode 644)
--- /dev/null
+++ .forgejo/workflows/audit.yml
@@ -0,0 +1,30 @@
+# .forgejo/workflows/audit.yml
+#
+# Forgejo Actions — Verificación estática del canal Guix.
+# Corre en cada push y pull request a main.
+# El badge del resultado aparece en el README.
+
+name: Audit
+
+on:
+  push:
+    branches: [main]
+  pull_request:
+    branches: [main]
+
+jobs:
+  audit:
+    name: Static Audit
+    runs-on: ubuntu-latest
+
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v4
+
+      - name: Set up Python
+        uses: actions/setup-python@v5
+        with:
+          python-version: "3.12"
+
+      - name: Run audit
+        run: python3 scripts/audit.py
blob - 0faa60f4ceb4969c7a30672887e9998487ddb22e
blob + c6ac4c2c73d4f565c72ecbb0960402c38dc2a74c
--- README.md
+++ README.md
@@ -1,2 +1,200 @@
 # guix-channel
 
+Canal personal de GNU Guix para el Nitro 5 — Richard Bernal Estrada.
+
+[![Audit](https://codeberg.org/Richard7987/guix-channel/actions/workflows/audit.yml/badge.svg)](https://codeberg.org/Richard7987/guix-channel/actions)
+[![Version](https://img.shields.io/badge/sistema-v2026.1-blue?style=flat)](https://codeberg.org/Richard7987/guix-channel/releases)
+[![Guix](https://img.shields.io/badge/GNU_Guix-1.5-orange?style=flat)](https://guix.gnu.org)
+[![Licencia](https://img.shields.io/badge/licencia-GPL--3.0-green?style=flat)](LICENSE)
+
+Canal con paquetes binarios y configuración de sistema para el Acer Nitro 5
+(Intel UHD 630 + GTX 1050 Max-Q, PRIME Render Offload, KDE Plasma).
+
+---
+
+## Estructura
+
+```
+guix-channel/
+├── .forgejo/workflows/
+│   └── audit.yml           ← CI: verificación estática automática
+├── richard/
+│   ├── packages/
+│   │   ├── zen-browser.scm ← Zen Browser 1.12.9b (binary wrap)
+│   │   └── mullvad.scm     ← Mullvad VPN 2026.1 (binary wrap desde .deb)
+│   └── services/
+│       └── mullvad.scm     ← Servicio Shepherd para mullvad-daemon
+├── scripts/
+│   └── audit.py            ← Script de verificación estática (58 checks)
+└── system/
+    ├── channels.scm        ← Canales: guix + nonguix + este canal
+    ├── config.scm          ← Configuración del sistema (/etc/config.scm)
+    └── home.scm            ← Guix Home: GPG, YubiKey, bash
+```
+
+---
+
+## Agregar el canal
+
+Añade esto a `~/.config/guix/channels.scm`:
+
+```scheme
+(channel
+  (name 'richard)
+  (url "https://codeberg.org/Richard7987/guix-channel")
+  (branch "main")
+  (introduction
+    (make-channel-introduction
+      "17ca291dac7ec48ce8266b3726d1fdcc513e99f7"
+      (openpgp-fingerprint
+        "91CA 581F 7B78 01E8 8673  D228 DBD5 F61D 8A0A 14D7"))))
+```
+
+Luego:
+
+```bash
+guix pull
+guix install zen-browser  # o mullvad-vpn
+```
+
+---
+
+## Instalar el sistema completo (Nitro 5)
+
+```bash
+# 1. Clonar el repo
+git clone git@codeberg.org:Richard7987/guix-channel.git ~/guix-channel
+
+# 2. Copiar configuraciones
+sudo cp ~/guix-channel/system/config.scm /etc/config.scm
+mkdir -p ~/.config/guix
+cp ~/guix-channel/system/channels.scm ~/.config/guix/channels.scm
+
+# 3. Actualizar canales y reconfigurar
+guix pull
+sudo guix system reconfigure /etc/config.scm
+
+# 4. Aplicar configuración de usuario (Guix Home)
+guix home reconfigure ~/guix-channel/system/home.scm
+```
+
+---
+
+## Paquetes incluidos
+
+### Zen Browser (`zen-browser`)
+
+Fork de Firefox enfocado en privacidad con barra lateral y espacios de trabajo.
+Empaquetado como binary wrap desde el tarball oficial de GitHub.
+
+```bash
+guix install zen-browser
+```
+
+Para actualizar a una versión nueva:
+
+```bash
+# 1. Editar richard/packages/zen-browser.scm — cambiar 'version'
+# 2. Obtener el hash nuevo:
+guix download https://github.com/zen-browser/desktop/releases/download/VERSION/zen.linux-x86_64.tar.xz
+# 3. Reemplazar el (base32 "...") con el hash obtenido
+git commit -am "zen-browser: actualizar a VERSION"
+git push
+```
+
+### Mullvad VPN (`mullvad-vpn` + servicio Shepherd)
+
+Cliente VPN centrado en privacidad. Incluye daemon (`mullvad-daemon`)
+y CLI (`mullvad`). El daemon arranca automáticamente con el sistema.
+
+```bash
+# Tras instalar el sistema, activar la cuenta:
+mullvad account login TU_NUMERO_DE_CUENTA
+
+# Conectar
+mullvad relay set location mx   # servidores en México
+mullvad connect
+
+# Estado
+mullvad status
+herd status mullvad
+```
+
+Para actualizar:
+
+```bash
+# 1. Editar richard/packages/mullvad.scm — cambiar 'version'
+# 2. Obtener el hash:
+wget https://github.com/mullvad/mullvadvpn-app/releases/download/VERSION/MullvadVPN-VERSION_amd64.deb
+sha256sum MullvadVPN-VERSION_amd64.deb | python3 scripts/nix32.py
+# 3. Reemplazar el (base32 "...") con el resultado
+```
+
+---
+
+## Hardware objetivo
+
+| Componente | Detalle |
+|---|---|
+| Laptop | Acer Nitro 5 |
+| CPU | Intel Coffee Lake-H |
+| iGPU | Intel UHD 630 (`PCI:0:2:0`) |
+| dGPU | NVIDIA GTX 1050 3 GB Max-Q (`PCI:1:0:0`) |
+| GPU Mode | PRIME Render Offload (sin MUX switch) |
+| DE | KDE Plasma 6 + SDDM |
+| Kernel | Linux no-libre (nonguix) |
+
+### Verificar PRIME tras instalar
+
+```bash
+# Debe mostrar Intel/Mesa
+glxinfo | grep "OpenGL renderer"
+
+# Debe mostrar NVIDIA GTX 1050
+__NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia \
+  glxinfo | grep "OpenGL renderer"
+
+# Lanzar Blender con NVIDIA
+__NV_PRIME_RENDER_OFFLOAD=1 __GLX_VENDOR_LIBRARY_NAME=nvidia blender
+```
+
+---
+
+## Versionado
+
+Este proyecto usa **CalVer** (`YYYY.N`):
+
+| Versión | Fecha | Cambios |
+|---|---|---|
+| v2026.1 | Mayo 2026 | Versión inicial: KDE Plasma, PRIME Offload, Mullvad, Zen Browser, YubiKey |
+
+Para crear un nuevo release en Codeberg:
+
+```bash
+git tag v2026.2
+git push origin v2026.2
+```
+
+---
+
+## CI — Verificación estática
+
+El script `scripts/audit.py` corre 58 checks automáticos en cada push:
+
+- Validez de hashes nix32 (formato y longitud)
+- Imports de módulos requeridos en todos los archivos `.scm`
+- Presencia de servicios críticos (`nvidia-service-type`, `sddm-service-type`, etc.)
+- Configuración PRIME (`BusID`, `AllowNVIDIAGPUScreens`, `nvda`)
+- Paquetes requeridos en el sistema
+- Configuración de Guix Home (GPG, YubiKey, pinentry)
+
+```bash
+# Correr localmente
+python3 scripts/audit.py
+```
+
+---
+
+## Licencia
+
+GPL-3.0 — ver [LICENSE](LICENSE)
blob - /dev/null
blob + f926fecfabb9fbedfa5976852ea563121a6b01f4 (mode 644)
--- /dev/null
+++ scripts/audit.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+"""
+audit.py — Verificación estática del canal Guix de Richard.
+Ejecuta checks sobre módulos, hashes, imports y estructura.
+Retorna exit code 0 si todo pasa, 1 si hay errores críticos.
+"""
+
+import re
+import sys
+import os
+
+BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+def load(path):
+    with open(os.path.join(BASE, path)) as f:
+        return f.read()
+
+c = {
+    "cfg":  load("system/config.scm"),
+    "chan": load("system/channels.scm"),
+    "home": load("system/home.scm"),
+    "zen":  load("richard/packages/zen-browser.scm"),
+    "mul":  load("richard/packages/mullvad.scm"),
+    "svc":  load("richard/services/mullvad.scm"),
+}
+
+NIX = set("0123456789abcdfghijklmnpqrsvwxyz")
+def hash_ok(h): return len(h) == 52 and all(x in NIX for x in h)
+
+passed, failed = [], []
+
+def ck(cond, label):
+    (passed if cond else failed).append(label)
+
+# ── channels.scm ────────────────────────────────────────────────
+ck("897c1a470da759236cc11798f4e0a5f7d4d59fbc" in c["chan"],     "channels: nonguix intro hash")
+ck("2A39 3FFF 68F4 EF7A" in c["chan"],                          "channels: nonguix fingerprint")
+ck("git.savannah.gnu.org/git/guix.git" in c["chan"],           "channels: guix URL oficial")
+ck("Richard7987/guix-channel" in c["chan"],                     "channels: canal personal URL")
+ck("17ca291dac7ec48ce8266b3726d1fdcc513e99f7" in c["chan"],     "channels: canal personal intro commit")
+
+# ── packages/zen-browser.scm ────────────────────────────────────
+ck(hash_ok("0zjck0yqly6lbyj4njdjcj0p0fwv9k69lx4rwks53f72caqs95hs"), "zen: hash nix32 válido")
+ck("(gnu packages base)" in c["zen"],                           "zen: import (gnu packages base)")
+ck("(gnu packages elf)" in c["zen"],                            "zen: import (gnu packages elf)")
+ck("LD_LIBRARY_PATH" in c["zen"],                               "zen: LD_LIBRARY_PATH en wrapper")
+ck("MOZ_ENABLE_WAYLAND" in c["zen"],                            "zen: Wayland habilitado")
+ck("zen-browser.desktop" in c["zen"],                           "zen: .desktop entry")
+ck("license:mpl2.0" in c["zen"],                                "zen: licencia MPL-2.0")
+
+# ── packages/mullvad.scm ────────────────────────────────────────
+ck(hash_ok("0gpg5yb1b4fw6zw06ymgicw46v7qj4sf7i5zd5srdhqvn66rlmqy"), "mullvad: hash nix32 válido")
+ck("(gnu packages binutils)" in c["mul"],                       "mullvad: import (gnu packages binutils)")
+ck("data.tar.xz" in c["mul"] and "data.tar.zst" in c["mul"],   "mullvad: detección xz+zst")
+ck("copy-recursively app-src lib-dir" in c["mul"],              "mullvad: copy-recursively (path con espacio)")
+ck("--set-interpreter" in c["mul"],                             "mullvad: patchelf interpreter")
+ck("--set-rpath" in c["mul"],                                   "mullvad: patchelf rpath")
+ck("license:gpl3+" in c["mul"],                                 "mullvad: licencia GPL-3+")
+
+# ── services/mullvad.scm ────────────────────────────────────────
+ck("(gnu services)" in c["svc"],                                "svc: import (gnu services)")
+ck("gnu services configuration" not in c["svc"],                "svc: sin módulo incorrecto")
+ck("lib/mullvad-vpn/mullvad-daemon" in c["svc"],                "svc: path daemon correcto")
+ck("(requirement '(networking nftables))" in c["svc"],          "svc: requirement correcto")
+ck("activation-service-type" in c["svc"],                       "svc: activation-service-type")
+ck("(respawn? #t)" in c["svc"],                                 "svc: respawn activado")
+
+# ── system/config.scm — imports ─────────────────────────────────
+ck("(gnu services sddm)" in c["cfg"],                           "cfg: import (gnu services sddm)")
+ck("(nongnu services nvidia)" in c["cfg"],                      "cfg: import (nongnu services nvidia)")
+ck("(guix transformations)" in c["cfg"],                        "cfg: import (guix transformations)")
+ck("(nongnu packages nvidia)" in c["cfg"],                      "cfg: import (nongnu packages nvidia)")
+ck("(richard packages zen-browser)" in c["cfg"],                "cfg: import richard/zen-browser")
+ck("(richard services mullvad)" in c["cfg"],                    "cfg: import richard/services/mullvad")
+
+# ── system/config.scm — sistema ─────────────────────────────────
+ck(bool(re.search(r'\(kernel\s+linux\)', c["cfg"])),            "cfg: kernel linux (nonguix)")
+ck("microcode-initrd" in c["cfg"],                              "cfg: microcode-initrd")
+ck("linux-firmware" in c["cfg"],                                "cfg: linux-firmware")
+ck("(kernel-loadable-modules (list nvidia-module))" in c["cfg"],"cfg: kernel-loadable-modules nvidia-module")
+ck("modprobe.blacklist=nouveau" in c["cfg"],                    "cfg: blacklist nouveau")
+ck("nvidia-drm.modeset=1" in c["cfg"],                          "cfg: nvidia-drm.modeset=1")
+ck("grub-efi-bootloader" in c["cfg"],                           "cfg: GRUB EFI")
+
+# ── system/config.scm — servicios ───────────────────────────────
+ck("(service nvidia-service-type)" in c["cfg"],                 "cfg: nvidia-service-type")
+ck("simple-service 'nvidia-udev" not in c["cfg"],               "cfg: sin udev manual")
+ck("plasma-desktop-service-type" in c["cfg"],                   "cfg: plasma-desktop-service-type")
+ck("sddm-service-type" in c["cfg"],                             "cfg: sddm-service-type")
+ck("(cons* nvda %default-xorg-modules)" in c["cfg"],            "cfg: nvda en Xorg modules")
+ck("mesa=nvda" in c["cfg"],                                     "cfg: graft mesa→nvda")
+ck("PCI:0:2:0" in c["cfg"],                                     "cfg: BusID Intel UHD 630")
+ck("PCI:1:0:0" in c["cfg"],                                     "cfg: BusID GTX 1050")
+ck("AllowNVIDIAGPUScreens" in c["cfg"],                         "cfg: PRIME AllowNVIDIAGPUScreens")
+ck("(mullvad-service)" in c["cfg"],                             "cfg: mullvad-service")
+ck("pcscd-service-type" in c["cfg"],                            "cfg: pcscd (YubiKey)")
+ck("nftables-service-type" in c["cfg"],                         "cfg: nftables firewall")
+ck("(delete gdm-service-type)" in c["cfg"],                     "cfg: GDM eliminado")
+ck("zen-browser)" in c["cfg"],                                  "cfg: zen-browser en packages")
+
+# ── system/home.scm ─────────────────────────────────────────────
+ck("simple-service 'gpg-agent-conf home-files-service-type" in c["home"], "home: simple-service correcto")
+ck('"pinentry"' in c["home"],                                   "home: pinentry instalado")
+ck(".guix-home/profile/bin/pinentry-curses" in c["home"],       "home: path pinentry-curses")
+ck("enable-ssh-support" in c["home"],                           "home: SSH support gpg-agent")
+ck("GPG_TTY" in c["home"],                                      "home: GPG_TTY en bashrc")
+ck("SSH_AUTH_SOCK" in c["home"],                                "home: SSH_AUTH_SOCK en bashrc")
+
+# ── Resultado ────────────────────────────────────────────────────
+total = len(passed) + len(failed)
+print(f"╔══════════════════════════════════════╗")
+print(f"║  Guix Channel Audit — {total} checks  ║")
+print(f"╠══════════════════════════════════════╣")
+print(f"║  ✅ Passed: {len(passed):>3}  ❌ Failed: {len(failed):>3}    ║")
+print(f"╚══════════════════════════════════════╝")
+
+if failed:
+    print("\n❌ FAILED CHECKS:")
+    for f in failed:
+        print(f"  ✗ {f}")
+    sys.exit(1)
+else:
+    print("\n✅ All checks passed — ready to install!")
+    sys.exit(0)