Repository navigation
Hosted ChatGPT plugin: pdfmux serve --remote (extract_tables, sandboxed, nothing-skipped) - #42
Merged
Merged
Conversation
…/dates, balance reconciliation) No models, no network, no paid fallback. 30 tests on generated PDFs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…x, XLSX, kit - extract_tables tool: file (openai/fileParams) or pdf_url → CSV inline (wrapped untrusted) + 15-minute signed XLSX link + "rows verified N of M"; neutral copy, annotations. - fetch.py: https-only, every resolved address must be global (blocks loopback, RFC1918, 169.254.169.254 metadata, 100.64/10 Tailscale, v4-mapped v6), connected peer re-checked (rebinding), manual re-validated redirects, 25 MB streaming cap, %PDF- magic. - sandbox.py + worker.py: parse in a separate process — docker run --network none --read-only --cap-drop ALL --user nobody with mem/cpu/pid limits in production, rlimits locally; timeout enforced from outside (SIGALRM can't stop C code). Front end never parses; worker never fetches. - outputs.py: CSV/XLSX from typed values (numbers stay numbers, dates real dates, summary sheet). - kit.py: Python port of chatgpt-plugin-kit (token trust, last-XFF IP, fail-closed limits, kill-switch file, banned copy, untrusted wrapper, JSONL logs without cell values). - FIX: PyMuPDF 1.27 find_tables().extract() splits "37.50" into "3750\n." and drops spaces — a silent 100x on every amount. Cells are now read via page.get_textbox(cell rect). Regression test pinned. (Core pdfmux's two extract() call sites are a follow-up.) Tests: 62 remote tests. Full suite: 803 passed; the only failures are the MCP test files, which need mcp>=2 that this local venv lacks (pre-existing, unrelated). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ontainer user Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…xtract_tables demo/tests Force-added past the *.pdf ignore on purpose: it's a deliberate public fixture. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…sheet) - remote/tables.py drops its private _cell_texts copy for pdfmux.table_cells (merged in #43). - outputs.py: wb.worksheets[0] instead of Optional wb.active (pyright reportOptionalSubscript). - ci.yml: install the remote extra so test_remote_server can import httpx/starlette/openpyxl. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… runs pytest, not python -m) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
pdfmux serve --remoteserves a hosted ChatGPT plugin (OpenAI Apps SDK) with one tool,extract_tables.openai/fileParamsor given aspdf_url.Decision: business-agent
products/pdfmux/decisions/2026-10-02-chatgpt-plugin-posture-exception.md, a founder-approved, bounded exception to the posture lock.Live at
mcp.pdfmux.com/mcp/<token>, deployed from this branch./mcpendpoint is untouched; nginx routes only/mcp/<48-hex>,/dl/and the challenge path to the plugin.Design: the front end never parses, the worker never fetches
remote/tables.pyfind_tables()plus the whitespace fallback, stitching across pages, typed numbers and dates, balance reconciliation, scan detectionremote/fetch.pyremote/sandbox.py+worker.py+deploy/sandbox.Dockerfiledocker run --network none --read-only --cap-drop ALL --user 65534with memory, CPU and pid limits. The timeout is enforced from outside. Verified on the box: network blocked, filesystem read-only.remote/outputs.pyremote/kit.pyremote/server.pyfetch.pyaccepts only:%PDF-magic byteskit.pyapplies the same rules as the TypeScript kit:<<<untrusted>>>.Correctness fix found along the way
PyMuPDF 1.27's
find_tables().extract()splits"37.50"into"3750\n."and drops spaces. After cleanup, that is a silent 100× on every amount, and reconciliation can't catch it because the error is uniform. Cells are now read withpage.get_textbox(cell_rect), and a regression test is pinned. Core pdfmux still callsextract()inextractors/fast.py:66andsegment.py:260; that's a follow-up task.Tests
tests/test_remote_tables.py,tests/test_remote_server.py).mcp>=2; CI has it.remoteextra (starlette, uvicorn, httpx, openpyxl).🤖 Generated with Claude Code