noqt commited on
Commit
a2ad45a
·
verified ·
1 Parent(s): 80ebc34

Sync GitHub source 53cbcb39510694c6b7d9d13720da39d07a1d4b37

Browse files

Canonical source: https://github.com/noqt/Lumi-Eggcracker/commit/53cbcb39510694c6b7d9d13720da39d07a1d4b37

HUGGINGFACE_MANIFEST.json CHANGED
@@ -37,7 +37,7 @@
37
  "size": 10537
38
  },
39
  "README.md": {
40
- "sha256": "416a714f25f243153fd6918a384826f2afdacb4f0aee2c61a16c0508e7d09451",
41
  "size": 48062
42
  },
43
  "RELEASE_NOTES.md": {
@@ -57,8 +57,8 @@
57
  "size": 1970
58
  },
59
  "TRY_IT.md": {
60
- "sha256": "60354eb8599bea8bceadb272be3cf8b34f50d58de882f691fe4eed13d008c21d",
61
- "size": 20535
62
  },
63
  "actions/validate-hosted-proof-receipt/action.yml": {
64
  "sha256": "4f66f6bfe972a945cdb686a570f51aeb7a474c48986608c9de862dfb6cf27ab3",
@@ -109,11 +109,11 @@
109
  "size": 1704
110
  },
111
  "examples/gguf-file/lumi-eggcracker-gguf-file.pyz": {
112
- "sha256": "199b651761743d6816970d7c3e0becf9036105670f85431bdeab014ca5683b2b",
113
- "size": 89855
114
  },
115
  "examples/gguf-file/lumi-eggcracker-gguf-file.pyz.sha256": {
116
- "sha256": "e6fda433da2bfd326069526613878144b6f3bafdfa8014122f96ec51cd074919",
117
  "size": 96
118
  },
119
  "examples/observe-first/benign.json": {
@@ -217,7 +217,7 @@
217
  "size": 4101
218
  },
219
  "index.html": {
220
- "sha256": "62121afdef8a9716842c192a71d747e51dbd7b68c0e9173aaca4c0847cc124bd",
221
  "size": 23351
222
  },
223
  "integrations/prometheus/eggcracker.rules.yml": {
@@ -265,7 +265,7 @@
265
  "size": 12375
266
  },
267
  "scripts/build_gguf_file_zipapp.py": {
268
- "sha256": "6dd0886496e1fd01dd9e8817d2870b36690f83635694194aeb315970c5c34f0e",
269
  "size": 13435
270
  },
271
  "scripts/build_huggingface_surface.py": {
@@ -513,8 +513,8 @@
513
  "size": 1505
514
  },
515
  "src/lumi_eggcracker/gguf_file_observe.py": {
516
- "sha256": "21a267f05a2920087d1518097292b91b38c3f35ba0b986e20f347cf98679fd48",
517
- "size": 14092
518
  },
519
  "src/lumi_eggcracker/hosted_proof.py": {
520
  "sha256": "7c2cf795d02eed4e35f0e238f455e3afbd52aeef146df08a9616af3275b0a075",
@@ -697,12 +697,12 @@
697
  "size": 78910
698
  },
699
  "tests/test_gguf_file_observe.py": {
700
- "sha256": "c2b7024ef21e0971f1b4dbc2b05c6dee5c1fe939e9a22c95d0585ade347a3a78",
701
- "size": 9951
702
  },
703
  "tests/test_gguf_file_zipapp.py": {
704
- "sha256": "cd9c019d65c08d2ca320a7b0a1886b4f8cdda481ace50ff1e80108fd8b2ebbee",
705
- "size": 11884
706
  },
707
  "tests/test_hosted_probe_result_form.py": {
708
  "sha256": "08d8e0bd53207712620363c6a38b734c66e47c33b2b362f0548f2f5453b14ea5",
@@ -903,6 +903,6 @@
903
  },
904
  "schema": "noqt.huggingface_manifest.v1",
905
  "source_repository": "https://github.com/noqt/Lumi-Eggcracker",
906
- "source_revision": "5346f7920d4d4de4ae92177110867b49f8935a2c",
907
- "source_url": "https://github.com/noqt/Lumi-Eggcracker/commit/5346f7920d4d4de4ae92177110867b49f8935a2c"
908
  }
 
37
  "size": 10537
38
  },
39
  "README.md": {
40
+ "sha256": "d0ed57b2b23db58fcb59a5b9a59696355424dc4af805b5f35289029782d4713f",
41
  "size": 48062
42
  },
43
  "RELEASE_NOTES.md": {
 
57
  "size": 1970
58
  },
59
  "TRY_IT.md": {
60
+ "sha256": "4d255dee589555818019e5824ba646bcbc341670f994c6b7cf783880a2df43f0",
61
+ "size": 21557
62
  },
63
  "actions/validate-hosted-proof-receipt/action.yml": {
64
  "sha256": "4f66f6bfe972a945cdb686a570f51aeb7a474c48986608c9de862dfb6cf27ab3",
 
109
  "size": 1704
110
  },
111
  "examples/gguf-file/lumi-eggcracker-gguf-file.pyz": {
112
+ "sha256": "1b93a8705325c5adaaaa1f49ef1f76a81bf080ad7ed4c73dcb61731c223026c0",
113
+ "size": 93453
114
  },
115
  "examples/gguf-file/lumi-eggcracker-gguf-file.pyz.sha256": {
116
+ "sha256": "7b6e4732ac6a08edc2f46bfed0d6b9fcd325088b9e574adad4ea30253fa8e61a",
117
  "size": 96
118
  },
119
  "examples/observe-first/benign.json": {
 
217
  "size": 4101
218
  },
219
  "index.html": {
220
+ "sha256": "9d37751d0fff2aa127d48e7b57d3a6c08095b910017010f21e4e8697824dac13",
221
  "size": 23351
222
  },
223
  "integrations/prometheus/eggcracker.rules.yml": {
 
265
  "size": 12375
266
  },
267
  "scripts/build_gguf_file_zipapp.py": {
268
+ "sha256": "b46c85b0e9dd0f50ad383588579d89a2570bf86f84d5bd6dcd3518a8db1a89d1",
269
  "size": 13435
270
  },
271
  "scripts/build_huggingface_surface.py": {
 
513
  "size": 1505
514
  },
515
  "src/lumi_eggcracker/gguf_file_observe.py": {
516
+ "sha256": "239b4901683c6e60504bd36985e1b6b2f3b3645c913cda8cc94d631916418471",
517
+ "size": 17690
518
  },
519
  "src/lumi_eggcracker/hosted_proof.py": {
520
  "sha256": "7c2cf795d02eed4e35f0e238f455e3afbd52aeef146df08a9616af3275b0a075",
 
697
  "size": 78910
698
  },
