ALL

Solo para leer y verificar. No puedes copiar, usar, modificar ni redistribuir este código. Aviso completo en la página principal.

src/all_mcp/tray/encryption_verify.py

SHA-256: 641d44389dd58a6c0fe58c87787efe55aec6a62a6ceed367c9f5e2a1b0ec14b2
143 líneas · 9360 bytes · Ver en GitHub

1"""ALL 2.0 (WP37): run-all verify-source. Listed installed files must match the MANIFEST's SHA-256; nothing else is checked. Nothing is sent.
2
3Which manifest decides what a pass means. The one bundled in the install lives beside the files it lists: whoever can change an installed file can change that manifest, so a pass
4against it proves only that the two agree, never that the files are the ones ALL published. The command says exactly that, prints the manifest's own SHA-256 and names the way to
5compare with the published one (a manifest downloaded from the page, passed with --manifest, whose SHA-256 the page also shows). Only that second pass says "the published ones"."""
6from __future__ import annotations
7
8import glob
9import hashlib
10import json
11from pathlib import Path
12from typing import Any
13
14PACKAGE_DIR = Path(__file__).resolve().parent.parent # the all_mcp package this module is installed in
15PREFIX = "src/all_mcp/"
16BUNDLED_MANIFEST = PACKAGE_DIR / "encryption-source-manifest.json"
17SCHEMA = "all-encryption-source/1"
18EXIT_OK, EXIT_FAILED, EXIT_USAGE = 0, 1, 64
19
20_TEXT = {
21 "es": {
22 "title": "Código publicado de ALL {version}: lo instalado",
23 "version_bad": "Instalada: {installed}. El manifiesto es de la versión {version}; usa el de tu versión.",
24 "no_manifest": "Esta copia no trae manifiesto. Usa: run-all verify-source --manifest RUTA (el de tu versión).",
25 "bad_manifest": "No pude leer el manifiesto: no es uno de ALL válido o está dañado.",
26 "changed": "Cambió: {path}",
27 "missing": "Falta: {path}",
28 "extra": "No está en el manifiesto: {path}",
29 "manifest": "Manifiesto: {source} (SHA-256 {digest})",
30 "source_bundled": "el que vino con esta instalación",
31 "source_file": "el archivo que indicaste",
32 "ok": "Correcto: los {count} archivos del manifiesto que corren en esta computadora coinciden con el manifiesto que indicaste. Compara el SHA-256 de arriba con el que muestra la página del código; si es el mismo, esos archivos son los publicados.",
33 "ok_bundled": "Los {count} archivos del manifiesto que corren en esta computadora coinciden con el manifiesto que vino con esta instalación. Eso solo muestra que ambos concuerdan: quien pudiera cambiar un archivo podría cambiar también ese manifiesto. Para compararlos con lo publicado, baja el manifiesto de tu versión de la página del código y corre: run-all verify-source --manifest RUTA",
34 "not_here": "{count} archivos del conjunto no corren en esta computadora. Este comando no los revisa.",
35 "failed": "No coincide: {count} problema(s) en los archivos del manifiesto.",
36 "usage": "uso: run-all verify-source [--manifest RUTA] [--json]",
37 },
38 "en": {
39 "title": "Published code of ALL {version}: what is installed",
40 "version_bad": "Installed: {installed}. The manifest is for {version}; use the one of your version.",
41 "no_manifest": "This copy has no manifest. Use: run-all verify-source --manifest PATH (the one of your version).",
42 "bad_manifest": "I could not read the manifest: it is not a valid ALL one or is damaged.",
43 "changed": "Changed: {path}",
44 "missing": "Missing: {path}",
45 "extra": "Not in the manifest: {path}",
46 "manifest": "Manifest: {source} (SHA-256 {digest})",
47 "source_bundled": "the one that came with this install",
48 "source_file": "the file you gave",
49 "ok": "OK: the {count} files of the manifest that run on this computer match the manifest you gave. Compare the SHA-256 above with the one the code page shows; if it is the same, those files are the published ones.",
50 "ok_bundled": "The {count} files of the manifest that run on this computer match the manifest that came with this install. That only shows the two agree: whoever could change a file could change that manifest too. To compare with what was published, download your version's manifest from the code page and run: run-all verify-source --manifest PATH",
51 "not_here": "{count} files of the set do not run on this computer. This command does not check them.",
52 "failed": "Does not match: {count} problem(s) in the files of the manifest.",
53 "usage": "usage: run-all verify-source [--manifest PATH] [--json]",
54 },
55}
56
57
58class ManifestError(Exception):
59 """The _TEXT key that says why the manifest cannot be used."""
60
61
62def _text(key: str, lang: str, **fields: Any) -> str:
63 return _TEXT["en" if lang == "en" else "es"][key].format(**fields)
64
65
66def manifest_sha256(path: Path | None = None) -> str:
67 """The SHA-256 of the manifest file itself (the bundled one when `path` is None): the number the code page shows beside the manifest it publishes."""
68 return hashlib.sha256((Path(path) if path is not None else BUNDLED_MANIFEST).read_bytes()).hexdigest()
69
70
71def load_manifest(path: Path | None = None) -> dict[str, Any]:
72 source = Path(path) if path is not None else BUNDLED_MANIFEST
73 if not source.is_file():
74 raise ManifestError("no_manifest")
75 try:
76 manifest = json.loads(source.read_text(encoding="utf-8"))
77 if (manifest.get("schema") == SCHEMA and isinstance(manifest.get("allowlist"), list)
78 and all(isinstance(e.get("path"), str) and isinstance(e.get("sha256"), str) for e in manifest["files"])):
79 return manifest
80 except (OSError, ValueError, AttributeError, TypeError, KeyError):
81 pass
82 raise ManifestError("bad_manifest")
83
84
85def verify(manifest: dict[str, Any], *, installed_version: str, package_dir: Path = PACKAGE_DIR) -> dict[str, Any]:
86 """`ok` only when the version matches, listed files run here and match, no allow-listed file is unlisted, and one file was checked."""
87 listed = {entry["path"] for entry in manifest["files"]}
88 out: dict[str, Any] = {"version": manifest.get("version"), "version_match": manifest.get("version") == installed_version,
89 "checked": [], "changed": [], "missing": [], "extra": [], "not_installed_here": []}
90 for entry in manifest["files"]:
91 rel = entry["path"]
92 local = package_dir / rel[len(PREFIX):]
93 if not rel.startswith(PREFIX):
94 out["not_installed_here"].append(rel)
95 elif not local.is_file():
96 out["missing"].append(rel)
97 else:
98 out["checked"].append(rel)
99 if hashlib.sha256(local.read_bytes()).hexdigest() != entry["sha256"]:
100 out["changed"].append(rel)
101 root = package_dir.resolve()
102 withheld = {rel for rel in manifest.get("withheld", []) if isinstance(rel, str)} # what the allow-list names and the export does not publish (the denylist): not an unlisted file
103 for pattern in (p for p in manifest["allowlist"] if p.startswith(PREFIX)):
104 for found in glob.glob(str(root / pattern[len(PREFIX):]), recursive=True, include_hidden=True):
105 rel = PREFIX + Path(found).relative_to(root).as_posix()
106 if Path(found).is_file() and rel not in listed and rel not in withheld and rel not in out["extra"]:
107 out["extra"].append(rel)
108 out["ok"] = bool(out["version_match"] and out["checked"] and not (out["changed"] or out["missing"] or out["extra"]))
109 return out
110
111
112def run(args: list[str], lang: str, *, installed_version: str | None = None,
113 package_dir: Path = PACKAGE_DIR) -> tuple[int, list[str], dict[str, Any] | None]:
114 """The command: (exit code, lines for the person's terminal, the report for --json)."""
115 if installed_version is None:
116 from .. import __version__ as installed_version # noqa: N813 (the version this build runs)
117 rest = [a for a in args if a != "--json"]
118 if rest and not (len(rest) == 2 and rest[0] == "--manifest"):
119 return EXIT_USAGE, [_text("usage", lang)], None
120 given = Path(rest[1]).expanduser() if rest else None
121 try:
122 manifest = load_manifest(given)
123 digest = manifest_sha256(given)
124 except ManifestError as error:
125 return EXIT_FAILED, [_text(str(error), lang)], None
126 except OSError:
127 return EXIT_FAILED, [_text("bad_manifest", lang)], None
128 report = verify(manifest, installed_version=installed_version, package_dir=package_dir)
129 report["manifest_source"] = "bundled" if given is None else "file"
130 report["manifest_sha256"] = digest
131 lines = [_text("title", lang, version=installed_version),
132 _text("manifest", lang, source=_text("source_bundled" if given is None else "source_file", lang), digest=digest)]
133 if not report["version_match"]:
134 lines.append(_text("version_bad", lang, installed=installed_version, version=report["version"]))
135 for key in ("changed", "missing", "extra"):
136 lines += [_text(key, lang, path=p) for p in report[key]]
137 if report["not_installed_here"]:
138 lines.append(_text("not_here", lang, count=len(report["not_installed_here"])))
139 as_json = report if "--json" in args else None
140 if report["ok"]:
141 return EXIT_OK, lines + [_text("ok_bundled" if given is None else "ok", lang, count=len(report["checked"]))], as_json
142 problems = len(report["changed"]) + len(report["missing"]) + len(report["extra"]) + (0 if report["version_match"] else 1)
143 return EXIT_FAILED, lines + [_text("failed", lang, count=max(problems, 1))], as_json