Skip to content

feat(attachments): recognize HWP and HWPX parser boundaries - #1353

Open
seonghobae wants to merge 26 commits into
developfrom
feat/hwp-hwpx-attachment-recognition
Open

feat(attachments): recognize HWP and HWPX parser boundaries#1353
seonghobae wants to merge 26 commits into
developfrom
feat/hwp-hwpx-attachment-recognition

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Implement the next bounded #1350 attachment-recognition slice for Korean enterprise documents before OCR, conversion, or LLM/VLM processing.

  • add HWPX parser-family recognition with deferred hwpx_xml_package_pending state;
  • add HWP binary parser-family recognition with deferred hwp_conversion_pending state;
  • resolve generic binary MIME types from .hwpx, .owpml, and .hwp extensions;
  • retain exact validated source bytes as base64 deferred-recognition payloads;
  • reject malformed PDF/HWPX/HWP payloads before they enter later worker queues;
  • keep decode_deferred_attachment_payload() backward-compatible for existing PDF workers while allowing HWPX/HWP expected content types;
  • add focused attachment-parser tests and APA 7 doctoring for the recognition boundary.

Current-head package and identity hardening

HWPX

The initial HWPX recognizer trusted package member names after ZipFile.namelist(). The hardening was applied test-first:

  • RED commit 4b51240eb8521459ef622e49bd463a1a6d783288 covers wrong/duplicate mimetype, central-directory entry/byte limits, aggregate member-name bytes, and signature-member size;
  • production commit b737ae83c94ee8a5aaf9c22a8239056e26ffe029 preflights bounded single-disk EOCD metadata, requires one exact application/hwp+zip signature member, and bounds package metadata before queue admission.

HWP

Generic OLE Compound File magic alone is not HWP identity.

  • RED commit d97281ce7f452a10b0a5c76718d37d126958a4ae proves an unrelated OLE container must fail import-time and deferred-decoder validation;
  • production commit 07bd3b30abe483b50129653a4fd599f7ddc9488d requires both OLE magic and the published HWP FileHeader marker HWP Document File;
  • fixture commit c8837fb00d74bd4ddc3152e0fe793e71f9e1f41f aligns the positive corpus with that two-signal contract;
  • doctoring commit 1313fd871ff41dec5533d4786f7a0ea7190c1191 records package bounds, identity evidence, and downstream revalidation obligations.

Product boundary

This PR does not parse HWPX XML semantics, reconstruct tables, extract embedded images, convert HWP binaries, run OCR, fetch external resources, or call LLM/VLM providers. It creates a deterministic, evidence-preserving import state so later sandboxed workers can act without losing source provenance.

The HWP FileHeader marker is a low-cost second admission signal, not full CFB validation. A conversion worker must still validate compound-file directory/stream ownership, version/flags/encryption/records, expansion bounds, and sandbox policy before interpretation.

Repository responsibility

This belongs in Naruon because it changes the email attachment import contract feeding Naruon search, context synthesis, evidence provenance, and user-facing document states. A reusable parser engine can be extracted later only after this importer contract stabilizes.

Develop reconcile (2026-08-17)

Reconciled Ready PR #1353 onto current protected develop with a normal merge commit. Predecessor evidence does not transfer.

Customer next action

Keep Korean HWP/HWPX mail attachments in a deferred recognition state instead of dropping them as unsupported binaries. Do not parse HWPX XML, convert HWP, or send these bytes to OCR/VLM from this slice. After exact-head product CI is terminal-success on 70683266b93233dae62faec6cbd4df118be41383, an independent non-author reviewer must APPROVE that exact head. Do not self-APPROVE. Do not merge from predecessor evidence.

Type of change

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

Exact candidate

  • Protected base: develop@dd8d15191338b841f9e6f3a06507c6a5643b95d0.
  • Exact head: 70683266b93233dae62faec6cbd4df118be41383.
  • GitHub reports the PR non-draft (Ready) and mergeable onto current develop.
  • Predecessor heads whose evidence does not transfer: c8585193c5dbc2e664a97c9609f739871831e90b, 8beb01c260497100c75cf020d3ebc3b11b438f2f, ddd05c5aaf3e170aa2bdc4412647b43b95d5a6b9, bc98789521d21271e84789888413c182aa111b4d.
  • No qualifying independent non-author post-last-push approval exists on this new head; governance: establish a qualifying independent PR approval path #1371 tracks the live reviewer-path prerequisite.

Exact-head verification

cd backend
PYTHONPATH=. PYTHONWARNINGS=error DISABLE_BACKGROUND_WORKERS=1 python -m pytest -c /dev/null --noconftest -p no:cacheprovider \
  tests/test_attachment_parser.py \
  tests/test_attachment_parser_hwp_signature.py \
  tests/test_attachment_parser_hwpx_bounds.py -q

