dante-watch 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +78 -23
  2. package/package.json +1 -1
  3. package/src/bib/answers.mjs +2 -2
  4. package/src/bib/bib.json +1 -1
  5. package/src/bib/ear.mjs +24 -21
  6. package/src/bib/net.json +1 -1
  7. package/src/bib/net.mjs +7 -9
  8. package/src/bib/probe.mjs +7 -8
  9. package/src/bib/pruef.json +1 -0
  10. package/src/bib/router.mjs +16 -19
  11. package/src/bib/system.mjs +22 -16
  12. package/src/bib/systems.json +1 -0
  13. package/src/bib/wash.mjs +5 -13
  14. package/src/checks/battery.mjs +15 -10
  15. package/src/checks/common.mjs +5 -5
  16. package/src/checks/demo.mjs +2 -2
  17. package/src/checks/formats.mjs +221 -0
  18. package/src/checks/hf.mjs +252 -0
  19. package/src/checks/loc.mjs +2 -4
  20. package/src/checks/php2shell.mjs +8 -9
  21. package/src/checks/rechte.mjs +2 -3
  22. package/src/checks/secrets.mjs +15 -6
  23. package/src/checks/sshd.mjs +3 -5
  24. package/src/checks/webshell.mjs +3 -5
  25. package/src/cli.mjs +15 -10
  26. package/src/core/check.mjs +4 -8
  27. package/src/core/consent.mjs +7 -7
  28. package/src/core/render.mjs +2 -2
  29. package/src/core/sh.mjs +34 -8
  30. package/src/i18n-checks.mjs +6 -3
  31. package/src/i18n.mjs +54 -14
  32. package/src/mascot.mjs +3 -5
  33. package/src/me/deep.mjs +37 -0
  34. package/src/me/diary.mjs +51 -0
  35. package/src/me/home.mjs +10 -0
  36. package/src/me/hostkey.mjs +94 -0
  37. package/src/me/lock.mjs +41 -0
  38. package/src/me/nudge.mjs +52 -0
  39. package/src/me/onboard.mjs +102 -0
  40. package/src/me/overview.mjs +10 -0
  41. package/src/me/patrol.mjs +43 -0
  42. package/src/me/pick.mjs +64 -0
  43. package/src/me/pool.mjs +15 -0
  44. package/src/me/recon.mjs +124 -0
  45. package/src/me/refresh.mjs +70 -0
  46. package/src/me/schedule-deep.mjs +86 -0
  47. package/src/me/schedule.mjs +120 -0
  48. package/src/me/servers.mjs +103 -0
  49. package/src/me/sysid.mjs +113 -0
  50. package/src/me/sysq.mjs +23 -0
  51. package/src/me/sysreport.mjs +73 -0
  52. package/src/me/texts.mjs +412 -0
  53. package/src/me/user.mjs +70 -0
  54. package/src/pack/builtin.mjs +115 -4
  55. package/src/pack/ere.mjs +87 -0
  56. package/src/pack/install.mjs +6 -8
  57. package/src/pack/key.mjs +2 -3
  58. package/src/pack/know.mjs +4 -5
  59. package/src/pack/pack.mjs +14 -10
  60. package/src/pack/rules.mjs +109 -1
  61. package/src/pack/texts.mjs +8 -7
  62. package/src/session.mjs +321 -51
  63. package/src/ticker.mjs +11 -10
  64. package/src/ui/footer.mjs +9 -5
  65. package/src/ui/job-worker.mjs +4 -4
  66. package/src/ui/job.mjs +7 -6
  67. package/src/ui/quips.mjs +1 -2
  68. package/src/ui/wait.mjs +3 -4
  69. package/src/version.mjs +11 -0
@@ -1,18 +1,15 @@
1
- // The ear: turns what a human types into an intent + a probability. No LLM, no network.
2
- // Weighted naive Bayes over four kinds of features, learned by counting a bib of example lines:
3
- // f: first word (the "starts with hi → greeting 78%" signal), w: words, b: word pairs,
4
- // c: letter triples (so "prüff", "servr", "chek" still land). Each kind carries its own weight.
5
- // A feature found in many intents ("me", "wie", "bitte") says little, so it is weighed down by
6
- // how many intents share it — the bib decides what is a filler word, not a hand-made list.
7
- // The answer is honest about doubt: below the threshold, or when most of the words are unknown,
8
- // it does not guess — it says "unklar" and hands back the two best candidates.
1
+ // Naive Bayes classifier for what the user typed: returns an intent and a probability. No network.
2
+ // Four feature kinds are counted from the example library: first word, words, word pairs, letter
3
+ // triples (so typos like "prüff" or "chek" still land). A feature shared by many intents counts for
4
+ // less, which makes filler words fall out without a stop-word list. Below the confidence threshold it
5
+ // answers "unklar" and returns the two best candidates instead of guessing.
9
6
 
10
7
  const WEIGHT = { f: 1.5, w: 1, b: 1, c: 0.25 };
11
8
  const ALPHA = 0.5; // smoothing: an unseen pairing is rare, not impossible
12
- const SHARP = 2; // measured on the held-out set: 1 → too shy, ≥2.5 → only bolder, not wiser
9
+ const SHARP = 2; // measured on the held-out set: 1 -> too shy, ≥2.5 -> only bolder, not wiser
13
10
  export const SURE = 0.6; // below this the router asks instead of acting
14
11
  // Risk-weighted: an intent that only ANSWERS (a question, small talk, a greeting) may speak from
15
- // SURE_ANSWER on — a wrong answer is wrong text, never a deed. Actions keep SURE.
12
+ // SURE_ANSWER on - a wrong answer is wrong text, never a deed. Actions keep SURE.
16
13
  // Measured (25.10.): 135 of 146 question misses had the right intent on top, only under 60 %.
17
14
  export const ANSWER_ONLY = new Set(["frage_luecke", "frage_urteil", "frage_gehackt", "frage_dante", "smalltalk", "gruss", "hilfe", "unklar"]);
18
15
  export let SURE_ANSWER = Number(process.env.DANTE_SURE_ANSWER || 0.4);
@@ -48,13 +45,13 @@ export function features(text) {
48
45
  return out;
49
46
  }
50
47
 
51
- // The model only keeps raw counts, so it can learn one line at a time (the kitchen loop adds a
52
- // line the moment it finds a gap and checks again right away). Everything derived — balance,
53
- // filler-word weight, trust — is worked out at the moment of hearing, from those counts.
48
+ // The model only keeps raw counts, so it can learn one line at a time (the build server loop adds a
49
+ // line the moment it finds a gap and checks again right away). Everything derived - balance,
50
+ // filler-word weight, trust - is worked out at the moment of hearing, from those counts.
54
51
  // balance: every intent weighs the same in total, so one huge intent ("unklar", 10× the others)
55
52
  // keeps its breadth of words but stops winning by sheer mass. Measured on the bib, not guessed.
56
53
  // trust: a feature seen once ("prüff" in one single line) gets a fifth of its weight, full weight
57
- // from TRUST sightings on — one example must not turn into "99.9 % sure".
54
+ // from TRUST sightings on - one example must not turn into "99.9 % sure".
58
55
  const TRUST = 5; // measured: 3 still let one "prüff"-line decide alone, 5 does not