699
  "tests/test_gguf_file_observe.py": {
700
+ "sha256": "1f762898d21c9e1be154c712889f2781565550b0255608d0eacc992f7d4f2ebf",
701
+ "size": 18747
702
  },
703
  "tests/test_gguf_file_zipapp.py": {
704
+ "sha256": "375563e84705594ee7853ec06b989ea6af7b4de7308f738789445094a6d508dd",
705
+ "size": 16674
706
  },
707
  "tests/test_hosted_probe_result_form.py": {
708
  "sha256": "08d8e0bd53207712620363c6a38b734c66e47c33b2b362f0548f2f5453b14ea5",
 
903
  },
904
  "schema": "noqt.huggingface_manifest.v1",
905
  "source_repository": "https://github.com/noqt/Lumi-Eggcracker",
906
+ "source_revision": "53cbcb39510694c6b7d9d13720da39d07a1d4b37",
907
+ "source_url": "https://github.com/noqt/Lumi-Eggcracker/commit/53cbcb39510694c6b7d9d13720da39d07a1d4b37"
908
  }
HUGGINGFACE_SYNC.json CHANGED
@@ -1,6 +1,6 @@
1
  {
2
  "manifest": "HUGGINGFACE_MANIFEST.json",
3
- "manifest_sha256": "4f1ba2c7d5a0e352485b57b460df2762090293020e71b18ac1bdc5abdf7339a3",
4
  "mirrored_files": 210,
5
  "mode": "DERIVED_READ_ONLY_MIRROR",
6
  "release_reference": {
@@ -65,7 +65,7 @@
65
  },
66
  "schema": "noqt.huggingface_sync.v1",
67
  "source_repository": "https://github.com/noqt/Lumi-Eggcracker",
68
- "source_revision": "5346f7920d4d4de4ae92177110867b49f8935a2c",
69
- "source_url": "https://github.com/noqt/Lumi-Eggcracker/commit/5346f7920d4d4de4ae92177110867b49f8935a2c",
70
  "target": "https://huggingface.co/spaces/noqt/eggcracker"
71
  }
 
1
  {
2
  "manifest": "HUGGINGFACE_MANIFEST.json",
3
+ "manifest_sha256": "59771665acdc47f0898a22a4e5c5b7b6a0a6fadb78df37885909562d2a0fbd4c",
4
  "mirrored_files": 210,
5
  "mode": "DERIVED_READ_ONLY_MIRROR",
6
  "release_reference": {
 
65
  },
66
  "schema": "noqt.huggingface_sync.v1",
67
  "source_repository": "https://github.com/noqt/Lumi-Eggcracker",
68
+ "source_revision": "53cbcb39510694c6b7d9d13720da39d07a1d4b37",
69
+ "source_url": "https://github.com/noqt/Lumi-Eggcracker/commit/53cbcb39510694c6b7d9d13720da39d07a1d4b37",
70
  "target": "https://huggingface.co/spaces/noqt/eggcracker"
71
  }
README.md CHANGED
@@ -11,7 +11,7 @@ short_description: Native Linux kill switch for supported local-AI workloads
11
  ---
12
 
13
  > Official noqt Hugging Face distribution, generated from GitHub commit
