Arquitectura
Los componentes del canal y cómo se conectan de extremo a extremo.
Vista de conjunto
El flujo tiene dos mitades: un pipeline privado que decide qué se publica y una cadena pública firmada que cualquiera puede verificar. El punto de decisión es decide.py: nada llega a la firma sin pasar por él.
Dibujando el diagrama…
flowchart TB
N["Nextron Systems<br/>Neo23x0/signature-base"]:::src
C["Community rules<br/>Yara-Rules/rules"]:::src
V["VirusTotal YARA-X<br/>recorded as engine, no rules"]:::src
P["prepare.py<br/>pin commit, extract, normalize"]:::src
R["rulecheck.py<br/>static classification"]:::val
G["dynamic_gate.py + bench.py<br/>YARA engine measurements"]:::val
D{"decide.py<br/>PUBLISH GATE"}:::gate
H["SHA-256 per file<br/>make_public_candidate.py"]:::sec
M["rules_root + manifest.json<br/>seal.py"]:::sec
S["Sigstore keyless<br/>cosign in publish.yml"]:::sec
RL["GitHub Release<br/>draft, then public"]:::pub
W["GitHub Pages + Cloudflare mirror<br/>site.yml"]:::pub
A["MacGuard GUI TUI CLI<br/>RuleInstaller"]:::pub
Q[("Private quarantine store<br/>admin/worker D1")]:::qua
API["Admin API and panel"]:::qua
HR["Human review<br/>approve, delete or keep"]:::qua
N --> P
C --> P
V -.-> P
P --> R --> G --> D
D -->|approved| H --> M --> S --> RL --> W --> A
D -->|not approved| Q --> API --> HR
HR -->|decision| R
classDef src fill:#cfe3ff,stroke:#2f6df0,color:#0b1b33
classDef val fill:#ffe9b8,stroke:#b8860b,color:#2b1d00
classDef sec fill:#cdeedd,stroke:#1b6e3c,color:#08210f
classDef pub fill:#e4d7ff,stroke:#6a3fd1,color:#1b0b3b
classDef qua fill:#ffd4cc,stroke:#c0392b,color:#33100b
classDef gate fill:#ffffff,stroke:#111111,stroke-width:3px,color:#111111Descripción del diagrama
Tres fuentes alimentan prepare.py. rulecheck.py clasifica los ficheros y dynamic_gate.py los mide. decide.py es la puerta de publicación: los aprobados reciben SHA-256, un rules_root Merkle y un manifiesto, se firman con Sigstore en publish.yml, se publican en una GitHub Release, se replican en GitHub Pages y Cloudflare Pages y los instala MacGuard. Los que no pasan van al almacén privado de cuarentena, una persona los revisa con la API de administración y la siguiente ejecución diaria los revalida.
Código Mermaid
flowchart TB
N["Nextron Systems<br/>Neo23x0/signature-base"]:::src
C["Community rules<br/>Yara-Rules/rules"]:::src
V["VirusTotal YARA-X<br/>recorded as engine, no rules"]:::src
P["prepare.py<br/>pin commit, extract, normalize"]:::src
R["rulecheck.py<br/>static classification"]:::val
G["dynamic_gate.py + bench.py<br/>YARA engine measurements"]:::val
D{"decide.py<br/>PUBLISH GATE"}:::gate
H["SHA-256 per file<br/>make_public_candidate.py"]:::sec
M["rules_root + manifest.json<br/>seal.py"]:::sec
S["Sigstore keyless<br/>cosign in publish.yml"]:::sec
RL["GitHub Release<br/>draft, then public"]:::pub
W["GitHub Pages + Cloudflare mirror<br/>site.yml"]:::pub
A["MacGuard GUI TUI CLI<br/>RuleInstaller"]:::pub
Q[("Private quarantine store<br/>admin/worker D1")]:::qua
API["Admin API and panel"]:::qua
HR["Human review<br/>approve, delete or keep"]:::qua
N --> P
C --> P
V -.-> P
P --> R --> G --> D
D -->|approved| H --> M --> S --> RL --> W --> A
D -->|not approved| Q --> API --> HR
HR -->|decision| R
classDef src fill:#cfe3ff,stroke:#2f6df0,color:#0b1b33
classDef val fill:#ffe9b8,stroke:#b8860b,color:#2b1d00
classDef sec fill:#cdeedd,stroke:#1b6e3c,color:#08210f
classDef pub fill:#e4d7ff,stroke:#6a3fd1,color:#1b0b3b
classDef qua fill:#ffd4cc,stroke:#c0392b,color:#33100b
classDef gate fill:#ffffff,stroke:#111111,stroke-width:3px,color:#111111Componentes
| Componente | Qué hace | Dónde |
|---|---|---|
daily.yml | Ejecución diaria 03:17 UTC o manual: recoge, clasifica, mide, decide y solicita la publicación. | .github/workflows/daily.yml |
publish.yml | Firma y publica la release; entorno stable-signing-auto si AUTO_PUBLISH=true, stable-signing con aprobador humano si no. | .github/workflows/publish.yml |
site.yml | Construye y verifica el sitio, lo despliega y comprueba la URL pública. | .github/workflows/site.yml |
| Servicio de cuarentena | Almacén privado y panel de revisión (Cloudflare Worker + D1). | admin/worker/ |
| MacGuard | GUI, TUI y CLI con un único motor compartido. | DMGTrustAuditor/DMGTrustAuditor/Core/ |
ACTUAL El servicio de cuarentena está implementado y probado con un servidor de desarrollo local, pero no está desplegado en producción: faltan credenciales de Cloudflare Workers/D1 y una aplicación OAuth de GitHub. Mientras tanto la cuarentena se aplica en el pipeline y solo se publica lo que supera todos los controles automáticos.
Límites de confianza
Dibujando el diagrama…
flowchart LR
subgraph UNTRUSTED["Untrusted input"]
U1["upstream rule repositories"]:::src
end
subgraph PRIVATE["Private zone"]
J["daily.yml review job"]:::val
QS[("quarantine store")]:::qua
AP["admin panel and API"]:::qua
end
subgraph SIGNING["Signing zone"]
PW["publish.yml<br/>OIDC identity"]:::sec
end
subgraph PUBLIC["Public zone"]
GR["GitHub Releases"]:::pub
PG["Pages and Cloudflare mirror"]:::pub
end
subgraph CLIENT["Client"]
MG["MacGuard<br/>pinned cosign, trusted checkpoint"]:::sec
end
U1 --> J
J -->|only approved files and counts| PW
J -->|everything else| QS
QS --- AP
PW --> GR --> PG --> MG
classDef src fill:#cfe3ff,stroke:#2f6df0,color:#0b1b33
classDef val fill:#ffe9b8,stroke:#b8860b,color:#2b1d00
classDef sec fill:#cdeedd,stroke:#1b6e3c,color:#08210f
classDef pub fill:#e4d7ff,stroke:#6a3fd1,color:#1b0b3b
classDef qua fill:#ffd4cc,stroke:#c0392b,color:#33100b
classDef gate fill:#ffffff,stroke:#111111,stroke-width:3px,color:#111111Descripción del diagrama
Las fuentes upstream son entrada no fiable. El job privado del pipeline y el almacén de cuarentena guardan todo lo relativo a reglas no publicadas. Solo el conjunto aprobado, cifras agregadas y los artefactos firmados pasan a la zona pública. El cliente confía en el verificador Sigstore fijado, en la identidad del workflow y en su propio checkpoint guardado, no en el sitio que aloja los ficheros.
Código Mermaid
flowchart LR
subgraph UNTRUSTED["Untrusted input"]
U1["upstream rule repositories"]:::src
end
subgraph PRIVATE["Private zone"]
J["daily.yml review job"]:::val
QS[("quarantine store")]:::qua
AP["admin panel and API"]:::qua
end
subgraph SIGNING["Signing zone"]
PW["publish.yml<br/>OIDC identity"]:::sec
end
subgraph PUBLIC["Public zone"]
GR["GitHub Releases"]:::pub
PG["Pages and Cloudflare mirror"]:::pub
end
subgraph CLIENT["Client"]
MG["MacGuard<br/>pinned cosign, trusted checkpoint"]:::sec
end
U1 --> J
J -->|only approved files and counts| PW
J -->|everything else| QS
QS --- AP
PW --> GR --> PG --> MG
classDef src fill:#cfe3ff,stroke:#2f6df0,color:#0b1b33
classDef val fill:#ffe9b8,stroke:#b8860b,color:#2b1d00
classDef sec fill:#cdeedd,stroke:#1b6e3c,color:#08210f
classDef pub fill:#e4d7ff,stroke:#6a3fd1,color:#1b0b3b
classDef qua fill:#ffd4cc,stroke:#c0392b,color:#33100b
classDef gate fill:#ffffff,stroke:#111111,stroke-width:3px,color:#111111Las fuentes son entrada no fiable. Lo relativo a reglas no publicadas (nombres, hallazgos, contenido) no sale del job privado salvo hacia el servicio privado; los artefactos, registros y el sitio públicos llevan solo cifras.