59
56
 
60
57
  export function model({ balance = true, trust = TRUST } = {}) {
@@ -73,7 +70,7 @@ export function learn(m, { intent, text }) {
73
70
  return m;
74
71
  }
75
72
 
76
- // The exact inverse of learn — the kitchen takes a line back out when it proved too broad.
73
+ // The exact inverse of learn - the build server takes a line back out when it proved too broad.
77
74
  export function unlearn(m, { intent, text }) {
78
75
  const k = m.intents[intent];
79
76
  if (!k) return m;
@@ -112,8 +109,8 @@ export function classify(m, text, { sharp = SHARP, all = false } = {}) {
112
109
  };
113
110
  const words = tokens(text);
114
111
  const known = words.length ? words.filter(knownWord).length / words.length : 0;
115
- // Complement: judge each intent by how badly the line fits ALL THE OTHERS. Big intents
116
- // (400 lines) then stop swallowing small ones (160 lines) — "ich geh jetzt" stays "raus".
112
+ // Complement: judge each intent by how badly the line fits all the OTHERS. Big intents
113
+ // (400 lines) then stop swallowing small ones (160 lines) - "ich geh jetzt" stays "raus".
117
114
  const restTotal = names.reduce((a, c, i) => a + scale[i] * totals[i], 0);
118
115
  const rest = fs.map(([f]) => names.reduce((a, c, i) => a + scale[i] * (m.intents[c].f[f] || 0), 0));
119
116
  const raw = names.map((c, i) => {
@@ -132,11 +129,11 @@ export function classify(m, text, { sharp = SHARP, all = false } = {}) {
132
129
  return { intent: sure ? best.intent : "unklar", p: best.p, known, ranked: all ? ranked : ranked.slice(0, 3) };
133
130
  }
134
131
 
135
- // "this machine" in any of the three languages — a slot, not an intent: "check local" is a check
132
+ // "this machine" in any of the three languages - a slot, not an intent: "check local" is a check
136
133
  // whose target is here. A word list decides it, no probability in between.
137
134
  const LOCAL = /(^|\s)(lokal|local|localhost|hier|here|aqu[ií]|diese[nm]? (rechner|laptop|mac|pc)|meine?[nm]? (rechner|laptop|mac|pc)|this (machine|computer|box|laptop|mac|pc)|my (own )?(machine|computer|box|laptop|mac|pc)|mi (compu|computadora|pc|equipo|laptop|mac)|este equipo|esta (compu|computadora|pc))(?=$|[\s,.!?])/i;
138
135
 
139
- // The value a command needs (target / key path / local), read from the raw line — never invented.
136
+ // The value a command needs (target / key path / local), read from the raw line - never invented.
140
137
  export function slots(text) {
141
138
  const ziel = String(text).match(/\b[\w.-]+@[\w.-]+\b/) || String(text).match(/\b\d{1,3}(\.\d{1,3}){3}\b/);
142
139
  const pfad = String(text).match(/(?:^|\s)((?:~|\.{0,2})\/\S+)/);
@@ -1,16 +1,10 @@
1
- // The sixth bib: system knowledge — kept apart from the five language bibs on purpose.
2
- // The language router (the "intent catcher") hears the user; when the move is a system job it
3
- // OPENS this book and works. Two parts:
4
- // S — the moves Dante must RECOGNISE (grows via the same kitchen loop as the language bib)
5
- // RECIPES — the HANDS: per system family, the exact command and which real line means a hit.
6
- // There is no E1/E2/E3 depth here: nothing personal to anonymise. The only split is the family,
7
- // and the family is a SLOT (like ziel/pfad), picked by the fingerprint — not an intent.
8
- // Dante does not trust what the user says the system is. He reads os-release himself first; that
9
- // reading is itself a recipe in this book (intent "fingerabdruck").
1
+ // Seeds for the three domain classifiers (system moves, check requests, knowledge questions) and the
2
+ // recipes for system-specific commands. The OS family is read from the target itself
3
+ // (os-release), never taken from what the user says. Unknown families yield "unbekannt", not a verdict.
10
4
 
11
- // System families Dante can stand on. Everything else is "unbekannt" → Dante says so, never SAFE.
5
+ // System families Dante can stand on. Everything else is "unbekannt" -> Dante says so, never SAFE.
12
6
  export const FAMILIES = ["debian", "alpine", "fedora", "arch", "unbekannt"];
13
- // os-release ID / ID_LIKE → family (the fingerprint maps real output to one column).
7
+ // os-release ID / ID_LIKE -> family (the fingerprint maps real output to one column).
14
8
  export const FAMILY_OF = {
15
9
  debian: "debian", ubuntu: "debian", raspbian: "debian", mint: "debian", devuan: "debian",
16
10
  alpine: "alpine",
@@ -20,7 +14,6 @@ export const FAMILY_OF = {
20
14
 
21
15
  // Seed phrasings per intent (DE/EN/ES), only to prove the ear. The real bib is cooked by the loop.
22
16
  const S = {
23
- fingerabdruck: ["auf welchem system bin ich", "was läuft hier für ein os", "welche distro", "bin auf debian 11", "ich hab ubuntu", "läuft auf alpine", "das ist ein centos", "which os is this", "im on debian", "running ubuntu 22", "its alpine", "en que sistema estoy", "tengo debian", "es un centos"],
24
17
  finde_php: ["läuft hier php", "welche php version", "wo ist mein php", "php 8.1 mit nginx", "ich hab php-fpm", "hab php 7.4 noch", "is php running", "what php version", "php 8.2 fpm", "where is php", "corre php aqui", "que version de php", "tengo php 8.0"],
25
18
  pruef_php2shell: ["bin ich von php2shell betroffen", "ist meine php version die lücke", "cve-2026-109618 bei mir", "php 8.1.5 sicher", "ist das die rce lücke", "am i affected by php2shell", "is my php version vulnerable", "php 8.2.3 safe", "estoy afectado por php2shell", "mi php es vulnerable"],
26
19
  beleg: ["zeig mir die zeile", "woran siehst du das", "was ist der beweis", "welche zeile beweist das", "show me the line", "whats the proof", "how do you know", "muestrame la linea", "cual es la prueba"],
@@ -29,8 +22,20 @@ const S = {
29
22
  export const SYS_PROBE = Object.entries(S).flatMap(([intent, xs]) => xs.map((text) => ({ intent, text })));
30
23
 
31
24
  // The Muster-Bib seed: how a user asks the watchman to look for what is WRONG (beyond php2shell).
32
- // Recognition only — the hands are the deterministic battery in src/checks/. Grown by the loop.
25
+ // Recognition only - the hands are the deterministic battery in src/checks/. Grown by the loop.
26
+ // lines of the old system-ear intent "fingerabdruck": they now belong to the muster intent meinsystem (same answer)
27
+ const FINGERPRINT_LINES = ["auf welchem system bin ich", "was läuft hier für ein os", "welche distro", "bin auf debian 11", "ich hab ubuntu", "läuft auf alpine", "das ist ein centos", "which os is this", "im on debian", "running ubuntu 22", "its alpine", "en que sistema estoy", "tengo debian", "es un centos"];
33
28
  const M = {
29
+ umschauen: ["schau dich um", "lern mich kennen", "sieh dich mal um", "was weißt du über meinen rechner", "mach dich mit meinem system vertraut", "look around", "get to know my machine", "have a look at my setup", "mira a tu alrededor", "conoce mi equipo", "echa un vistazo a mi sistema"],
30
+ scharf: ["schalt dich scharf", "aktiviere die patrouille", "lauf mehrmals am tag", "überwache mich automatisch", "arm yourself", "turn on the patrol", "run on a schedule", "watch my machine automatically", "ponte en marcha", "activa la patrulla", "revisa automáticamente"],
31
+ systeme_info: ["was kannst du mir über meine systeme sagen", "erzähl mir was über meine rechner", "gib mir einen überblick über alles was ich habe", "was weißt du über meine maschinen", "tell me about my systems", "what can you tell me about my machines", "give me an overview of everything i own", "dime algo de mis sistemas", "qué sabes de mis equipos", "dame un resumen de todo lo que tengo"],
32
+ was_los: ["was ist da los", "was geht auf dem server ab", "was läuft gerade auf meinem rechner", "warum ist der so langsam", "wer ist gerade eingeloggt", "welche ports sind offen", "what's going on on my server", "what is running right now", "why is it so slow", "who is logged in", "which ports are open", "qué pasa en mi servidor", "qué está corriendo ahora", "por qué va tan lento", "quién está conectado", "qué puertos están abiertos"],
33
+ meinsystem: [...FINGERPRINT_LINES, "was ist mein system", "welcher ist mein mac", "was für ein rechner ist das", "welches betriebssystem hab ich", "wie viel ram hab ich", "zeig mir die systeminfo", "what machine is this", "which os am i running", "what is my mac", "show system info", "how much memory do i have", "qué sistema tengo", "qué ordenador es este", "cuánta memoria tengo", "info del sistema", "qué versión de linux es"],
34
+ server_finden: ["finde meine server", "such mal meine server", "spür meine rechner auf", "entdecke meine server", "find my servers", "discover my machines", "look for my servers", "search for servers i own", "busca mis servidores", "encuentra mis servidores", "descubre mis máquinas", "encuentra mis servidores por favor"],
35
+ server_status: ["wie geht's meinen servern", "wie läuft es bei meinen servern", "alles ok bei meinen servern", "wie stehen meine server da", "status meiner server", "how are my servers", "how are my servers doing", "is everything ok with my servers", "status of my servers", "cómo están mis servidores", "cómo van mis servidores", "todo bien con mis servidores"],
36
+ server_liste: ["kennst du meine server", "welche server hast du gefunden", "was für server hab ich", "zeig mir meine server", "welche rechner kennst du von mir", "liste meine server auf", "weißt du welche server ich habe", "do you know my servers", "which servers did you find", "what servers do i have", "list my servers", "show me my machines", "qué servidores conoces", "cuáles son mis servidores", "muéstrame mis servidores", "conoces mis servidores"],
37
+ hf: ["prüf meine modelle", "ist das modell sicher zu laden", "schau dir meine ki modelle an", "was darf mein agent", "prüf meine mcp server", "check meine huggingface modelle", "laden meine gewichte fremden code", "check my models", "are my huggingface models safe to load", "look at my mcp servers", "what is my agent allowed to do", "scan my downloaded models", "revisa mis modelos", "son seguros mis modelos de hugging face", "mira mis servidores mcp", "qué puede hacer mi agente"],
38
+ abschalten: ["schalt dich ab", "stopp die patrouille", "lauf nicht mehr automatisch", "nimm den zeitplan raus", "disarm", "turn off the patrol", "stop running automatically", "remove the schedule", "desarmar", "apaga la patrulla", "quita el horario"],
34
39
  patrouille: ["prüf alles", "mach die runde", "kompletter check", "check alles durch", "alles scannen", "komplett prüfen", "mach die ganze runde", "scan everything", "full check", "run all checks", "check everything", "revisa todo", "chequeo completo", "escanéalo todo"],
35
40
  webshell: ["hat mir wer was reingelegt", "gibt es fremde dateien", "such nach webshells", "ist ne hintertür drin", "schädliche php dateien", "backdoor finden", "fremder code im webroot", "check for webshells", "any backdoor files", "malicious php files", "look for a shell", "busca webshells", "archivos maliciosos", "hay una puerta trasera"],
36
41
  secrets: ["ist meine env offen", "leaken meine geheimnisse", "ist mein git public", "sind passwörter sichtbar", "liegt die .env offen", "db passwort sichtbar", "are my secrets exposed", "is my .env public", "exposed env file", "secrets leaking", "mis secretos están expuestos", "está mi env público", "contraseña de la base visible"],
@@ -39,6 +44,7 @@ const M = {
39
44
  };
40
45
  // The Fachwissen seed: how people ask Dante to explain (what he watches / one topic or finding).
41
46
  const W = {
47
+ bericht: ["was ist passiert", "was hast du gemacht", "gibt es was neues", "wie lief die nacht", "hast du was gefunden", "was war seit gestern", "what happened", "what did you do", "anything new", "did you find anything", "what was going on while i was away", "qué pasó", "qué hiciste", "hay novedades", "encontraste algo", "cómo fue la noche"],
42
48
  job: ["was überwachst du", "was ist dein job", "was prüfst du alles", "wofür bist du da", "was kannst du inhaltlich", "worauf achtest du", "what do you watch", "what is your job", "what do you check", "what are you for", "what do you look for", "que vigilas", "cual es tu trabajo", "que revisas", "para que sirves", "en que te fijas"],
43
49
  thema: ["was ist eine webshell", "woran erkenne ich offene geheimnisse", "warum ist root login gefährlich", "wie prüfst du ssh", "ist das normal", "was tue ich dagegen", "was bedeutet php2shell", "what is a webshell", "what stands out about open secrets", "why is root login dangerous", "how do you check ssh", "is that normal", "what do i do about it", "que es una webshell", "que llama la atencion en los permisos", "por que es peligroso el login de root", "como compruebas ssh", "es normal esto", "que hago al respecto"],
44
50
  };
@@ -46,11 +52,11 @@ export const WISSEN_PROBE = Object.entries(W).flatMap(([intent, xs]) => xs.map((
46
52
 
47
53
  export const MUSTER_PROBE = Object.entries(M).flatMap(([intent, xs]) => xs.map((text) => ({ intent, text })));
48
54
 
49
- // The HANDS. Per family: the exact command Dante runs on the real server, and the rule that reads
50
- // the real output. Small and hand-verified — this is where "every verdict carries a real line"
55
+ // The hands. Per family: the exact command Dante runs on the real server, and the rule that reads
56
+ // the real output. Small and hand-verified - this is where "every verdict carries a real line"
51
57
  // lives. The loop may PROPOSE additions, but a recipe is only the shape below; the hit-logic is
52
58
  // deterministic code in src, never DeepSeek prose. php2shell = CVE-2026-109618 (fictional here):
53
- // affected PHP < 8.1.27, 8.2.0–8.2.13, 8.3.0–8.3.1 — AND only when the vulnerable module is loaded.
59
+ // affected PHP < 8.1.27, 8.2.0–8.2.13, 8.3.0–8.3.1 - and only when the vulnerable module is loaded.
54
60
  export const RECIPES = {
55
61
  debian: {
56
62
  fingerabdruck: { cmd: ". /etc/os-release 2>/dev/null; echo \"$ID ${VERSION_ID}\"", beleg: "die ID-Zeile aus /etc/os-release" },
@@ -0,0 +1 @@
1
+ {"v":1,"systems":[{"id":"opnsense","kind":"router","name":{"de":"OPNsense","en":"OPNsense","es":"OPNsense"},"identify":[{"probe":"freebsd_version","re":"^[0-9]+\\.[0-9]+-"},{"probe":"uname","re":"^FreeBSD "},{"probe":"opnsense_version","re":"^OPNsense"}],"facts":{"pkg":"pkg","init":"rc","firewall":"pf","logs":"/var/log","sshd":"/etc/ssh/sshd_config"}},{"id":"amazon-linux-2","kind":"server","name":{"de":"Amazon Linux 2","en":"Amazon Linux 2","es":"Amazon Linux 2"},"identify":[{"probe":"os_release","re":"^ID=\"amzn\"$"},{"probe":"os_release","re":"^VERSION_ID=\"2.*\"$"},{"probe":"uname","re":"^Linux.*"}],"facts":{"pkg":"yum","init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"freebsd","kind":"server","name":{"de":"FreeBSD","en":"FreeBSD","es":"FreeBSD"},"identify":[{"probe":"freebsd_version","re":"^[0-9]+\\.[0-9]+-"},{"probe":"uname","re":"^FreeBSD "}],"facts":{"pkg":"pkg","init":"rc","firewall":"pf, ipfw","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"pfsense","kind":"router","name":{"de":"pfSense","en":"pfSense","es":"pfSense"},"identify":[{"probe":"platform_file","re":"^pfSense"},{"probe":"uname","re":"^FreeBSD "}],"facts":{"pkg":"pkg","init":"rc","firewall":"pf","logs":"/var/log","sshd":"/etc/ssh/sshd_config"}},{"id":"proxmox-ve","kind":"hypervisor","name":{"de":"Proxmox VE","en":"Proxmox VE","es":"Proxmox VE"},"identify":[{"probe":"os_release","re":"^ID=\"?debian\"?$"},{"probe":"proxmox","re":"^pve-manager/"}],"facts":{"pkg":"apt","init":"systemd","firewall":"pve-firewall (nftables)","logs":"journalctl","sshd":"/etc/ssh/sshd_config"}},{"id":"almalinux","kind":"server","name":{"de":"AlmaLinux","en":"AlmaLinux","es":"AlmaLinux"},"identify":[{"probe":"os_release","re":"^ID=\"almalinux\"$"},{"probe":"redhat_release","re":"^AlmaLinux release .*"}],"facts":{"pkg":"dnf","init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"android","kind":"other","name":{"de":"Android","en":"Android","es":"Android"},"identify":[{"probe":"os_release","re":"^ID=\"?android\"?$"},{"probe":"version_file","re":"^Android version.*$"}],"facts":{}},{"id":"android-tv","kind":"other","name":{"de":"Android TV","en":"Android TV","es":"Android TV"},"identify":[{"probe":"os_release","re":"^ID=\"?android\"?$"},{"probe":"uname","re":"^Linux .* (aarch64|armv7l|armv8l).*$"}],"facts":{}},{"id":"antix","kind":"desktop","name":{"de":"antiX","en":"antiX","es":"antiX"},"identify":[{"probe":"os_release","re":"^ID=\"?antix\"?$"},{"probe":"os_release","re":"^NAME=\"?antiX\"?"}],"facts":{"pkg":"apt","init":"sysvinit","firewall":"iptables"}},{"id":"centos-stream","kind":"server","name":{"de":"CentOS Stream","en":"CentOS Stream","es":"CentOS Stream"},"identify":[{"probe":"os_release","re":"^ID=\"?centos\"?$"},{"probe":"os_release","re":"^NAME=\"?CentOS Stream\"?$"}],"facts":{"pkg":"dnf","init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"coreos","kind":"container","name":{"de":"CoreOS Container Linux","en":"CoreOS Container Linux","es":"CoreOS Container Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?coreos\"?$"},{"probe":"version_file","re":"^VERSION=\"?.*\"?$"}],"facts":{"init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"dd-wrt","kind":"router","name":{"de":"DD-WRT","en":"DD-WRT","es":"DD-WRT"},"identify":[{"probe":"os_release","re":"^ID=\"dd-wrt\"$"},{"probe":"device_model","re":"^.*$"}],"facts":{"pkg":"opkg","firewall":"iptables"}},{"id":"dragonflybsd","kind":"server","name":{"de":"DragonFly BSD","en":"DragonFly BSD","es":"DragonFly BSD"},"identify":[{"probe":"os_release","re":"^ID=\"dragonfly\"$"},{"probe":"freebsd_version","re":"^.*$"}],"facts":{"pkg":"pkg","init":"rc"}},{"id":"elementary-os","kind":"desktop","name":{"de":"elementary OS","en":"elementary OS","es":"elementary OS"},"identify":[{"probe":"os_release","re":"^ID=\"?elementary\"?$"},{"probe":"os_release","re":"^NAME=\"?elementary OS\"?$"}],"facts":{"pkg":"apt","init":"systemd","logs":"/var/log/syslog"}},{"id":"hp-ux","kind":"server","name":{"de":"HP-UX","en":"HP-UX","es":"HP-UX"},"identify":[{"probe":"uname","re":"^HP-UX .*"},{"probe":"issue","re":"^HP-UX"}],"facts":{"logs":"/var/adm/syslog/syslog.log"}},{"id":"juniper-junos","kind":"router","name":{"de":"Juniper Junos","en":"Juniper Junos","es":"Juniper Junos"},"identify":[{"probe":"uname","re":"^JUNOS"},{"probe":"uname","re":"JNPR"}],"facts":{"sshd":"/etc/ssh/sshd_config"}},{"id":"linux-lite","kind":"desktop","name":{"de":"Linux Lite","en":"Linux Lite","es":"Linux Lite"},"identify":[{"probe":"os_release","re":"^ID=\"?linuxlite\"?$"},{"probe":"os_release","re":"^NAME=\"?Linux Lite\"?$"}],"facts":{"pkg":"apt","init":"systemd"}},{"id":"linux-mint","kind":"desktop","name":{"de":"Linux Mint","en":"Linux Mint","es":"Linux Mint"},"identify":[{"probe":"os_release","re":"^ID=\"?linuxmint\"?$"},{"probe":"os_release","re":"^NAME=\"?Linux Mint\"?$"}],"facts":{"pkg":"apt","init":"systemd","firewall":"ufw","logs":"/var/log/syslog","sshd":"/etc/ssh/sshd_config"}},{"id":"macos","kind":"desktop","name":{"de":"macOS","en":"macOS","es":"macOS"},"identify":[{"probe":"sw_vers","re":"^ProductName:[[:space:]]*macOS"},{"probe":"uname","re":"^Darwin"}],"facts":{"init":"launchd","sshd":"/etc/ssh/sshd_config"}},{"id":"mx-linux","kind":"desktop","name":{"de":"MX Linux","en":"MX Linux","es":"MX Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?mx\"?$"},{"probe":"os_release","re":"^NAME=\"?MX Linux\"?$"}],"facts":{"pkg":"apt","init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"openbsd","kind":"server","name":{"de":"OpenBSD","en":"OpenBSD","es":"OpenBSD"},"identify":[{"probe":"uname","re":"^OpenBSD .*"},{"probe":"hw_model","re":"^[A-Za-z0-9].*"}],"facts":{"firewall":"pf","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"opensuse-leap","kind":"server","name":{"de":"openSUSE Leap","en":"openSUSE Leap","es":"openSUSE Leap"},"identify":[{"probe":"os_release","re":"^ID=\"opensuse-leap\"$"},{"probe":"os_release","re":"^VERSION_ID=\".*\"$"}],"facts":{"pkg":"zypper","init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"opensuse-tumbleweed","kind":"desktop","name":{"de":"openSUSE Tumbleweed","en":"openSUSE Tumbleweed","es":"openSUSE Tumbleweed"},"identify":[{"probe":"os_release","re":"^ID=\"?opensuse-tumbleweed\"?$"},{"probe":"os_release","re":"^NAME=\"?openSUSE Tumbleweed\"?$"}],"facts":{"pkg":"zypper","init":"systemd","firewall":"firewalld","sshd":"/etc/ssh/sshd_config"}},{"id":"pclinuxos","kind":"desktop","name":{"de":"PCLinuxOS","en":"PCLinuxOS","es":"PCLinuxOS"},"identify":[{"probe":"os_release","re":"^ID=\"?pclinuxos\"?$"},{"probe":"os_release","re":"^NAME=\"?PCLinuxOS\"?$"}],"facts":{"init":"systemd","firewall":"iptables","sshd":"/etc/ssh/sshd_config"}},{"id":"peppermint-os","kind":"desktop","name":{"de":"Peppermint OS","en":"Peppermint OS","es":"Peppermint OS"},"identify":[{"probe":"os_release","re":"^ID=\"?peppermint\"?$"},{"probe":"os_release","re":"^NAME=\"?Peppermint OS\"?$"}],"facts":{"pkg":"apt","init":"systemd","firewall":"ufw","sshd":"/etc/ssh/sshd_config"}},{"id":"puppy-linux","kind":"desktop","name":{"de":"Puppy Linux","en":"Puppy Linux","es":"Puppy Linux"},"identify":[{"probe":"os_release","re":"^(ID=\"?puppy\"?|NAME=\"?Puppy Linux\"?)$"},{"probe":"version_file","re":"puppy"}],"facts":{}},{"id":"q4os","kind":"desktop","name":{"de":"Q4OS","en":"Q4OS","es":"Q4OS"},"identify":[{"probe":"os_release","re":"^ID=\"?q4os\"?$"},{"probe":"os_release","re":"^NAME=\"?Q4OS\"?$"}],"facts":{"pkg":"apt","init":"systemd","firewall":"ufw","sshd":"/etc/ssh/sshd_config"}},{"id":"raspberry-pi-os","kind":"embedded","name":{"de":"Raspberry Pi OS","en":"Raspberry Pi OS","es":"Raspberry Pi OS"},"identify":[{"probe":"os_release","re":"^ID=\"?raspbian\"?$"},{"probe":"device_model","re":"^Raspberry Pi"}],"facts":{"pkg":"apt","init":"systemd","logs":"/var/log/syslog"}},{"id":"rhel","kind":"server","name":{"de":"Red Hat Enterprise Linux","en":"Red Hat Enterprise Linux","es":"Red Hat Enterprise Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?rhel\"?$"},{"probe":"redhat_release","re":"^Red Hat Enterprise Linux"}],"facts":{"pkg":"dnf","init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"rockstor","kind":"nas","name":{"de":"Rockstor","en":"Rockstor","es":"Rockstor"},"identify":[{"probe":"os_release","re":"^ID=\"?rockstor\"?$"},{"probe":"os_release","re":"^NAME=\"?Rockstor\"?$"}],"facts":{"init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"slackware","kind":"desktop","name":{"de":"Slackware Linux","en":"Slackware Linux","es":"Slackware Linux"},"identify":[{"probe":"os_release","re":"^NAME=\"?Slackware\"?$"},{"probe":"version_file","re":"^Slackware [0-9]+\\.[0-9]+"}],"facts":{"firewall":"iptables","sshd":"/etc/ssh/sshd_config"}},{"id":"solaris","kind":"server","name":{"de":"Oracle Solaris","en":"Oracle Solaris","es":"Oracle Solaris"},"identify":[{"probe":"uname","re":"^SunOS [^ ]+ 5\\.[0-9]+ .*"},{"probe":"issue","re":"^(Oracle )?Solaris"}],"facts":{"sshd":"/etc/ssh/sshd_config"}},{"id":"sonic","kind":"router","name":{"de":"SONiC","en":"SONiC","es":"SONiC"},"identify":[{"probe":"os_release","re":"^ID=\"?sonic\"?$"},{"probe":"version_file","re":"sonic"}],"facts":{"pkg":"apt","init":"systemd","firewall":"iptables"}},{"id":"tizen","kind":"other","name":{"de":"Tizen","en":"Tizen","es":"Tizen"},"identify":[{"probe":"os_release","re":"^ID=\"?tizen\"?$"},{"probe":"version_file","re":"tizen"}],"facts":{"init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"tomato","kind":"router","name":{"de":"Tomato","en":"Tomato","es":"Tomato"},"identify":[{"probe":"os_release","re":"^ID=\"?tomato\"?$"},{"probe":"issue","re":"tomato"}],"facts":{"firewall":"iptables","logs":"/var/log/messages"}},{"id":"truenas-core","kind":"nas","name":{"de":"TrueNAS CORE","en":"TrueNAS CORE","es":"TrueNAS CORE"},"identify":[{"probe":"version_file","re":"^TrueNAS-.*"},{"probe":"uname","re":"FreeBSD"}],"facts":{"pkg":"pkg","firewall":"pf","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"truenas-scale","kind":"nas","name":{"de":"TrueNAS SCALE","en":"TrueNAS SCALE","es":"TrueNAS SCALE"},"identify":[{"probe":"os_release","re":"^ID=\"truenas\"$"},{"probe":"version_file","re":"^VERSION=\"1\\.2\\.0\"$"}],"facts":{}},{"id":"webos","kind":"other","name":{"de":"webOS","en":"webOS","es":"webOS"},"identify":[{"probe":"os_release","re":"^ID=\"?webos\"?$"},{"probe":"os_release","re":"^NAME=\"?webOS\"?$"}],"facts":{"sshd":"/etc/ssh/sshd_config"}},{"id":"xcp-ng","kind":"hypervisor","name":{"de":"XCP-ng","en":"XCP-ng","es":"XCP-ng"},"identify":[{"probe":"os_release","re":"^ID=\"xcp-ng\"$"},{"probe":"version_file","re":"^XCP-ng version .*$"}],"facts":{"init":"systemd","firewall":"iptables","sshd":"/etc/ssh/sshd_config"}},{"id":"zorin-os","kind":"desktop","name":{"de":"Zorin OS","en":"Zorin OS","es":"Zorin OS"},"identify":[{"probe":"os_release","re":"^ID=\"?zorin\"?$"},{"probe":"os_release","re":"^NAME=\"?Zorin OS\"?$"}],"facts":{"pkg":"apt","init":"systemd","logs":"/var/log/syslog","sshd":"/etc/ssh/sshd_config"}},{"id":"amazon-linux","kind":"server","name":{"de":"Amazon Linux","en":"Amazon Linux","es":"Amazon Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?amzn\"?$"}],"facts":{"pkg":"dnf, yum","init":"systemd","firewall":"nftables, iptables","logs":"journalctl","sshd":"/etc/ssh/sshd_config"}},{"id":"esxi","kind":"hypervisor","name":{"de":"VMware ESXi","en":"VMware ESXi","es":"VMware ESXi"},"identify":[{"probe":"esxi","re":"^VMware ESXi"}],"facts":{"pkg":"esxcli software","init":"init scripts","firewall":"esxcli network firewall","logs":"/var/log","sshd":"/etc/ssh/sshd_config"}},{"id":"openwrt","kind":"router","name":{"de":"OpenWrt","en":"OpenWrt","es":"OpenWrt"},"identify":[{"probe":"openwrt_release","re":"^DISTRIB_ID='?OpenWrt"}],"facts":{"pkg":"opkg, apk","init":"procd","firewall":"fw4 (nftables)","logs":"logread","sshd":"/etc/config/dropbear"}},{"id":"oracle-linux","kind":"server","name":{"de":"Oracle Linux","en":"Oracle Linux","es":"Oracle Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?ol\"?$"}],"facts":{"pkg":"dnf, yum","init":"systemd","firewall":"firewalld","logs":"journalctl","sshd":"/etc/ssh/sshd_config"}},{"id":"rocky-linux","kind":"server","name":{"de":"Rocky Linux","en":"Rocky Linux","es":"Rocky Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?rocky\"?$"}],"facts":{"pkg":"dnf","init":"systemd","firewall":"firewalld","logs":"journalctl","sshd":"/etc/ssh/sshd_config"}},{"id":"synology-dsm","kind":"nas","name":{"de":"Synology DSM","en":"Synology DSM","es":"Synology DSM"},"identify":[{"probe":"synology","re":"^productversion=\"?[0-9]"}],"facts":{"pkg":"Paketzentrum (synopkg)","init":"systemd","firewall":"DSM-Firewall (iptables)","logs":"/var/log","sshd":"/etc/ssh/sshd_config"}},{"id":"alpine","kind":"server","name":{"de":"Alpine Linux","en":"Alpine Linux","es":"Alpine Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?alpine\"?$"}],"facts":{"pkg":"apk","init":"OpenRC"}},{"id":"arch-linux","kind":"server","name":{"de":"Arch Linux","en":"Arch Linux","es":"Arch Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?arch\"?$"}],"facts":{"pkg":"pacman","init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"arista-eos","kind":"router","name":{"de":"Arista EOS","en":"Arista EOS","es":"Arista EOS"},"identify":[{"probe":"os_release","re":"^ID=\"?eos\"?$"}],"facts":{"init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"artix-linux","kind":"desktop","name":{"de":"Artix Linux","en":"Artix Linux","es":"Artix Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?artix\"?$"}],"facts":{"pkg":"pacman","init":"openrc"}},{"id":"balenaos","kind":"embedded","name":{"de":"balenaOS","en":"balenaOS","es":"balenaOS"},"identify":[{"probe":"os_release","re":"^ID=\"?balena\"?$"}],"facts":{"init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"bottlerocket","kind":"container","name":{"de":"Bottlerocket","en":"Bottlerocket","es":"Bottlerocket"},"identify":[{"probe":"os_release","re":"^ID=\"?bottlerocket\"?$"}],"facts":{"init":"systemd"}},{"id":"centos","kind":"server","name":{"de":"CentOS","en":"CentOS","es":"CentOS"},"identify":[{"probe":"os_release","re":"^ID=\"?centos\"?$"}],"facts":{"init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"chromeos","kind":"desktop","name":{"de":"ChromeOS","en":"ChromeOS","es":"ChromeOS"},"identify":[{"probe":"os_release","re":"^ID=\"?chromeos\"?$"}],"facts":{}},{"id":"cisco-ios","kind":"router","name":{"de":"Cisco IOS","en":"Cisco IOS","es":"Cisco IOS"},"identify":[{"probe":"os_release","re":"^ID=\"?cisco-ios\"?$"}],"facts":{}},{"id":"clearos","kind":"server","name":{"de":"ClearOS","en":"ClearOS","es":"ClearOS"},"identify":[{"probe":"os_release","re":"^ID=\"?clearos\"?$"}],"facts":{"pkg":"yum","init":"systemd","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"debian","kind":"server","name":{"de":"Debian GNU/Linux","en":"Debian GNU/Linux","es":"Debian GNU/Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?debian\"?$"}],"facts":{"pkg":"apt","init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"deepin","kind":"desktop","name":{"de":"deepin","en":"deepin","es":"deepin"},"identify":[{"probe":"os_release","re":"^ID=\"?deepin\"?$"}],"facts":{"pkg":"apt","init":"systemd","logs":"/var/log/syslog"}},{"id":"dietpi","kind":"embedded","name":{"de":"DietPi","en":"DietPi","es":"DietPi"},"identify":[{"probe":"os_release","re":"^ID=\"?dietpi\"?$"}],"facts":{"pkg":"apt","init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"fedora","kind":"desktop","name":{"de":"Fedora","en":"Fedora","es":"Fedora"},"identify":[{"probe":"os_release","re":"^ID=\"?fedora\"?$"}],"facts":{"pkg":"dnf","init":"systemd","firewall":"firewalld","sshd":"/etc/ssh/sshd_config"}},{"id":"flatcar","kind":"container","name":{"de":"Flatcar Container Linux","en":"Flatcar Container Linux","es":"Flatcar Container Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?flatcar\"?$"}],"facts":{"init":"systemd"}},{"id":"freenas","kind":"nas","name":{"de":"FreeNAS","en":"FreeNAS","es":"FreeNAS"},"identify":[{"probe":"os_release","re":"^ID=\"freebsd\"$"}],"facts":{}},{"id":"garuda-linux","kind":"desktop","name":{"de":"Garuda Linux","en":"Garuda Linux","es":"Garuda Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?garuda\"?$"}],"facts":{"init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"google-container-optimized-os","kind":"server","name":{"de":"Google Container-Optimized OS","en":"Google Container-Optimized OS","es":"Google Container-Optimized OS"},"identify":[{"probe":"os_release","re":"^ID=\"?cos\"?$"}],"facts":{"init":"systemd"}},{"id":"illumos","kind":"server","name":{"de":"illumos","en":"illumos","es":"illumos"},"identify":[{"probe":"uname","re":"^SunOS .* (illumos|oi|omnios|openindiana).*"}],"facts":{"init":"smf","sshd":"/etc/ssh/sshd_config"}},{"id":"kali-linux","kind":"server","name":{"de":"Kali Linux","en":"Kali Linux","es":"Kali Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?kali\"?$"}],"facts":{"pkg":"apt","init":"systemd","sshd":"/etc/ssh/sshd_config"}},{"id":"manjaro","kind":"desktop","name":{"de":"Manjaro Linux","en":"Manjaro Linux","es":"Manjaro Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?manjaro\"?$"}],"facts":{"pkg":"pacman","init":"systemd"}},{"id":"mikrotik-routeros","kind":"router","name":{"de":"MikroTik RouterOS","en":"MikroTik RouterOS","es":"MikroTik RouterOS"},"identify":[{"probe":"os_release","re":"^ID=\"routeros\"$"}],"facts":{}},{"id":"minix","kind":"other","name":{"de":"MINIX 3","en":"MINIX 3","es":"MINIX 3"},"identify":[{"probe":"uname","re":"^.*MINIX.*$"}],"facts":{}},{"id":"netbsd","kind":"server","name":{"de":"NetBSD","en":"NetBSD","es":"NetBSD"},"identify":[{"probe":"uname","re":"^NetBSD "}],"facts":{"init":"rc.d","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"openfiler","kind":"nas","name":{"de":"Openfiler","en":"Openfiler","es":"Openfiler"},"identify":[{"probe":"os_release","re":"^ID=\"openfiler\"$"}],"facts":{"firewall":"iptables","sshd":"/etc/ssh/sshd_config"}},{"id":"pop-os","kind":"desktop","name":{"de":"Pop!_OS","en":"Pop!_OS","es":"Pop!_OS"},"identify":[{"probe":"os_release","re":"^ID=\"?pop\"?$"}],"facts":{"pkg":"apt","init":"systemd","logs":"/var/log/syslog","sshd":"/etc/ssh/sshd_config"}},{"id":"qnap-qts","kind":"nas","name":{"de":"QNAP QTS","en":"QNAP QTS","es":"QNAP QTS"},"identify":[{"probe":"platform_file","re":"^TS-\\S+|^NAS\\b|QNAP"}],"facts":{"sshd":"/etc/ssh/sshd_config"}},{"id":"rancher-os","kind":"container","name":{"de":"RancherOS","en":"RancherOS","es":"RancherOS"},"identify":[{"probe":"os_release","re":"^ID=\"?rancheros\"?$"}],"facts":{"sshd":"/etc/ssh/sshd_config"}},{"id":"solus","kind":"desktop","name":{"de":"Solus","en":"Solus","es":"Solus"},"identify":[{"probe":"os_release","re":"^ID=\"?solus\"?$"}],"facts":{"pkg":"eopkg","init":"systemd"}},{"id":"suse-linux-enterprise-server","kind":"server","name":{"de":"SUSE Linux Enterprise Server","en":"SUSE Linux Enterprise Server","es":"SUSE Linux Enterprise Server"},"identify":[{"probe":"os_release","re":"^ID=\"?sles\"?$"}],"facts":{"pkg":"zypper","init":"systemd","firewall":"firewalld","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"tails","kind":"desktop","name":{"de":"Tails","en":"Tails","es":"Tails"},"identify":[{"probe":"os_release","re":"^ID=\"?tails\"?$"}],"facts":{"pkg":"apt","init":"systemd","firewall":"ufw","sshd":"/etc/ssh/sshd_config"}},{"id":"talos-linux","kind":"container","name":{"de":"Talos Linux","en":"Talos Linux","es":"Talos Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?talos\"?$"}],"facts":{}},{"id":"truenas","kind":"nas","name":{"de":"TrueNAS","en":"TrueNAS","es":"TrueNAS"},"identify":[{"probe":"os_release","re":"^ID=\"?truenas\"?$"}],"facts":{"sshd":"/etc/ssh/sshd_config"}},{"id":"ubuntu","kind":"server","name":{"de":"Ubuntu","en":"Ubuntu","es":"Ubuntu"},"identify":[{"probe":"os_release","re":"^ID=\"?ubuntu\"?$"}],"facts":{"pkg":"apt","init":"systemd","firewall":"ufw","logs":"/var/log/syslog","sshd":"/etc/ssh/sshd_config"}},{"id":"ubuntu-core","kind":"embedded","name":{"de":"Ubuntu Core","en":"Ubuntu Core","es":"Ubuntu Core"},"identify":[{"probe":"os_release","re":"^ID=\"?ubuntu-core\"?$"}],"facts":{"pkg":"snap","init":"systemd","firewall":"ufw","sshd":"/etc/ssh/sshd_config"}},{"id":"void-linux","kind":"desktop","name":{"de":"Void Linux","en":"Void Linux","es":"Void Linux"},"identify":[{"probe":"os_release","re":"^ID=\"?void\"?$"}],"facts":{"pkg":"xbps","init":"runit","sshd":"/etc/ssh/sshd_config"}},{"id":"vyos","kind":"router","name":{"de":"VyOS","en":"VyOS","es":"VyOS"},"identify":[{"probe":"os_release","re":"^ID=\"?vyos\"?$"}],"facts":{"pkg":"apt","init":"systemd","logs":"/var/log/messages","sshd":"/etc/ssh/sshd_config"}},{"id":"windows-server","kind":"server","name":{"de":"Windows Server","en":"Windows Server","es":"Windows Server"},"identify":[{"probe":"windows_ver","re":"^Microsoft Windows \\[Version [0-9.]+\\]$"}],"facts":{}},{"id":"yocto","kind":"embedded","name":{"de":"Yocto","en":"Yocto","es":"Yocto"},"identify":[{"probe":"os_release","re":"^ID=\"?yocto\"?$"}],"facts":{"init":"systemd","sshd":"/etc/ssh/sshd_config"}}]}
package/src/bib/wash.mjs CHANGED
@@ -1,16 +1,8 @@
1
- // Washer for the language library: replaces personal values in a user sentence with global
2
- // placeholders and leaves the rest 1:1. wash(text) -> { text, hits } (hits = count per placeholder).
3
- //
4
- // Order matters so nothing is half-matched: URL > key paths > mail > user@host > tokens > IP >
5
- // domain > path > card/IBAN > phone > long numbers > hex/base64 keys > secret labels > names.
6
- //
7
- // Limits (on purpose "better too little than too much"):
8
- // - {NAME} only fires for (a) a known first name + capitalized surname, (b) a title cue
9
- // (Herr/Frau/Dr./Mr./Sr./...) + capitalized name, (c) an intro cue ("mein Name ist", "me llamo",
10
- // "my name is") + name, (d) Spanish messaging cue ("escribirle a danny jose ...", lowercase ok). Lone first names, lowercase names and unknown pairs stay untouched.
11
- // - Windows paths with spaces are cut at the first space. Relative paths (src/x.mjs) stay.
12
- // - Domains are only recognised with a known TLD (so index.php / app.js survive).
13
- // - {NUM} also eats plain big numbers (1000000); versions (8.3.6) and CVE-2026-109618 stay.
1
+ // Replaces personal values in a sentence (paths, hosts, mails, tokens, numbers, names) with placeholders
2
+ // before it is used as training data. wash(text) returns { text, hits }.
3
+ // The order of the rules matters, longer patterns first. It prefers leaving something in over
4
+ // removing too much: names are only replaced with a clear cue (known first name + surname, title,
5
+ // "my name is"), domains need a known TLD, versions and CVE ids stay.
14
6
 
