Dashboard › institutional-transition-lab › Session 0XzZzxSQLaAG
0XzZzxSQLaAGJA7bvPerform a fresh, minimal, read-only security audit of only actual decompressed-byte enforcement for issue #4 in /home/byk/Code/institutional-transition-lab. This replaces a resource-accounting reviewer that returned empty twice and is disjoint from declared-size arithmetic. Never edit files or inspect governance records/codings/outcomes/reports/dates/detectors/source adjudication.
Scope only: member stream read amount and loop behavior; actual per-member and aggregate decompressed-byte accounting; short/partial reads; streams producing more or fewer bytes than declared; compression-bomb termination; cleanup/error behavior. Do not inspect central declared-size arithmetic, CRC/required-member identity/content equality, archive names/path/mode/encryption/count, regular-file reads, JSON/pins/hashes, or CLI outputs.
Review only relevant ZIP stream code/constants in src/institution_lab/governance_adjudication.py and narrow tests. Run small read-only probes. Return substantive evidence, never empty. Findings first with exact file:line references and PASS/CONCERN/MUST-FIX/BLOCKED labels; deterministic regression for every defect. End exactly MERGE or DO-NOT-MERGE.
I’ll trace only ZIP member streaming and actual decompressed-byte counters, then run focused read-only tests and synthetic stream probes. I will not inspect the excluded metadata, governance, provenance, or CLI paths.
Found 15 matches /home/byk/Code/institutional-transition-lab/src/institution_lab/governance_adjudication.py: Line 65: MAX_INPUT_BYTES = 16 * 1024 * 1024 Line 66: MAX_ARTIFACT_BYTES = 32 * 1024 * 1024 Line 68: MAX_ARCHIVE_MEMBER_BYTES = 16 * 1024 * 1024 Line 69: MAX_ARCHIVE_EXPANDED_BYTES = 64 * 1024 * 1024 Line 94: def _read_regular_file(path: Path, *, max_bytes: int = MAX_INPUT_BYTES) -> bytes: Line 106: payload = source.read(max_bytes + 1) Line 113: return _bytes_sha256(_read_regular_file(path, max_bytes=MAX_ARTIFACT_BYTES)) Line 188: if sum(info.file_size for info in infos) > MAX_ARCHIVE_EXPANDED_BYTES: Line 194: for member_name, durable_bytes in members.items(): Line 199: if info.file_size > MAX_ARCHIVE_MEMBER_BYTES: Line 202: member_bytes = source.read(MAX_ARCHIVE_MEMBER_BYTES + 1) Line 203: if len(member_bytes) > MAX_ARCHIVE_MEMBER_BYTES: Line 205: if member_bytes != durable_bytes: Line 233: ...
/home/byk/Code/institutional-transition-lab/tests/test_governance_adjudication.py
Found 1 matches /home/byk/Code/institutional-transition-lab/tests/test_governance_adjudication.py: Line 979: def test_committed_partial_fragment_validates_but_cannot_be_the_full_envelope() -> None:
Found 19 matches
/home/byk/Code/institutional-transition-lab/tests/test_governance_adjudication.py:
Line 8: import zipfile
Line 52: "artifact": tmp_path / "artifact.zip",
Line 65: with zipfile.ZipFile(paths["artifact"], "w") as archive:
Line 66: archive.writestr("documents.json", paths["documents"].read_bytes())
Line 67: archive.writestr(
Line 687: artifact = tmp_path / "artifact.zip"
Line 703: with zipfile.ZipFile(artifact, "w") as archive:
Line 704: archive.writestr("documents.json", documents.read_bytes())
Line 705: archive.writestr("v1.2-adjudication-package.json", coding_package.read_bytes())
Line 733: artifact = tmp_path / "artifact.zip"
Line 743: with zipfile.ZipFile(artifact, "w") as archive:
Line 744: archive.writestr("documents.json", b"different documents")
Line 745: archive.writestr("v1.2-adjudication-package.json", coding_package.read_bytes())
Line 890: zipfile.ZipFile(paths["artifact"], "a") as archive,
...
<path>/home/byk/Code/institutional-transition-lab/src/institution_lab/governance_adjudication.py</path>
<type>file</type>
<content>
55: }
56: CLAIM_FIELDS = {
57: "record_class",
58: "event_kind",
59: "title",
60: "announced_on",
61: "effective_on",
62: "affected_scope",
63: "body_patch_relation",
64: }
65: MAX_INPUT_BYTES = 16 * 1024 * 1024
66: MAX_ARTIFACT_BYTES = 32 * 1024 * 1024
67: MAX_ARCHIVE_MEMBERS = 128
68: MAX_ARCHIVE_MEMBER_BYTES = 16 * 1024 * 1024
69: MAX_ARCHIVE_EXPANDED_BYTES = 64 * 1024 * 1024
70:
71:
72: @dataclass(frozen=True)
73: class VerifiedInputBundle:
74: pins: dict[str, Any]
(Showing lines 55-74 of 946. Use offset=75 to continue.)
</content>
<path>/home/byk/Code/institutional-transition-lab/src/institution_lab/governance_adjudication.py</path>
<type>file</type>
<content>
176: for field, value in computed.items():
177: if manifest.get(field) != value:
178: raise ValueError(f"input manifest mismatch: {field}")
179: try:
180: with zipfile.ZipFile(io.BytesIO(artifact)) as archive:
181: infos = archive.infolist()
182: if len(infos) > MAX_ARCHIVE_MEMBERS:
183: raise ValueError("artifact member count exceeds limit")
184: member_counts = Counter(info.filename for info in infos)
185: for member_name, count in member_counts.items():
186: if count != 1:
187: raise ValueError(f"artifact member is not unique: {member_name}")
188: if sum(info.file_size for info in infos) > MAX_ARCHIVE_EXPANDED_BYTES:
189: raise ValueError("artifact expanded size exceeds limit")
190: members = {
191: "documents.json": documents,
192: "v1.2-adjudication-package.json": coding_package,
193: }
194: ...
No files found
Found 3 matches /home/byk/Code/institutional-transition-lab/tests/test_governance_adjudication.py: Line 729: def test_input_manifest_rejects_files_not_from_pinned_artifact( Line 883: def test_input_manifest_rejects_duplicate_artifact_members( Line 908: def test_input_manifest_rejects_excessive_artifact_member_count(
Found 9 matches
/home/byk/Code/institutional-transition-lab/src/institution_lab/governance_adjudication.py:
Line 68: MAX_ARCHIVE_MEMBER_BYTES = 16 * 1024 * 1024
Line 69: MAX_ARCHIVE_EXPANDED_BYTES = 64 * 1024 * 1024
Line 188: if sum(info.file_size for info in infos) > MAX_ARCHIVE_EXPANDED_BYTES:
Line 189: raise ValueError("artifact expanded size exceeds limit")
Line 199: if info.file_size > MAX_ARCHIVE_MEMBER_BYTES:
Line 200: raise ValueError(f"artifact member exceeds size limit: {member_name}")
Line 202: member_bytes = source.read(MAX_ARCHIVE_MEMBER_BYTES + 1)
Line 203: if len(member_bytes) > MAX_ARCHIVE_MEMBER_BYTES:
Line 204: raise ValueError(f"artifact member exceeds size limit: {member_name}")
Found 3 matches /home/byk/Code/institutional-transition-lab/src/institution_lab/governance_adjudication.py: Line 157: def _verify_input_payloads( Line 220: def verify_input_manifest( Line 835: def _validate_output_paths(*, inputs: list[Path], outputs: list[Path]) -> None:
<path>/home/byk/Code/institutional-transition-lab/src/institution_lab/governance_adjudication.py</path> <type>file</type> <content> 157: def _verify_input_payloads( 158: manifest: Any, 159: *, 160: artifact: bytes, 161: documents: bytes, 162: coding_package: bytes, 163: protocol: bytes, 164: coding_schema: bytes, (Showing lines 157-164 of 946. Use offset=165 to continue.) </content>
Python 3.12.3
def read(self, n=-1):
"""Read and return up to n bytes.
If the argument is omitted, None, or negative, data is read and returned until EOF is reached.
"""
if self.closed:
raise ValueError("read from closed file.")
if n is None or n < 0:
buf = self._readbuffer[self._offset:]
self._readbuffer = b''
self._offset = 0
while not self._eof:
buf += self._read1(self.MAX_N)
return buf
end = n + self._offset
if end < len(self._readbuffer):
buf = self._readbuffer[self._offset:end]
self._offset = end
return buf
n = end - len(self._readbuffer)
buf = self._readbuffer[self._offset:]
self._readbuffer = b''
self._offset = 0
while n > 0 and not self._eof:
data = self._read1(n)
if n < len(data):
self._readbuffer = data
...
No files found
Found 6 matches /home/byk/Code/institutional-transition-lab/tests/test_governance_adjudication.py: Line 652: def test_input_manifest_rejects_self_consistent_substitute(field: str) -> None: Line 683: def test_input_manifest_rejects_changed_file_bytes( Line 729: def test_input_manifest_rejects_files_not_from_pinned_artifact( Line 870: def test_input_manifest_rejects_non_object() -> None: Line 883: def test_input_manifest_rejects_duplicate_artifact_members( Line 908: def test_input_manifest_rejects_excessive_artifact_member_count(
def _read2(self, n):
if self._compress_left <= 0:
return b''
n = max(n, self.MIN_READ_SIZE)
n = min(n, self._compress_left)
data = self._fileobj.read(n)
self._compress_left -= len(data)
if not data:
raise EOFError
if self._decrypter is not None:
data = self._decrypter(data)
return data
class LZMADecompressor:
def __init__(self):
self._decomp = None
self._unconsumed = b''
self.eof = False
def decompress(self, data):
if self._decomp is None:
self._unconsumed += data
if len(self._unconsumed) <= 4:
return b''
psize, = struct.unpack('<H', self._unconsumed[2:4])
if len(self._unconsumed) <= 4 + psize:
return b''
self._decomp = lzma.LZMADecompressor(lzma.FORMAT_RAW, filters=[
lzma._decode_filter_properties(lzma.FILTER_LZMA1,
self._unconsumed[4:4 + psize])
])
data = self._unconsumed[4 + psize:]
del self._unconsumed
result = self._decomp.decompress(data)
self.eof = self._decomp.eof
return result
Traceback (most recent call last): File "<stdin>", line 7, in <module> ModuleNotFoundError: No module named 'institution_lab'
more-than-declared encoded_expansion=16777217 declared=1 returned=1 next_read=0 peak_traced=47587880 fewer-than-declared encoded_expansion=1 declared=8 returned=1 next_read=0 partial-compressed-reads returned=32768 underlying_partial_reads=46
read-error OSError source_closed=True archive_closed=True
No files found
No files found
MAX_ARCHIVE_MEMBER_BYTES and MAX_ARCHIVE_EXPANDED_BYTES are defined at src/institution_lab/governance_adjudication.py:68-69, but the stream loop only:
source.read(MAX_ARCHIVE_MEMBER_BYTES + 1) at :201-202;:203-204;:194 and :201-204.CPython 3.12.3’s ZipExtFile clips returned data to the declared size. Its BZIP2 and LZMA paths can decompress the entire supplied compressed chunk before clipping. Therefore len(member_bytes) does not measure actual decoder output.
An in-memory BZIP2 probe produced:
encoded_expansion=16777217 declared=1 returned=1 next_read=0 peak_traced=47587880
The true expansion exceeded the 16 MiB member limit, but line 203 observed one byte. The same behavior leaves aggregate decompression unbounded and permits compression-bomb CPU/memory exhaustion before either check runs.
A second probe showed that a stream producing fewer bytes than declared also reaches EOF without a stream error:
encoded_expansion=1 declared=8 returned=1 next_read=0
Deterministic regressions:
monkeypatch; construct BZIP2 and LZMA streams whose expansion is member_limit + 1 but whose declared length matches a short valid prefix. Require rejection based on actual expansion.For the concrete ZipExtFile returned at src/institution_lab/governance_adjudication.py:201, the one-shot call at ...
Date: September 9, 2026 * 🔴 (05:38) User stated issue #4 in `/home/byk/Code/institutional-transition-lab` concerns actual decompressed-byte enforcement, is disjoint from declared-size arithmetic, and replaces a resource-accounting review that returned empty twice. * 🔴 [requested-security-audit] (05:38) User requested a fresh, minimal, substantive, read-only security audit limited to actual ZIP …