@nosserb/prmt 0.0.0-stage → 2.0.0
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.
- package/LICENSE +21 -0
- package/README.md +191 -2
- package/bin/prmt.mjs +174 -0
- package/dist/assets/AuditModule-BOO_iRy8.js +1 -0
- package/dist/assets/Audits-yUBm0EpW.js +1 -0
- package/dist/assets/BrainPage-FIWO_9Nc.js +3 -0
- package/dist/assets/BrainPage-XQCEGRc5.css +1 -0
- package/dist/assets/Carte-CPuiR1Ha.css +1 -0
- package/dist/assets/Carte-xycu1mQn.js +1 -0
- package/dist/assets/Dashboard-DKvCQcX8.js +2 -0
- package/dist/assets/Dashboard-XdhC6_hM.css +1 -0
- package/dist/assets/Field-C7c2mCbb.js +2 -0
- package/dist/assets/Journal-BLIIlh80.css +1 -0
- package/dist/assets/Journal-BaelFjwV.js +1 -0
- package/dist/assets/Landing-B2jxV3zs.css +1 -0
- package/dist/assets/Landing-Dr612Zdu.js +26 -0
- package/dist/assets/Register-DA_Aq5f8.js +1 -0
- package/dist/assets/Reports-8wfDNSxH.js +1 -0
- package/dist/assets/Reports-B8GXN95N.css +1 -0
- package/dist/assets/SavoirPage-BTxbH3LY.css +1 -0
- package/dist/assets/SavoirPage-Dp3eUCHp.js +1 -0
- package/dist/assets/SettingsPage-BElIP46c.css +1 -0
- package/dist/assets/SettingsPage-BiQbnw3o.js +1 -0
- package/dist/assets/Shell-BAyHVljp.css +1 -0
- package/dist/assets/Shell-CQRlx9-V.js +2 -0
- package/dist/assets/Table-DUmGel5e.js +1 -0
- package/dist/assets/Tabs-CfhbELZk.js +1 -0
- package/dist/assets/Terminal-Bv1IJfi9.js +3 -0
- package/dist/assets/Terminal-CEfj38NV.css +1 -0
- package/dist/assets/arrow-right-Cx3pAEhl.js +1 -0
- package/dist/assets/auditViews-BMza2Sdz.js +1 -0
- package/dist/assets/auditViews-BePWj26h.css +1 -0
- package/dist/assets/bricolage-grotesque-latin-ext-opsz-normal-IcJDqblK.woff2 +0 -0
- package/dist/assets/bricolage-grotesque-latin-opsz-normal-Cre6nC2_.woff2 +0 -0
- package/dist/assets/bricolage-grotesque-vietnamese-opsz-normal-D9N6E8K1.woff2 +0 -0
- package/dist/assets/charts-BcijSJ4J.js +1 -0
- package/dist/assets/circle-stop-C33BAcKW.js +1 -0
- package/dist/assets/command-ChA49Xk7.js +1 -0
- package/dist/assets/command-Ck4pdQCv.css +1 -0
- package/dist/assets/download-CeuKOenD.js +1 -0
- package/dist/assets/eye-CXXHBBpr.js +1 -0
- package/dist/assets/geist-cyrillic-ext-wght-normal-DjL33-gN.woff2 +0 -0
- package/dist/assets/geist-cyrillic-wght-normal-BEAKL7Jp.woff2 +0 -0
- package/dist/assets/geist-latin-ext-wght-normal-DC-KSUi6.woff2 +0 -0
- package/dist/assets/geist-latin-wght-normal-BgDaEnEv.woff2 +0 -0
- package/dist/assets/geist-vietnamese-wght-normal-6IgcOCM7.woff2 +0 -0
- package/dist/assets/habillage-B5mMBadn.js +1 -0
- package/dist/assets/index-BH1etemR.css +1 -0
- package/dist/assets/index-COSiM-R9.js +14 -0
- package/dist/assets/jetbrains-mono-cyrillic-ext-wght-normal-EocZY2iu.woff2 +0 -0
- package/dist/assets/jetbrains-mono-cyrillic-wght-normal-D73BlboJ.woff2 +0 -0
- package/dist/assets/jetbrains-mono-greek-wght-normal-Bw9x6K1M.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/dist/assets/jetbrains-mono-vietnamese-wght-normal-Bt-aOZkq.woff2 +0 -0
- package/dist/assets/layers-2x-Bpkbi35X.png +0 -0
- package/dist/assets/layers-BWBAp2CZ.png +0 -0
- package/dist/assets/markdown-DF87LQh1.css +1 -0
- package/dist/assets/markdown-o5sMhPHN.js +4 -0
- package/dist/assets/marker-icon-hN30_KVU.png +0 -0
- package/dist/assets/play-Daw4K_73.js +1 -0
- package/dist/assets/plus-D_QHm8ud.js +1 -0
- package/dist/assets/trash-DLpHM-s8.js +1 -0
- package/dist/assets/web-6j1-aY67.js +1 -0
- package/dist/favicon.svg +1 -0
- package/dist/index.html +18 -0
- package/docs/ANALYSE.md +87 -0
- package/docs/SECURITE.md +188 -0
- package/lib/scripts/lier.js +15 -0
- package/lib/scripts/searxng.js +91 -0
- package/lib/server/app.js +444 -0
- package/lib/server/audits/modules/local.js +429 -0
- package/lib/server/audits/modules/network.js +331 -0
- package/lib/server/audits/modules/web.js +302 -0
- package/lib/server/audits/net.js +141 -0
- package/lib/server/audits/registry.js +202 -0
- package/lib/server/audits/types.js +58 -0
- package/lib/server/brain/brain.js +624 -0
- package/lib/server/brain/conversations.js +82 -0
- package/lib/server/brain/ollama.js +197 -0
- package/lib/server/brain/prompt.js +188 -0
- package/lib/server/brain/provider.js +1 -0
- package/lib/server/cli/bridge.js +292 -0
- package/lib/server/cli/pont.js +62 -0
- package/lib/server/config.js +68 -0
- package/lib/server/engine/analyzer.js +205 -0
- package/lib/server/engine/catalog.js +229 -0
- package/lib/server/engine/decoder.js +91 -0
- package/lib/server/engine/engine.js +194 -0
- package/lib/server/engine/paths.js +129 -0
- package/lib/server/engine/policy.js +397 -0
- package/lib/server/engine/relax.js +10 -0
- package/lib/server/engine/runner.js +193 -0
- package/lib/server/errors.js +23 -0
- package/lib/server/http/guard.js +75 -0
- package/lib/server/http/router.js +154 -0
- package/lib/server/http/static.js +76 -0
- package/lib/server/index.js +40 -0
- package/lib/server/journal.js +139 -0
- package/lib/server/lien.js +33 -0
- package/lib/server/savoir/base.js +284 -0
- package/lib/server/savoir/lecture.js +406 -0
- package/lib/server/savoir/memoire.js +115 -0
- package/lib/server/search/categories.js +179 -0
- package/lib/server/search/fiche.js +326 -0
- package/lib/server/search/lieux.js +134 -0
- package/lib/server/search/overpass.js +216 -0
- package/lib/server/search/searxng.js +223 -0
- package/lib/server/search/tiles.js +103 -0
- package/lib/server/status.js +157 -0
- package/lib/server/stores.js +141 -0
- package/lib/server/telephone/acces.js +457 -0
- package/lib/server/telephone/certificat.js +79 -0
- package/lib/server/telephone/qr.js +308 -0
- package/lib/shared/analysis.js +40 -0
- package/lib/shared/schemas.js +105 -0
- package/lib/shared/types.js +10 -0
- package/package.json +81 -4
- package/searxng/settings.yml +35 -0
- package/tui/Modelfile +23 -0
- package/tui/README.md +103 -0
- package/tui/prmt_tui.py +65 -0
- package/tui/promethee/__init__.py +1 -0
- package/tui/promethee/__main__.py +4 -0
- package/tui/promethee/accueil.py +66 -0
- package/tui/promethee/agents.py +220 -0
- package/tui/promethee/app/__init__.py +4 -0
- package/tui/promethee/app/application.py +299 -0
- package/tui/promethee/app/clavier.py +99 -0
- package/tui/promethee/app/commandes_slash.py +164 -0
- package/tui/promethee/app/contexte.py +188 -0
- package/tui/promethee/app/definitions.py +518 -0
- package/tui/promethee/app/ecran.py +177 -0
- package/tui/promethee/app/envoi.py +141 -0
- package/tui/promethee/app/historique.py +373 -0
- package/tui/promethee/app/modele.py +108 -0
- package/tui/promethee/app/notes.py +63 -0
- package/tui/promethee/app/outils.py +589 -0
- package/tui/promethee/app/plateforme.py +409 -0
- package/tui/promethee/app/saisie.py +100 -0
- package/tui/promethee/app/taches.py +92 -0
- package/tui/promethee/app/tour.py +539 -0
- package/tui/promethee/app/validation.py +210 -0
- package/tui/promethee/appels.py +35 -0
- package/tui/promethee/commandes.py +154 -0
- package/tui/promethee/completion.py +140 -0
- package/tui/promethee/config.py +12 -0
- package/tui/promethee/consignes.py +278 -0
- package/tui/promethee/conversation.py +94 -0
- package/tui/promethee/etat.py +253 -0
- package/tui/promethee/fichiers.py +354 -0
- package/tui/promethee/journal.py +116 -0
- package/tui/promethee/logo.py +132 -0
- package/tui/promethee/memoire.py +50 -0
- package/tui/promethee/ollama.py +52 -0
- package/tui/promethee/plan.py +91 -0
- package/tui/promethee/politique.py +429 -0
- package/tui/promethee/preferences.py +65 -0
- package/tui/promethee/presse_papiers.py +44 -0
- package/tui/promethee/recherche.py +581 -0
- package/tui/promethee/securite.py +204 -0
- package/tui/promethee/shell.py +190 -0
- package/tui/promethee/textes.py +190 -0
- package/tui/promethee/theme.py +92 -0
- package/tui/promethee/widgets.py +493 -0
- package/tui/requirements.txt +1 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@layer composants{.markdown{gap:var(--md-ecart,var(--esp-3));overflow-wrap:anywhere;min-inline-size:0;display:grid}.markdown>*{min-inline-size:0;margin:0}.markdown-titre{color:var(--md-fort,var(--texte));font-weight:var(--graisse-forte)}.markdown :is(ul,ol){gap:var(--md-ecart-liste,var(--esp-1));padding-inline-start:var(--md-retrait,var(--esp-5));display:grid}.markdown li::marker{color:var(--md-puce,var(--texte-2))}.markdown strong{color:var(--md-fort,var(--texte));font-weight:var(--graisse-forte)}.markdown :is(p,li) code{color:var(--md-code,var(--texte));font:var(--t-code);font-variant-ligatures:none;overflow-wrap:anywhere;background:0 0;border:0;border-radius:0;padding:0}.markdown a{color:var(--md-lien,var(--or));text-underline-offset:.2em;text-decoration:underline}.markdown a:hover{color:var(--texte)}.markdown-renvoi{font-variant-numeric:tabular-nums;white-space:nowrap}.markdown-brut{padding:var(--esp-3) var(--esp-4);border:1px solid var(--trait-2);border-radius:var(--r-controle);background:var(--creux);color:var(--texte);font:var(--t-code);font-variant-ligatures:none;white-space:pre-wrap;overflow-wrap:anywhere}.markdown[data-curseur]>:last-child:not(ul,ol):after,.markdown[data-curseur]>:is(ul,ol):last-child>li:last-child:after{content:"";background:var(--ambre);vertical-align:text-bottom;block-size:1.1em;inline-size:.55em;margin-inline-start:2px;display:inline-block}}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import{f as e}from"./Field-C7c2mCbb.js";import{$ as t,Et as n,Ot as r,ct as i}from"./index-COSiM-R9.js";import{n as a,t as o}from"./web-6j1-aY67.js";var s={name:`rotate-ccw`,size:24,node:[[`path`,{d:`M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8`,key:`1357e3`}],[`path`,{d:`M3 3v5h5`,key:`1xhq8a`}]]};s.node;var c=n(s),l=r(),u=t(),d=/(`[^`\n]+`|\*\*[^*\n]+\*\*|\[[^\]\n]+\]\(https?:\/\/[^\s)]+\))/g,f=/\[(\d{1,2}(?:\s*,\s*\d{1,2})*)\]/g;function p(e,t,n){if(!n||n.length===0||!e.includes(`[`))return[e];let r=[],i=0;for(let s of e.matchAll(f)){let c=(s[1]??``).split(`,`).map(e=>n.find(t=>t.n===Number(e.trim())&&o(t.url)));if(c.some(e=>e===void 0))continue;let l=s.index;r.push(e.slice(i,l),`[`),c.forEach((e,n)=>{e&&(n>0&&r.push(`, `),r.push((0,u.jsxs)(`a`,{className:`markdown-renvoi`,href:e.url,target:`_blank`,rel:`noopener noreferrer`,title:e.title,children:[e.n,(0,u.jsxs)(`span`,{className:`sr`,children:[`, source `,a(e.url)]})]},`${t}-r${l}-${n}`)))}),r.push(`]`),i=l+s[0].length}return r.push(e.slice(i)),r}function m(e,t,n){return e.split(d).flatMap((e,r)=>{let i=`${t}-${r}`;if(e.startsWith("`")&&e.endsWith("`")&&e.length>2)return(0,u.jsx)(`code`,{children:e.slice(1,-1)},i);if(e.startsWith(`**`)&&e.endsWith(`**`)&&e.length>4)return(0,u.jsx)(`strong`,{children:e.slice(2,-2)},i);let a=/^\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)$/.exec(e);return a?(0,u.jsx)(`a`,{href:a[2],target:`_blank`,rel:`noopener noreferrer`,children:a[1]},i):p(e,i,n)})}var h=new Set([`powershell`,`ps1`,`ps`,`pwsh`,`shell`,`console`,`cmd`,`bat`,`bash`,`sh`]),g=(0,l.memo)(function({source:t,curseur:n=!1,className:r,sources:a}){let o=[],s=t.replace(/\r\n/g,`
|
|
2
|
+
`).split(`
|
|
3
|
+
`),c=0,l=0;for(;c<s.length;){let t=s[c]??``,n=/^\s*```\s*([\w+-]*)\s*$/.exec(t);if(n){let t=(n[1]??``).toLowerCase(),r=[];for(c++;c<s.length&&!/^\s*```\s*$/.test(s[c]??``);)r.push(s[c++]??``);c++;let i=r.join(`
|
|
4
|
+
`);o.push(h.has(t)||t===``?(0,u.jsx)(e,{as:`bloc`,code:i,className:`markdown-code`},l++):(0,u.jsx)(`pre`,{className:`markdown-brut`,children:i},l++));continue}if(t.trim()===``){c++;continue}let r=/^(#{1,4})\s+(.*)$/.exec(t);if(r){o.push((0,u.jsx)(`p`,{className:`markdown-titre`,children:m(r[2]??``,`h${l}`,a)},l++)),c++;continue}let i=/^\s*(?:[-*•]|\d{1,2}[.)])\s+/;if(i.test(t)){let e=/^\s*\d/.test(t),n=Number(/^\s*(\d{1,2})/.exec(t)?.[1]??1),r=[];for(;c<s.length&&i.test(s[c]??``);)r.push((0,u.jsx)(`li`,{children:m((s[c]??``).replace(i,``),`l${l}-${r.length}`,a)},r.length)),c++;o.push(e?(0,u.jsx)(`ol`,{start:n===1?void 0:n,children:r},l++):(0,u.jsx)(`ul`,{children:r},l++));continue}let d=[];for(;c<s.length&&(s[c]??``).trim()!==``&&!/^\s*```/.test(s[c]??``)&&!i.test(s[c]??``)&&!/^#{1,4}\s/.test(s[c]??``);)d.push(s[c++]??``);o.push((0,u.jsx)(`p`,{children:d.flatMap((e,t)=>[...t>0?[(0,u.jsx)(`br`,{},`br${t}`)]:[],...m(e,`p${l}-${t}`,a)])},l++))}return(0,u.jsx)(`div`,{className:i(`markdown`,r),"data-curseur":n?``:void 0,children:o})});export{c as n,g as t};
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Et as e}from"./index-COSiM-R9.js";var t={name:`play`,size:24,node:[[`path`,{d:`M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z`,key:`10ikf1`}]]};t.node;var n=e(t);export{n as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Et as e}from"./index-COSiM-R9.js";var t={name:`plus`,size:24,node:[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]};t.node;var n=e(t);export{n as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Et as e}from"./index-COSiM-R9.js";var t={name:`trash`,size:24,node:[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]],aliases:[`trash-2`]};t.node;var n=e(t);export{n as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=e=>/^https?:\/\/\S+$/i.test(e);function t(e){try{return new URL(e).hostname.replace(/^www\./i,``)||e}catch{return e}}export{t as n,e as t};
|
package/dist/favicon.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 0 22 22" shape-rendering="crispEdges"><rect x="9" y="0" width="1" height="1" fill="#ff5f00"/><rect x="9" y="1" width="1" height="1" fill="#ff5f00"/><rect x="10" y="1" width="1" height="1" fill="#ff5f00"/><rect x="8" y="2" width="1" height="1" fill="#ff5f00"/><rect x="9" y="2" width="1" height="1" fill="#ff8700"/><rect x="10" y="2" width="1" height="1" fill="#ff5f00"/><rect x="7" y="3" width="1" height="1" fill="#ff5f00"/><rect x="8" y="3" width="1" height="1" fill="#ff8700"/><rect x="9" y="3" width="1" height="1" fill="#ff8700"/><rect x="10" y="3" width="1" height="1" fill="#ff5f00"/><rect x="14" y="3" width="1" height="1" fill="#ff5f00"/><rect x="4" y="4" width="1" height="1" fill="#ff5f00"/><rect x="7" y="4" width="1" height="1" fill="#ff5f00"/><rect x="8" y="4" width="1" height="1" fill="#ff8700"/><rect x="9" y="4" width="1" height="1" fill="#ffd700"/><rect x="10" y="4" width="1" height="1" fill="#ff8700"/><rect x="11" y="4" width="1" height="1" fill="#ff5f00"/><rect x="13" y="4" width="1" height="1" fill="#ff5f00"/><rect x="14" y="4" width="1" height="1" fill="#ff5f00"/><rect x="4" y="5" width="1" height="1" fill="#ff5f00"/><rect x="5" y="5" width="1" height="1" fill="#ff5f00"/><rect x="7" y="5" width="1" height="1" fill="#ff5f00"/><rect x="8" y="5" width="1" height="1" fill="#ff8700"/><rect x="9" y="5" width="1" height="1" fill="#ffd700"/><rect x="10" y="5" width="1" height="1" fill="#ffd700"/><rect x="11" y="5" width="1" height="1" fill="#ff8700"/><rect x="12" y="5" width="1" height="1" fill="#ff5f00"/><rect x="13" y="5" width="1" height="1" fill="#ff5f00"/><rect x="14" y="5" width="1" height="1" fill="#ff8700"/><rect x="15" y="5" width="1" height="1" fill="#ff5f00"/><rect x="3" y="6" width="1" height="1" fill="#ff5f00"/><rect x="4" y="6" width="1" height="1" fill="#ff8700"/><rect x="5" y="6" width="1" height="1" fill="#ff8700"/><rect x="6" y="6" width="1" height="1" fill="#ff5f00"/><rect x="7" y="6" width="1" height="1" fill="#ff8700"/><rect x="8" y="6" width="1" height="1" fill="#ffd700"/><rect x="9" y="6" width="1" height="1" fill="#ffffaf"/><rect x="10" y="6" width="1" height="1" fill="#ffd700"/><rect x="11" y="6" width="1" height="1" fill="#ff8700"/><rect x="12" y="6" width="1" height="1" fill="#ff5f00"/><rect x="13" y="6" width="1" height="1" fill="#ff8700"/><rect x="14" y="6" width="1" height="1" fill="#ff8700"/><rect x="15" y="6" width="1" height="1" fill="#ff5f00"/><rect x="2" y="7" width="1" height="1" fill="#ff5f00"/><rect x="3" y="7" width="1" height="1" fill="#ff8700"/><rect x="4" y="7" width="1" height="1" fill="#ff8700"/><rect x="5" y="7" width="1" height="1" fill="#ff8700"/><rect x="6" y="7" width="1" height="1" fill="#ffd700"/><rect x="7" y="7" width="1" height="1" fill="#ffd700"/><rect x="8" y="7" width="1" height="1" fill="#ffffaf"/><rect x="9" y="7" width="1" height="1" fill="#ffffaf"/><rect x="10" y="7" width="1" height="1" fill="#ffd700"/><rect x="11" y="7" width="1" height="1" fill="#ffd700"/><rect x="12" y="7" width="1" height="1" fill="#ff8700"/><rect x="13" y="7" width="1" height="1" fill="#ff8700"/><rect x="14" y="7" width="1" height="1" fill="#ff8700"/><rect x="15" y="7" width="1" height="1" fill="#ff5f00"/><rect x="2" y="8" width="1" height="1" fill="#ff5f00"/><rect x="3" y="8" width="1" height="1" fill="#ff8700"/><rect x="4" y="8" width="1" height="1" fill="#ff8700"/><rect x="5" y="8" width="1" height="1" fill="#ffd700"/><rect x="6" y="8" width="1" height="1" fill="#ffd700"/><rect x="7" y="8" width="1" height="1" fill="#ffffaf"/><rect x="8" y="8" width="1" height="1" fill="#ffffaf"/><rect x="9" y="8" width="1" height="1" fill="#ffffaf"/><rect x="10" y="8" width="1" height="1" fill="#ffffaf"/><rect x="11" y="8" width="1" height="1" fill="#ffd700"/><rect x="12" y="8" width="1" height="1" fill="#ffd700"/><rect x="13" y="8" width="1" height="1" fill="#ff8700"/><rect x="14" y="8" width="1" height="1" fill="#ff8700"/><rect x="15" y="8" width="1" height="1" fill="#ff5f00"/><rect x="2" y="9" width="1" height="1" fill="#ff5f00"/><rect x="3" y="9" width="1" height="1" fill="#ff8700"/><rect x="4" y="9" width="1" height="1" fill="#ffd700"/><rect x="5" y="9" width="1" height="1" fill="#ffd700"/><rect x="6" y="9" width="1" height="1" fill="#ffffaf"/><rect x="7" y="9" width="1" height="1" fill="#ffffaf"/><rect x="8" y="9" width="1" height="1" fill="#ffffaf"/><rect x="9" y="9" width="1" height="1" fill="#ffffaf"/><rect x="10" y="9" width="1" height="1" fill="#ffffaf"/><rect x="11" y="9" width="1" height="1" fill="#ffffaf"/><rect x="12" y="9" width="1" height="1" fill="#ffd700"/><rect x="13" y="9" width="1" height="1" fill="#ffd700"/><rect x="14" y="9" width="1" height="1" fill="#ff8700"/><rect x="15" y="9" width="1" height="1" fill="#ff5f00"/><rect x="2" y="10" width="1" height="1" fill="#d70000"/><rect x="3" y="10" width="1" height="1" fill="#ff5f00"/><rect x="4" y="10" width="1" height="1" fill="#ff8700"/><rect x="5" y="10" width="1" height="1" fill="#ffd700"/><rect x="6" y="10" width="1" height="1" fill="#ffd700"/><rect x="7" y="10" width="1" height="1" fill="#ffffaf"/><rect x="8" y="10" width="1" height="1" fill="#ffffaf"/><rect x="9" y="10" width="1" height="1" fill="#ffffaf"/><rect x="10" y="10" width="1" height="1" fill="#ffffaf"/><rect x="11" y="10" width="1" height="1" fill="#ffd700"/><rect x="12" y="10" width="1" height="1" fill="#ffd700"/><rect x="13" y="10" width="1" height="1" fill="#ff8700"/><rect x="14" y="10" width="1" height="1" fill="#ff5f00"/><rect x="15" y="10" width="1" height="1" fill="#d70000"/><rect x="3" y="11" width="1" height="1" fill="#d70000"/><rect x="4" y="11" width="1" height="1" fill="#ff5f00"/><rect x="5" y="11" width="1" height="1" fill="#ff8700"/><rect x="6" y="11" width="1" height="1" fill="#ff8700"/><rect x="7" y="11" width="1" height="1" fill="#ffd700"/><rect x="8" y="11" width="1" height="1" fill="#ffd700"/><rect x="9" y="11" width="1" height="1" fill="#ffd700"/><rect x="10" y="11" width="1" height="1" fill="#ffd700"/><rect x="11" y="11" width="1" height="1" fill="#ff8700"/><rect x="12" y="11" width="1" height="1" fill="#ff8700"/><rect x="13" y="11" width="1" height="1" fill="#ff5f00"/><rect x="14" y="11" width="1" height="1" fill="#d70000"/><rect x="4" y="12" width="1" height="1" fill="#d70000"/><rect x="5" y="12" width="1" height="1" fill="#d70000"/><rect x="6" y="12" width="1" height="1" fill="#ff5f00"/><rect x="7" y="12" width="1" height="1" fill="#ff5f00"/><rect x="8" y="12" width="1" height="1" fill="#ff8700"/><rect x="9" y="12" width="1" height="1" fill="#ff8700"/><rect x="10" y="12" width="1" height="1" fill="#ff5f00"/><rect x="11" y="12" width="1" height="1" fill="#ff5f00"/><rect x="12" y="12" width="1" height="1" fill="#d70000"/><rect x="13" y="12" width="1" height="1" fill="#d70000"/><rect x="1" y="13" width="1" height="1" fill="#d7875f"/><rect x="2" y="13" width="1" height="1" fill="#d7875f"/><rect x="3" y="13" width="1" height="1" fill="#d7875f"/><rect x="4" y="13" width="1" height="1" fill="#d7875f"/><rect x="5" y="13" width="1" height="1" fill="#d7875f"/><rect x="6" y="13" width="1" height="1" fill="#d7875f"/><rect x="7" y="13" width="1" height="1" fill="#d7875f"/><rect x="8" y="13" width="1" height="1" fill="#d7875f"/><rect x="9" y="13" width="1" height="1" fill="#d7875f"/><rect x="10" y="13" width="1" height="1" fill="#d7875f"/><rect x="11" y="13" width="1" height="1" fill="#d7875f"/><rect x="12" y="13" width="1" height="1" fill="#d7875f"/><rect x="13" y="13" width="1" height="1" fill="#d7875f"/><rect x="14" y="13" width="1" height="1" fill="#d7875f"/><rect x="15" y="13" width="1" height="1" fill="#d7875f"/><rect x="16" y="13" width="1" height="1" fill="#d7875f"/><rect x="1" y="14" width="1" height="1" fill="#5f3700"/><rect x="2" y="14" width="1" height="1" fill="#af5f00"/><rect x="3" y="14" width="1" height="1" fill="#af5f00"/><rect x="4" y="14" width="1" height="1" fill="#af5f00"/><rect x="5" y="14" width="1" height="1" fill="#af5f00"/><rect x="6" y="14" width="1" height="1" fill="#af5f00"/><rect x="7" y="14" width="1" height="1" fill="#af5f00"/><rect x="8" y="14" width="1" height="1" fill="#af5f00"/><rect x="9" y="14" width="1" height="1" fill="#af5f00"/><rect x="10" y="14" width="1" height="1" fill="#af5f00"/><rect x="11" y="14" width="1" height="1" fill="#af5f00"/><rect x="12" y="14" width="1" height="1" fill="#af5f00"/><rect x="13" y="14" width="1" height="1" fill="#af5f00"/><rect x="14" y="14" width="1" height="1" fill="#af5f00"/><rect x="15" y="14" width="1" height="1" fill="#af5f00"/><rect x="16" y="14" width="1" height="1" fill="#5f3700"/><rect x="2" y="15" width="1" height="1" fill="#5f3700"/><rect x="3" y="15" width="1" height="1" fill="#5f3700"/><rect x="4" y="15" width="1" height="1" fill="#5f3700"/><rect x="5" y="15" width="1" height="1" fill="#5f3700"/><rect x="6" y="15" width="1" height="1" fill="#5f3700"/><rect x="7" y="15" width="1" height="1" fill="#5f3700"/><rect x="8" y="15" width="1" height="1" fill="#5f3700"/><rect x="9" y="15" width="1" height="1" fill="#5f3700"/><rect x="10" y="15" width="1" height="1" fill="#5f3700"/><rect x="11" y="15" width="1" height="1" fill="#5f3700"/><rect x="12" y="15" width="1" height="1" fill="#5f3700"/><rect x="13" y="15" width="1" height="1" fill="#5f3700"/><rect x="14" y="15" width="1" height="1" fill="#5f3700"/><rect x="15" y="15" width="1" height="1" fill="#5f3700"/><rect x="3" y="16" width="1" height="1" fill="#5f3700"/><rect x="4" y="16" width="1" height="1" fill="#af5f00"/><rect x="5" y="16" width="1" height="1" fill="#af5f00"/><rect x="6" y="16" width="1" height="1" fill="#af5f00"/><rect x="7" y="16" width="1" height="1" fill="#af5f00"/><rect x="8" y="16" width="1" height="1" fill="#af5f00"/><rect x="9" y="16" width="1" height="1" fill="#af5f00"/><rect x="10" y="16" width="1" height="1" fill="#af5f00"/><rect x="11" y="16" width="1" height="1" fill="#af5f00"/><rect x="12" y="16" width="1" height="1" fill="#af5f00"/><rect x="13" y="16" width="1" height="1" fill="#af5f00"/><rect x="14" y="16" width="1" height="1" fill="#5f3700"/><rect x="3" y="17" width="1" height="1" fill="#5f3700"/><rect x="4" y="17" width="1" height="1" fill="#af5f00"/><rect x="5" y="17" width="1" height="1" fill="#d78700"/><rect x="6" y="17" width="1" height="1" fill="#d78700"/><rect x="7" y="17" width="1" height="1" fill="#d78700"/><rect x="8" y="17" width="1" height="1" fill="#d78700"/><rect x="9" y="17" width="1" height="1" fill="#d78700"/><rect x="10" y="17" width="1" height="1" fill="#d78700"/><rect x="11" y="17" width="1" height="1" fill="#d78700"/><rect x="12" y="17" width="1" height="1" fill="#d78700"/><rect x="13" y="17" width="1" height="1" fill="#af5f00"/><rect x="14" y="17" width="1" height="1" fill="#5f3700"/><rect x="3" y="18" width="1" height="1" fill="#5f3700"/><rect x="4" y="18" width="1" height="1" fill="#af5f00"/><rect x="5" y="18" width="1" height="1" fill="#d78700"/><rect x="6" y="18" width="1" height="1" fill="#af5f00"/><rect x="7" y="18" width="1" height="1" fill="#af5f00"/><rect x="8" y="18" width="1" height="1" fill="#af5f00"/><rect x="9" y="18" width="1" height="1" fill="#af5f00"/><rect x="10" y="18" width="1" height="1" fill="#af5f00"/><rect x="11" y="18" width="1" height="1" fill="#af5f00"/><rect x="12" y="18" width="1" height="1" fill="#d78700"/><rect x="13" y="18" width="1" height="1" fill="#af5f00"/><rect x="14" y="18" width="1" height="1" fill="#5f3700"/><rect x="3" y="19" width="1" height="1" fill="#5f3700"/><rect x="4" y="19" width="1" height="1" fill="#af5f00"/><rect x="5" y="19" width="1" height="1" fill="#d78700"/><rect x="6" y="19" width="1" height="1" fill="#d78700"/><rect x="7" y="19" width="1" height="1" fill="#d78700"/><rect x="8" y="19" width="1" height="1" fill="#d78700"/><rect x="9" y="19" width="1" height="1" fill="#d78700"/><rect x="10" y="19" width="1" height="1" fill="#d78700"/><rect x="11" y="19" width="1" height="1" fill="#d78700"/><rect x="12" y="19" width="1" height="1" fill="#d78700"/><rect x="13" y="19" width="1" height="1" fill="#af5f00"/><rect x="14" y="19" width="1" height="1" fill="#5f3700"/><rect x="3" y="20" width="1" height="1" fill="#5f3700"/><rect x="4" y="20" width="1" height="1" fill="#af5f00"/><rect x="5" y="20" width="1" height="1" fill="#af5f00"/><rect x="6" y="20" width="1" height="1" fill="#af5f00"/><rect x="7" y="20" width="1" height="1" fill="#af5f00"/><rect x="8" y="20" width="1" height="1" fill="#af5f00"/><rect x="9" y="20" width="1" height="1" fill="#af5f00"/><rect x="10" y="20" width="1" height="1" fill="#af5f00"/><rect x="11" y="20" width="1" height="1" fill="#af5f00"/><rect x="12" y="20" width="1" height="1" fill="#af5f00"/><rect x="13" y="20" width="1" height="1" fill="#af5f00"/><rect x="14" y="20" width="1" height="1" fill="#5f3700"/><rect x="2" y="21" width="1" height="1" fill="#5f3700"/><rect x="3" y="21" width="1" height="1" fill="#5f3700"/><rect x="4" y="21" width="1" height="1" fill="#5f3700"/><rect x="5" y="21" width="1" height="1" fill="#5f3700"/><rect x="6" y="21" width="1" height="1" fill="#5f3700"/><rect x="7" y="21" width="1" height="1" fill="#5f3700"/><rect x="8" y="21" width="1" height="1" fill="#5f3700"/><rect x="9" y="21" width="1" height="1" fill="#5f3700"/><rect x="10" y="21" width="1" height="1" fill="#5f3700"/><rect x="11" y="21" width="1" height="1" fill="#5f3700"/><rect x="12" y="21" width="1" height="1" fill="#5f3700"/><rect x="13" y="21" width="1" height="1" fill="#5f3700"/><rect x="14" y="21" width="1" height="1" fill="#5f3700"/><rect x="15" y="21" width="1" height="1" fill="#5f3700"/></svg>
|
package/dist/index.html
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="fr">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, interactive-widget=resizes-content" />
|
|
6
|
+
<meta name="color-scheme" content="dark" />
|
|
7
|
+
<meta name="theme-color" content="#0A0908" />
|
|
8
|
+
<meta name="description" content="Prométhée, plateforme locale de cybersécurité : IA locale avec Ollama, terminal PowerShell sous liste blanche, audits de tes propres systèmes." />
|
|
9
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
10
|
+
<title>Prométhée</title>
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-COSiM-R9.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BH1etemR.css">
|
|
13
|
+
</head>
|
|
14
|
+
<body>
|
|
15
|
+
<div id="root"></div>
|
|
16
|
+
<div id="calques"></div>
|
|
17
|
+
</body>
|
|
18
|
+
</html>
|
package/docs/ANALYSE.md
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Analyse, architecture et design
|
|
2
|
+
|
|
3
|
+
Ce document suit la méthode de `prompt.md` : l'existant, ses défauts, l'architecture retenue, le système de design, et ce qui a été vérifié.
|
|
4
|
+
|
|
5
|
+
## 1. L'existant
|
|
6
|
+
|
|
7
|
+
| Élément | Emplacement | État |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| TUI `prmt` | `ollama/promethee` (Python, Textual). Un fichier de 5 270 lignes au départ, un paquet de 40 modules après sa refonte | Fonctionnelle : outils, validation des commandes, agents, mémoire, contrôles automatiques. Son analyse et sa refonte sont décrites dans `ollama/promethee/docs/ANALYSE.md`. |
|
|
10
|
+
| Modèle | `ollama/promethee/Modelfile` (RedSage-Qwen3-8B, Q4_K_M) | Choisi sur le banc d'essai `ollama/eval`. |
|
|
11
|
+
| Vitrine v1 | un seul fichier HTML (conservé dans `reference/vitrine-v1.html`) | Statique. |
|
|
12
|
+
|
|
13
|
+
## 2. Défauts relevés
|
|
14
|
+
|
|
15
|
+
- **Aucune plateforme.** La vitrine décrivait la TUI mais ne faisait rien : pas de lien avec Ollama ni avec PowerShell, démo entièrement reconstituée.
|
|
16
|
+
- **Un fichier de 96 Ko, sans types ni tests.** CSS, données et 600 lignes de JavaScript dans la même page.
|
|
17
|
+
- **Dépendance en ligne.** Les polices venaient de Google Fonts, pour un outil présenté comme local.
|
|
18
|
+
- **Pas de tableau de bord, pas de journal, pas d'historique** en dehors des fichiers de session de la TUI.
|
|
19
|
+
- **Validation visuelle seulement.** Dans la TUI, la sécurité reposait sur la lecture de chaque commande par l'utilisateur et sur des listes de mots dangereux. Il n'y avait ni liste blanche, ni contrôle des arguments, ni périmètre, ni journal. C'est corrigé : la TUI interroge maintenant la politique de la console.
|
|
20
|
+
|
|
21
|
+
## 3. Décisions
|
|
22
|
+
|
|
23
|
+
**La TUI reste en Python, et elle est refondue sur place.** Elle fonctionne, elle a été mise au point sur des mesures, et la réécrire en TypeScript n'apporterait rien. Elle a été découpée en modules, dotée de tests, d'un journal et d'un thème à la palette de Prométhée. La console lit ses sessions et son journal en lecture seule.
|
|
24
|
+
|
|
25
|
+
**Une seule politique, en TypeScript.** La TUI ne réimplémente pas la liste blanche. Elle lance un pont (`server/cli/pont.ts`) qui lui rend les verdicts de `server/engine/policy.ts`. Les réglages et le périmètre sont dans les mêmes fichiers pour les deux interfaces, relus dès que l'autre les modifie.
|
|
26
|
+
|
|
27
|
+
**TypeScript partout dans la console**, en mode strict (`strict`, `noUncheckedIndexedAccess`, `verbatimModuleSyntax`), sans aucun `any`. La pile reprend celle du projet `vinpro` : Vite 8, React 19, TypeScript 7.
|
|
28
|
+
|
|
29
|
+
**Un serveur local est indispensable.** Un navigateur ne peut ni lancer PowerShell ni lire le disque. Le serveur est en Node, exécuté directement depuis les sources TypeScript (Node 24+ sait le faire) : pas d'étape de compilation, pas d'outil en plus.
|
|
30
|
+
|
|
31
|
+
**Peu de dépendances.** À l'exécution : React, zod (validation), lucide (icônes) et trois polices embarquées. Pas de framework serveur, pas de bibliothèque de graphiques ni de routeur : le routeur HTTP fait 170 lignes, les graphiques sont en SVG.
|
|
32
|
+
|
|
33
|
+
**Reprendre ce qui a fait ses preuves dans la TUI** : l'analyse par le parseur de PowerShell, le classement action ou explication avant de répondre, le contrôle des valeurs citées absentes des sorties, le format des résultats renvoyés au modèle.
|
|
34
|
+
|
|
35
|
+
## 4. Architecture
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
navigateur (React) ──HTTP sur 127.0.0.1── serveur local (Node) ──┬── PowerShell (analyse, puis exécution)
|
|
39
|
+
├── Ollama (API HTTP locale)
|
|
40
|
+
└── cibles d'audit déclarées
|
|
41
|
+
|
|
42
|
+
TUI prmt (Python) ──JSON, une ligne par demande── pont (Node) ──── PowerShell (analyse seulement)
|
|
43
|
+
│ │
|
|
44
|
+
└── journal.jsonl (lu par la console) └── réglages et périmètre de la console
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
- `shared/` : les contrats. Types des réponses, schémas zod des entrées. Importé des deux côtés.
|
|
48
|
+
- `server/engine/` : le seul chemin d'exécution. `analyzer` (arbre syntaxique), `catalog` (liste blanche), `policy` (verdict, fonction pure), `runner` (PowerShell), `engine` (tickets, confirmation, journal). `relax` dit ce que la TUI fait d'un verdict selon son mode, strict ou souple.
|
|
49
|
+
- `server/cli/` : `bridge` répond aux demandes de la TUI (verdict, liste blanche, périmètre), `pont` le branche sur l'entrée et la sortie standard. `server/lien.ts` écrit le fichier de liaison.
|
|
50
|
+
- `server/brain/` : `provider.ts` définit le contrat d'un fournisseur de modèles, `ollama.ts` l'implémente. Brancher un autre moteur d'inférence revient à écrire un second fichier de ce type.
|
|
51
|
+
- `server/audits/` : un module par fichier logique, chacun avec son objectif, son périmètre et ses résultats. Les analyseurs sont des fonctions pures, testées sans réseau.
|
|
52
|
+
- `src/` : l'interface ne contient aucune logique métier. Elle appelle l'API par `services/api.ts` et gère trois états pour chaque donnée : chargement, erreur, résultat.
|
|
53
|
+
|
|
54
|
+
Les erreurs passent par un seul type (`AppError` côté serveur, `ApiError` côté interface), avec un code stable et un message lisible.
|
|
55
|
+
|
|
56
|
+
## 5. Système de design
|
|
57
|
+
|
|
58
|
+
Direction : la nuit, l'or antique et le feu. Une console sombre dont la seule lumière vient de la flamme.
|
|
59
|
+
|
|
60
|
+
| Rôle | Valeur |
|
|
61
|
+
|---|---|
|
|
62
|
+
| Noir profond, noir secondaire | `#0A0908`, `#12100E` |
|
|
63
|
+
| Or antique | `#D99A21` |
|
|
64
|
+
| Ambre incandescent, orange feu | `#FF9900`, `#FF6500` |
|
|
65
|
+
| Blanc chaud | `#F5F0E8` |
|
|
66
|
+
|
|
67
|
+
- **Conservé de la TUI** : la flamme en pixel art sur son pupitre, le nom en capitales antiques, la frise grecque (méandre), le nom grec. Leurs grilles de pixels viennent du code Python.
|
|
68
|
+
- **Motifs grecs** : frise en tête de la barre latérale, sous les titres des fenêtres modales et dans le pied de page. Lettres grecques comme repères des huit modules d'audit.
|
|
69
|
+
- **Typographie** : Bricolage Grotesque (titres), Geist (texte), JetBrains Mono (code). Embarquées, donc disponibles hors ligne.
|
|
70
|
+
- **États** : vert, jaune et rouge, toujours avec une icône et un libellé.
|
|
71
|
+
- **Gravité des constats** : une rampe « braise » d'une seule teinte, plus claire quand c'est plus grave. Lisible sans distinguer les couleurs, et chaque segment porte son nombre.
|
|
72
|
+
- **Graphiques** : deux séries au plus, validées pour le daltonisme sur le fond sombre (or `#C98500`, rouge `#D03B3B`), légende, infobulle au survol et au clavier.
|
|
73
|
+
- **Mouvement** : apparitions courtes, lueur qui suit le pointeur, flamme qui vacille pendant un chargement. Tout est coupé si le système demande moins d'animations.
|
|
74
|
+
|
|
75
|
+
## 6. Ce qui a été vérifié
|
|
76
|
+
|
|
77
|
+
- Types stricts sur l'interface, le serveur et les tests de bout en bout.
|
|
78
|
+
- 199 tests unitaires et d'intégration, dont 64 cas de politique enregistrés avec le vrai parseur, 22 tests du pont de la TUI, et 9 tests qui lancent le vrai PowerShell.
|
|
79
|
+
- Côté TUI : 109 tests sans écran, dont quatre avec le vrai pont ou le vrai PowerShell, et un essai de bout en bout avec le vrai modèle, le vrai PowerShell et le vrai pont.
|
|
80
|
+
- 10 parcours dans Chrome avec le vrai serveur : terminal, refus, écriture confirmée, journal, audit, réglages, cerveau avec le modèle réel, mise en page à 390 et 820 px.
|
|
81
|
+
- Aucune erreur de console sur les pages capturées.
|
|
82
|
+
|
|
83
|
+
Trois défauts ont été trouvés par ces tests et corrigés :
|
|
84
|
+
|
|
85
|
+
1. Les tableaux mis en forme automatiquement par PowerShell étaient perdus (le script appelait `exit` avant la fin du pipeline).
|
|
86
|
+
2. Une cible écrite avec un masque (`10.0.0.0/24`) était acceptée en perdant son masque.
|
|
87
|
+
3. La détection de secrets ratait les noms comme `SECRET_KEY`.
|
package/docs/SECURITE.md
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# Sécurité de la console
|
|
2
|
+
|
|
3
|
+
La console exécute des commandes sur la machine. Ce document décrit ce qui l'en empêche de le faire à tort, et ce qu'elle ne protège pas.
|
|
4
|
+
|
|
5
|
+
## Ce contre quoi elle protège
|
|
6
|
+
|
|
7
|
+
| Menace | Réponse |
|
|
8
|
+
|---|---|
|
|
9
|
+
| Le modèle propose une commande dangereuse ou inventée | Il ne peut que proposer. La politique refuse ce qui n'est pas dans la liste blanche, et l'humain confirme le reste. |
|
|
10
|
+
| Une commande autorisée en cache une autre | L'arbre syntaxique complet est contrôlé, pas seulement le premier mot. |
|
|
11
|
+
| Une page web ouverte dans le navigateur appelle le serveur local | Garde de l'API : hôte, origine, jeton. |
|
|
12
|
+
| Une écriture ou un test réseau sort du cadre | Périmètre de dossiers et périmètre de cibles, vérifiés par le serveur. |
|
|
13
|
+
| Une action passe inaperçue | Journal en ajout seul, y compris pour les refus. |
|
|
14
|
+
| Un résultat de recherche web, ou une page lue, contient des instructions pour le modèle | La réponse qui suit une recherche ou un rappel du savoir est produite sans l'outil de commande. Résultats et passages sont présentés au modèle comme des données non vérifiées. Le texte des pages n'est donné qu'à ce tour-là. |
|
|
15
|
+
| Un résultat de recherche pousse le serveur à lire une page de ton réseau ou du PC lui-même (SSRF) | Le serveur résout lui-même le nom et refuse toute adresse privée, locale ou réservée, au moment de la connexion et à chaque redirection. http ou https, ports 80 et 443 seulement. |
|
|
16
|
+
| Un appareil du Wi-Fi joint la console quand l'accès téléphone est ouvert | Il reçoit l'interface, sans aucun secret. L'API exige le cookie d'un téléphone appairé avec un code à usage unique, plus le jeton de session. Tout passe en HTTPS. |
|
|
17
|
+
| Un téléphone appairé, perdu ou volé, élargit la politique | Depuis le téléphone, la liste blanche, les dossiers autorisés, le langage contraint, la confirmation des lectures et les adresses d'Ollama et de SearXNG ne se changent pas. Le retirer sur le PC coupe ses connexions. |
|
|
18
|
+
| Un résultat de recherche pousse le serveur à télécharger une adresse interne (image de fiche) | Le serveur ne télécharge que les vignettes qu'il a choisies, en https, sur une liste fermée d'hôtes, sans redirection. La page n'envoie qu'un identifiant opaque. |
|
|
19
|
+
|
|
20
|
+
Elle ne protège pas contre un programme malveillant déjà lancé avec tes droits : il n'a pas besoin de Prométhée.
|
|
21
|
+
|
|
22
|
+
## Le chemin d'une commande
|
|
23
|
+
|
|
24
|
+
Il n'y en a qu'un, que la commande vienne du terminal, du modèle ou d'un module d'audit.
|
|
25
|
+
|
|
26
|
+
1. **Prévisualisation** (`POST /api/engine/preview`). Le texte est transmis en base64 à un processus PowerShell qui ne fait que deux choses : construire l'arbre syntaxique (`Parser::ParseInput`) et demander à `Get-Command` ce que chaque nom désigne. Rien n'est exécuté.
|
|
27
|
+
2. **Politique** (`server/engine/policy.ts`). Fonction pure qui rend un verdict : lecture, sensible ou refusée, avec les raisons.
|
|
28
|
+
3. **Ticket.** Si la commande n'est pas refusée, le serveur délivre un ticket à usage unique, valable 5 minutes, lié au texte exact analysé.
|
|
29
|
+
4. **Confirmation** (`POST /api/engine/run`). Le serveur exige le ticket et `confirm: true`. Une commande sensible exige en plus `acknowledge: true` (la case cochée). La politique est réévaluée à ce moment, au cas où les réglages auraient changé.
|
|
30
|
+
5. **Exécution.** PowerShell reçoit le script par l'entrée standard, encodé en base64 : pas de fichier temporaire, pas de contournement de la politique d'exécution, aucune citation à échapper.
|
|
31
|
+
6. **Journal.** Commande, verdict, origine, type de confirmation, code de sortie, durée.
|
|
32
|
+
|
|
33
|
+
Le modèle n'a accès qu'à l'étape 1. L'étape 4 n'est déclenchée que par un clic.
|
|
34
|
+
|
|
35
|
+
## Ce que la politique contrôle
|
|
36
|
+
|
|
37
|
+
**Refus par défaut à tous les niveaux.**
|
|
38
|
+
|
|
39
|
+
- **Constructions.** Seuls les nœuds syntaxiques d'une liste sont admis. Sont refusés entre autres : définitions de fonction, `param()`, classes, `trap`, `using`, DSC.
|
|
40
|
+
- **Commandes.** Chaque commande de l'arbre, y compris dans les blocs `{ }` et les sous-expressions, doit être dans la liste blanche. Les alias sont résolus par PowerShell (`rm` est jugé comme `Remove-Item`).
|
|
41
|
+
- **Quatre niveaux.** Lecture, sensible (écrit, contacte le réseau, agit sur le système), destructive (refusée tant que tu ne la débloques pas dans les réglages), interdite (jamais).
|
|
42
|
+
- **Jamais exécutable, même débloqué ou ajouté à la main :** `Invoke-Expression`, `Invoke-Command`, `Add-Type`, `New-Object`, `Import-Module`, `Set-Alias`, `Set-ExecutionPolicy`, `Set-MpPreference`, `Format-Volume`, et les interpréteurs (`powershell`, `cmd`, `wscript`, `mshta`, `rundll32`, `certutil`, `wsl`…). `Start-Process` débloqué ne peut pas les lancer non plus.
|
|
43
|
+
- **Commandes dynamiques.** `& $variable`, script lancé par chemin, point-source : refusés, parce que la commande réelle n'est pas visible.
|
|
44
|
+
- **.NET.** Appels de méthode limités à une liste (chaînes, dates). Types limités aux types de base. `[IO.File]::Delete()` et `$_.Kill()` sont refusés.
|
|
45
|
+
- **Détournements.** Affectation à `$env:` (PATH), variables de lecteur (`$alias:`, `$function:`, `${C:\fichier}`), `$PSDefaultParameterValues`, affectation de propriété (`(Get-Item x).IsReadOnly = $true`), arguments éclatés (`@params`), `ForEach-Object NomDeMéthode`.
|
|
46
|
+
- **Chemins écrits.** Doivent être des constantes, résolues puis comparées aux dossiers autorisés. Les jonctions sont suivies. Le dossier de Windows, les chemins réseau et les lecteurs PowerShell (`HKLM:`, `Function:`) sont refusés en écriture.
|
|
47
|
+
- **Chemins réseau (`\\serveur\partage`).** Refusés partout : ils enverraient tes identifiants Windows au serveur visé.
|
|
48
|
+
- **Outils système.** `whoami`, `ipconfig`, `netstat`… doivent se trouver dans `System32`, et le PATH de l'exécution place les dossiers de Windows en tête.
|
|
49
|
+
- **Arguments.** `ipconfig` et `route` en lecture seulement. `winget` : chercher et lister sont des lectures, installer ou désinstaller demande un déblocage. `ping` sans envoi continu ni paquets surdimensionnés. `curl.exe` en GET, HEAD ou OPTIONS vers http(s). `nmap` : options de découverte, une cible à la fois, ni leurres, ni usurpation, ni cibles aléatoires, ni scripts offensifs ou de déni de service.
|
|
50
|
+
|
|
51
|
+
Chaque règle a un cas dans `tests/server/cases.ts`, enregistré avec le vrai parseur.
|
|
52
|
+
|
|
53
|
+
## Deuxième barrière : le mode de langage contraint
|
|
54
|
+
|
|
55
|
+
Par défaut, la commande s'exécute en `ConstrainedLanguage`. PowerShell bloque alors lui-même les appels .NET arbitraires, même si la politique était contournée. Un test le vérifie avec le vrai PowerShell (`moteur.windows.test.ts`). Les modules de fonctions (NetTCPIP, NetSecurity…) sont chargés juste avant le passage en mode contraint, sinon ils ne se chargeraient pas.
|
|
56
|
+
|
|
57
|
+
## Périmètre réseau
|
|
58
|
+
|
|
59
|
+
Les audits réseau et les tests de ports (`nmap`, `Test-NetConnection -Port`) n'acceptent que :
|
|
60
|
+
|
|
61
|
+
- la machine locale ;
|
|
62
|
+
- les cibles déclarées dans Audits › Périmètre, ou dans la TUI avec `/perimetre ajouter`, avec attestation que la cible t'appartient ou que tu as une autorisation écrite.
|
|
63
|
+
|
|
64
|
+
La vérification est faite par le serveur avant le premier paquet. Chaque déclaration et chaque refus sont écrits au journal. Les redirections HTTP qui sortent du périmètre ne sont pas suivies.
|
|
65
|
+
|
|
66
|
+
## La TUI `prmt`
|
|
67
|
+
|
|
68
|
+
La TUI applique la même politique, sans la réimplémenter. Elle lance le pont (`server/cli/pont.ts`) et lui envoie chaque commande avant de te la montrer. Le pont fait les étapes 1 et 2 du chemin ci-dessus, analyse et verdict, et rien d'autre : il n'exécute jamais.
|
|
69
|
+
|
|
70
|
+
| | Console | TUI |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| Analyse et liste blanche | `policy.ts` | `policy.ts`, par le pont |
|
|
73
|
+
| Commande refusée | refusée | refusée, non proposée, raison rendue au modèle |
|
|
74
|
+
| Confirmation | ticket à usage unique, clic | demande de validation au clavier |
|
|
75
|
+
| Exécution | mode de langage contraint | mode de langage contraint pour les commandes de la liste blanche, langage complet pour ce que tu valides « hors politique » |
|
|
76
|
+
| Journal | `data/journal.jsonl` | `Documents\Promethee\journal.jsonl`, lu par la console |
|
|
77
|
+
|
|
78
|
+
La TUI a un second mode, **souple**, choisi avec `/politique souple`. Ce que l'analyse ne sait pas vérifier (script, compilateur, programme lancé par son chemin) t'est alors montré comme « hors politique », en rouge, et tu le valides. Certains refus sont des **planchers** et tiennent dans les deux modes (`floor` dans `policy.ts`, décision dans `relax.ts`) :
|
|
79
|
+
|
|
80
|
+
- commande destructrice non débloquée, y compris `winget install`
|
|
81
|
+
- test de ports ou scan vers une cible hors périmètre, ou vers une cible calculée
|
|
82
|
+
- commande qui affaiblit une protection de Windows ou efface un disque
|
|
83
|
+
- chemin réseau
|
|
84
|
+
- erreur de syntaxe
|
|
85
|
+
|
|
86
|
+
En mode souple, le pont regarde aussi ce que l'analyse d'une ligne ne montre pas. Un script `.ps1` lancé par son chemin est lu et analysé : s'il contient un plancher, il est refusé. Une adresse IP ou un hôte d'URL écrit en clair dans les arguments d'une commande hors liste (`python scan.py 10.0.0.5`) doit être dans le périmètre, sinon la commande est refusée.
|
|
87
|
+
|
|
88
|
+
Si le pont ne répond pas, la TUI n'invente pas de verdict : elle retombe sur la validation manuelle de chaque commande et l'affiche dans sa barre d'état.
|
|
89
|
+
|
|
90
|
+
## Garde de l'API
|
|
91
|
+
|
|
92
|
+
- Le serveur écoute sur `127.0.0.1`. L'accès téléphone, fermé par défaut, ajoute une seconde écoute sur le réseau local, avec sa propre garde (partie suivante).
|
|
93
|
+
- `Host` doit être `127.0.0.1` ou `localhost` sur le bon port : cela bloque le « DNS rebinding ».
|
|
94
|
+
- `Origin`, s'il est présent, doit être l'interface elle-même. `Sec-Fetch-Site: cross-site` est refusé.
|
|
95
|
+
- Un jeton aléatoire, tiré à chaque démarrage, est exigé sur toute l'API. Une autre page ne peut pas le lire : aucune autorisation CORS n'est accordée.
|
|
96
|
+
- Les rejets sont comptés, journalisés et affichés dans les alertes du tableau de bord.
|
|
97
|
+
- L'interface est servie avec une politique de sécurité du contenu stricte (`script-src 'self'`, pas de cadre, pas de formulaire externe).
|
|
98
|
+
|
|
99
|
+
## Accès depuis le téléphone
|
|
100
|
+
|
|
101
|
+
Fermé par défaut. Il s'ouvre et se ferme dans Réglages, Téléphone, sur le PC seulement. Une fois ouvert, il le reste aux démarrages suivants, jusqu'à ce que tu le fermes. Chaque ouverture, fermeture, appairage et retrait est noté au journal.
|
|
102
|
+
|
|
103
|
+
- **Écoute.** Le port 4318 (`PROMETHEE_PORT_TELEPHONE`), sur les adresses IPv4 privées du PC (`10/8`, `172.16/12`, `192.168/16`) et sur son adresse Tailscale (`100.64/10`, sur la carte Tailscale seulement). Les cartes virtuelles (WSL, Hyper-V, VirtualBox, VMware, Docker) sont écartées. Les adresses sont relues toutes les 30 secondes : un autre Wi-Fi, ou Tailscale qui démarre, sont pris en compte, et noté au journal. Le serveur de `127.0.0.1:4317` ne change pas.
|
|
104
|
+
- **De l'extérieur.** Seulement par Tailscale : le port n'est jamais ouvert sur internet, et seuls les appareils de ton réseau Tailscale atteignent l'adresse `100.x`. Le trafic y est chiffré de bout en bout, puis encore par le HTTPS de la console.
|
|
105
|
+
- **HTTPS.** Un certificat ECDSA P-256, valable un an, fabriqué par le PC pour ses adresses (`data/telephone/`). Aucune autorité ne le signe : le navigateur du téléphone avertit à la première visite. Le chiffrement protège de l'écoute sur le Wi-Fi. Une requête en clair sur le port reçoit une redirection vers https, rien d'autre.
|
|
106
|
+
- **Garde.** `Host` doit être une adresse écoutée avec son port, `Origin` ce même hôte en https, et `Sec-Fetch-Site` doit dire la même origine. L'interface est servie à tous (elle ne contient aucun secret). Toute l'API exige le cookie d'un appareil appairé, puis le jeton de session, sauf la route d'appairage.
|
|
107
|
+
- **Appairage.** Un code de 8 caractères (environ 40 bits), à usage unique, valable 10 minutes, affiché sur le PC en clair et en QR code. Le QR code porte le code dans l'ancre de l'adresse, qui ne part dans aucune requête. Cinq essais faux grillent le code, et 20 essais par minute au plus sont acceptés, tous codes confondus.
|
|
108
|
+
- **Cookie d'appareil.** `__Host-promethee-appareil` : `HttpOnly`, `Secure`, `SameSite=Strict`, 30 jours, repoussés à chaque visite. Le serveur n'en garde que l'empreinte SHA-256. Un appareil absent depuis 30 jours est oublié.
|
|
109
|
+
- **Ce que le téléphone ne fait pas.** Changer la liste blanche, les dossiers autorisés, le mode de langage contraint, la confirmation des lectures, les adresses d'Ollama et de SearXNG, et gérer l'accès téléphone lui-même (403 `pc_only`). Le reste de la console marche comme sur le PC : chaque commande passe par la politique et par ta confirmation, sur l'écran du téléphone.
|
|
110
|
+
- **Journal.** Les entrées causées par le téléphone portent `via : telephone` et le nom de l'appareil (« Chrome sur Android »), tiré du navigateur.
|
|
111
|
+
- **Retrait.** Retirer un appareil sur le PC invalide son cookie et coupe ses connexions ouvertes. Fermer l'accès coupe tout et libère le port.
|
|
112
|
+
|
|
113
|
+
## Recherche web et carte
|
|
114
|
+
|
|
115
|
+
- La recherche passe par SearXNG, et seulement à une adresse en boucle locale (`127.0.0.1`, `localhost`, `[::1]`) : les réglages refusent toute autre adresse, et le client la vérifie encore avant chaque requête. C'est SearXNG qui sort vers les moteurs.
|
|
116
|
+
- La page ne contacte que le serveur local. Ce que le serveur envoie lui-même sur internet, et à qui :
|
|
117
|
+
|
|
118
|
+
| Service | Ce qu'il reçoit | Quand |
|
|
119
|
+
|---|---|---|
|
|
120
|
+
| Moteurs (Google, Bing, DuckDuckGo, Brave), via SearXNG | La requête du classificateur, en mots-clés. Pour une fiche : « nom du lieu + ville ». | Une recherche, l'ouverture d'une fiche |
|
|
121
|
+
| `tile.openstreetmap.org` | Les numéros des tuiles affichées | Une carte |
|
|
122
|
+
| Overpass (`overpass-api.de`, puis `maps.mail.ru` si le premier refuse ou tarde) | Une catégorie (« hôtels ») et une zone (aire d'une ville, boîte ou rayon) | Une carte à plusieurs lieux, l'ouverture d'une fiche (étiquettes du lieu) |
|
|
123
|
+
| `fr.wikipedia.org`, `www.wikidata.org` | Le titre de l'article ou l'identifiant Wikidata du lieu | L'ouverture d'une fiche |
|
|
124
|
+
| Hôtes des vignettes (`upload.wikimedia.org`, `thumb.wikimedia.org`, `*.mm.bing.net`, `th.bing.com`, `imgs.search.brave.com`) | L'adresse de la vignette choisie | L'affichage d'une image de fiche |
|
|
125
|
+
| Les sites des 3 premiers résultats lisibles, joints directement (sans SearXNG) | Une requête GET de la page du résultat, sans cookie | Une recherche, quand l'apprentissage est actif (partie suivante) |
|
|
126
|
+
|
|
127
|
+
Jamais la conversation entière. Pas de compte, pas de clé, pas d'adresse de contact : le User-Agent nomme l'application, rien de plus. Ton adresse IP publique, elle, reste visible de ces services, comme pour toute recherche faite depuis cette connexion.
|
|
128
|
+
- Les images des fiches : le serveur ne télécharge que les adresses qu'il a lui-même choisies (la page n'envoie qu'un identifiant opaque), en https, sur la liste fermée d'hôtes ci-dessus, sans redirection, 2 Mo au plus, et seulement du jpeg, png, webp ou gif, renvoyé avec `X-Content-Type-Options: nosniff`. La page ne peut pas s'en servir pour joindre une autre adresse.
|
|
129
|
+
- La catégorie d'une carte à plusieurs lieux doit être une des 32 du serveur, qui fournit lui-même le filtre Overpass : la page ne peut pas écrire de requête Overpass. Une zone de plus de 100 km de diagonale est refusée.
|
|
130
|
+
- Les routes de la carte (tuiles, points, fiches, images) exigent le jeton comme le reste de l'API, et répondent 403 quand la recherche est coupée. Points et tuiles sont gardés 7 jours dans `data/`. Chaque fiche cherchée est notée au journal.
|
|
131
|
+
- Après une recherche, le modèle répond sans l'outil de commande. Dans les tours suivants, la liste des résultats reste dans l'historique (sans le texte des pages lues) : une commande qu'elle inspirerait passe encore par la politique et par ta confirmation.
|
|
132
|
+
- L'interrupteur des réglages coupe tout : ni classement de recherche, ni requête, ni tuile, ni point, ni fiche.
|
|
133
|
+
|
|
134
|
+
## Savoir local
|
|
135
|
+
|
|
136
|
+
Après une recherche, le serveur lit en entier les 3 premiers résultats lisibles et en garde le texte dans `data/savoir.db` (SQLite). Avant de répondre, le modèle relit les passages utiles de ces pages et des pages retenues lors de recherches précédentes. Le modèle lui-même ne change pas. Un réglage, actif par défaut, coupe la lecture et le rappel.
|
|
137
|
+
|
|
138
|
+
- **Lecture des pages** (`server/savoir/lecture.ts`). Les adresses viennent d'internet, le serveur ne leur fait pas confiance :
|
|
139
|
+
- http ou https, ports 80 et 443, pas d'identifiants dans l'adresse. Les noms `localhost`, `.local`, `.lan`, `.internal`, `.home.arpa` et les adresses IP privées écrites en clair (y compris sous forme décimale ou hexadécimale) sont refusés avant toute requête.
|
|
140
|
+
- Le nom est résolu par le serveur, et la connexion se fait sur l'adresse résolue. Si une seule des adresses rendues est privée (`10/8`, `172.16/12`, `192.168/16`), de boucle locale, locale au lien (`169.254/16`, `fe80::/10`), de partage d'opérateur ou Tailscale (`100.64/10`), locale unique (`fc00::/7`), multicast ou réservée, la page est refusée. Il n'y a pas de seconde résolution qu'un DNS changeant pourrait détourner.
|
|
141
|
+
- Les redirections ne sont pas suivies par la bibliothèque : chacune est revérifiée comme une nouvelle adresse, 4 au plus.
|
|
142
|
+
- 3 Mo au plus une fois décompressés, 12 s sans réponse au plus par page, 15 s pour l'ensemble, du HTML ou du texte seulement, statut 200 seulement, aucun cookie ni envoyé ni gardé.
|
|
143
|
+
- Le User-Agent dit `Mozilla/5.0 (compatible; Promethee/<version>; lecture locale pour son utilisateur)`, rien de plus. Les sites lus voient ton adresse IP publique, comme quand tu les ouvres toi-même.
|
|
144
|
+
- **Ce qui est gardé.** Le texte lisible de la page (60 000 caractères au plus), son adresse, son titre, la requête qui l'a fait lire, les dates de lecture et d'utilisation. Ni image, ni script, ni cookie. Une page lue il y a moins de 7 jours n'est pas relue. Au-delà de 15 millions de caractères, les pages les moins récemment utilisées sont oubliées.
|
|
145
|
+
- **Ce que le modèle en reçoit.** 6 passages au plus, 1 200 caractères chacun, 6 000 en tout, numérotés comme les sources, présentés comme des données venues d'internet et non vérifiées, avec la consigne de n'obéir à aucune instruction qu'ils contiennent. Ils ne sont donnés qu'à la réponse qui suit la recherche ou le rappel, produite sans l'outil de commande. Dans les tours suivants, il ne reste que la liste des résultats.
|
|
146
|
+
- **Rappel sans recherche.** Pour une question d'explication seulement, et seulement si des passages contiennent l'essentiel des mots de la question. Une demande d'action ne reçoit jamais de passage : elle garde son outil de commande, sans texte venu d'internet à côté.
|
|
147
|
+
- **Contrôle.** La page Savoir de la console liste les pages retenues, montre leur texte, permet d'en oublier une ou tout. Ces routes (`/api/savoir`) exigent le jeton comme le reste de l'API. Chaque lecture de pages, chaque rappel et chaque oubli est noté au journal.
|
|
148
|
+
|
|
149
|
+
## Mode full cyber
|
|
150
|
+
|
|
151
|
+
Un réglage (Réglages, Cerveau, sur le PC seulement), coupé par défaut. Il change l'invite système du modèle : Prométhée répond alors comme un assistant de sécurité offensive sans retenue (exploitation, payloads, élévation de privilèges, post-exploitation, contournement de protections), pour un usage white hat autorisé. C'est fait pour tes propres machines, un CTF, ou un pentest pour lequel tu as une autorisation écrite. Le créateur décline toute responsabilité, et tu restes seul responsable de la légalité de tes actes.
|
|
152
|
+
|
|
153
|
+
**Ce que le mode ne change pas.** Rien du côté de l'exécution. Le texte du modèle n'est que du conseil : la liste blanche contrôle toujours chaque commande, la confirmation humaine reste exigée, les commandes destructrices restent bloquées tant que tu ne les débloques pas, et surtout le périmètre réseau tient. Un scan ou un test de ports ne vise toujours que la machine locale ou une cible que tu as déclarée avec attestation. Autrement dit, le mode te donne plus de savoir, pas plus de pouvoir sur des systèmes tiers.
|
|
154
|
+
|
|
155
|
+
Le mode ne se règle pas depuis le téléphone (403 `pc_only`). Il est signalé dans le Cerveau par une pastille, et chaque activation ou coupure est notée au journal.
|
|
156
|
+
|
|
157
|
+
## Mode auto
|
|
158
|
+
|
|
159
|
+
Un second réglage, sous full cyber (il n'a d'effet que si full cyber est actif), coupé par défaut, PC seulement. À partir d'un but que tu donnes dans le Cerveau, le modèle exécute lui-même les commandes, les unes après les autres, sans te les faire valider une par une, jusqu'à atteindre le but ou la limite de 20 commandes. C'est la seule partie de Prométhée qui lève la confirmation humaine par commande, et seulement pour ce que la politique autorise déjà.
|
|
160
|
+
|
|
161
|
+
**Ce qui part tout seul.** Les commandes de niveau lecture et sensible (qui écrivent dans tes dossiers autorisés ou contactent le réseau). Le mode auto fournit par programme la confirmation qu'un humain donnerait d'un clic. Rien de plus : il passe par le même `engine.start()` que la confirmation humaine, avec le même ticket.
|
|
162
|
+
|
|
163
|
+
**Ce qui ne part jamais tout seul, même en auto.** Les garde-fous durs de l'exécution ne bougent pas, parce que c'est le moteur, pas la boucle auto, qui les applique :
|
|
164
|
+
|
|
165
|
+
- une commande destructrice, interdite, ou qui affaiblit une protection de Windows, n'obtient pas de ticket à la prévisualisation. Elle est refusée, le modèle reçoit la raison et doit faire autrement ou s'arrêter.
|
|
166
|
+
- un test de ports ou un scan vers une cible hors du périmètre déclaré est refusé de la même façon.
|
|
167
|
+
- la politique est réévaluée au lancement de chaque commande (`engine.start`), le mode de langage contraint s'applique toujours, et une écriture reste bornée aux dossiers autorisés.
|
|
168
|
+
|
|
169
|
+
Autrement dit, le mode auto te donne de l'autonomie sur ce qui était déjà jugé sûr, pas un passe-droit : pour débloquer une commande destructrice ou déclarer une cible, il faut toujours ton geste à toi, sur le PC.
|
|
170
|
+
|
|
171
|
+
**Bornes.** 20 commandes au plus par but, puis le modèle s'arrête et le dit. Une seule réponse à la fois par conversation. « Arrêter » coupe la boucle et annule la commande en cours. Chaque commande exécutée est au journal (origine `ai`), et le lancement du mode auto y est noté avec le but.
|
|
172
|
+
|
|
173
|
+
## Limites connues
|
|
174
|
+
|
|
175
|
+
- **Liste personnelle.** Les arguments d'une commande que tu ajoutes à la main ne sont pas contrôlés. C'est signalé à l'ajout et à chaque exécution.
|
|
176
|
+
- **Lectures.** Lire hors des dossiers autorisés est permis (un audit de configuration doit lire le registre et `System32`). C'est indiqué dans le verdict.
|
|
177
|
+
- **Recherche web.** Les mots-clés de la requête partent vers Google, Bing, DuckDuckGo et Brave via SearXNG, une catégorie et une zone vers Overpass, le nom d'un lieu ouvert en fiche vers les moteurs et Wikipédia, et, quand l'apprentissage est actif, une requête vers les sites des 3 premiers résultats. Coupe la recherche dans les réglages si une conversation ne doit pas sortir de la machine.
|
|
178
|
+
- **Mode full cyber.** Il débride ce que le modèle accepte d'expliquer, pas sa justesse : un exploit ou un payload qu'il te donne peut être faux ou dépassé, vérifie avant de t'en servir. Le modèle 8B ne suit pas parfaitement l'invite (il ajoute encore des avertissements, et vouvoie parfois). Le mode ne te dispense d'aucune autorisation : la responsabilité légale de ce que tu fais des réponses est la tienne.
|
|
179
|
+
- **Mode auto.** Il enchaîne sans ta validation des commandes de lecture et des commandes sensibles (écriture dans tes dossiers autorisés, accès réseau). Un modèle qui se trompe peut donc écrire un fichier ou lancer une requête que tu n'aurais pas validée, dans les limites de la politique. Les commandes destructrices, interdites et hors périmètre restent refusées, mais garde un œil sur ce qu'il fait et coupe avec « Arrêter » au moindre doute. À réserver aux buts et aux machines où ce niveau d'autonomie te convient.
|
|
180
|
+
- **Savoir local.** Une page retenue peut contenir une erreur ou une instruction cachée, et le modèle peut la relire plus tard pour une autre question. Il la reçoit toujours sans outil de commande et avec sa source, mais rien ne garantit qu'elle dise vrai : la page Savoir permet de l'oublier. Les pages dont le texte n'apparaît qu'avec JavaScript ne sont pas lisibles. Le rappel cherche par mots (accents et fins de mots ignorés), pas par le sens : une question formulée autrement peut ne rien retrouver.
|
|
181
|
+
- **Fiches.** L'extrait et l'image viennent du premier résultat qui porte tout le nom du lieu (et sa ville, pour une image d'un autre site). Un lieu au nom courant peut recevoir la fiche d'un homonyme : la source est toujours affichée sous chaque morceau.
|
|
182
|
+
- **Requêtes web.** `curl.exe` et `Invoke-WebRequest` peuvent contacter n'importe quel hôte en lecture. Ils sont classés sensibles, l'hôte est affiché, mais le périmètre réseau ne s'applique qu'aux tests de ports.
|
|
183
|
+
- **Mode contraint désactivable.** Si tu le coupes dans les réglages, il ne reste que la politique.
|
|
184
|
+
- **Sortie des commandes.** Le journal garde les 800 derniers caractères de chaque sortie. Il reste sur ta machine, dans `data/`.
|
|
185
|
+
- **Accès téléphone et certificat.** L'avertissement du navigateur ne distingue pas le certificat du PC d'un autre. Un attaquant actif sur ton Wi-Fi au moment de la première visite pourrait s'interposer. Compare le début de l'empreinte affichée dans Réglages, Téléphone avec celle que montre le navigateur avant de continuer.
|
|
186
|
+
- **Accès téléphone et réseau.** Tout appareil du même réseau peut charger l'interface et tenter un code. Sur un Wi-Fi public, ferme l'accès. Le pare-feu de Windows décide si le port est joignable : une règle qui autorise Node.js sur les réseaux publics l'ouvre aussi sur ceux-là.
|
|
187
|
+
- **Windows uniquement.** Le moteur vise PowerShell 5.1. Les tests qui l'exercent sont ignorés ailleurs.
|
|
188
|
+
- **TUI, mode souple.** Une commande hors politique s'exécute en langage complet, avec tes droits, après ta validation. Le contenu d'un script n'est lu que s'il est en PowerShell (`.ps1`). Pour un script Python ou un exécutable, seules les cibles écrites en clair dans ses arguments sont contrôlées.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relie la TUI « prmt » à la console sans démarrer le serveur : écrit le fichier de rendez-vous
|
|
3
|
+
* (Documents\Promethee\plateforme.json) que la TUI lit pour trouver le pont de politique.
|
|
4
|
+
* Le serveur l'écrit aussi à chaque démarrage. Usage : npm run lier
|
|
5
|
+
*/
|
|
6
|
+
import { loadConfig } from '../server/config.js';
|
|
7
|
+
import { writeRendezvous } from '../server/lien.js';
|
|
8
|
+
const config = loadConfig();
|
|
9
|
+
const file = writeRendezvous(config);
|
|
10
|
+
if (!file) {
|
|
11
|
+
console.error(`Impossible d'écrire dans ${config.tuiDir}.`);
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
console.log(`TUI reliée : ${file}`);
|
|
15
|
+
console.log(`Données communes : ${config.dataDir}`);
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installe et démarre SearXNG, le moteur de recherche web de Prométhée, dans Docker.
|
|
3
|
+
*
|
|
4
|
+
* Usage :
|
|
5
|
+
* npm run searxng installe au premier lancement, sinon redémarre le conteneur
|
|
6
|
+
* npm run searxng -- arreter arrête le conteneur (la recherche web répond alors « injoignable »)
|
|
7
|
+
*
|
|
8
|
+
* Ce que fait le script, et rien d'autre :
|
|
9
|
+
* - copie searxng/settings.yml dans Documents\Promethee\searxng\ s'il n'y est pas encore (tes modifications y restent) ;
|
|
10
|
+
* - tire un secret au hasard une seule fois, gardé dans ce même dossier (fichier « secret ») ;
|
|
11
|
+
* - lance l'image officielle searxng/searxng, publiée sur 127.0.0.1:8888 seulement, redémarrée avec Docker ;
|
|
12
|
+
* - attend que /healthz réponde, puis vérifie que la sortie JSON est active.
|
|
13
|
+
*/
|
|
14
|
+
import { spawnSync } from 'node:child_process';
|
|
15
|
+
import { randomBytes } from 'node:crypto';
|
|
16
|
+
import fs from 'node:fs';
|
|
17
|
+
import path from 'node:path';
|
|
18
|
+
import { PACKAGE_ROOT, loadConfig } from '../server/config.js';
|
|
19
|
+
const NOM = 'promethee-searxng';
|
|
20
|
+
const IMAGE = 'searxng/searxng:latest';
|
|
21
|
+
const ADRESSE = 'http://127.0.0.1:8888';
|
|
22
|
+
function docker(args) {
|
|
23
|
+
const r = spawnSync('docker', args, { encoding: 'utf8' });
|
|
24
|
+
return { ok: r.status === 0, out: `${r.stdout ?? ''}${r.stderr ?? ''}`.trim() };
|
|
25
|
+
}
|
|
26
|
+
function stop(message) {
|
|
27
|
+
console.error(message);
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
const config = loadConfig();
|
|
31
|
+
const dossier = path.join(config.tuiDir, 'searxng');
|
|
32
|
+
if (process.argv[2] === 'arreter') {
|
|
33
|
+
const r = docker(['stop', NOM]);
|
|
34
|
+
console.log(r.ok ? 'SearXNG arrêté. La recherche web de Prométhée répondra « injoignable » jusqu’au prochain « npm run searxng ».' : r.out);
|
|
35
|
+
process.exit(r.ok ? 0 : 1);
|
|
36
|
+
}
|
|
37
|
+
const moteur = docker(['info', '--format', '{{.ServerVersion}}']);
|
|
38
|
+
if (!moteur.ok)
|
|
39
|
+
stop('Docker ne répond pas. Lance Docker Desktop, attends qu’il soit prêt, puis relance « npm run searxng ».');
|
|
40
|
+
fs.mkdirSync(dossier, { recursive: true });
|
|
41
|
+
const reglages = path.join(dossier, 'settings.yml');
|
|
42
|
+
if (!fs.existsSync(reglages)) {
|
|
43
|
+
fs.copyFileSync(path.join(PACKAGE_ROOT, 'searxng', 'settings.yml'), reglages);
|
|
44
|
+
console.log(`Réglages copiés : ${reglages}`);
|
|
45
|
+
}
|
|
46
|
+
else
|
|
47
|
+
console.log(`Réglages gardés : ${reglages}`);
|
|
48
|
+
const fichierSecret = path.join(dossier, 'secret');
|
|
49
|
+
if (!fs.existsSync(fichierSecret))
|
|
50
|
+
fs.writeFileSync(fichierSecret, randomBytes(32).toString('hex'), { mode: 0o600 });
|
|
51
|
+
const secret = fs.readFileSync(fichierSecret, 'utf8').trim();
|
|
52
|
+
const existe = docker(['container', 'inspect', '--format', '{{.State.Running}}', NOM]);
|
|
53
|
+
if (existe.ok) {
|
|
54
|
+
if (existe.out !== 'true') {
|
|
55
|
+
const r = docker(['start', NOM]);
|
|
56
|
+
if (!r.ok)
|
|
57
|
+
stop(r.out);
|
|
58
|
+
}
|
|
59
|
+
console.log('Conteneur déjà installé, démarré.');
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
const r = docker([
|
|
63
|
+
'run', '--detach', '--name', NOM, '--restart', 'unless-stopped',
|
|
64
|
+
'--publish', '127.0.0.1:8888:8080',
|
|
65
|
+
'--volume', `${dossier}:/etc/searxng`,
|
|
66
|
+
'--env', `SEARXNG_SECRET=${secret}`,
|
|
67
|
+
'--env', `SEARXNG_BASE_URL=${ADRESSE}/`,
|
|
68
|
+
IMAGE,
|
|
69
|
+
]);
|
|
70
|
+
if (!r.ok)
|
|
71
|
+
stop(r.out);
|
|
72
|
+
console.log('Conteneur installé et démarré.');
|
|
73
|
+
}
|
|
74
|
+
let pret = false;
|
|
75
|
+
for (let i = 0; i < 40 && !pret; i++) {
|
|
76
|
+
try {
|
|
77
|
+
pret = (await fetch(`${ADRESSE}/healthz`, { signal: AbortSignal.timeout(2000) })).ok;
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
// pas encore prêt
|
|
81
|
+
}
|
|
82
|
+
if (!pret)
|
|
83
|
+
await new Promise((r) => setTimeout(r, 1000));
|
|
84
|
+
}
|
|
85
|
+
if (!pret)
|
|
86
|
+
stop(`SearXNG ne répond pas sur ${ADRESSE}/healthz après 40 s. Journal : docker logs ${NOM}`);
|
|
87
|
+
const essai = await fetch(`${ADRESSE}/search?q=searxng&format=json`, { signal: AbortSignal.timeout(15_000) }).catch(() => null);
|
|
88
|
+
if (!essai || !essai.ok)
|
|
89
|
+
stop(`SearXNG répond, mais pas en JSON (${essai?.status ?? 'aucune réponse'}). Vérifie « formats » dans ${reglages}.`);
|
|
90
|
+
const corps = (await essai.json());
|
|
91
|
+
console.log(`SearXNG prêt sur ${ADRESSE} : ${corps.results?.length ?? 0} résultats pour l’essai.`);
|