15
7
  const L = "\\p{L}\\p{N}_";
16
8
  const TLD = "com|net|org|io|de|es|fr|uk|us|ai|app|dev|co|info|biz|eu|online|space|xyz|site|cloud|me|tv|ch|at|nl|it|ru|cn|jp|do|edu|gov|store|shop|pro|tech";
@@ -1,19 +1,23 @@
1
- // The watchman's battery: the full patrol, built from RULES. The free state is the built-in rule
2
- // list; every installed pack adds rules or replaces ones with the same id (newest pack wins). One
3
- // ordered list so the session, the patrol and the tests all run the SAME set. Each check is
4
- // read-only and carries its own real lines. `rechte` (world-writable files) has no rule type yet and
5
- // stays plain code.
1
+ // Assembles the checks from rules. Built-in rules are the free tier; each installed pack adds rules or
2
+ // replaces one with the same id (newest wins). Deep rules (secret formats, models, agent config) are
3
+ // kept out of the light battery and run in the deep run or on request. `rechte` has no rule type
4
+ // yet and stays plain code.
6
5
  import { versionCheck } from "./php2shell.mjs";
7
6
  import { exposedCheck } from "./secrets.mjs";
8
7
  import { patternCheck } from "./webshell.mjs";
9
8
  import { sshdCheck } from "./sshd.mjs";
