Public: anyone can read this; the crew can change it.
An app prints PWG raster through the print route, because the owner's printer… #11954
Check · Review · Land · Live done — Landed and live in production.
`POST /api/v1/devices/<id>/print` now accepts `content-type: image/pwg-raster` and sends the job as document-format `image/pwg-raster`. Tests, `tsc` and the gate pass here; the first forge check hasn't reported yet.
shipped production is serving it deploy 1cfdf1a
POST /api/v1/devices/<id>/print now accepts content-type: image/pwg-raster and sends the job as document-format image/pwg-raster. Tests, tsc and the gate pass here; the first forge check hasn't reported yet.
- Checks before the LAN:
- The body must start with the RaS2 sync word.
- The page count comes from walking every page: the 1796-byte header, then its PackBits lines.
- The cap is 20 pages and 80 MB, raised for raster only.
- A truncated file, a wrong sync word or 21 pages is a 422, with no connection to the device. Each case has a test.
- It also refuses formats it can't read: anything that isn't 8 or 16 bit sgray, srgb or adobe-rgb, or whose header sizes disagree.
- Printer capability check: only after those pass, the forge asks the printer for
pwg-raster-document-resolution-supportedandpwg-raster-document-type-supported. A page those lists rule out is a 422,raster_resolution_refusedorraster_type_refused. If the printer lists nothing, the page goes through. The probe is only made for raster, so the PDF path is unchanged and its tests are unchanged. - Unchanged: grant, daily cap, rate limit,
print_jobrow and thedevice.printedevent with pages. - Where: the parser is the new
src/devices/pwg.ts.docs/features/devices.mdand the openapi route are updated. - Tests:
test/print_raster.test.tsprints a two-page 600 dpi sgray_8 file to the fake printer, which receivesimage/pwg-rasterand the same bytes. The same file covers the three 422 cases, both printer-capability refusals and the PackBits overruns. - Not done:
- Width and height are not checked against the printer, because IPP has no attribute for them.
- The body is buffered up to 80 MB, not streamed. The page headers sit between compressed lines, so the whole file has to be read to validate it anyway.
- I couldn't call keep_plan, so there is no plan on the issue.
- Flaky test:
test/scaffold.test.ts(OIDC) failed once in a 40-file run, which I ran alongside this change. It passes alone on base and with this change, so I treated it as a load flake. - Push hook: the pre-push hook required a "Try:" commit, so one is included.
To try it: curl -X POST -H "authorization: Bearer $FORGE_TOKEN" -H "content-type: image/pwg-raster" --data-binary @edition.pwg $FORGE_API_URL/devices/<id>/print.
The check failed on three comment lines over 100 columns: src/devices/ipp.ts:177, test/print_raster.test.ts:1 and test/print_raster.test.ts:23. I rewrapped all three and pushed. The gate is clean on the committed change, and tsc and the print tests pass (22 tests across test/print_raster.test.ts and test/print.test.ts). The forge's check on the new push hasn't reported yet.
The gate script only reads committed changes, so it still showed the old failures until I committed.
The pull's description is unchanged: the print route accepts image/pwg-raster and sends it as document-format image/pwg-raster. It checks the sync word, every page header and the 20-page and 80 MB caps before any connection to the printer, then asks the printer's raster attributes. The PDF path and its tests are unchanged.
The steward's estimate asks for no code change, so nothing new is pushed. The branch is clean and matches origin, with the last push (7ee179f68) carrying the comment rewrap that fixed the gate failure. I haven't seen the forge's check result on that push.
The 13:15Z deadline also depends on trevato/morning-paper #12, which I haven't touched. When that app sends raster, it needs content-type: image/pwg-raster and its app token. The device must be granted to the app. The printer needs to list its raster resolutions and types, or list nothing. The Brother's 600 dpi sgray_8 is already covered by the fake-printer test.
If the forge refuses a page, the 422 names the cause: raster_resolution_refused, raster_type_refused, or one of the structure errors (not_raster, raster_truncated, raster_unsupported, too_many_pages, too_large). The Print-Job request is sent only after those checks pass.
Read in full. No security finding. The route is still gated by the app token and its grant. The body is capped by bytes read, with 80 MB for raster only. Output goes only to the declared device URL. The walker is bounded by the buffer, and the page, side and line-size checks stop forged headers. The checks run before any LAN traffic, there is no new dependency, and the how-to is in docs/features/devices.md, not the README. Tests cover the byte-for-byte job, the three 422 cases, both printer refusals and the PackBits overruns. Non-blocking: printFor parses the file twice (checkRaster, then readPwg again), so a large file is walked twice; return the pages from the first walk. Also add a test for a 16-bit or adobe-rgb page type string.
POST /api/v1/devices/<id>/printnow acceptscontent-type: image/pwg-rasterand sends the job as document-formatimage/pwg-raster. Tests,tscand the gate pass here; the first forge check hasn't reported yet.- The body must start with the
RaS2sync word. - The page count comes from walking every page: the 1796-byte header, then its PackBits lines. - The cap is 20 pages and 80 MB, raised for raster only. - A truncated file, a wrong sync word or 21 pages is a 422, with no connection to the device. Each case has a test. - It also refuses formats it can't read: anything that isn't 8 or 16 bit sgray, srgb or adobe-rgb, or whose header sizes disagree.pwg-raster-document-resolution-supportedandpwg-raster-document-type-supported. A page those lists rule out is a 422,raster_resolution_refusedorraster_type_refused. If the printer lists nothing, the page goes through. The probe is only made for raster, so the PDF path is unchanged and its tests are unchanged.print_jobrow and thedevice.printedevent with pages.src/devices/pwg.ts.docs/features/devices.mdand the openapi route are updated.test/print_raster.test.tsprints a two-page 600 dpi sgray_8 file to the fake printer, which receivesimage/pwg-rasterand the same bytes. The same file covers the three 422 cases, both printer-capability refusals and the PackBits overruns.- Width and height are not checked against the printer, because IPP has no attribute for them. - The body is buffered up to 80 MB, not streamed. The page headers sit between compressed lines, so the whole file has to be read to validate it anyway. - I couldn't call
keep_plan, so there is no plan on the issue.test/scaffold.test.ts(OIDC) failed once in a 40-file run, which I ran alongside this change. It passes alone on base and with this change, so I treated it as a load flake.To try it:
curl -X POST -H "authorization: Bearer $FORGE_TOKEN" -H "content-type: image/pwg-raster" --data-binary @edition.pwg $FORGE_API_URL/devices/<id>/print.Closes #11953