14
- > [`5346f7920d4d`](https://github.com/noqt/Lumi-Eggcracker/commit/5346f7920d4d4de4ae92177110867b49f8935a2c). This Space distributes the source for
15
  > discovery and cloning; Eggcracker itself runs on a supported native Linux
16
  > host, not on Hugging Face. A snapshot is called current only after the
17
  > release-linked sync job verifies its returned Hub commit and full manifest.
 
11
  ---
12
 
13
  > Official noqt Hugging Face distribution, generated from GitHub commit
14
+ > [`53cbcb395106`](https://github.com/noqt/Lumi-Eggcracker/commit/53cbcb39510694c6b7d9d13720da39d07a1d4b37). This Space distributes the source for
15
  > discovery and cloning; Eggcracker itself runs on a supported native Linux
16
  > host, not on Hugging Face. A snapshot is called current only after the
17
  > release-linked sync job verifies its returned Hub commit and full manifest.
TRY_IT.md CHANGED
@@ -169,6 +169,10 @@ bucket, and a SHA-256 digest of only the inspected prefix; it is not a full-file
169
  hash. Runtime and topology evidence remain empty, and file content alone does
170
  not complete an Eggcracker profile. The observer reads only the selected
171
  bounded regular file and performs no actuation.
 
 
 
 
172
 
173
  This source-only preview is unreleased and outside signed v1.0.10 and v1.0.11.
174
  It is not native-qualified and does not establish workload identity,
@@ -193,6 +197,18 @@ $env:PYTHONPATH = "src"
193
  python -m lumi_eggcracker.gguf_file_observe path\to\model.gguf
194
  ```
195
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  Successful output reports only facts read from that selected file: the GGUF
197
  version and content evidence ID, a size bucket, the number of inspected prefix
198
  bytes, and a SHA-256 digest whose scope is explicitly `first_prefix_only`.
 
169
  hash. Runtime and topology evidence remain empty, and file content alone does
170
  not complete an Eggcracker profile. The observer reads only the selected
171
  bounded regular file and performs no actuation.
172
+ Refusals from the downloaded archive use the same fixed `rc=2` contract
173
+ described in the source-checkout section: pre-output refusals leave stdout
174
+ empty, and selected paths or exception details are not reported. A failure
175
+ after output has started is not presented as a rollback.
176
 
177
  This source-only preview is unreleased and outside signed v1.0.10 and v1.0.11.
178
  It is not native-qualified and does not establish workload identity,
 
197
  python -m lumi_eggcracker.gguf_file_observe path\to\model.gguf
198
  ```
199
 
200
+ For this source-checkout observer, a refusal exits with status `2` and writes
201
+ one fixed ASCII token to stderr: `USAGE`,
202
+ `FILE_UNAVAILABLE_OR_UNSUPPORTED_TYPE`, `NOT_USABLE_GGUF`,
203
+ `FILE_CHANGED_DURING_OBSERVATION`, or `INTERNAL_REPORT_FAILURE`. The selected
204
+ path and exception details are never included. Stdout is empty when refusal
205
+ happens before report output starts; if output has already started and then
206
+ fails, the observer does not claim that partial output was rolled back.
207
+ An initially accessible regular file shorter than the fixed minimum is
208
+ `NOT_USABLE_GGUF`; an oversized selection remains
209
+ `FILE_UNAVAILABLE_OR_UNSUPPORTED_TYPE`. Parser faults are categorized only
210
+ after the safe post-state checks, so an evidenced mutation wins.
211
+
212
  Successful output reports only facts read from that selected file: the GGUF
213
  version and content evidence ID, a size bucket, the number of inspected prefix
214
  bytes, and a SHA-256 digest whose scope is explicitly `first_prefix_only`.
examples/gguf-file/lumi-eggcracker-gguf-file.pyz CHANGED
Binary files a/examples/gguf-file/lumi-eggcracker-gguf-file.pyz and b/examples/gguf-file/lumi-eggcracker-gguf-file.pyz differ
 
examples/gguf-file/lumi-eggcracker-gguf-file.pyz.sha256 CHANGED
@@ -1 +1 @@
1
- 199b651761743d6816970d7c3e0becf9036105670f85431bdeab014ca5683b2b lumi-eggcracker-gguf-file.pyz
 
1
+ 1b93a8705325c5adaaaa1f49ef1f76a81bf080ad7ed4c73dcb61731c223026c0 lumi-eggcracker-gguf-file.pyz
index.html CHANGED
@@ -4,7 +4,7 @@
4
  <meta charset="utf-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
  <meta name="description" content="Lumi Eggcracker is noqt's native Linux kill switch for unapproved supported local-AI workloads. Clone the complete source from Hugging Face.">
7
- <meta name="noqt-source-revision" content="5346f7920d4d4de4ae92177110867b49f8935a2c">
8
  <meta name="theme-color" content="#090a0c">
9
  <title>Lumi Eggcracker — Native Linux AI kill switch</title>
10
  <style>
@@ -652,7 +652,7 @@ sudo /usr/bin/python3 -I -S scripts/first_kill.py \
652
  <section>
653
  <div class="shell source-bar">
654
  <div>
655
- <div class="source-id">SOURCE COMMIT · 5346f7920d4d</div>
656
  <h2>Inspect every line.</h2>
657
  <p>Complete source, tests, qualification documents and reproducible proof tooling are distributed in this repository.</p>
658
  </div>
 
4
  <meta charset="utf-8">
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
6
  <meta name="description" content="Lumi Eggcracker is noqt's native Linux kill switch for unapproved supported local-AI workloads. Clone the complete source from Hugging Face.">
7
+ <meta name="noqt-source-revision" content="53cbcb39510694c6b7d9d13720da39d07a1d4b37">
8
  <meta name="theme-color" content="#090a0c">
9
  <title>Lumi Eggcracker — Native Linux AI kill switch</title>
10
  <style>
 
652
  <section>
653
  <div class="shell source-bar">
654
  <div>
655
+ <div class="source-id">SOURCE COMMIT · 53cbcb395106</div>
656
  <h2>Inspect every line.</h2>
657
  <p>Complete source, tests, qualification documents and reproducible proof tooling are distributed in this repository.</p>
658
  </div>
scripts/build_gguf_file_zipapp.py CHANGED
@@ -13,7 +13,7 @@ import zipfile
13
  from pathlib import Path
14
 
15
  ROOT = Path(__file__).resolve().parents[1]
16
- SOURCE_COMMIT = "5e7e6070fa973016f8ef73e44843e2c4cbbb1f06"
17
  MANIFEST_NAME = "SOURCE-MANIFEST.json"
18
  MANIFEST_SCHEMA = "lumi-eggcracker.gguf-file-source-manifest.v1"
19
  MAIN_MODULE = (
@@ -62,7 +62,7 @@ SOURCE_INPUTS = (
62
  (
63
  "src/lumi_eggcracker/gguf_file_observe.py",
64
  "lumi_eggcracker/gguf_file_observe.py",
65
- "7463a29d883a324b5c05382c2874f175f5bb4aa0",
66
  ),
67
  (
68
  "src/lumi_eggcracker/jsonio.py",
 
13
  from pathlib import Path
14
 
15
  ROOT = Path(__file__).resolve().parents[1]
16
+ SOURCE_COMMIT = "7b9b1dcc7242c47c64fcec7d493f1aa5bfc158ef"
17
  MANIFEST_NAME = "SOURCE-MANIFEST.json"
18
  MANIFEST_SCHEMA = "lumi-eggcracker.gguf-file-source-manifest.v1"
19
  MAIN_MODULE = (
 
62
  (
63
  "src/lumi_eggcracker/gguf_file_observe.py",
64
  "lumi_eggcracker/gguf_file_observe.py",
65
+ "5118cd45cf9183d59c8a07abe468a4045f42d4a0",
66
  ),
67
  (
68
  "src/lumi_eggcracker/jsonio.py",
src/lumi_eggcracker/gguf_file_observe.py CHANGED
@@ -33,7 +33,35 @@ MAX_PROFILE_GROUPS = 8
33
  MAX_GROUP_VALUES = 16
34
  MAX_LIST_ITEMS = 32
35
 
36
- ERROR_TEXT = "file evidence observation refused\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  CONTENT_GROUPS = ("MODEL_CONTENT", "MODEL_RUNTIME", "MODEL_TOPOLOGY")
38
  LIMITATIONS = (
39
  "file evidence does not establish runtime or topology",
@@ -83,15 +111,15 @@ def _path_argument(path: str | os.PathLike[str]) -> str | bytes:
83
  try:
84
  value = os.fspath(path)
85
  except (TypeError, ValueError) as error:
86
- raise JsonInputError("selected path is invalid") from error
87
  if not isinstance(value, (str, bytes)) or not value:
88
- raise JsonInputError("selected path is invalid")
89
  try:
90
  encoded = os.fsencode(value)
91
  except (TypeError, UnicodeError) as error:
92
- raise JsonInputError("selected path is invalid") from error
93
  if not encoded or len(encoded) > MAX_PATH_BYTES or b"\0" in encoded:
94
- raise JsonInputError("selected path exceeds the fixed limit")
95
  return value
96
 
97
 
@@ -110,7 +138,7 @@ def _stable_identity(metadata: os.stat_result) -> _StableIdentity:
110
  int(metadata.st_mode),
111
  )
112
  except (AttributeError, TypeError, ValueError, OverflowError) as error:
113
- raise JsonInputError("file identity is unavailable") from error
114
 
115
 
116
  def _change_marker(metadata: os.stat_result) -> _ChangeMarker:
@@ -118,36 +146,40 @@ def _change_marker(metadata: os.stat_result) -> _ChangeMarker:
118
  try:
119
  mtime_ns = int(metadata.st_mtime_ns)
120
  except (AttributeError, TypeError, ValueError, OverflowError) as error:
121
- raise JsonInputError("file change marker is unavailable") from error
122
  return _ChangeMarker(identity, mtime_ns)
123
 
124
 
125
  def _check_regular(metadata: os.stat_result) -> _StableIdentity:
126
  if stat.S_ISLNK(metadata.st_mode) or _is_reparse(metadata):
127
- raise JsonInputError("selected path must not be a link or reparse point")
128
  if not stat.S_ISREG(metadata.st_mode):
129
- raise JsonInputError("selected path must be a regular file")
130
  identity = _stable_identity(metadata)
131
- if not MIN_FILE_BYTES <= identity.size <= MAX_FILE_BYTES:
132
- raise JsonInputError("selected file size is outside the fixed limit")
 
 
133
  return identity
134
 
135
 
136
- def _lstat(path: str | bytes) -> os.stat_result:
137
  try:
138
  metadata = os.lstat(path)
139
  except (OSError, ValueError) as error:
140
- raise JsonInputError("selected file cannot be inspected") from error
141
- _check_regular(metadata)
 
142
  return metadata
143
 
144
 
145
- def _fstat(descriptor: int) -> os.stat_result:
146
  try:
147
  metadata = os.fstat(descriptor)
148
  except (OSError, ValueError) as error:
149
- raise JsonInputError("opened file identity is unavailable") from error
150
- _check_regular(metadata)
 
151
  return metadata
152
 
153
 
@@ -164,7 +196,7 @@ def _open_selected(path: str | bytes) -> int:
164
  try:
165
  return os.open(path, _open_flags())
166
  except (OSError, ValueError) as error:
167
- raise JsonInputError("selected file cannot be opened") from error
168
 
169
 
170
  def _version(evidence: ArtifactEvidence) -> int:
@@ -300,28 +332,70 @@ def observe_file(path: str | os.PathLike[str]) -> dict[str, object]:
300
  path_identity = _stable_identity(path_before)
301
  path_marker = _change_marker(path_before)
302
  descriptor = _open_selected(selected)
 
 
303
  try:
304
  fd_before = _fstat(descriptor)
305
  if _stable_identity(fd_before) != path_identity:
306
- raise JsonInputError("selected path changed while opening")
307
  fd_marker = _change_marker(fd_before)
308
- evidence = validate_gguf_fd(descriptor)
309
- fd_after = _fstat(descriptor)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  if _change_marker(fd_after) != fd_marker:
311
- raise JsonInputError("selected file changed during observation")
312
- path_after = _lstat(selected)
313
- if _stable_identity(path_after) != path_identity:
314
- raise JsonInputError("selected path changed during observation")
 
 
315
  if _change_marker(path_after) != path_marker:
316
- raise JsonInputError("selected file changed during observation")
317
- if _stable_identity(fd_after) != _stable_identity(path_after):
318
- raise JsonInputError("selected path changed during observation")
 
 
 
319
  finally:
320
  try:
321
  os.close(descriptor)
322
  except OSError:
323
  pass
324
- return _report(evidence, load_bundled())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
 
326
 
327
  def observe(path: str | os.PathLike[str]) -> dict[str, object]:
@@ -334,19 +408,29 @@ def _emit_report(report: dict[str, object]) -> None:
334
  try:
335
  raw = canonical_bytes(report)
336
  except (TypeError, ValueError, JsonInputError) as error:
337
- raise JsonInputError("report encoding failed") from error
338
  if len(raw) > MAX_OUTPUT_BYTES:
339
- raise JsonInputError("report exceeds the fixed output limit")
340
  try:
341
- sys.stdout.write(raw.decode("ascii"))
342
- except (UnicodeError, OSError) as error:
343
- raise JsonInputError("report output failed") from error
344
-
345
-
346
- def _emit_error() -> None:
347
- message = ERROR_TEXT
 
 
 
 
 
 
 
 
 
 
348
  if len(message.encode("ascii")) > MAX_ERROR_BYTES:
349
- message = "file evidence error\n"
350
  try:
351
  sys.stderr.write(message)
352
  except OSError:
@@ -358,16 +442,27 @@ def main(argv: list[str] | None = None) -> int:
358
 
359
  arguments = sys.argv[1:] if argv is None else argv
360
  if not isinstance(arguments, list) or len(arguments) != 1:
361
- _emit_error()
362
  return 2
363
  try:
364
  report = observe_file(arguments[0])
365
  _emit_report(report)
366
- except (OSError, TypeError, ValueError, OverflowError):
367
- # The command boundary intentionally reveals neither parser details nor
368
- # selected-path data. KeyboardInterrupt/SystemExit remain outside this
369
- # ordinary failure path.
370
- _emit_error()
 
 
 
 
 
 
 
 
 
 
 
371
  return 2
372
  return 0
373
 
 
33
  MAX_GROUP_VALUES = 16
34
  MAX_LIST_ITEMS = 32
35
 
36
+ USAGE = "USAGE"
37
+ FILE_UNAVAILABLE_OR_UNSUPPORTED_TYPE = "FILE_UNAVAILABLE_OR_UNSUPPORTED_TYPE"
38
+ NOT_USABLE_GGUF = "NOT_USABLE_GGUF"
39
+ FILE_CHANGED_DURING_OBSERVATION = "FILE_CHANGED_DURING_OBSERVATION"
40
+ INTERNAL_REPORT_FAILURE = "INTERNAL_REPORT_FAILURE"
41
+
42
+
43
+ class _ObservationFailure(JsonInputError):
44
+ """Typed refusal boundary for the command-line observer."""
45
+
46
+ token = INTERNAL_REPORT_FAILURE
47
+
48
+
49
+ class _FileUnavailableFailure(_ObservationFailure):
50
+ token = FILE_UNAVAILABLE_OR_UNSUPPORTED_TYPE
51
+
52
+
53
+ class _NotUsableGgufFailure(_ObservationFailure):
54
+ token = NOT_USABLE_GGUF
55
+
56
+
57
+ class _FileChangedFailure(_ObservationFailure):
58
+ token = FILE_CHANGED_DURING_OBSERVATION
59
+
60
+
61
+ class _InternalReportFailure(_ObservationFailure):
62
+ token = INTERNAL_REPORT_FAILURE
63
+
64
+
65
  CONTENT_GROUPS = ("MODEL_CONTENT", "MODEL_RUNTIME", "MODEL_TOPOLOGY")
66
  LIMITATIONS = (
67
  "file evidence does not establish runtime or topology",
 
111
  try:
112
  value = os.fspath(path)
113
  except (TypeError, ValueError) as error:
114
+ raise _FileUnavailableFailure("selected path is invalid") from error
115
  if not isinstance(value, (str, bytes)) or not value:
116
+ raise _FileUnavailableFailure("selected path is invalid")
117
  try:
118
  encoded = os.fsencode(value)
119
  except (TypeError, UnicodeError) as error:
120
+ raise _FileUnavailableFailure("selected path is invalid") from error
121
  if not encoded or len(encoded) > MAX_PATH_BYTES or b"\0" in encoded:
122
+ raise _FileUnavailableFailure("selected path exceeds the fixed limit")
123
  return value
124
 
125
 
 
138
  int(metadata.st_mode),
139
  )
140
  except (AttributeError, TypeError, ValueError, OverflowError) as error:
141
+ raise _FileUnavailableFailure("file identity is unavailable") from error
142
 
143
 
144
  def _change_marker(metadata: os.stat_result) -> _ChangeMarker:
 
146
  try:
147
  mtime_ns = int(metadata.st_mtime_ns)
148
  except (AttributeError, TypeError, ValueError, OverflowError) as error:
149
+ raise _FileUnavailableFailure("file change marker is unavailable") from error
150
  return _ChangeMarker(identity, mtime_ns)
151
 
152
 
153
  def _check_regular(metadata: os.stat_result) -> _StableIdentity:
154
  if stat.S_ISLNK(metadata.st_mode) or _is_reparse(metadata):
155
+ raise _FileUnavailableFailure("selected path must not be a link or reparse point")
156
  if not stat.S_ISREG(metadata.st_mode):
157
+ raise _FileUnavailableFailure("selected path must be a regular file")
158
  identity = _stable_identity(metadata)
159
+ if identity.size < MIN_FILE_BYTES:
160
+ raise _NotUsableGgufFailure("selected file is too small to be GGUF")
161
+ if identity.size > MAX_FILE_BYTES:
162
+ raise _FileUnavailableFailure("selected file size is outside the fixed limit")
163
  return identity
164
 
165
 
166
+ def _lstat(path: str | bytes, *, check: bool = True) -> os.stat_result:
167
  try:
168
  metadata = os.lstat(path)
169
  except (OSError, ValueError) as error:
170
+ raise _FileUnavailableFailure("selected file cannot be inspected") from error
171
+ if check:
172
+ _check_regular(metadata)
173
  return metadata
174
 
175
 
176
+ def _fstat(descriptor: int, *, check: bool = True) -> os.stat_result:
177
  try:
178
  metadata = os.fstat(descriptor)
179
  except (OSError, ValueError) as error:
180
+ raise _FileUnavailableFailure("opened file identity is unavailable") from error
181
+ if check:
182
+ _check_regular(metadata)
183
  return metadata
184
 
185
 
 
196
  try:
197
  return os.open(path, _open_flags())
198
  except (OSError, ValueError) as error:
199
+ raise _FileUnavailableFailure("selected file cannot be opened") from error
200
 
201
 
202
  def _version(evidence: ArtifactEvidence) -> int:
 
332
  path_identity = _stable_identity(path_before)
333
  path_marker = _change_marker(path_before)
334
  descriptor = _open_selected(selected)
335
+ evidence: ArtifactEvidence | None = None
336
+ parser_failure: Exception | None = None
337
  try:
338
  fd_before = _fstat(descriptor)
339
  if _stable_identity(fd_before) != path_identity:
340
+ raise _FileChangedFailure("selected path changed while opening")
341
  fd_marker = _change_marker(fd_before)
342
+ try:
343
+ evidence = validate_gguf_fd(descriptor)
344
+ except (
345
+ JsonInputError,
346
+ OSError,
347
+ TypeError,
348
+ ValueError,
349
+ OverflowError,
350
+ AttributeError,
351
+ RuntimeError,
352
+ ) as error:
353
+ # Parser results are deliberately held until the existing safe
354
+ # post-state checks complete. A parser refusal is not evidence of
355
+ # a malformed file when the selected object cannot be rechecked.
356
+ parser_failure = error
357
+ fd_after = _fstat(descriptor, check=False)
358
+ fd_after_identity = _stable_identity(fd_after)
359
  if _change_marker(fd_after) != fd_marker:
360
+ raise _FileChangedFailure("selected file changed during observation")
361
+ _check_regular(fd_after)
362
+ path_after = _lstat(selected, check=False)
363
+ path_after_identity = _stable_identity(path_after)
364
+ if path_after_identity != path_identity:
365
+ raise _FileChangedFailure("selected path changed during observation")
366
  if _change_marker(path_after) != path_marker:
367
+ raise _FileChangedFailure("selected file changed during observation")
368
+ if _is_reparse(path_after) != _is_reparse(path_before):
369
+ raise _FileChangedFailure("selected path changed during observation")
370
+ _check_regular(path_after)
371
+ if fd_after_identity != path_after_identity:
372
+ raise _FileChangedFailure("selected path changed during observation")
373
  finally:
374
  try:
375
  os.close(descriptor)
376
  except OSError:
377
  pass
378
+ if parser_failure is not None:
379
+ if isinstance(parser_failure, JsonInputError):
380
+ raise _NotUsableGgufFailure("candidate GGUF is not usable") from parser_failure
381
+ if isinstance(parser_failure, OSError):
382
+ raise _FileUnavailableFailure("selected file cannot be validated") from parser_failure
383
+ raise _InternalReportFailure("file evidence parser failed") from parser_failure
384
+ if evidence is None:
385
+ raise _InternalReportFailure("file evidence parser returned no result")
386
+ try:
387
+ return _report(evidence, load_bundled())
388
+ except (
389
+ JsonInputError,
390
+ OSError,
391
+ TypeError,
392
+ ValueError,
393
+ OverflowError,
394
+ AttributeError,
395
+ KeyError,
396
+ RuntimeError,
397
+ ) as error:
398
+ raise _InternalReportFailure("file evidence report failed") from error
399
 
400
 
401
  def observe(path: str | os.PathLike[str]) -> dict[str, object]:
 
408
  try:
409
  raw = canonical_bytes(report)
410
  except (TypeError, ValueError, JsonInputError) as error:
411
+ raise _InternalReportFailure("report encoding failed") from error
412
  if len(raw) > MAX_OUTPUT_BYTES:
413
+ raise _InternalReportFailure("report exceeds the fixed output limit")
414
  try:
415
+ expected = len(raw)
416
+ binary_stdout = getattr(sys.stdout, "buffer", None)
417
+ if binary_stdout is not None:
418
+ written = binary_stdout.write(raw)
419
+ else:
420
+ text = raw.decode("ascii")
421
+ written = sys.stdout.write(text)
422
+ if written != expected:
423
+ raise _InternalReportFailure("report output failed")
424
+ except _InternalReportFailure:
425
+ raise
426
+ except (UnicodeError, OSError, TypeError, ValueError) as error:
427
+ raise _InternalReportFailure("report output failed") from error
428
+
429
+
430
+ def _emit_error(token: str) -> None:
431
+ message = f"{token}\n"
432
  if len(message.encode("ascii")) > MAX_ERROR_BYTES:
433
+ message = f"{INTERNAL_REPORT_FAILURE}\n"
434
  try:
435
  sys.stderr.write(message)
436
  except OSError:
 
442
 
443
  arguments = sys.argv[1:] if argv is None else argv
444
  if not isinstance(arguments, list) or len(arguments) != 1:
445
+ _emit_error(USAGE)
446
  return 2
447
  try:
448
  report = observe_file(arguments[0])
449
  _emit_report(report)
450
+ except _FileUnavailableFailure:
451
+ _emit_error(FILE_UNAVAILABLE_OR_UNSUPPORTED_TYPE)
452
+ return 2
453
+ except _NotUsableGgufFailure:
454
+ _emit_error(NOT_USABLE_GGUF)
455
+ return 2
456
+ except _FileChangedFailure:
457
+ _emit_error(FILE_CHANGED_DURING_OBSERVATION)
458
+ return 2
459
+ except _InternalReportFailure:
460
+ _emit_error(INTERNAL_REPORT_FAILURE)
461
+ return 2
462
+ except (OSError, TypeError, ValueError, OverflowError, AttributeError, RuntimeError):
463
+ # Any untyped ordinary failure remains a fixed internal refusal. No
464
+ # exception text or selected-path data crosses the command boundary.
465
+ _emit_error(INTERNAL_REPORT_FAILURE)
466
  return 2
467
  return 0
468
 
tests/test_gguf_file_observe.py CHANGED
@@ -1,6 +1,7 @@
1
  from __future__ import annotations
2
 
3
  import contextlib
 
4
  import io
5
  import json
6
  import stat
@@ -226,5 +227,203 @@ class GgufFileObserveTests(unittest.TestCase):
226
  self.assertLessEqual(len(stderr.getvalue().encode("utf-8")), observer.MAX_ERROR_BYTES)
227
 
228
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  if __name__ == "__main__":
230
  unittest.main()
 
1
  from __future__ import annotations
2
 
3
  import contextlib
4
+ import hashlib
5
  import io
6
  import json
7
  import stat
 
227
  self.assertLessEqual(len(stderr.getvalue().encode("utf-8")), observer.MAX_ERROR_BYTES)
228
 
229
 
230
+ class GgufFileObserveRefusalDeltaTests(unittest.TestCase):
231
+ def _run(self, arguments: list[object]) -> tuple[int, str, str]:
232
+ stdout = io.StringIO()
233
+ stderr = io.StringIO()
234
+ with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
235
+ status = observer.main(arguments)
236
+ return status, stdout.getvalue(), stderr.getvalue()
237
+
238
+ def test_usage_selection_and_parser_tokens_are_fixed(self) -> None:
239
+ status, stdout, stderr = self._run([])
240
+ self.assertEqual((2, "", f"{observer.USAGE}\n"), (status, stdout, stderr))
241
+
242
+ with tempfile.TemporaryDirectory() as raw:
243
+ root = Path(raw)
244
+ status, stdout, stderr = self._run([str(root / "missing")])
245
+ self.assertEqual(
246
+ (2, "", f"{observer.FILE_UNAVAILABLE_OR_UNSUPPORTED_TYPE}\n"),
247
+ (status, stdout, stderr),
248
+ )
249
+
250
+ malformed = root / "malformed"
251
+ malformed.write_bytes(b"x" * observer.MIN_FILE_BYTES)
252
+ status, stdout, stderr = self._run([str(malformed)])
253
+ self.assertEqual((2, "", f"{observer.NOT_USABLE_GGUF}\n"), (status, stdout, stderr))
254
+
255
+ with patch.object(observer, "validate_gguf_fd", side_effect=OSError("read detail")):
256
+ status, stdout, stderr = self._run([str(malformed)])
257
+ self.assertEqual(
258
+ (2, "", f"{observer.FILE_UNAVAILABLE_OR_UNSUPPORTED_TYPE}\n"),
259
+ (status, stdout, stderr),
260
+ )
261
+
262
+ self.assertLessEqual(len(stderr.encode("ascii")), observer.MAX_ERROR_BYTES)
263
+
264
+ def test_parser_fault_categories_are_typed_and_none_is_internal(self) -> None:
265
+ with tempfile.TemporaryDirectory() as raw:
266
+ path = Path(raw) / "model"
267
+ path.write_bytes(gguf())
268
+ for fault in (
269
+ TypeError("parser detail"),
270
+ ValueError("parser detail"),
271
+ OverflowError("parser detail"),
272
+ AttributeError("parser detail"),
273
+ RuntimeError("parser detail"),
274
+ ):
275
+ with self.subTest(fault=type(fault).__name__), patch.object(
276
+ observer, "validate_gguf_fd", side_effect=fault
277
+ ):
278
+ status, stdout, stderr = self._run([str(path)])
279
+ self.assertEqual(
280
+ (2, "", f"{observer.INTERNAL_REPORT_FAILURE}\n"),
281
+ (status, stdout, stderr),
282
+ )
283
+
284
+ with patch.object(observer, "validate_gguf_fd", return_value=None):
285
+ status, stdout, stderr = self._run([str(path)])
286
+ self.assertEqual(
287
+ (2, "", f"{observer.INTERNAL_REPORT_FAILURE}\n"),
288
+ (status, stdout, stderr),
289
+ )
290
+
291
+ with patch.object(observer, "validate_gguf_fd", side_effect=JsonInputError("header")):
292
+ status, stdout, stderr = self._run([str(path)])
293
+ self.assertEqual(
294
+ (2, "", f"{observer.NOT_USABLE_GGUF}\n"),
295
+ (status, stdout, stderr),
296
+ )
297
+
298
+ with patch.object(observer, "validate_gguf_fd", side_effect=OSError("read detail")):
299
+ status, stdout, stderr = self._run([str(path)])
300
+ self.assertEqual(
301
+ (2, "", f"{observer.FILE_UNAVAILABLE_OR_UNSUPPORTED_TYPE}\n"),
302
+ (status, stdout, stderr),
303
+ )
304
+
305
+ def test_regular_size_boundary_tokens_are_distinct(self) -> None:
306
+ with tempfile.TemporaryDirectory() as raw:
307
+ root = Path(raw)
308
+ short = root / "short"
309
+ short.write_bytes(b"x" * (observer.MIN_FILE_BYTES - 1))
310
+ status, stdout, stderr = self._run([str(short)])
311
+ self.assertEqual(
312
+ (2, "", f"{observer.NOT_USABLE_GGUF}\n"),
313
+ (status, stdout, stderr),
314
+ )
315
+
316
+ oversized = root / "oversized"
317
+ oversized.write_bytes(gguf())
318
+ with patch.object(observer, "MAX_FILE_BYTES", observer.MIN_FILE_BYTES):
319
+ status, stdout, stderr = self._run([str(oversized)])
320
+ self.assertEqual(
321
+ (2, "", f"{observer.FILE_UNAVAILABLE_OR_UNSUPPORTED_TYPE}\n"),
322
+ (status, stdout, stderr),
323
+ )
324
+
325
+ def test_existing_malformed_header_variants_use_not_usable_token(self) -> None:
326
+ invalid = (
327
+ b"GGUF" + b"\0" * (observer.MIN_FILE_BYTES - 4),
328
+ b"GGUF" + struct.pack("<IQQ", 1, 1, 0) + b"\0" * 64,
329
+ gguf(tensors=0),
330
+ gguf(tensors=10_000_001),
331
+ gguf(metadata=10_000_001),
332
+ gguf(tensors=1, metadata=1, padding=0) + b"\0",
333
+ )
334
+ with tempfile.TemporaryDirectory() as raw:
335
+ root = Path(raw)
336
+ for index, body in enumerate(invalid):
337
+ path = root / str(index)
338
+ path.write_bytes(body)
339
+ with self.subTest(index=index):
340
+ status, stdout, stderr = self._run([str(path)])
341
+ self.assertEqual(
342
+ (2, "", f"{observer.NOT_USABLE_GGUF}\n"),
343
+ (status, stdout, stderr),
344
+ )
345
+
346
+ def test_parser_failure_checks_change_before_selecting_not_usable(self) -> None:
347
+ with tempfile.TemporaryDirectory() as raw:
348
+ root = Path(raw)
349
+ path = root / "model"
350
+ path.write_bytes(gguf())
351
+
352
+ def fail_after_change(descriptor: int) -> object:
353
+ with path.open("ab") as handle:
354
+ handle.write(b"x")
355
+ raise JsonInputError("parser detail includes a path")
356
+
357
+ with patch.object(observer, "validate_gguf_fd", fail_after_change):
358
+ status, stdout, stderr = self._run([str(path)])
359
+ self.assertEqual(
360
+ (2, "", f"{observer.FILE_CHANGED_DURING_OBSERVATION}\n"),
361
+ (status, stdout, stderr),
362
+ )
363
+ self.assertNotIn(observer.NOT_USABLE_GGUF, stderr)
364
+
365
+ path.write_bytes(gguf())
366
+ original_lstat = observer.os.lstat
367
+ calls = 0
368
+
369
+ def fail_post_lstat(value: object) -> object:
370
+ nonlocal calls
371
+ calls += 1
372
+ if calls == 2:
373
+ raise OSError("post-state details")
374
+ return original_lstat(value)
375
+
376
+ with (
377
+ patch.object(observer, "validate_gguf_fd", side_effect=JsonInputError("bad")),
378
+ patch.object(observer.os, "lstat", side_effect=fail_post_lstat),
379
+ ):
380
+ status, stdout, stderr = self._run([str(path)])
381
+ self.assertEqual(
382
+ (2, "", f"{observer.FILE_UNAVAILABLE_OR_UNSUPPORTED_TYPE}\n"),
383
+ (status, stdout, stderr),
384
+ )
385
+ self.assertNotIn(observer.FILE_CHANGED_DURING_OBSERVATION, stderr)
386
+ self.assertNotIn(observer.NOT_USABLE_GGUF, stderr)
387
+
388
+ def test_report_refusal_is_internal_and_partial_stdout_is_not_rolled_back(self) -> None:
389
+ with tempfile.TemporaryDirectory() as raw:
390
+ path = Path(raw) / "model"
391
+ path.write_bytes(gguf())
392
+
393
+ with patch.object(observer, "_report", side_effect=JsonInputError("report detail")):
394
+ status, stdout, stderr = self._run([str(path)])
395
+ self.assertEqual((2, "", f"{observer.INTERNAL_REPORT_FAILURE}\n"), (status, stdout, stderr))
396
+
397
+ class PartialWriter(io.StringIO):
398
+ def write(self, value: str) -> int:
399
+ super().write(value[:1])
400
+ raise OSError("output detail")
401
+
402
+ partial = PartialWriter()
403
+ stderr = io.StringIO()
404
+ with patch.object(observer.sys, "stdout", partial), contextlib.redirect_stderr(stderr):
405
+ status = observer.main([str(path)])
406
+ self.assertEqual(2, status)
407
+ self.assertTrue(partial.getvalue())
408
+ self.assertEqual(f"{observer.INTERNAL_REPORT_FAILURE}\n", stderr.getvalue())
409
+
410
+ def test_success_bytes_and_direct_api_inheritance_remain_unchanged(self) -> None:
411
+ with tempfile.TemporaryDirectory() as raw:
412
+ path = Path(raw) / "model"
413
+ path.write_bytes(gguf())
414
+ status, stdout, stderr = self._run([str(path)])
415
+ self.assertEqual(0, status)
416
+ self.assertEqual("", stderr)
417
+ encoded = stdout.encode("ascii")
418
+ self.assertEqual(2515, len(encoded))
419
+ self.assertEqual(
420
+ "cfd215a8867ee289445b27837c64d3b426834217b3953e629a1206201b142c16",
421
+ hashlib.sha256(encoded).hexdigest(),
422
+ )
423
+
424
+ with self.assertRaises(JsonInputError):
425
+ observer.observe_file(path.with_name("missing"))
426
+
427
+
428
  if __name__ == "__main__":
429
  unittest.main()
tests/test_gguf_file_zipapp.py CHANGED
@@ -5,6 +5,7 @@ import json
5
  import os
6
  import shutil
7
  import stat
 
8
  import subprocess
9
  import sys
10
  import tempfile
@@ -18,7 +19,7 @@ from scripts import build_gguf_file_zipapp as builder
18
 
19
  ROOT = Path(__file__).resolve().parents[1]
20
  BUILDER = ROOT / "scripts" / "build_gguf_file_zipapp.py"
21
- SOURCE_COMMIT = "5e7e6070fa973016f8ef73e44843e2c4cbbb1f06"
22
  MANIFEST_NAME = "SOURCE-MANIFEST.json"
23
  MANIFEST_SCHEMA = "lumi-eggcracker.gguf-file-source-manifest.v1"
24
  MAIN_MODULE = (
@@ -32,7 +33,7 @@ SOURCE_BLOBS = {
32
  "lumi_eggcracker/detector_catalogue.json": "23d0592f1df359d954f54d057b9a38ac87d85dff",
33
  "lumi_eggcracker/detectors.py": "3fa79bc6af1295517da4510985d133444c5a962c",
34
  "lumi_eggcracker/discovery.py": "10cec85df3931c2b4d775484da9e97cc555927a9",
35
- "lumi_eggcracker/gguf_file_observe.py": "7463a29d883a324b5c05382c2874f175f5bb4aa0",
36
  "lumi_eggcracker/jsonio.py": "d09c32d35df2c423aa504f6e178c3820dae765cd",
37
  "lumi_eggcracker/procfd.py": "1cb27cd57f064eaf9ed1ca0c14146ae46b4191be",
38
  }
@@ -268,3 +269,104 @@ class GgufFileZipappTests(unittest.TestCase):
268
  self.assertEqual(nonblock, flags & nonblock)
269
  fstat.assert_called_once_with(descriptor)
270
  close.assert_called_once_with(descriptor)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
  import os
6
  import shutil
7
  import stat
8
+ import struct
9
  import subprocess
10
  import sys
11
  import tempfile
 
19
 
20
  ROOT = Path(__file__).resolve().parents[1]
21
  BUILDER = ROOT / "scripts" / "build_gguf_file_zipapp.py"
22
+ SOURCE_COMMIT = "7b9b1dcc7242c47c64fcec7d493f1aa5bfc158ef"
23
  MANIFEST_NAME = "SOURCE-MANIFEST.json"
24
  MANIFEST_SCHEMA = "lumi-eggcracker.gguf-file-source-manifest.v1"
25
  MAIN_MODULE = (
 
33
  "lumi_eggcracker/detector_catalogue.json": "23d0592f1df359d954f54d057b9a38ac87d85dff",
34
  "lumi_eggcracker/detectors.py": "3fa79bc6af1295517da4510985d133444c5a962c",
35
  "lumi_eggcracker/discovery.py": "10cec85df3931c2b4d775484da9e97cc555927a9",
36
+ "lumi_eggcracker/gguf_file_observe.py": "5118cd45cf9183d59c8a07abe468a4045f42d4a0",
37
  "lumi_eggcracker/jsonio.py": "d09c32d35df2c423aa504f6e178c3820dae765cd",
38
  "lumi_eggcracker/procfd.py": "1cb27cd57f064eaf9ed1ca0c14146ae46b4191be",
39
  }
 
269
  self.assertEqual(nonblock, flags & nonblock)
270
  fstat.assert_called_once_with(descriptor)
271
  close.assert_called_once_with(descriptor)
272
+
273
+
274
+ class GgufFileZipappRefusalDeltaTests(unittest.TestCase):
275
+ def setUp(self) -> None:
276
+ self._archive_temp = tempfile.TemporaryDirectory(prefix="gguf-file-zipapp-archive-")
277
+ self.addCleanup(self._archive_temp.cleanup)
278
+ self._fixture_temp = tempfile.TemporaryDirectory(prefix="gguf-file-zipapp-fixtures-")
279
+ self.addCleanup(self._fixture_temp.cleanup)
280
+
281
+ source_archive = ROOT / "examples/gguf-file/lumi-eggcracker-gguf-file.pyz"
282
+ source_checksum = source_archive.with_name(f"{source_archive.name}.sha256")
283
+ self._candidate_path = Path(self._archive_temp.name) / source_archive.name
284
+ self._checksum_path = Path(self._archive_temp.name) / source_checksum.name
285
+ shutil.copyfile(source_archive, self._candidate_path)
286
+ shutil.copyfile(source_checksum, self._checksum_path)
287
+ self._fixture_path = Path(self._fixture_temp.name)
288
+
289
+ def _candidate(self) -> Path:
290
+ return self._candidate_path
291
+
292
+ def _scratch(self) -> Path:
293
+ return self._fixture_path
294
+
295
+ def _run_archive(self, candidate: Path, arguments: list[str]) -> subprocess.CompletedProcess[bytes]:
296
+ environment = os.environ.copy()
297
+ environment.pop("PYTHONPATH", None)
298
+ environment["PYTHONDONTWRITEBYTECODE"] = "1"
299
+ return subprocess.run(
300
+ [sys.executable, "-B", str(candidate), *arguments],
301
+ cwd=self._scratch(),
302
+ env=environment,
303
+ capture_output=True,
304
+ check=False,
305
+ )
306
+
307
+ def _assert_refusal(
308
+ self,
309
+ result: subprocess.CompletedProcess[bytes],
310
+ token: str,
311
+ leaked_path: Path | None = None,
312
+ ) -> None:
313
+ self.assertEqual(2, result.returncode)
314
+ self.assertEqual(b"", result.stdout)
315
+ self.assertEqual(token.encode("ascii") + os.linesep.encode("ascii"), result.stderr)
316
+ self.assertLessEqual(len(result.stderr), 128)
317
+ self.assertTrue(result.stderr.isascii())
318
+ if leaked_path is not None:
319
+ encoded_path = os.fsencode(leaked_path)
320
+ self.assertNotIn(encoded_path, result.stdout + result.stderr)
321
+
322
+ def test_packaged_candidate_members_are_canonical_and_pinned(self) -> None:
323
+ candidate = self._candidate()
324
+ checksum = Path(f"{candidate}.sha256")
325
+ digest = hashlib.sha256(candidate.read_bytes()).hexdigest()
326
+ self.assertEqual(f"{digest} {candidate.name}\n", checksum.read_text(encoding="ascii"))
327
+
328
+ with zipfile.ZipFile(candidate) as archive:
329
+ infos = archive.infolist()
330
+ self.assertEqual(sorted(EXPECTED_MEMBERS), [item.filename for item in infos])
331
+ self.assertEqual(MAIN_MODULE, archive.read("__main__.py"))
332
+ for name in SOURCE_BLOBS:
333
+ source = ROOT / ("LICENSE" if name == "LICENSE" else f"src/{name}")
334
+ self.assertEqual(source.read_bytes(), archive.read(name))
335
+ manifest_bytes = archive.read(MANIFEST_NAME)
336
+ manifest = json.loads(manifest_bytes)
337
+ self.assertEqual(SOURCE_COMMIT, manifest["base_commit"])
338
+ self.assertEqual(SOURCE_BLOBS, {item["path"]: item["git_blob"] for item in manifest["source_members"]})
339
+ self.assertEqual(
340
+ (json.dumps(manifest, sort_keys=True, separators=(",", ":")) + "\n").encode("ascii"),
341
+ manifest_bytes,
342
+ )
343
+
344
+ def test_packaged_candidate_refusals_and_success_bytes_are_fixed(self) -> None:
345
+ candidate = self._candidate()
346
+ scratch = self._scratch()
347
+ result = self._run_archive(candidate, [])
348
+ self._assert_refusal(result, "USAGE")
349
+
350
+ missing = scratch / "package-delta-missing.gguf"
351
+ result = self._run_archive(candidate, [str(missing)])
352
+ self._assert_refusal(result, "FILE_UNAVAILABLE_OR_UNSUPPORTED_TYPE", missing)
353
+
354
+ invalid = scratch / "package-delta-invalid.gguf"
355
+ invalid.write_bytes(b"x" * 25)
356
+ result = self._run_archive(candidate, [str(invalid)])
357
+ self._assert_refusal(result, "NOT_USABLE_GGUF", invalid)
358
+
359
+ valid = scratch / "package-delta-valid.gguf"
360
+ valid.write_bytes(b"GGUF" + struct.pack("<IQQ", 3, 1, 0) + b"\0" * 64)
361
+ result = self._run_archive(candidate, [str(valid)])
362
+ self.assertEqual(0, result.returncode)
363
+ self.assertEqual(b"", result.stderr)
364
+ self.assertEqual(2515, len(result.stdout))
365
+ self.assertEqual(
366
+ "cfd215a8867ee289445b27837c64d3b426834217b3953e629a1206201b142c16",
367
+ hashlib.sha256(result.stdout).hexdigest(),
368
+ )
369
+ self.assertTrue(result.stdout.isascii())
370
+ self.assertNotIn(os.fsencode(valid), result.stdout)
371
+ parsed = json.loads(result.stdout)
372
+ self.assertEqual("FILE_EVIDENCE_ONLY", parsed["result"])