9
+ import { formatsCheck } from "./formats.mjs";
10
+ import { modelCardCheck, modelFilesCheck, agentConfigCheck } from "./hf.mjs";
10
11
  import { rechte } from "./rechte.mjs";
11
12
  import { BUILTIN } from "../pack/builtin.mjs";
12
13
  import { loadPacks } from "../pack/pack.mjs";
13
14
 
14
- const FACTORY = { version_cve: versionCheck, path_exposed: exposedCheck, file_pattern: patternCheck, sshd_setting: sshdCheck };
15
+ const FACTORY = { version_cve: versionCheck, path_exposed: exposedCheck, file_pattern: patternCheck, sshd_setting: sshdCheck, secret_format: formatsCheck, model_card: modelCardCheck, model_files: modelFilesCheck, agent_config: agentConfigCheck };
15
16
 
16
- export const buildBattery = (rules) => [...rules.map((r) => FACTORY[r.type](r)), rechte];
17
+ // Deep rules (the Prüf-Bib's secret formats) are not part of the light battery that the patrol and the session run;
18
+ // they run in the deep run only (buildDeep).
19
+ export const buildBattery = (rules) => [...rules.filter((r) => !r.deep).map((r) => FACTORY[r.type](r)), rechte];
20
+ export const buildDeep = (rules) => rules.filter((r) => r.deep).map((r) => FACTORY[r.type](r));
17
21
 
