saber: manuales cosechados e indice publico pre-construido
- manuales.py cosecha el --help de las herramientas que no traen man page (ffuf, sqlmap, suite impacket, netexec, hydra...) y lo escribe como markdown en conocimiento/09 - Manuales/. Es la referencia de opciones que la man page no da; complementa el cheatsheet de invocaciones comunes. - indexa.py --publico construye saber-publico.jsonl: glosario + pack de conocimiento con los vectores ya calculados, 100% publico y portable. - busca.py usa ese indice publico como fallback cuando no hay indice personal, asi un clon recien hecho consulta al instante sin reindexar nada. - .gitignore deja pasar saber-publico.jsonl; el personal (saber.jsonl) sigue fuera. - docs/rag.md y el README del pack documentan ambas cosas.
This commit is contained in:
parent
1dfb3513e6
commit
9fa0a40edf
12 changed files with 1206 additions and 45 deletions
|
|
@ -36,6 +36,10 @@ import sys
|
|||
AQUI = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
COFRE = os.path.expanduser("~/COFRE")
|
||||
INDICE = os.path.join(AQUI, "datos", "saber.jsonl")
|
||||
# El indice PUBLICO y portable: solo glosario + pack de conocimiento, sin nada de
|
||||
# la maquina (ni COFRE, ni man pages, ni servidores). Se commitea con vectores ya
|
||||
# calculados para que un clon recien hecho consulte al instante, sin reindexar.
|
||||
INDICE_PUBLICO = os.path.join(AQUI, "datos", "saber-publico.jsonl")
|
||||
|
||||
# Los perfiles que se indexan. Cada uno es una carpeta de ~/COFRE.
|
||||
PERFILES = ["PENTESTERS", "PHISHERS", "REVERSERS", "PROTECTORS", "HARD-WARERS",
|
||||
|
|
@ -145,6 +149,66 @@ def trocea(ruta):
|
|||
yield buffer.strip()
|
||||
|
||||
|
||||
def _conocimiento():
|
||||
"""El pack de metodologia y manuales que viene con el repo (conocimiento/)."""
|
||||
fragmentos = []
|
||||
base_con = os.path.join(os.path.dirname(os.path.abspath(__file__)), "conocimiento")
|
||||
if not os.path.isdir(base_con):
|
||||
return fragmentos
|
||||
for raiz, _, ficheros in os.walk(base_con):
|
||||
m = re.match(r"^\d{2}\s*-\s*(.+)$", os.path.basename(raiz))
|
||||
tema = m.group(1).strip().lower() if m else ""
|
||||
for fich in ficheros:
|
||||
if not fich.endswith(".md"):
|
||||
continue
|
||||
for trozo in trocea(os.path.join(raiz, fich)):
|
||||
fragmentos.append({
|
||||
"tipo": "metodologia", "herramienta": fich[:-3],
|
||||
"perfil": "PENTESTERS", "tema": tema,
|
||||
"fichero": os.path.join("conocimiento", os.path.relpath(
|
||||
os.path.join(raiz, fich), base_con)),
|
||||
"texto": trozo})
|
||||
return fragmentos
|
||||
|
||||
|
||||
def _guarda_indice(todo, ruta):
|
||||
"""Calcula los vectores de las entradas y las escribe a un indice jsonl."""
|
||||
print(" cargando el modelo de embeddings...", flush=True)
|
||||
from model2vec import StaticModel
|
||||
modelo = StaticModel.from_pretrained("minishlab/potion-multilingual-128M")
|
||||
|
||||
print(" calculando vectores...", flush=True)
|
||||
vectores = modelo.encode([e["texto"] for e in todo], show_progress_bar=False)
|
||||
|
||||
os.makedirs(os.path.dirname(ruta), exist_ok=True)
|
||||
with open(ruta, "w", encoding="utf-8") as f:
|
||||
for entrada, vec in zip(todo, vectores):
|
||||
entrada["v"] = [round(float(x), 5) for x in vec]
|
||||
f.write(json.dumps(entrada, ensure_ascii=False) + "\n")
|
||||
print(f" indice guardado: {ruta} ({os.path.getsize(ruta)//1024} KB)")
|
||||
|
||||
|
||||
def construye_publico(solo_cuenta=False):
|
||||
"""El indice PORTABLE que se sube al repo: glosario + pack de conocimiento.
|
||||
|
||||
Nada de la maquina —ni COFRE, ni man pages, ni servidores SSH—, asi que es
|
||||
100 % publico y vale igual en cualquier equipo. Un clon lo usa tal cual hasta
|
||||
que corre su propio indexa.py; asi el trabajo de indexar el pack no se repite.
|
||||
"""
|
||||
try:
|
||||
from saber import glosario
|
||||
except ImportError:
|
||||
import glosario
|
||||
glo = list(glosario.entradas())
|
||||
con = _conocimiento()
|
||||
todo = glo + con
|
||||
print(f" glosario {len(glo)} + conocimiento {len(con)} = {len(todo)} entradas publicas")
|
||||
if solo_cuenta:
|
||||
return 0
|
||||
_guarda_indice(todo, INDICE_PUBLICO)
|
||||
return 0
|
||||
|
||||
|
||||
def construye(solo_cuenta=False, solo_cofre=False):
|
||||
fichas, fragmentos = [], []
|
||||
|
||||
|
|
@ -195,23 +259,8 @@ def construye(solo_cuenta=False, solo_cofre=False):
|
|||
# esta scrubeado, asi que un clon recien hecho —sin apuntes propios de COFRE—
|
||||
# ya sabe de pentesting. En la maquina del usuario se solapa con sus apuntes
|
||||
# y el deduplicado de busca lo colapsa.
|
||||
conocimiento = []
|
||||
base_con = os.path.join(os.path.dirname(os.path.abspath(__file__)), "conocimiento")
|
||||
if os.path.isdir(base_con):
|
||||
for raiz, _, ficheros in os.walk(base_con):
|
||||
m = re.match(r"^\d{2}\s*-\s*(.+)$", os.path.basename(raiz))
|
||||
tema = m.group(1).strip().lower() if m else ""
|
||||
for fich in ficheros:
|
||||
if not fich.endswith(".md"):
|
||||
continue
|
||||
for trozo in trocea(os.path.join(raiz, fich)):
|
||||
conocimiento.append({
|
||||
"tipo": "metodologia", "herramienta": fich[:-3],
|
||||
"perfil": "PENTESTERS", "tema": tema,
|
||||
"fichero": os.path.join("conocimiento", os.path.relpath(
|
||||
os.path.join(raiz, fich), base_con)),
|
||||
"texto": trozo})
|
||||
print(f" CONOCIMIENTO {len(conocimiento):5d} fragmentos (pack del repo)")
|
||||
conocimiento = _conocimiento()
|
||||
print(f" CONOCIMIENTO {len(conocimiento):5d} fragmentos (pack del repo)")
|
||||
|
||||
todo = fichas + fragmentos + sistema + conocimiento
|
||||
print(f"\n total: {len(fichas)} fichas + {len(fragmentos)} apuntes + "
|
||||
|
|
@ -219,19 +268,7 @@ def construye(solo_cuenta=False, solo_cofre=False):
|
|||
if solo_cuenta:
|
||||
return 0
|
||||
|
||||
print(" cargando el modelo de embeddings...", flush=True)
|
||||
from model2vec import StaticModel
|
||||
modelo = StaticModel.from_pretrained("minishlab/potion-multilingual-128M")
|
||||
|
||||
print(" calculando vectores...", flush=True)
|
||||
vectores = modelo.encode([e["texto"] for e in todo], show_progress_bar=False)
|
||||
|
||||
os.makedirs(os.path.dirname(INDICE), exist_ok=True)
|
||||
with open(INDICE, "w", encoding="utf-8") as f:
|
||||
for entrada, vec in zip(todo, vectores):
|
||||
entrada["v"] = [round(float(x), 5) for x in vec]
|
||||
f.write(json.dumps(entrada, ensure_ascii=False) + "\n")
|
||||
print(f" indice guardado: {INDICE} ({os.path.getsize(INDICE)//1024} KB)")
|
||||
_guarda_indice(todo, INDICE)
|
||||
return 0
|
||||
|
||||
|
||||
|
|
@ -246,7 +283,11 @@ def main() -> int:
|
|||
help="di que encontrarias, sin indexar")
|
||||
p.add_argument("--solo-cofre", action="store_true",
|
||||
help="indexar solo COFRE, sin la documentacion del sistema")
|
||||
p.add_argument("--publico", action="store_true",
|
||||
help="construir el indice portable (glosario + conocimiento) que se sube al repo")
|
||||
a = p.parse_args()
|
||||
if a.publico:
|
||||
return construye_publico(solo_cuenta=a.cuenta)
|
||||
return construye(solo_cuenta=a.cuenta, solo_cofre=a.solo_cofre)
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue