Skip to content

fix(import): accept XML delimiter whitespace - #467

Merged
opencode-agent[bot] merged 10 commits into
developfrom
fix/xml-tag-whitespace-410
Aug 16, 2026
Merged

fix(import): accept XML delimiter whitespace#467
opencode-agent[bot] merged 10 commits into
developfrom
fix/xml-tag-whitespace-410

Conversation

@seonghobae

@seonghobae seonghobae commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Buyer impact

Standards-compliant Microsoft Project XML may contain space, tab, carriage return, or line feed between an exact element name and >. ScopeWeave's byte-exact scanner previously reported such exports as containing no tasks.

This PR broadens only that delimiter boundary while preserving the linear, regex-free import profile and its malformed-input protections.

Closes #410 only after protected integration.

Exact current state

Protected base: develop@b88e66e81e9701404d29a0f5de4f58573ceee14f.

Current contributor head: 766eb2d2d48d3eaef66fdb093b5aa54abf3ce55c.

The current protected-base PR diff remains limited to five intended XML-import files:

  • cloud-sync.js
  • tests/unit/msproject.test.mjs
  • docs/security.md
  • CHANGELOG.md
  • docs/doctoring/ms-project-xml-import-boundary.md

No Hono, package, lockfile, workflow, server, authentication, Clearfolio, attachment, or other security-runtime change is part of the current PR diff. A short-lived attempt to add an attachment-view authentication regression after a central security finding was deliberately removed rather than broadening this parser PR or competing with the dedicated #413 access-grant architecture; package/test registration was restored. The resulting PR diff is still the same five parser/documentation files.

Parser contract

  • exact Task, PredecessorLink, and scalar names remain required;
  • XML 1.0 whitespace U+0020, U+0009, U+000D, and U+000A is accepted before >;
  • attributes, namespace prefixes, longer names, U+000B, and other delimiters are rejected;
  • truncated elements yield no value;
  • a same-name nested opening may not consume a later closing delimiter;
  • the scanner remains monotonic and does not use dynamic or lazy whole-document regular expressions.

TDD and parser repair evidence

Regression-only head 3491f51959a97a4f7bfcc32394b07b130ed6c395 established the missing scalar invariant. Exact-head Server Tests run 31869862197 observed RED at tests/unit/msproject.test.mjs:116: <Name>outer<Name>inner</Name> was incorrectly accepted as outer<Name>inner.

The parser repair mirrors the already-hardened block invariant: tag() resolves both the candidate same-name closing delimiter and the next same-name opening delimiter and returns an empty scalar when the next opening precedes the close. The regression remains alongside XML-whitespace, exact-name, U+000B, truncation, block-nesting, scalar, and predecessor cases.

All CodeRabbit inline findings on the parser diff are resolved; the three review threads are resolved/outdated as appropriate. There is no qualifying independent current-head approval.

Security-gate finding discovered after parser GREEN

Predecessor parser head e8182369c5078587b726322ee1a8a3e8e910f29d had terminal-success repository-native parser/test/coverage checks, but the central exact-head Strix gate failed. Its artifact identified a valid repository-wide HIGH finding: the attachment viewer still places the general session JWT in a URL query parameter for a new-tab navigation path. That broad bearer credential can leak through browser history, logs, telemetry, intermediaries, screenshots, or copied URLs.

This finding is not introduced by this five-file XML diff; it exists in protected behavior and therefore remains a real repository-owned security debt rather than something that may be ignored to merge this PR. The causal remediation belongs to the purpose-bound credential work tracked by #413. PR #506 currently provides the short-lived opaque access-grant domain groundwork, including purpose/audience/resource binding, one-time consumption, expiry, membership-version checks, and hash-only persistence. The runtime migration of attachment-view URL credentials still needs to land on that security architecture; stuffing an independent auth redesign into this XML parser branch would create competing authority and an unrelated semantic blast radius.

The Strix report's prose must not be treated as proof of remediation: its execution log shows attempted client patches failed to apply, so the protected attachment-view JWT-in-query behavior remains unfixed.

Current exact-head verification state

The current head 766eb2d2... was created after restoring the XML-only PR scope, so predecessor success does not transfer. At the last exact-current-head refetch, all six repository-native workflows were pending or queued: Server Tests, Fuzz, OSV Scanner, Dependency Review, Security Scan, and SAST Semgrep. The broader check suite was also still being created/executed. Pending, queued, skipped-required, neutral, failed, absent, stale, or predecessor evidence is non-passing.

The GitHub UI currently shows this PR as Ready for review, but that UI state is not a merge-readiness claim. The unresolved repository-wide Strix security finding, current-head in-flight evidence, and missing independent last-push approval are hard merge blockers under the live rulesets.

Standards, compatibility, and rollback

docs/doctoring/ms-project-xml-import-boundary.md records the supported XML profile, complexity/security boundary, compatibility, rollback, and the XML 1.0 Fifth Edition reference in APA 7th form.

Rollback reverts only the scanner, focused regressions, security guidance, doctoring record, and CHANGELOG entry. It does not touch persisted project data or server contracts.

Merge gate

Do not integrate until the unchanged current head satisfies every applicable live required check and security gate, including resolution of the valid attachment-view credential finding through the dedicated access-grant/runtime path, zero valid unresolved review findings, and a qualifying current-head independent approval from someone other than the last pusher under the live protected-branch rules. Pending, skipped-required, neutral, failed, stale, predecessor-head, author-only, status-only, synthetic, or model-only evidence is non-passing.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review available on request

  • 🔍 Trigger review

Reviews should be triggered manually for repositories with fewer than 10 stars. Select Trigger review above or comment @coderabbitai review to review the latest changes. For a full review, comment @coderabbitai full review.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 73b511e0-0a81-49bd-a5cd-b5aa50be36f5

📝 Walkthrough

Walkthrough

MS Project XML 파서가 태그명 뒤의 XML 공백을 허용하고 정확한 > 경계를 확인하도록 변경되었습니다. 잘못된 태그명, 비XML 공백, 중첩 또는 닫히지 않은 블록을 검증하는 테스트와 보안 문서가 추가되었습니다. Hono 버전도 갱신되었습니다.

Changes

MS Project XML 파싱

Layer / File(s) Summary
태그 경계 스캐너 및 블록 수집
cloud-sync.js
문자열 기반 스캐너가 XML 공백과 정확한 태그명을 확인합니다. tag, collectBlocks, predecessorIdsTask 블록 수집 호출이 새 경계를 사용합니다. 중첩되거나 닫히지 않은 블록에서는 수집을 중단합니다.
파서 검증 및 규칙 문서
tests/unit/msproject.test.mjs, docs/security.md, CHANGELOG.md
허용되는 XML 공백, TaskX 오인식 방지, 비XML 공백 거부, 중첩 태그 및 잘린 입력 처리를 검증합니다. XML 추출 규칙과 변경 로그를 갱신합니다.

Hono 의존성 갱신

Layer / File(s) Summary
Hono 버전 범위 갱신
package.json
Hono 버전 범위를 ^4.12.32에서 ^4.13.1로 변경했습니다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant MSProjectXML
  participant XMLTagScanner
  participant MSProjectParser
  participant ParsedTasks
  MSProjectXML->>XMLTagScanner: 태그명과 XML 공백 뒤의 > 탐색
  XMLTagScanner->>MSProjectParser: 정확한 시작 태그와 종료 태그 전달
  MSProjectParser->>ParsedTasks: Task 및 하위 블록 파싱
  ParsedTasks-->>MSProjectParser: 작업 ID, 단계명, 날짜, 선행 작업 반환
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning package.json의 Hono 업데이트는 연결된 이슈의 XML 파서 요구 사항과 직접 관련이 없습니다. Hono 의존성 업데이트를 별도 변경으로 분리하거나, 연결된 이슈와의 필요성을 PR 설명에 명확히 입증하십시오.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed 파서는 XML 공백, 정확한 태그명, 선형·정규식 없는 처리, 오류 입력 중단 및 회귀 테스트 요구 사항을 충족합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 XML 구분자 공백 허용이라는 주요 변경 사항을 정확하고 간결하게 설명합니다.
✨ 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 fix/xml-tag-whitespace-410

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
seonghobae marked this pull request as ready for review August 11, 2026 03:37

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cloud-sync.js`:
- Around line 775-780: Update the block extraction logic around findTagBoundary
so a closing tag is accepted only when no subsequent same-name opening tag
appears before it; otherwise stop at the unmatched outer opening and do not
collect that block. Add a regression test covering an incomplete outer Task
followed by a complete nested Task block.

In `@tests/unit/msproject.test.mjs`:
- Around line 99-103: Update the malformed XML fixture in the parseMsProjectXml
test to contain an actual U+000B vertical tab using the JavaScript \u000B escape
instead of the literal backslash-v sequence, while preserving the expected empty
result and assertion message.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 22909d81-5171-403f-b335-1b5d6400849d

📥 Commits

Reviewing files that changed from the base of the PR and between 74a5e99 and a160536.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (5)
  • CHANGELOG.md
  • cloud-sync.js
  • docs/security.md
  • package.json
  • tests/unit/msproject.test.mjs

Comment thread cloud-sync.js
Comment thread tests/unit/msproject.test.mjs
@seonghobae
seonghobae changed the base branch from develop to fix/hono-cves-2026-69207-71848-71850 August 11, 2026 13:28

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

Please review exact current head 24512574696bda29845053bc39aa0530c1c7f532 against stack base 24c86489800ef4405e737a8e3d5bc3d54d7628dd. The effective diff is limited to the XML scanner, its realistic regressions, security guidance, and CHANGELOG; all six exact-head repository-native workflows are terminal-success and both predecessor findings are resolved. Do not transfer a predecessor-head status.

Copy link
Copy Markdown
Contributor Author

@opencode-agent review

Please submit an independent formal review for exact current head 24512574696bda29845053bc39aa0530c1c7f532 against stack base 24c86489800ef4405e737a8e3d5bc3d54d7628dd. Verify exact tag-name matching, XML-whitespace-only delimiters, safe truncated/nested handling, and the absence of package changes from the effective diff. All six native workflows are terminal-success and there are zero unresolved threads. Do not mutate, merge, or transfer predecessor-head evidence.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

base='24c86489800ef4405e737a8e3d5bc3d54d7628dd'
head='24512574696bda29845053bc39aa0530c1c7f532'

echo '=== Effective changed files ==='
git diff --name-status "$base" "$head"

echo '=== Effective diff ==='
git diff --find-renames --find-copies --unified=80 "$base" "$head" -- \
  cloud-sync.js tests/unit/msproject.test.mjs docs/security.md CHANGELOG.md package.json

echo '=== Parser structure ==='
ast-grep outline cloud-sync.js --items all --type function --match 'parseMsProjectXml|tag|collectBlocks|predecessorIds' || true

echo '=== Parser references ==='
rg -n -C 5 -P '\b(parseMsProjectXml|collectBlocks|predecessorIds|function\s+tag|const\s+tag)\b' cloud-sync.js

echo '=== Test structure ==='
ast-grep outline tests/unit/msproject.test.mjs --items all --type function || true

Length of output: 26905


🏁 Script executed:

#!/bin/bash
set -euo pipefail

head='24512574696bda29845053bc39aa0530c1c7f532'
echo '=== GitHub check runs for exact head ==='
gh api "repos/ContextualWisdomLab/scopeweave/commits/${head}/check-runs?per_page=100" \
  --jq '.check_runs[] | [.name, .status, .conclusion, .html_url] | `@tsv`' || true

echo '=== GitHub combined status for exact head ==='
gh api "repos/ContextualWisdomLab/scopeweave/commits/${head}/status" \
  --jq '.state, (.statuses[]? | [.context, .state, .target_url] | `@tsv`)' || true

Length of output: 5170


🏁 Script executed:

#!/bin/bash
set -euo pipefail

head='24512574696bda29845053bc39aa0530c1c7f532'
gh api "repos/ContextualWisdomLab/scopeweave/commits/${head}/check-runs?per_page=100" \
  --jq '.check_runs[] | select(.name == "strix") | [.name, .status, (.conclusion // "none"), .html_url] | `@tsv`'

Length of output: 531


@seonghobae I reviewed 24512574696bda29845053bc39aa0530c1c7f532 against 24c86489800ef4405e737a8e3d5bc3d54d7628dd.

I found no code findings.

The effective diff changes only the XML scanner, regression tests, security guidance, and CHANGELOG.md. It has no package.json or lockfile change.

The scanner enforces exact tag-name matching. It accepts only space, tab, CR, and LF before >. It rejects attributes, longer names, and other whitespace code points. The block collector stops safely on truncated input and nested unmatched Task elements. The regression coverage matches these cases.

Exact-head workflow verification is incomplete. The strix check is still in_progress, so I cannot confirm that all exact-head workflows are terminal-success yet.

⚠️ Action not completed

Already reviewed.

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
seonghobae changed the base branch from fix/hono-cves-2026-69207-71848-71850 to develop August 14, 2026 09:01
@seonghobae
seonghobae force-pushed the fix/xml-tag-whitespace-410 branch from 2451257 to ededaee Compare August 14, 2026 09:05

Copy link
Copy Markdown
Contributor Author

@opencode-agent @cwl-noema-review

Review exact clean head ededaee16cc3d70f414735ad865d7ab0dfb66518 against current protected develop. Verify the parser accepts only XML 1.0 space/tab/CR/LF before the exact closing >, rejects attributes, namespace prefixes, lookalike names and U+000B, remains linear and regex-free, and does not carry Hono, package, lockfile, workflow, server, or stale-stack changes. Publish a formal current-head verdict after queued checks are terminal; do not mutate the branch.

@seonghobae
seonghobae enabled auto-merge (squash) August 14, 2026 09:07

Copy link
Copy Markdown
Contributor Author

@opencode-agent review

Please submit an independent formal review for exact current head ededaee16cc3d70f414735ad865d7ab0dfb66518. All six repository-native workflows are terminal-success on this exact head, and both CodeRabbit parser findings are resolved. Verify the linear exact-name XML boundary, accepted XML 1.0 delimiter whitespace, malformed/nested same-name handling, and vertical-tab rejection. Do not transfer predecessor-head evidence, mutate the branch, merge, or bypass the required last-push approval rule.

@seonghobae
seonghobae marked this pull request as draft August 14, 2026 16:28
auto-merge was automatically disabled August 14, 2026 16:28

Pull request was converted to draft

@seonghobae
seonghobae marked this pull request as ready for review August 14, 2026 16:28

Copy link
Copy Markdown
Contributor Author

@opencode-agent
@cwl-noema-review

Copy link
Copy Markdown
Contributor Author

@opencode-agent

@seonghobae
seonghobae enabled auto-merge (squash) August 14, 2026 18:25

Copy link
Copy Markdown
Contributor Author

@opencode-agent
@cwl-noema-review

Review exact current head ededaee16cc3d70f414735ad865d7ab0dfb66518 against live develop@b88e66e81e9701404d29a0f5de4f58573ceee14f. All six repository-native workflows are terminal-success and the historical CodeRabbit findings are resolved on this head. Verify only XML 1.0 delimiter whitespace is broadened, exact element-name/malformed-input protections remain fail-closed, actual U+000B and nested-unmatched regressions execute, and no package/lockfile/server/workflow/security-runtime drift is present. Publish current-head review evidence only; do not mutate or merge.

Copy link
Copy Markdown
Contributor Author

@opencode-agent @cwl-noema-review

Please perform a fresh independent formal review of exact current head ededaee16cc3d70f414735ad865d7ab0dfb66518 against live protected develop@b88e66e81e9701404d29a0f5de4f58573ceee14f. All six repository-native workflows are terminal-success on this exact head, and both prior CodeRabbit findings are resolved on the current diff. Verify exact XML 1.0 delimiter whitespace handling, rejection of U+000B/attributes/lookalikes, the unmatched same-name outer/nested block guard, and the five-file focused scope. Publish current-head review evidence only; do not mutate the branch, merge, or bypass repository policy.

@opencode-agent

opencode-agent Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

OpenCode Review Overview

  • Head SHA: 5c9a3f1c6703c82fd1e61c52bbc153a88586fa88
  • Workflow run: 31933244848
  • Workflow attempt: 1
  • Gate result: APPROVE (exit 0)
B['parseMsProjectXml (cloud-sync.js:741)']; B --> C['findTagBoundary: XML-whitespace + exact 0x3e (cloud-sync.js:744)']; C --> D['tag/collectBlocks nested & truncation guards']; C -->|rejected| F['[] no tasks (linear, DoS-safe)']; D --> E['ScopeWeave task rows (msp-UID)']; D -->|rejected| F; E --> V['node tests/unit/msproject.test.mjs (Coverage PASS)'] \u2014 reflects base-to-head changed flow (byte-exact delimiter scanning broadened to XML whitespace; nested same-name handling tightened). PoC/execution: unit suite passed on this exact head; no package or lockfile change. DDD/domain: import-adapter boundary recorded in docs/doctoring/ms-project-xml-import-boundary.md with rollback instructions. CDD/context: docs/security.md XML-import section updated consistently with the scanner behavior. Similar issues: prior CodeRabbit parser findings (nested scalar/block pairing) are resolved on this head \u2014 current-head thread evidence lists no unresolved threads. Claim/concept check: accepted code points equal the XML 1.0 S production (#x20|#x9|#xD|#xA) and match the W3C Fifth Edition reference cited in the decision record. Standards search: XML 1.0 (Fifth Edition) reference present in the decision record. Compatibility/convention: no DB/API/config objects added; new locals (isXmlWhitespace, findTagBoundary, opening/closing/nextOpening, delimiter, searchFrom) are idiomatic camelCase and not reserved words; byte-exact exports keep identical ids, names, dates, parents, progress, and predecessors. Breaking-change/backcompat: only malformed-input behavior tightens (nested same-name elements now yield no value), documented in CHANGELOG and the decision record. Performance: scanner remains linear \u2014 constant bounded indexOf/slice passes per block with monotone searchFrom advance; the 5000-unclosed-block case at tests/unit/msproject.test.mjs:71-73 asserts no hang. Developer experience: test-file header documents the run command (node tests/unit/msproject.test.mjs); decision record documents the boundary and rollback. User experience: standards-compliant MS Project exports with formatting whitespace before '>' now import instead of silently yielding zero tasks. Visual/DOM: non-web change \u2014 the reviewed interaction surface is the import-parser CLI/API path and its node test harness; no DOM/visual impact. Accessibility/i18n: no UI change; Korean task-name fixtures in the tests remain intact. Supply-chain/license: no dependency changes. Packaging: no package or lockfile change. Security/privacy: no new identifier exposure or auth surface; import path remains regex-free and linear, preserving the ReDoS denial-of-service boundary documented in docs/security.md; U+000B and attribute input are rejected at the delimiter.\n\nApproval sufficiency: bounded evidence supplied affirmative approval evidence for changed files, coverage/docstring posture, risk surfaces, and current-head verification; approval is not based merely on the absence of known blockers.\nVerification posture: CodeGraph evidence was initialized and bounded current-head evidence reviewed for changed-file evidence including CHANGELOG.md, cloud-sync.js, docs/doctoring/ms-project-xml-import-boundary.md, docs/security.md, tests/unit/msproject.test.mjs.\nLinter/static: workflow/static review evidence is bounded by the current-head GitHub Checks gate and changed-file evidence.\nTDD/regression: coverage execution evidence and focused changed hunks were reviewed from bounded-review-evidence.md.\nCoverage: coverage execution evidence reports supported repository test suites passed.\nDocstring coverage: coverage execution evidence reports configured repository docstring gates passed or docstring coverage was advisory.\nDAG: CodeGraph/source-backed behavior map connects CHANGELOG.md to the affected review, runtime, or workflow path and required checks.\nPoC/execution: coverage-evidence job executed on the current head and reported PASS.\nDDD/domain: workflow and repository-governance invariants were reviewed against changed files in bounded evidence.\nCDD/context: CodeGraph evidence, changed-file history, and focused hunks were reviewed from bounded-review-evidence.md.\nSimilar issues: changed-file history evidence was reviewed for comparable local precedents.\nClaim/concept check: bounded evidence, repository source, current-head workflow evidence, and, where numeric, scientific, statistical, or literature-backed claims are affected, original-paper/formula evidence and parameter-recovery expectations were used for claims.\nStandards search: standards and external-source claims require trusted bounded source evidence prepared outside the isolated model process; no evidence-backed standards blocker is present in bounded evidence.\nCompatibility/convention: changed workflow/script conventions, object naming, and reserved-word safety for schema/API/config/code surfaces were checked in bounded evidence.\nBreaking-change/backcompat: deployment evidence and changed-file history were checked for backward-compatibility risk.\nPerformance: changed surfaces were checked for performance risk in bounded evidence.\nDeveloper experience: changed automation, review, test, setup, and maintenance surfaces were checked for helpful or obstructive DX impact in bounded evidence.\nUser experience: connected user, operator, API, CLI, documentation, review-comment, status-check, rendering, and workflow-reader behavior was checked for contradictions against code, docs, and tests in bounded evidence.\nVisual/DOM: deterministic repair does not infer browser runtime execution; source-backed DOM/UI evidence and trusted workflow receipts were reviewed when present, and non-web surfaces used API/CLI/log/docs/workflow evidence instead.\nAccessibility/i18n: accessibility, localization, and human-readable text surfaces were checked where UI, CLI, API message, docs, logs, or review text changed.\nSupply-chain/license: dependency, package, model, container, and external-tool changes were checked in bounded evidence.\nPackaging: package, build, test, lint, and security contracts were checked in bounded evidence.\nSecurity/privacy: workflow-token, review-gate, and repository-automation security/privacy boundaries were checked in bounded evidence.\n","adversarial_validation":{"status":"passed","probes":[{"path":"cloud-sync.js","line":744,"hypothesis":"Crafted input with thousands of repeated unclosed blocks causes quadratic rescanning or a hang in the broadened scanner.","attack_or_counterexample":"'' + '9open'.repeat(5000) + '' (the exact trusted regression input at tests/unit/msproject.test.mjs:71-73).","evidence":"Trusted unit suite passed under Coverage execution evidence (Result: PASS, supported repository test suites passed on head 5c9a3f1); tests/unit/msproject.test.mjs:71-73 executed the 5000-unclosed-block input and asserted deepEqual(parseMsProjectXml(input), []) with the scanner completing (no hang), and the source trace shows findTagBoundary around cloud-sync.js:744 advances searchFrom monotonically past every inspected byte so the missing closing tag yields a single linear indexOf pass rather than a rescan; source-line-sha256=38b4147ab3278cf9384b3a7fb8079b59a5d927ca62efba25cfecadd5fec3ee5a","outcome":"falsified"},{"path":"tests/unit/msproject.test.mjs","line":75,"hypothesis":"An unmatched outer block pairs with a nested 's closing tag and silently produces a mis-parented task from malformed input.","attack_or_counterexample":"'11unclosed outer12nested'.","evidence":"Trusted unit suite passed (Coverage execution evidence Result: PASS); tests/unit/msproject.test.mjs:75-81 asserts parseMsProjectXml of that input deep-equals [] ('an unmatched outer Task cannot consume a nested Task closing tag'), matching the collectBlocks guard that stops at the first unmatched same-name opening instead of pairing it with a later block's closing tag; source-line-sha256=cc344544257d020b5c61ba1982850cda041d79a1a81588f3001c1fae1767b6ba","outcome":"falsified"},{"path":"cloud-sync.js","line":744,"hypothesis":"The broadened delimiter scan accepts non-XML whitespace (U+000B) or attribute-style text before '>', violating the documented import boundary and broadening the attack surface.","attack_or_counterexample":"'9wrong whitespace' and '9wrong'.","evidence":"Trusted unit suite passed (Coverage execution evidence Result: PASS); tests/unit/msproject.test.mjs:106-110 asserts the U+000B-delimited input deep-equals [] and tests/unit/msproject.test.mjs:101-105 asserts the lookalike yields []; the source trace at cloud-sync.js:744-746 (isXmlWhitespace predicate) accepts only 0x20/0x09/0x0d/0x0a and the follow-on boundary check requires exactly 0x3e next, so U+000B and attribute characters fall through to monotone rejection; source-line-sha256=38b4147ab3278cf9384b3a7fb8079b59a5d927ca62efba25cfecadd5fec3ee5a","outcome":"falsified"}],"residual_risk":"Bounded: importMsProjectFile (cloud-sync.js:832) has no dedicated unit test (pre-existing, unchanged by this PR); attribute-form rejection () is exercised only through the scanner mechanism, not a dedicated test case; String.trim() still strips non-XML whitespace inside element content exactly as before this PR (content trimming was not part of the delimiter boundary change)."},"findings":[]}

-->

Changed-File Evidence Map

flowchart LR
  PR["PR changed files"] --> Evidence["OpenCode bounded evidence"]
  Evidence --> S1["Changed file (2 files)"]
  S1 --> I1["repository behavior"]
  I1 --> R1["Review risk: Changed file (2 files)"]
  R1 --> V1["required checks"]
  Evidence --> S2["Docs (2 files)"]
  S2 --> I2["operator or user guidance"]
  I2 --> R2["Review risk: Docs (2 files)"]
  R2 --> V2["docs review"]
  Evidence --> S3["Test: msproject.test.mjs"]
  S3 --> I3["regression suite"]
  I3 --> R3["Review risk: Test: msproject.test.mjs"]
  R3 --> V3["targeted test run"]
Loading

@seonghobae
seonghobae marked this pull request as draft August 15, 2026 06:38
auto-merge was automatically disabled August 15, 2026 06:38

Pull request was converted to draft

@seonghobae seonghobae left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Exact-head Server Tests run 31869862197 now provides the intended RED evidence for the regression-only head 3491f51959a97a4f7bfcc32394b07b130ed6c395: tests/unit/msproject.test.mjs:116 fails because the scalar parser accepts <Name>outer<Name>inner</Name> as outer<Name>inner. The production fix must mirror collectBlocks()' same-name nesting invariant in tag(); do not weaken or remove the regression. After the source fix, rerun the full exact-head repository/security/coverage gates before returning this Draft to Ready.

Comment thread cloud-sync.js Outdated
@seonghobae
seonghobae marked this pull request as ready for review August 15, 2026 15:24

@opencode-agent opencode-agent Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

OpenCode reviewed the current-head bounded evidence and found no blocking issues.

Findings

No blocking findings.

Summary

APPROVE PR #467 (fix(import): accept XML delimiter whitespace). Changed-file evidence inspected: cloud-sync.js (isXmlWhitespace/findTagBoundary scanner around parseMsProjectXml at cloud-sync.js:741), tests/unit/msproject.test.mjs (whitespace, lookalike-name, U+000B, truncation, and nested same-name cases), CHANGELOG.md:56-59, docs/security.md:22, docs/doctoring/ms-project-xml-import-boundary.md. The scanner accepts only U+0020/U+0009/U+000D/U+000A between an exact element name and '>', rejects attributes, longer names, non-XML whitespace, nested unmatched same-name blocks, and truncated input, and stays monotone and regex-free. CodeGraph: parseMsProjectXml (cloud-sync.js:741) has 2 callers in cloud-sync.js and is covered by tests/unit/msproject.test.mjs; importMsProjectFile (cloud-sync.js:832) is unchanged. Approval sufficiency: yes — code, tests, security doc, decision record, and CHANGELOG all match the PR intent and each other. Verification posture: trusted Coverage execution evidence Result: PASS (supported repository test suites passed on head 5c9a3f1); no completed failed GitHub Checks; mergeStateStatus blocked is branch policy/review state, not a conflict (mergeable: true). Linter/static: no lint findings; only hadolint Dockerfile is configured and this PR touches no Docker files. TDD/regression: nested-scalar rejection (tests/unit/msproject.test.mjs:116-121) was driven by a prior RED run on regression head 3491f51 (run 31869862197) and mirrors the collectBlocks guard; whitespace cases cover space/tab/CR/LF on Task, UID, Name, OutlineLevel, Start, Finish, PredecessorLink, and PredecessorUID tags. Coverage: Coverage execution evidence Result: PASS with supported repository test suites passed. Docstring coverage: configured repository docstring gates passed or advisory per Coverage execution evidence. DAG: flowchart LR; A['MS Project XML upload'] --> B['parseMsProjectXml (cloud-sync.js:741)']; B --> C['findTagBoundary: XML-whitespace + exact 0x3e (cloud-sync.js:744)']; C --> D['tag/collectBlocks nested & truncation guards']; C -->|rejected| F['[] no tasks (linear, DoS-safe)']; D --> E['ScopeWeave task rows (msp-UID)']; D -->|rejected| F; E --> V['node tests/unit/msproject.test.mjs (Coverage PASS)'] — reflects base-to-head changed flow (byte-exact delimiter scanning broadened to XML whitespace; nested same-name handling tightened). PoC/execution: unit suite passed on this exact head; no package or lockfile change. DDD/domain: import-adapter boundary recorded in docs/doctoring/ms-project-xml-import-boundary.md with rollback instructions. CDD/context: docs/security.md XML-import section updated consistently with the scanner behavior. Similar issues: prior CodeRabbit parser findings (nested scalar/block pairing) are resolved on this head — current-head thread evidence lists no unresolved threads. Claim/concept check: accepted code points equal the XML 1.0 S production (#x20|#x9|#xD|#xA) and match the W3C Fifth Edition reference cited in the decision record. Standards search: XML 1.0 (Fifth Edition) reference present in the decision record. Compatibility/convention: no DB/API/config objects added; new locals (isXmlWhitespace, findTagBoundary, opening/closing/nextOpening, delimiter, searchFrom) are idiomatic camelCase and not reserved words; byte-exact exports keep identical ids, names, dates, parents, progress, and predecessors. Breaking-change/backcompat: only malformed-input behavior tightens (nested same-name elements now yield no value), documented in CHANGELOG and the decision record. Performance: scanner remains linear — constant bounded indexOf/slice passes per block with monotone searchFrom advance; the 5000-unclosed-block case at tests/unit/msproject.test.mjs:71-73 asserts no hang. Developer experience: test-file header documents the run command (node tests/unit/msproject.test.mjs); decision record documents the boundary and rollback. User experience: standards-compliant MS Project exports with formatting whitespace before '>' now import instead of silently yielding zero tasks. Visual/DOM: non-web change — the reviewed interaction surface is the import-parser CLI/API path and its node test harness; no DOM/visual impact. Accessibility/i18n: no UI change; Korean task-name fixtures in the tests remain intact. Supply-chain/license: no dependency changes. Packaging: no package or lockfile change. Security/privacy: no new identifier exposure or auth surface; import path remains regex-free and linear, preserving the ReDoS denial-of-service boundary documented in docs/security.md; U+000B and attribute input are rejected at the delimiter.

Approval sufficiency: bounded evidence supplied affirmative approval evidence for changed files, coverage/docstring posture, risk surfaces, and current-head verification; approval is not based merely on the absence of known blockers.
Verification posture: CodeGraph evidence was initialized and bounded current-head evidence reviewed for changed-file evidence including CHANGELOG.md, cloud-sync.js, docs/doctoring/ms-project-xml-import-boundary.md, docs/security.md, tests/unit/msproject.test.mjs.
Linter/static: workflow/static review evidence is bounded by the current-head GitHub Checks gate and changed-file evidence.
TDD/regression: coverage execution evidence and focused changed hunks were reviewed from bounded-review-evidence.md.
Coverage: coverage execution evidence reports supported repository test suites passed.
Docstring coverage: coverage execution evidence reports configured repository docstring gates passed or docstring coverage was advisory.
DAG: CodeGraph/source-backed behavior map connects CHANGELOG.md to the affected review, runtime, or workflow path and required checks.
PoC/execution: coverage-evidence job executed on the current head and reported PASS.
DDD/domain: workflow and repository-governance invariants were reviewed against changed files in bounded evidence.
CDD/context: CodeGraph evidence, changed-file history, and focused hunks were reviewed from bounded-review-evidence.md.
Similar issues: changed-file history evidence was reviewed for comparable local precedents.
Claim/concept check: bounded evidence, repository source, current-head workflow evidence, and, where numeric, scientific, statistical, or literature-backed claims are affected, original-paper/formula evidence and parameter-recovery expectations were used for claims.
Standards search: standards and external-source claims require trusted bounded source evidence prepared outside the isolated model process; no evidence-backed standards blocker is present in bounded evidence.
Compatibility/convention: changed workflow/script conventions, object naming, and reserved-word safety for schema/API/config/code surfaces were checked in bounded evidence.
Breaking-change/backcompat: deployment evidence and changed-file history were checked for backward-compatibility risk.
Performance: changed surfaces were checked for performance risk in bounded evidence.
Developer experience: changed automation, review, test, setup, and maintenance surfaces were checked for helpful or obstructive DX impact in bounded evidence.
User experience: connected user, operator, API, CLI, documentation, review-comment, status-check, rendering, and workflow-reader behavior was checked for contradictions against code, docs, and tests in bounded evidence.
Visual/DOM: deterministic repair does not infer browser runtime execution; source-backed DOM/UI evidence and trusted workflow receipts were reviewed when present, and non-web surfaces used API/CLI/log/docs/workflow evidence instead.
Accessibility/i18n: accessibility, localization, and human-readable text surfaces were checked where UI, CLI, API message, docs, logs, or review text changed.
Supply-chain/license: dependency, package, model, container, and external-tool changes were checked in bounded evidence.
Packaging: package, build, test, lint, and security contracts were checked in bounded evidence.
Security/privacy: workflow-token, review-gate, and repository-automation security/privacy boundaries were checked in bounded evidence.

Adversarial validation

{"status":"passed","probes":[{"path":"cloud-sync.js","line":744,"hypothesis":"Crafted input with thousands of repeated unclosed <Task> blocks causes quadratic rescanning or a hang in the broadened scanner.","attack_or_counterexample":"'<Project><Tasks>' + '<Task><UID>9</UID><Name>open</Name>'.repeat(5000) + '</Tasks></Project>' (the exact trusted regression input at tests/unit/msproject.test.mjs:71-73).","evidence":"Trusted unit suite passed under Coverage execution evidence (Result: PASS, supported repository test suites passed on head 5c9a3f1c); tests/unit/msproject.test.mjs:71-73 executed the 5000-unclosed-block input and asserted deepEqual(parseMsProjectXml(input), []) with the scanner completing (no hang), and the source trace shows findTagBoundary around cloud-sync.js:744 advances searchFrom monotonically past every inspected byte so the missing closing tag yields a single linear indexOf pass rather than a rescan; source-line-sha256=38b4147ab3278cf9384b3a7fb8079b59a5d927ca62efba25cfecadd5fec3ee5a","outcome":"falsified"},{"path":"tests/unit/msproject.test.mjs","line":75,"hypothesis":"An unmatched outer <Task> block pairs with a nested <Task>'s closing tag and silently produces a mis-parented task from malformed input.","attack_or_counterexample":"'<Project><Tasks><Task><UID>11</UID><Name>unclosed outer</Name><Task><UID>12</UID><Name>nested</Name></Task></Tasks></Project>'.","evidence":"Trusted unit suite passed (Coverage execution evidence Result: PASS); tests/unit/msproject.test.mjs:75-81 asserts parseMsProjectXml of that input deep-equals [] ('an unmatched outer Task cannot consume a nested Task closing tag'), matching the collectBlocks guard that stops at the first unmatched same-name opening instead of pairing it with a later block's closing tag; source-line-sha256=cc344544257d020b5c61ba1982850cda041d79a1a81588f3001c1fae1767b6ba","outcome":"falsified"},{"path":"cloud-sync.js","line":744,"hypothesis":"The broadened delimiter scan accepts non-XML whitespace (U+000B) or attribute-style text before '>', violating the documented import boundary and broadening the attack surface.","attack_or_counterexample":"'<Project><Tasks><Task\\u000B><UID>9</UID><Name>wrong whitespace</Name></Task\\u000B></Tasks></Project>' and '<Project><Tasks><TaskX><UID>9</UID><Name>wrong</Name></TaskX></Tasks></Project>'.","evidence":"Trusted unit suite passed (Coverage execution evidence Result: PASS); tests/unit/msproject.test.mjs:106-110 asserts the U+000B-delimited input deep-equals [] and tests/unit/msproject.test.mjs:101-105 asserts the <TaskX> lookalike yields []; the source trace at cloud-sync.js:744-746 (isXmlWhitespace predicate) accepts only 0x20/0x09/0x0d/0x0a and the follow-on boundary check requires exactly 0x3e next, so U+000B and attribute characters fall through to monotone rejection; source-line-sha256=38b4147ab3278cf9384b3a7fb8079b59a5d927ca62efba25cfecadd5fec3ee5a","outcome":"falsified"}],"residual_risk":"Bounded: importMsProjectFile (cloud-sync.js:832) has no dedicated unit test (pre-existing, unchanged by this PR); attribute-form rejection (<Task a=\"b\">) is exercised only through the scanner mechanism, not a dedicated test case; String.trim() still strips non-XML whitespace inside element content exactly as before this PR (content trimming was not part of the delimiter boundary change)."}
  • Result: APPROVE
  • Reason: MS Project XML delimiter change is correct, linear, well-tested, and consistently documented across code, security.md, decision record, and CHANGELOG; trusted unit suite passed on this head and no failed checks or unresolved threads exist.
  • Head SHA: 5c9a3f1c6703c82fd1e61c52bbc153a88586fa88
  • Workflow run: 31933244848
  • Workflow attempt: 1

@opencode-agent
opencode-agent Bot merged commit 28420da into develop Aug 16, 2026
38 checks passed
@opencode-agent
opencode-agent Bot deleted the fix/xml-tag-whitespace-410 branch August 16, 2026 08:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(import): accept XML whitespace before exact tag delimiters

1 participant