18
22
  // a rule of a later list replaces the rule with the same id, new ids are added
19
23
  export function mergeRules(base, ...more) {
@@ -30,15 +34,16 @@ export const BATTERY = buildBattery(BUILTIN.rules);
30
34
  // checks. notices lists the pack files he refused (code per file), for the person to be told once.
31
35
  export function activeBattery(opts) {
32
36
  const { packs, notices } = loadPacks(opts);
33
- return { battery: buildBattery(rulesWith(packs)), packs, notices };
37
+ const rules = rulesWith(packs);
38
+ return { battery: buildBattery(rules), deep: buildDeep(rules), packs, notices };
34
39
  }
35
40
 
36
- // muster intent → check id. The ear recognises the worry; this says which hand to use.
41
+ // muster intent -> check id. The ear recognises the worry; this says which hand to use.
37
42
  export const MUSTER = { pruef_php2shell: "php2shell", secrets: "secrets", webshell: "webshell", sshd: "sshd", rechte: "rechte" };
38
43
 
39
44
  export const checkById = (id, list = BATTERY) => list.find((c) => c.id === id) || null;
40
45
 
41
- // Run one check safely — a thrown check becomes an honest UNKNOWN, never a crash or a false verdict.
46
+ // Run one check safely - a thrown check becomes an honest UNKNOWN, never a crash or a false verdict.
42
47
  export function runCheck(check) {
43
48
  try { return check.run(); }
44
49
  catch (e) { return { id: check.id, title: check.title, verdict: "unknown", was: "Check brach ab.", wie: String(e.message || e), wo: "", evidence: [] }; }
@@ -1,8 +1,8 @@
1
- // Shared bits for the watchman battery. Read-only helpers only — a real line, or nothing.
1
+ // Helpers shared by the checks: quoting, web root lookup, line trimming. Read-only.
2
2
  import { run, firstLine } from "../core/sh.mjs";
3
3
 
4
4
  // Single-quote an argument for the remote shell. Double quotes would let the shell expand a `$` in
5
- // a regex (e.g. $_GET → the _ variable), which silently mangled the webshell pattern. Single quotes
5
+ // a regex (e.g. $_GET -> the _ variable), which silently mangled the webshell pattern. Single quotes
6
6
  // make every character literal; an embedded ' is closed, escaped and reopened.
7
7
  export const sq = (s) => "'" + String(s).replace(/'/g, "'\\''") + "'";
8
8
 
@@ -13,17 +13,17 @@ export const WEBROOTS = ["/var/www/html", "/var/www", "/usr/share/nginx/html", "
13
13
  // Which of the standard web roots actually exist on the target (its own output decides).
14
14
  // Exit code is unreliable here: the for-loop's last `[ -d ] && echo` fails for the last missing
15
15
  // path, so the loop exits non-zero even when it printed real roots. We trust the OUTPUT (the lines
16
- // the machine actually printed), not the exit code — ran is enough.
16
+ // the machine actually printed), not the exit code - ran is enough.
17
17
  export function webRoots() {
18
18
  const r = run("for d in " + WEBROOTS.join(" ") + "; do [ -d \"$d\" ] && echo \"$d\"; done");
19
19
  let roots = r.ran ? r.out.split("\n").map((s) => s.trim()).filter(Boolean) : [];
20
- // Drop a root that sits inside another found root (/var/www/html under /var/www) — otherwise a
20
+ // Drop a root that sits inside another found root (/var/www/html under /var/www) - otherwise a
21
21
  // deep search finds the same file through both and reports it twice.
22
22
  roots = roots.filter((d) => !roots.some((o) => o !== d && (d === o || d.startsWith(o + "/"))));
23
23
  return { ran: r.ran, roots, line: firstLine(r.err || r.out) };
24
24
  }
25
25
 
26
- // First N non-empty lines of some output, trimmed — for a compact, honest evidence list.
26
+ // First N non-empty lines of some output, trimmed - for a compact, honest evidence list.
27
27
  export function lines(s, n = 10) {
28
28
  return String(s || "").split("\n").map((x) => x.trim()).filter(Boolean).slice(0, n);
29
29
  }
@@ -1,5 +1,5 @@
1
- // Demo check (only with --demo): a harmless "open door" = a temp file. Lets you watch the whole
2
- // loop — human-listen → plan → ja/nein → fix → re-prove — without touching anything real.
1
+ // Harmless demo check for --demo: a temp file stands in for an open door, so the whole
2
+ // ask -> plan -> confirm -> fix -> verify loop can be tried without touching anything real.
3
3
  import { run, firstLine } from "../core/sh.mjs";
4
4
  import { result, evidence, SAFE, RISK } from "../core/check.mjs";
5
5