From a1fb3a09b5328defdea350211f38ba119ecf3ecd Mon Sep 17 00:00:00 2001 From: Phelim Date: Mon, 12 Oct 2026 17:24:44 +0800 Subject: [PATCH] test(fixtures): add a JianYing 9.0.0 Windows capture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A real 剪映专业版 9.0.0 (Windows 10.0.19045) project, captured with `capcut fixture` after the app had opened a draft this CLI wrote, so the app encrypted `draft_content.json` / `template-2.tmp` / `draft_meta_info.json` in place and materialised `Timelines/` while leaving the primary `draft_info.json` plaintext. That state is worth committing because it is the one the docs cannot describe from memory: the project stays readable through its plaintext primary, the encrypted mirrors are skipped rather than fatal, and the version markers come off the primary. The test pins all three, plus the current write-guard verdict for the version so a future change to it is deliberate. Two things the capture also establishes, recorded in the fixture README and the new docs/version-support.md row rather than asserted here: - On this build an *app-authored* project is a plaintext `draft_content.json` with no `draft_info.json` or `template-2.tmp` at all, so the 6.0+ note that the primary has been `draft_info.json` since 6.0 does not hold here. - A segment the app itself carries can have a `target_timerange` with no `start` and no `speed`. The write guard is deliberately untouched by this commit: a committed fixture backs the storage shape, not a round-trip on every 9.0.0 build, and one machine's capture is not evidence enough to narrow the 6.0+ refusal. --- CHANGELOG.md | 4 ++ docs/version-support.md | 1 + .../fixtures/jianying-9-0-0-windows/README.md | 51 ++++++++++++++++ .../draft_content.json | 1 + .../Timelines/project.json | 1 + .../jianying-9-0-0-windows/draft_content.json | 1 + .../jianying-9-0-0-windows/draft_info.json | 1 + .../draft_meta_info.json | 1 + .../jianying-9-0-0-windows/template-2.tmp | 1 + test/jianying-9-0-0-windows.test.mjs | 58 +++++++++++++++++++ 10 files changed, 120 insertions(+) create mode 100644 test/fixtures/jianying-9-0-0-windows/README.md create mode 100644 test/fixtures/jianying-9-0-0-windows/Timelines/469574b7-ab5c-47f4-af82-f96ea7fbaea9/draft_content.json create mode 100644 test/fixtures/jianying-9-0-0-windows/Timelines/project.json create mode 100644 test/fixtures/jianying-9-0-0-windows/draft_content.json create mode 100644 test/fixtures/jianying-9-0-0-windows/draft_info.json create mode 100644 test/fixtures/jianying-9-0-0-windows/draft_meta_info.json create mode 100644 test/fixtures/jianying-9-0-0-windows/template-2.tmp create mode 100644 test/jianying-9-0-0-windows.test.mjs diff --git a/CHANGELOG.md b/CHANGELOG.md index ec02070..02b7da5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to capcut-cli are documented here. The format follows [Keep ## [Unreleased] +### Added + +- `test/fixtures/jianying-9-0-0-windows/` — a real JianYing 9.0.0 (Windows) project captured after the app opened a tool-written draft: the plaintext `draft_info.json` primary alongside the `draft_content.json` / `template-2.tmp` / `draft_meta_info.json` mirrors the app rewrote into encrypted blobs, plus the materialised `Timelines/` layout. A regression test pins that the encrypted mirrors are reported as unparseable rather than breaking canonical selection, and `docs/version-support.md` gains a JianYing 9.0.0 (Windows) row (evidence: reported; storage shape fixture-backed). The write guard is deliberately unchanged — one machine's capture is not a round-trip claim. + ## [0.29.0] — 2026-10-09 ### Added diff --git a/docs/version-support.md b/docs/version-support.md index 59fee0c..3a5f2d8 100644 --- a/docs/version-support.md +++ b/docs/version-support.md @@ -35,6 +35,7 @@ There is no blanket “6.x–9.x tested” claim. Only versions with committed f |---|---|---|---| | 5.9.x | community-reported | expected-compatible | Last widely used plaintext line; no sanitized app-created fixture is currently committed. | | 6.0+ | reported | known-broken for encrypted files | `capcut decrypt` detects encryption and explains the workaround; it does not decrypt the file. Plaintext/exported variants can still be inspected normally, but the write guard refuses mutating writes even on plaintext variants without `--force-write` — the 6.0+ app is the encrypted-draft era and a plaintext write may be ignored or shown as corrupted. | +| 9.0.0 (Windows) | reported; storage shape fixture-backed | tool-written plaintext primary accepted on open; the app encrypts the legacy mirrors on close | A draft written by this CLI was closed and opened in 剪映专业版 9.0.0 on Windows (10.0.19045): the added text segment was present and editable. The capture after that open is committed as `test/fixtures/jianying-9-0-0-windows/` — plaintext `draft_info.json` (the primary, carrying `platform.app_version` 9.0.0 / `app_source` `lv`), with `draft_content.json`, `template-2.tmp` and `draft_meta_info.json`, plus a materialised `Timelines/` layout, rewritten by the app into encrypted blobs. The CLI keeps reading the project through the plaintext primary and never writes into those mirrors. Two more observations from the same build: an app-authored project here is a plaintext `draft_content.json` with **no** `draft_info.json`/`template-2.tmp` at all — so "the primary has been `draft_info.json` since 6.0" (the 11.4.0 row below) does not hold for this build; and a segment written by the app can carry a `target_timerange` with no `start` and no `speed`. The write guard stays as the 6.0+ row describes until a second build confirms the round-trip. | | 11.4.0 (macOS) | reported | plaintext drafts accepted on open — generation is not blocked | A plaintext `draft_info.json` written by a tool is opened, upgraded to the encrypted format in place, and completed with `Timelines/` and a cover by the app itself; the engine probes plaintext vs cipher per file (`DraftIO::getUriCipherTypeStatically`) and the primary file name has been `draft_info.json` since 6.0 — a `draft_content.json` dropped into the folder is what produces "草稿内容已损坏" ([pyJianYingDraft#198](https://github.com/GuanYixuan/pyJianYingDraft/issues/198), 2026-09-10). So encryption limits *reading* an app-authored draft, not writing a new one; the write guard above stays conservative until a fixture from such a build is committed (`--force-write` writes). Media under `~/Desktop`, `~/Documents` or `~/Downloads` triggers a "no access permission" relink prompt on this build (macOS TCC) — `lint` names it and `lint --fix` stages the file into the draft. | ## v0.11 storage and write safety diff --git a/test/fixtures/jianying-9-0-0-windows/README.md b/test/fixtures/jianying-9-0-0-windows/README.md new file mode 100644 index 0000000..c1982ba --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/README.md @@ -0,0 +1,51 @@ +# Fixture: JianYing 9.0.0 on Windows + +A real project folder from 剪映专业版 (JianYing) **9.0.0 on Windows 10**, captured +with `capcut fixture`, after the app had opened it. Only timeline JSON is +committed — no media; home paths, emails and device identifiers are redacted. + +``` +platform.app_version 9.0.0 +platform.app_source lv +tracks 2 text segments +canonical (diagnose) draft_info.json +``` + +## What the capture shows + +Captured **after the app opened a draft that a tool had written**: + +| File | State | Notes | +|---|---|---| +| `draft_info.json` | plaintext JSON, 3485 bytes | the primary; still the bytes the CLI wrote before the open — the app did not rewrite it | +| `draft_content.json` | encrypted blob | rewritten by the app on close | +| `template-2.tmp` | encrypted blob | rewritten by the app on close | +| `draft_meta_info.json` | encrypted blob | rewritten on close | +| `Timelines/project.json`, `Timelines/469574b7-…/draft_content.json` | layout + encrypted blob | the nested layout the app materialised | + +Two facts this bundle pins down on this build: + +1. **A plaintext tool-written primary is accepted.** The draft was written by + `capcut-cli` (a `text` segment added, then a text template applied), closed, + and opened in the app, which showed the added segment and allowed editing it. + The app then encrypted the *legacy mirrors* but left `draft_info.json` + plaintext — so the CLI still reads the project through its canonical file and + never writes into the encrypted mirrors. +2. **`target_timerange.start` is not guaranteed.** The `smoke-test` segment + carries `{"duration":3000000}` with no `start` and no `speed`, while the + `smoke-cta-default` segment carries both. The app renders the first one + normally; `capcut segments -H` printed `NaN:00NaN` / `undefinedx` for it + before the read-side fix in the same series. + +## Scope of the claim + +This is *one machine*. It establishes the storage shape and that this build +opened a tool-written draft; it is not a claim that every JianYing 9.0.0 build +does. `docs/version-support.md` keeps the write guard conservative on the +strength of that — see its JianYing 9.0.0 (Windows) row. + +An app-authored project on the same build looks different: a plaintext +`draft_content.json` and **no** `draft_info.json` / `template-2.tmp` at all. That +shape is not committed here (its content is the owner's), but it is why the +"primary file name is `draft_info.json` since 6.0" note in +`docs/version-support.md` does not hold for this build. diff --git a/test/fixtures/jianying-9-0-0-windows/Timelines/469574b7-ab5c-47f4-af82-f96ea7fbaea9/draft_content.json b/test/fixtures/jianying-9-0-0-windows/Timelines/469574b7-ab5c-47f4-af82-f96ea7fbaea9/draft_content.json new file mode 100644 index 0000000..17b8c96 --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/Timelines/469574b7-ab5c-47f4-af82-f96ea7fbaea9/draft_content.json @@ -0,0 +1 @@ +8g5dJ3cJC6gaEHvljj7Iid0FZ8jeSbZtH71jdvbTB7e03rBB3eBCZ9PJzEhgGhBYDVEcFdnySRJQ4ceJ0G5Jk95aqJF2g01yTAw09IhxX6XsYu9IH9bpDUr1C7NoNaqHGj0/BVWPZElE0OKUFJbHZn+U9DvaXBQz320t+QZlgik1CvpdNLptDaxscpoCsCpcssVOUndtvTmyu6qd64t5/3wJoQav+U727eO4jfy2/Z5RZLEnhx5aFVzO9fxZwkjgFg+eFSfYt1+b06c0E10j73eyU7fZvUsNR5i7ObQUssm6KeJrP1R7IK/WMHcGuxA9+1IuxRP5usK4lOJ8UxMpz5HVkFJr9vAGwGMNOs9JvRIavL7+nTEszDDvT8CVaodI3EllaXs8IVJ5azbqlXNsZGwy/Fw+0YvKXdftDLmTSk/oa64aTh2V6w1Z/H0brYVOBZz/jvNsCzTA8nORP61Z5Y5E08hM378EZktYqIsRZwFdoX31JpxR2PiQPWc+wFp7JxNlNH9Pq0NabifIP+RnuUCNT90IMSFJReGv9RPWDBBDK3jqN+hIjDcfzE4kYLYSDgQcretLxZE366ClO48jDoKcX6zbK8EkAjyzhYZkAKILLCbOsTLzKLuCy4rG1Lk4tPOqerJsyeJoJbO7UYStdhyWtXz5CcfS5Bs+BYk4uePlTMG2RxJa7Er8+ztYD40tKymwhMmqpQaW+qEfrTutp9Mis8svC4+I/sNg3mlXbz1iGc7EryCyfx/kc9hX4opnWf8odY5+dCGGlgvAi4qGtcymzIw5vjT8m5OcWEoKuKbXmgV895VaUMzlLuRtG+aULYrCusrMABT9/BBh5wp2Sij23GTOs0o/sRSBClz1zS7bcp3WzvQL4cGcFfQQ1oq6pokfgCbPNf1ox7Teye6EfU1ba8FWVjwTxPo7p/SM3Nkyposu8dYyku15iR+E9bZC2YUgxhdiQb0IFpwdSmBGjkBMXaXYyn1kA95qkpVBrsbYyiH7zOP7lyCi+JFTBr4qRtkEO5TYzinYFFJ3ZDldNyJtxwosazOSlLIXulOc4mBOdL0+f1jJn9dYxuub52b2gzs4266ycKpU4Sc4j+gS+wd+GGCLoJ2oa5WPTf8K8IGUbisO25mJE7IMuioFO/AJDf14IRkjqcoTKqoM3b9jHtGaKA0R/5YMKUNgu2YBlr7+fp6Q5BdpH0N4t77Hvk7h+o100ZV4hqUQ1xUDhCZ6UPTEktwffEghLA1GPlHGvSdkBIZJIsXAWmsrzKq0rJ2ZQ/6EQSlxJ8fn9mQqs03XHbKmPH+WVc+MltydLCkQ+KMB4Qq7rIdbIn4RxlzDWiIsRuBpinqR3bMi4N6WcKh/KmQVd8EtpdyI9YpgEOrCT2UWe8NIWjZdyhRoL1G/aNiI03jXgCcOTOfFKLsDPoSYudhfHASjLc4y/tBvvZEpx/+cRmB0Bb/HnWF9qWo2KexInXCHzurdNmO+NTGMZVRXsGE4YPpDeqJhckTSR3Doa1MYE/XG6l6G6ni860GVDzC0CPKa5IRw/Cy839v04aiOF3Z7z538mDdwswmMoynC8T5cS8duqkb6g+afuWap5e0pYLCYbx/7OIN4F69lczJgLRoa9HyniJJWxkcnFQ1i2VVQ0GEG2C/ZlN4kNQ7/Sd5xTLsaIlJcWJUvrZy4XqQg96v9GV6QXOVxpjZQQFB1szN15mfckImC0jVLRyXara4Uoup53F+NpIbxq19rHKCu/vYSnCsueejaF2fS3jgt9czRgYErgrkGtFxieP2PMSQxrLUwQaVv+dOx8MmhuB1RG9FkuA2FmvOJ1e0HhckanRDfAFfFxLVlFZfEDPxBch4nVoOUV9XcZiPPT4FZgiUUNHuew0xfgsGeF4HrXIWdE9lVm2eGhivIk4OYgjs2nbLwFRQv+ATE4ResZHtNBIdDU5vVblH4pVE0CMygiPft67Yrc20iWtH8NYvObAUw38V+OaMrDXGqZpk9jz9n/fEOiv9OLEFvUMfVI11kPnN3HFtXbPcpc57uNiVQF7BDRYtqTdNNKHPSggfqARpiqw97uTdRFJGZkm1JX1Obde2EMn3LZ9efZ4X73OeVlr8RQ3AVPXBDnEJo4EXdinTtH7JlEHPs4/bgdBrjBb0+HDbC+5gc49Gu6Q2GHyDtorSSqD78/cf6gp9JWQuJPJqlGtyVVbgcO/r1zlTo90QzZob4oONhp0g4FuorH6x2S6h55hwzVk0jGJ/o6S6Xr7+GDR9PJoMQ4ddzLTkHpLmxGfaRKfEToq93ArbgJEhVtA56IFTldNEN13VGAOUnZLdleJKcu+uKiX1SU0kF5B8mCrk4x5kd/iIthH6Noke3hvXlJtMxAAh9YAqs6Zzr+qyA14XNA3A2fyFRwoPCxes/5G5lHDP7yIzwGxwHFyleWiKHKVGuzb311C9oARJl29Zxc2CdFYEGK8fUBZPmB8ssV+Z/7Z6tR3aVwEoWfSs9UQ5vYhukjSQuPsEp1LVJntEnaf9Y+VMVSimJ4nmBpcjqxIc9sv72HJdFUY4fySUjys8b8mY8ejvRQIXGCPnER0/a6yicHezioqpD+n1G9PsiHwE3C7IIKpUnmtHo8IQ2mUOYVBv+ZSxRB7asA/Vie/GIpXGh6XLvD8D8gS6pXxb/ufdPYki3WmoihayP1nMY+fCpDHy4+1+cpneeep7+o0GM/MJYCxvjKGX6cJYSc9dfN3mlED0M1UiChIjhjS3OI4t8rJXIGwi2xTNJKkr0k23+eUv61nKIukFSUUg7RxXqcyV9DwmCyuARe4Un+qq3MF5OSOKGdVSMPg49nD0Tv9P6R5LwUtUL66i3P2z+f+EwxsApLx3PwZ+S2snmf1nzdhIfg5lBlDD5z0Y0claq/pKSDXzg9oatf2wyJ6S0w4yafUbif8rLZP6mYr6m8v/jY/Rqtyh+reivk7KPtFcr2GE3ErwjbNGpHfNLcq1sdBRa3j2+ \ No newline at end of file diff --git a/test/fixtures/jianying-9-0-0-windows/Timelines/project.json b/test/fixtures/jianying-9-0-0-windows/Timelines/project.json new file mode 100644 index 0000000..8eef90e --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/Timelines/project.json @@ -0,0 +1 @@ +{"config":{"color_space":-1,"render_index_track_mode_on":false,"use_float_render":false},"create_time":1791791682378893,"id":"469574b7-ab5c-47f4-af82-f96ea7fbaea9","main_timeline_id":"469574b7-ab5c-47f4-af82-f96ea7fbaea9","timelines":[{"create_time":1791791682378893,"id":"469574b7-ab5c-47f4-af82-f96ea7fbaea9","is_marked_delete":false,"name":"时间线01","update_time":1791791682378893}],"update_time":1791791682378893,"version":0} \ No newline at end of file diff --git a/test/fixtures/jianying-9-0-0-windows/draft_content.json b/test/fixtures/jianying-9-0-0-windows/draft_content.json new file mode 100644 index 0000000..17b8c96 --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/draft_content.json @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/test/fixtures/jianying-9-0-0-windows/draft_info.json b/test/fixtures/jianying-9-0-0-windows/draft_info.json new file mode 100644 index 0000000..d3e3f4f --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/draft_info.json @@ -0,0 +1 @@ +{"id":"469574b7-ab5c-47f4-af82-f96ea7fbaea9","new_version":"","name":"_smoke","config":{},"canvas_config":{"ratio":"16:9","width":1920,"height":1080},"tracks":[{"id":"235808b6-0511-4e81-80dd-246bd8baf520","type":"text","segments":[{"id":"62a041c7-5af2-4aab-88ef-04fd75bcb923","target_timerange":{"duration":3000000},"render_timerange":{},"clip":{"scale":{"x":1,"y":1},"transform":{"x":0,"y":0},"flip":{}},"uniform_scale":{},"material_id":"9b4ae774-d7c1-45ec-b462-558d44838ac7","render_index":15000,"enable_lut":false,"enable_adjust":false,"enable_hsl":false,"responsive_layout":{},"enable_adjust_mask":false,"raw_segment_id":"235808b6-0511-4e81-80dd-246bd8baf520","source":"segmentsourcenormal"},{"id":"f9b0e86a-9080-4224-80be-ba2a80d4191e","material_id":"357ded67-34ba-45e6-930d-ab8b01ca1eaf","raw_segment_id":"235808b6-0511-4e81-80dd-246bd8baf520","target_timerange":{"start":0,"duration":3000000},"source_timerange":{"start":0,"duration":3000000},"speed":1,"volume":1,"visible":true,"reverse":false,"clip":{"alpha":1,"rotation":0,"scale":{"x":1,"y":1},"transform":{"x":0,"y":0.7},"flip":{"horizontal":false,"vertical":false}},"render_index":15000,"track_render_index":0,"track_attribute":0,"extra_material_refs":["c852a521-f867-43dd-adde-f30f635768d3","5cc6b12c-4c07-402a-acd8-58b0cf6b0eae","65659df4-165d-42e8-9440-dca4167d88e1","7d7e5189-970d-47d8-8409-ecdeb021769d"],"common_keyframes":[],"keyframe_refs":[]}],"name":"text"}],"materials":{"texts":[{"id":"9b4ae774-d7c1-45ec-b462-558d44838ac7","type":"text","content":"{\"styles\":[{\"range\":[0,10],\"size\":15,\"bold\":false,\"italic\":false,\"underline\":false,\"fill\":{\"alpha\":1,\"content\":{\"render_type\":\"solid\",\"solid\":{\"alpha\":1,\"color\":[1,1,1]}}}}],\"text\":\"smoke-test\"}","words":{},"current_words":{},"combo_info":{},"caption_template_info":{"resource_id":"","path":""},"line_spacing":0.02,"shadow_point":{"x":0,"y":0},"text_color":"#FFFFFF","font_path":"D:/软件/JianyingPro/10.9.0.14199/Resources/Font/SystemFont/zh-hans.ttf","lyrics_template":{"resource_id":"","path":""}},{"id":"357ded67-34ba-45e6-930d-ab8b01ca1eaf","type":"text","content":"{\"styles\":[{\"range\":[0,17],\"size\":18,\"bold\":false,\"italic\":false,\"underline\":false,\"fill\":{\"alpha\":1,\"content\":{\"render_type\":\"solid\",\"solid\":{\"alpha\":1,\"color\":[1,0.8431372549019608,0]}}}}],\"text\":\"smoke-cta-default\"}","alignment":1,"font_size":18,"text_color":"#FFD700","typesetting":0,"letter_spacing":0,"line_spacing":0.02,"line_feed":1,"line_max_width":0.82,"force_apply_line_max_width":false,"check_flag":7,"fixed_width":-1,"fixed_height":-1}],"speeds":[{"id":"c852a521-f867-43dd-adde-f30f635768d3","type":"speed","speed":1,"mode":0,"curve_speed":null}],"placeholder_infos":[{"id":"5cc6b12c-4c07-402a-acd8-58b0cf6b0eae","type":"placeholder_info","error_path":"","error_text":"","meta_type":"none","res_path":"","res_text":""}],"sound_channel_mappings":[{"id":"65659df4-165d-42e8-9440-dca4167d88e1","type":"none","audio_channel_mapping":0,"is_config_open":false}],"vocal_separations":[{"id":"7d7e5189-970d-47d8-8409-ecdeb021769d","type":"vocal_separation","choice":0,"enter_from":"","final_algorithm":"","production_path":"","removed_sounds":[],"time_range":null}]},"keyframes":{},"platform":{"app_version":"9.0.0","app_source":"lv"},"last_modified_platform":{"app_version":"9.0.0","app_source":"lv"},"extra_info":{},"path":"","uneven_animation_template_info":{},"smart_ads_info":{},"function_assistant_info":{"fps":{}}} \ No newline at end of file diff --git a/test/fixtures/jianying-9-0-0-windows/draft_meta_info.json b/test/fixtures/jianying-9-0-0-windows/draft_meta_info.json new file mode 100644 index 0000000..efbbcfd --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/draft_meta_info.json @@ -0,0 +1 @@ +2BA8xSy9f3isWpmKuSFpdIEJhw1c3dvW3bBHiGh313hiCcGB4gH0lMakcZSd3ecLBsjDaIqwiR+l0FIIqUttq4X1r424AN9ABta2bE7853Q9X72qVwgVbXaSTKPjtwRF4hb/qOjuvCpHI8k7N8Bfy3Muaw8fQpkbXLDPQLXQltzhreGoa1KTjVdsv+XnQ2K0Qz63Y/swIMxS1Lk2KmC9jWp3vAfjEBBcHtTengNkZDCp5QtgsassZGsrRceS9qlultzZhyXg7apAjJzLuD4H8YtkvSZxZVXOZAdUe5DAAe4s+am0fSa7a8Dx4DeRgapms460s4JtKSVvSllBMejlzepIHdZffeRDLX1m8vZCZG9NF9JYDTFgoHanu65AwR9+dy+vHqhLjoPvL77jxgwztUiFMuFvO/iS23izF6XY9fDuSLjVRUl1zeVSjr3p+OWj6hb+BBq0fF824Sk7ewxP2hXpf4DcCrzeptfHRoB8q+JcmfEuJXsAk0RAQblYCXjo3NpnNIYASeEq7zuXcXkGZLzWgcLSvomFXq5ou08cwgsVqbFOPQ/JV2oDHbiqH8kbyOaqkf7MF9FCUK1sl9tRvY6BE04VgIhGDE2WeHYGxy9T++s2GKQ8a820ORE2DTNZ3t8BTDbqzPuF+7jkojD92iHhF+0x0yS+141ZOM4ChLRrUhP/Wyu34+6YAAZ++fq9LgxDlKVBNaUYR8hVEGvgc0Y6SVrxxfn6eH+XC3pQ4lCPnlYzveUYbd/kjZB6nr41DQel36emngMQaEU/JJ4bILfgcTJivFHSUG8I6rtE3PI4kIbkPuokj72/+f9YD8jE8WXNkVxyz0TA8Xbq8Y/PN13HEb/jio71k6NGEauIYVTuaKKbhbvR2JDfvYarqPXuRWoGHM8guUrd7MyNUm9dkT2ZKjd+W3LCj56o5QqJHp+SWEo8b1/O0ekBOAbWco4sd4IkxsMgAOIPk0Khu1oCq2aqI966lxuUbDWlw5pO+7YRKOze9ocItiIEcbO2Tntj72IqJn7J3vqPwif/9JshIQngeBfeBFk+kpZozNlVZ1zDH7FvMzB/QAEwE/DP7tOqXkHlLIpSxGcw+hvUDXkcd6zzR6w8ecamBari78+aB+0yzNfpk0UKlAQJe2AjI8fJG7v1qT2wvSRrNnzelow1CBWvVWLJXorj7tCdlhFKOxY6k8/Ps/LIHGazCvgH/xSyFBfWY7xHseinMKovxtCQ9Zg4XYUjuTAtJBPtMTCYAs5gMa/mJXmm4DrYmnRDPc9wj53f21vVtccLkfH1fDtceYtDJcavX1i8LB7gSAKsYJ3vf9Gya+WCIfKGX3kHX6Aaf3p/PdMcaNqG+U+ZgYThpoR8dq2Y21jZ/sNQBLuV8Sfdhuo11mjs8W07JZwu6YSydHxbzSQYAQIj9hxL7YT48WlX8sh/gk2j9uEi/G+fEF5atNWy8PakA7G5+AlslHHppVLysyRyDLSx6aSbEYMnz2DchDlhJJn06nW9VaiXIR+ChbR6Ow1EyLU45vQM39CHVsE7lQzgKUVobCYC0tgN6SdmMlvltk8sKGLUUyNg+q6R4nTXdahBSwgzVqVnEvrgQ6rTT2fVU1P/R7e1AxLYjakJTT07ZZJ29UyxE3+ecU1Jz9rbr5Ai7kxyhnpNIDWJPv3YvG1LjdpX6mWhY0b4PNYuDSn2WCiSTOw7975qVSW/6N2vMgrsHrksWYbtol+gA9divnGhO3uf54IaiQcP5jS2z+MIuPQ5i3n/FD0XbsnDUZSjNysPJnKuBK5n7u/4salPXFDsnK4wJ0/a7QrvBn03jPlZpJ2Nl6SueLI8dgssyhd6GvGc4B+tC6g3pJSB6j0grRQ23Lt2HKlA64WkKssvL1MQ+y11jMTz/gzk6cteC0VijR2WJREVlnNfxCShmzvZbjKf5t4AvNfQ/qoAsN7triSrtlje5O18gs2yymt8hHcPSFNE5HAJHv6+Sk4caLjG3ZhTqJBSqF87yO+SwbZUWcjpyI5Xn3Ig+VTOgZhhQdamPP9JcbiCJPWcothp5E5uJc6K9TJzFaSIHUvREIkxNX9Xc4FacA0W3s/ka12iMldz2jNmbCjRpgk/a4ApGBCtKKlk1zsaFhjeZX70mFCZ6G6t2BSdzNBSr29EMdoOH/YaM4S4qI4lE7ebpbyk+JpE8JiKHVu7Lu0zvF9nTEWva2uyBfe5/EEDyYTLk7aXSigS4mS65NG9mld0NQKZ8qQnDWeqmSMRFNt5eqip+osDk5ZFo9OjYefRi80IlBRI3MwZnJXAbsStvSLf5TkoFiu92HTRzmBpIGwqf8191IZMGUvw3UYdh3cMo8dk1nSnMZSugRFfP8OxFJdd50507e/f4VP8SZRSD5anOOBi1It037vo8lZhq8pFnCIRru0ytIl199yu8Adj5E7PNHI560Ljnzwg42lwn3NxQ/jy1J51joN7BW4kCeClgnOFaAgbKNBp7Yt4887Asn8g3Cwph0iuyA26DqsaeJBxipzoZe0/TbJO/2BwlKsMWjugbzQoKApcotRhvrAmWQDpmZep2TcaPHW9XjoGWgQjuxeFIWOmjrF6u8IXSQuxt2BiCTqXKVKCaXEKaoC0QmjB0ygH6PeN4ycrCzOsDyp9WvHO47yLmM9HZQyb/Ia6quhnHH/kbUvkoGOnUSDsCXDN1ez1l9KD1Ub5T4Z6F6W+8a6gC21rMrCHwjIcSfZQhG91mqCYPdLyx5OzQJtSQkMKT8fHilJX1SzxbxdWdOw/qKbJKtwA2j/0MP/94FPvJ6hdYsHKiaRHMGBjiTaQ5LIcMEBbvgLY8DFGJVoufuVyqIlTKoHqZlCfj+gd8KcVOrnUVtGyKTUqg05Xzz34qiHufQDQqRAIo+rNeMvHkQP07rxS4BwnqWfA0QqR17t0w+FrE0/8WiBxSMLkopIEvr3RQ1n7yBRU9Xn9M33PnIzOnuKIPtykLVM76SxrkEEoKnvXWxTBAEmyK0KoVDxbvbwH1WbIR6rAfkm9me2BhMfxD02c5uoY7bmLwjPli0t01XBhLGlAS46lS+qKCaer23Vye2G0HMoEEwlpQTZ9TV9RnxWOnJyXTgrfAyL05moZ/K2DsShJRkhna7qnhMOSNcpBmEQbFF8vfHAHlXIdC7IlGEyhwXace3jDs6yGpSfe0fF4mzWrYjXxA0QMvRgXbxW/jsY6USzgNW+Gn5xICwGfLn28LRn4J9SvDp0/wOnRXCaHpGDUP4vDICh36LykkM6ZdkCbQyikl6BOpzPrmhY1IWPiD8L2GGfRLE/FSm/gKLhriODXMrF81uU8pA7Rfz+aWYgv52/uSQtuH7belv+INEQQwaLTWUONCHcdbA== \ No newline at end of file diff --git a/test/fixtures/jianying-9-0-0-windows/template-2.tmp b/test/fixtures/jianying-9-0-0-windows/template-2.tmp new file mode 100644 index 0000000..17b8c96 --- /dev/null +++ b/test/fixtures/jianying-9-0-0-windows/template-2.tmp @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/test/jianying-9-0-0-windows.test.mjs b/test/jianying-9-0-0-windows.test.mjs new file mode 100644 index 0000000..4dcd387 --- /dev/null +++ b/test/jianying-9-0-0-windows.test.mjs @@ -0,0 +1,58 @@ +import assert from "node:assert/strict"; +import { dirname, join } from "node:path"; +import { describe, it } from "node:test"; +import { fileURLToPath } from "node:url"; +import { spawnCli } from "./helpers/spawn-cli.mjs"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const FIXTURE = join(__dirname, "fixtures", "jianying-9-0-0-windows"); + +/** + * A real JianYing 9.0.0 (Windows) project that the app opened and closed, so + * the app encrypted `draft_content.json`, `template-2.tmp` and + * `draft_meta_info.json` in place while leaving the primary `draft_info.json` + * plaintext. See the fixture README for the full capture. + * + * What these tests guard: the project stays *readable* through its plaintext + * primary, the version markers are read off that primary, and the write guard + * verdict for this version does not change silently. + */ +describe("JianYing 9.0.0 (Windows): encrypted legacy mirrors", () => { + it("selects the plaintext draft_info.json as canonical", () => { + const r = spawnCli(["diagnose", FIXTURE]); + assert.equal(r.status, 0, `stderr: ${r.stderr}`); + assert.equal(r.json.canonical, "draft_info.json"); + assert.equal(r.json.version, "9.0.0"); + assert.equal(r.json.diverged, false); + }); + + it("reports the app-encrypted mirrors instead of failing on them", () => { + const r = spawnCli(["diagnose", FIXTURE]); + const byName = new Map(r.json.candidates.map((c) => [c.file, c])); + assert.equal(byName.get("draft_info.json").parseable_timeline, true); + for (const name of ["draft_content.json", "template-2.tmp", "draft_meta_info.json"]) { + const candidate = byName.get(name); + assert.ok(candidate?.exists, `${name} should be reported as present`); + assert.equal(candidate.parseable_timeline, false, `${name} is an encrypted blob, not a timeline`); + } + // The readable primary still carries the timeline. + assert.equal(byName.get("draft_info.json").tracks, 1); + }); + + it("reads the version markers from the primary", () => { + const r = spawnCli(["version", FIXTURE]); + assert.equal(r.status, 0, `stderr: ${r.stderr}`); + assert.equal(r.json.app, "JianYing"); + assert.equal(r.json.app_source, "lv"); + assert.equal(r.json.app_version, "9.0.0"); + }); + + it("keeps the conservative write guard for this version", () => { + const r = spawnCli(["version", FIXTURE]); + // Committing a fixture is evidence for the storage shape, not a licence to + // write: a second build still has to confirm the round-trip. + assert.equal(r.json.support.status, "known-broken"); + assert.equal(r.json.support.write_guard, "refuse"); + assert.equal(r.json.support.beyond_known_range, true); + }); +});