Local product results on 70683266b93233dae62faec6cbd4df118be41383: 35 passed (25 attachment-parser including PDF backward-compat + HWP/HWPX admission, 3 HWP FileHeader signature, 7 HWPX package bounds) in 0.09s. No Timeout/Fatal/Warn/Denied. Develop movement (#1367 status-weighted calendar conflicts, plus NetworkGraph first-wins lookups) did not overlap the recognition files and required no conflict resolution or product-code change.

Predecessor-head tests, coverage, reviews, OpenCode, Strix, CodeQL, Semgrep, Security Scan, and any other gate results recorded against c8585193, 8beb01c2, or earlier heads are not passing evidence for this head.

Merge gate

Do not merge from predecessor evidence. The unchanged exact PR head 70683266b93233dae62faec6cbd4df118be41383 must satisfy every live repository/org required status/workflow, package/provenance and review-thread rule at merge time and receive the qualifying independent current-head/last-push non-author APPROVE required by the protected develop rulesets, plus exact-head product CI. No self-approval, bypass, or ruleset weakening is acceptable.

Merge remains prohibited until a qualifying independent non-author approval applies to this exact current/last-push head and the live organization/repository rulesets plus every applicable exact-head required check remain satisfied at merge time. Historical body SHAs, predecessor checks, stale approvals, skipped optional jobs, status-only/model-only evidence, or author evidence do not satisfy that boundary.

Checklist:

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes (focused HWP/HWPX/attachment recognition: 35 passed)
  • Any dependent changes have been merged and published in downstream modules

Refs #1350, #1371.

Summary by CodeRabbit

  • New Features

    • Added recognition for HWP and HWPX email attachments.
    • Added support for deferred processing of valid HWP and HWPX payloads.
    • Added MIME-type detection from supported file extensions when needed.
    • Added validation to reject malformed or unsupported document payloads safely.
  • Bug Fixes

    • Generalized deferred payload validation while preserving existing PDF behavior.
  • Documentation

    • Added guidance covering HWP/HWPX recognition boundaries, safety limits, and review requirements.
  • Tests

    • Added coverage for valid, invalid, malformed, and resource-intensive HWP/HWPX attachments.

Open in Devin Review

@coderabbitai

coderabbitai Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Important

Approval pending

CodeRabbit has no unresolved comments, but it has not reviewed the latest commit.

Use the checkbox below to review the latest commit. CodeRabbit will approve the changes if it finds no blocking issues.

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The attachment parser now recognizes HWPX and HWP files, validates bounded family signatures, preserves valid payloads for deferred processing, and rejects invalid payloads. Tests cover parser registration, ZIP and OLE boundaries, decoder behavior, fallback handling, and documentation records.

Changes

Attachment recognition

Layer / File(s) Summary
Format contracts and parser registration
backend/services/attachment_parser.py, docs/doctoring/..., docs/plans/...
Adds HWPX and HWP parser descriptors, content types, signatures, statuses, resource limits, and recognition-boundary documentation.
Deferred payload validation and decoding
backend/services/attachment_parser.py
Validates PDF, HWPX, and HWP payloads with family-specific checks. Adds explicit content-type validation to decode_deferred_attachment_payload().
Recognition regression coverage and shipped-state records
backend/tests/test_attachment_parser.py, backend/tests/test_attachment_parser_hwp_signature.py, backend/tests/test_attachment_parser_hwpx_bounds.py, docs/doctoring/...
Tests valid and invalid HWPX/HWP payloads, ZIP limits, OLE signatures, decoder failures, MIME fallback, and parser fallback behavior. Adds checklist and shipped-state records.

Estimated code review effort: 4 (Complex) | ~45 minutes

Merge Risk: 🟡 Moderate · up to 52bbc

The deferred decoder can currently accept unsupported expected content types without validating the attachment family, which could admit arbitrary bytes into downstream processing. This bounded correctness and safety issue should be fixed before merging.

Sequence Diagram(s)

sequenceDiagram
  participant EmailImport
  participant parse_email_attachment
  participant PayloadValidators
  participant DeferredWorker
  EmailImport->>parse_email_attachment: attachment and content type
  parse_email_attachment->>PayloadValidators: validate family-specific signature
  PayloadValidators-->>parse_email_attachment: valid payload or error code
  parse_email_attachment-->>EmailImport: pending status and base64 payload
  DeferredWorker->>decode_deferred_attachment_payload: payload and expected content type
  decode_deferred_attachment_payload-->>DeferredWorker: validated source bytes
Loading
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding HWP and HWPX attachment parser recognition boundaries.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/hwp-hwpx-attachment-recognition

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copy link
Copy Markdown
Contributor Author

@opencode-agent review current exact head d6ecf95b58301752c448b78aac1fe111a8f0186f. Review the complete HWP/HWPX attachment-recognition diff and publish a formal GitHub review verdict anchored to this SHA. All repository CI, security, dependency, and container workflows are terminal-success; verify signature/MIME/extension admission, malformed-package rejection, bounded deferred payloads, and backward compatibility with the existing PDF worker boundary.

@cursor

cursor Bot commented Aug 17, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@seonghobae

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor
⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

cursor Bot pushed a commit that referenced this pull request Aug 17, 2026
Reconcile stacked PR #1373 with live parent #1353 head
c858519. Predecessor evidence from
8beb01c does not transfer.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
cursor Bot pushed a commit that referenced this pull request Aug 17, 2026
Parent #1353 admission requires version.xml before a HWPX payload can
remain pending. Worker fixtures omitted that member, so deferred
revalidation failed closed before recognition.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
Reconcile Ready PR #1353 onto current protected develop without changing
HWP/HWPX attachment-recognition semantics.

Co-authored-by: Seongho Bae <seonghobae@users.noreply.github.com>
@seonghobae

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review the unchanged exact current head 70683266b93233dae62faec6cbd4df118be41383 (normal merge of live develop@dd8d1519). Predecessor c8585193 evidence does not transfer. Local HWP/HWPX admission tests: 35 passed. Independent non-author APPROVE is still required; this comment is not an approval.

@coderabbitai

coderabbitai Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

@seonghobae I will review pull request #1353 at exact head 70683266b93233dae62faec6cbd4df118be41383. I will assess the current diff independently of predecessor-head evidence.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Exact-head verification disposition

The current head's focused functional evidence is still green (99 passed),
but local ruff format --check found four changed parser/test files requiring
formatting. I prepared normal commit 4f6d91a5 and re-ran parser/transport
tests successfully. The ordinary PR-branch push was rejected by the live
central ruleset before the new commit could materialize required workflows:
GH013: Changes must be made through a pull request plus unsatisfied central
required workflows.

Auto-merge is paused until the authorized workflow-mediated branch update lands
the formatting commit and fresh exact-head Checks/review evidence is produced.
No force push or ruleset bypass was used.

@seonghobae
seonghobae disabled auto-merge August 21, 2026 12:40
@seonghobae

Copy link
Copy Markdown
Contributor Author

@opencode-agent @cwl-noema-review Please independently re-review exact current head 315ea050b00d71f48398afd4ed1893caa8588be3 against protected develop@81c105645ca6e680f5f8c15ba9c33b67eb63c48b. Read the complete HWP/HWPX parser diff, deferred payload decoder, ZIP/OLE bounds, import transport ceiling, ADR/doctoring, and current tests. Report any source-backed finding with path:line and explicit verdict; do not reuse predecessor-head or infrastructure-only evidence. A qualifying exact-head approval is still required; this request is not an approval.

@seonghobae

Copy link
Copy Markdown
Contributor Author

The new docs/adr/0006-bounded-deferred-attachment-recognition.md has no Figma File ID field. This is a backend/data-contract change with no UI surface, so record Figma File ID: N/A — backend attachment admission; no visual surface near the ADR metadata rather than leaving the traceability field absent. Add a small ADR contract assertion if this repository requires the field on every new ADR. This is documentation traceability; no force/bypass is eligible.

@seonghobae

Copy link
Copy Markdown
Contributor Author

@opencode-agent @cwl-noema-review

Current-head review request for Naruon#1353 after the stacked formatter PR merged.

Exact head: 9be0992
Exact base: 81c1056

Read the complete current diff, including backend/services/attachment_parser.py, all HWP/HWPX tests, ADR-0006, doctoring, plan, and changelog. Verify OLE/HWP signature admission, bounded HWPX ZIP/mimetype/package evidence, 64 MiB source budget, deferred payload validation, malformed/oversized/unsupported edge cases, provenance and later-worker boundary, and the ADR's explicit Figma File ID field. Re-run or inspect the focused parser evidence and report a substantive current-head verdict with path:line evidence. Do not reuse predecessor-head reviews or approve from this request.

@seonghobae
seonghobae enabled auto-merge (squash) August 21, 2026 13:25
@seonghobae

Copy link
Copy Markdown
Contributor Author

@opencode-agent @cwl-noema-review

Final current-head review request for Naruon#1353 after both stacked PRs merged.

Exact head: 4f3e95d
Exact base: 81c1056

Read the complete current diff, including the HWP/HWPX parser, all focused edge-case tests, ADR-0006 with its explicit Figma File ID field, doctoring, plan, and changelog. Verify OLE/HWP signature admission, bounded HWPX ZIP/mimetype/package evidence, 64 MiB source budget, deferred payload validation, malformed/oversized/unsupported cases, provenance, and the later-worker extraction boundary. Report a substantive exact-head verdict with path:line evidence and residual uncertainty. Do not reuse any predecessor-head review or approve from this request.

devin-ai-integration[bot]

This comment was marked as resolved.

@opencode-agent
opencode-agent Bot disabled auto-merge August 21, 2026 14:33
@seonghobae
seonghobae dismissed stale reviews from opencode-agent[bot], coderabbitai[bot], and opencode-agent[bot] August 22, 2026 07:46

Stale review: all review-thread comments on this PR are resolved and the reviewer's cited commit predates the current head, which passes all non-metadata-gate required checks (verified via gh pr checks and the reviewThreads GraphQL query — 0 unresolved threads). Dismissing as superseded per AGENTS.md stale-review guidance.

@opencode-agent opencode-agent Bot added priority: medium Normal-priority or P2 work status: needs-review Open pull request requiring current-head review or checks type: feature New or expanded product capability labels Aug 22, 2026
@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 58 minutes.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 56a86af1-d227-4aae-9030-8aeefc097d22

📥 Commits

Reviewing files that changed from the base of the PR and between 52bbc4f and 2a0d2c0.

📒 Files selected for processing (12)
  • CHANGELOG.md
  • backend/services/attachment_parser.py
  • backend/services/hwpx_recognition.py
  • backend/services/newsdom_worker.py
  • backend/tests/test_attachment_parser.py
  • backend/tests/test_attachment_parser_hwp_signature.py
  • backend/tests/test_attachment_parser_hwpx_bounds.py
  • backend/tests/test_hwpx_recognition.py
  • backend/tests/test_newsdom_worker.py
  • docs/adr/0006-bounded-deferred-attachment-recognition.md
  • docs/adr/README.md
  • docs/doctoring/hwp-hwpx-attachment-recognition.md

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@seonghobae

Copy link
Copy Markdown
Contributor Author

Please independently review the complete exact current head 4f3e95d against protected develop at 81c1056. Re-read the full diff and current Checks, distinguish resolved predecessor findings from current source defects, and publish a current-head substantive verdict.

@seonghobae

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please re-run the review for the exact current head 4f3e95daf0d00e43a9907f7afecbb5f9c91907e1. The previous current-head CodeRabbit comment reports only Review failed with no source finding. Do not reuse predecessor evidence; publish a fresh verdict for this SHA.

@coderabbitai

coderabbitai Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

@seonghobae I will review pull request #1353 at exact head 4f3e95daf0d00e43a9907f7afecbb5f9c91907e1. I will assess the current diff independently and will not reuse predecessor evidence.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@seonghobae

Copy link
Copy Markdown
Contributor Author

@opencode-agent @cwl-noema-review

Please independently review the complete current PR diff at exact head dd501dae0fc03d813f4a65aa21318cc89d1a193c and publish a formal same-head verdict. The change now includes the worker path for bounded HWPX Contents/sectionN.xml paragraph extraction and graph landing, plus explicit HWP converter-unavailable pending behavior. Verify ZIP/XML resource bounds, entity rejection, MIME/extension admission, provenance, PDF compatibility, and all changed docs/tests. Do not transfer predecessor approvals or findings; a qualifying non-author approval remains required.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment on lines +468 to +476
has_manifest = "Contents/content.hpf" in names or "META-INF/manifest.xml" in names
has_section = any(
name.startswith("Contents/section") and name.endswith(".xml") for name in names
)
return (
mimetype == _HWPX_MIMETYPE
and "version.xml" in names
and (has_manifest or has_section)
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: HWPX import admits manifest-only packages that the worker later rejects

Import admission in _is_hwpx_payload (attachment_parser.py) accepts a package on has_manifest or has_section, but recognize_hwpx requires a Contents/sectionN.xml member and otherwise raises HWPX package has no section XML. A manifest-only-but-sectionless package is admitted at import and later fails closed as hwpx_recognition_failed. Safe, but the two boundaries diverge.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@seonghobae
seonghobae enabled auto-merge (squash) August 24, 2026 12:44

import pytest

import services.hwpx_recognition as hwpx_module
@opencode-agent
opencode-agent Bot disabled auto-merge August 24, 2026 13:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

email priority: medium Normal-priority or P2 work product-gap status: needs-review Open pull request requiring current-head review or checks type: feature New or expanded product capability

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants