night evidence: both Nextcloud upload trees 3031/3033 byte-identical against the night manifest (the 2 missing are the uploader's by-design skips)
gates / gates (push) Successful in 15m49s

This commit is contained in:
2026-10-22 01:12:36 +02:00
parent dee26da3fa
commit 97f088ec02
3 changed files with 3474 additions and 0 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,6 @@
nextcloud Csalad_feltoltes: manifest 3033 files; on the box 3031; byte-identical 3031; missing/different 2; extra 0
MISSING /Csalad_feltoltes/nagy_fajl_1_5GB.bin
MISSING /Csalad_feltoltes/Kulonleges_nevek/link_a_nagy_fajlra
nextcloud Csalad_proof1: manifest 3033 files; on the box 3031; byte-identical 3031; missing/different 2; extra 0
MISSING /Csalad_proof1/nagy_fajl_1_5GB.bin
MISSING /Csalad_proof1/Kulonleges_nevek/link_a_nagy_fajlra
@@ -0,0 +1,53 @@
#!/usr/bin/env python3
"""nc_compare.py (night 2026-10-21 copy: folder as argv[1], the night manifest) — every file under Ödön's „Csalad" folder through Nextcloud's own WebDAV door (the box's LAN address with
the Host header; TLS not verified, the rehearsal's tester4.test has no DNS), sha256 against the rehearsal's A5 manifest.
Env: REHEARSAL_2026_10_20_ODON_PW (under `sec run`). Prints counts and up to 15 differing names; never a secret."""
import base64, hashlib, http.client, os, ssl, sys, unicodedata, urllib.parse, xml.etree.ElementTree as ET
import sys
IP, HOST = "192.168.0.125", "cloud.tester4.test"
FOLDER = sys.argv[1] # night 2026-10-21: the uploaded folder (Csalad_feltoltes / Csalad_proof1)
MAN = "/mnt/5_hdd/felhom.eu/git/felhom.eu/documentation/audits/night-2026-10-21/P1-soak/05-MANIFEST-night.tsv"
auth = "Basic " + base64.b64encode(("odon:" + os.environ["REHEARSAL_2026_10_20_ODON_PW"]).encode()).decode()
ctx = ssl._create_unverified_context()
def req(method, path, body=None, extra=None):
c = http.client.HTTPSConnection(IP, 443, context=ctx, timeout=300)
h = {"Host": HOST, "Authorization": auth}; h.update(extra or {})
c.request(method, path, body=body, headers=h); r = c.getresponse(); data = r.read(); c.close()
return r.status, data
base = "/remote.php/dav/files/odon"
files = {}
def walk(path):
st, data = req("PROPFIND", urllib.parse.quote(base + path), b'<?xml version="1.0"?><d:propfind xmlns:d="DAV:"><d:prop><d:resourcetype/></d:prop></d:propfind>', {"Depth": "1"})
if st != 207:
print("PROPFIND", path, st); return
for resp in ET.fromstring(data).findall("{DAV:}response"):
href = urllib.parse.unquote(resp.find("{DAV:}href").text)
rel = href[len(base):]
if rel.rstrip("/") == path.rstrip("/"):
continue
if resp.find(".//{DAV:}collection") is not None:
walk(rel)
else:
files[rel] = href
walk("/" + FOLDER + "/")
want = {}
for line in open(MAN, encoding="utf-8"):
p = line.rstrip("\n").split("\t")
if p[0].startswith("nextcloud/Csalad/"):
want[unicodedata.normalize("NFC", "/" + FOLDER + p[0][len("nextcloud/Csalad"):])] = p[2]
same, differ, extra = 0, [], []
got = {}
for rel, href in files.items():
st, data = req("GET", urllib.parse.quote(href))
got[unicodedata.normalize("NFC", rel)] = hashlib.sha256(data).hexdigest() if st == 200 else f"HTTP{st}"
for k, h in want.items():
if got.get(k) == h:
same += 1
else:
differ.append(("MISSING" if k not in got else "DIFFERS") + " " + k)
extra = [k for k in got if k not in want]
print(f"nextcloud {FOLDER}: manifest {len(want)} files; on the box {len(got)}; byte-identical {same}; missing/different {len(differ)}; extra {len(extra)}")
for d in differ[:15]:
print(" ", d)
for e in extra[:8]:
print(" EXTRA", e)