28 lines
4.4 KiB
Markdown
28 lines
4.4 KiB
Markdown
FAIL
|
||
|
||
Ran `cargo test -p ely-platform` (all pass) and `cargo clippy -p ely-platform --all-targets` (clean). Probes A–C ran against a local server in a scratch crate that depends on `ely-platform`.
|
||
|
||
1. crates/ely-platform/src/update.rs:221-230: The rule "https only, loopback excepted" can be bypassed with userinfo. The code checks the URL by string prefix, and `"http://127.0.0.1:" + anything` passes. ureq treats `127.0.0.1:1@` as userinfo and connects to the host after `@`.
|
||
Scenario (probe B): `check(.., "http://127.0.0.1:1@192.168.31.221:PORT/latest.json")` returned `Ok(Available(..))`. The server logged `host: 192.168.31.221`, so the manifest came over plain http from a non-loopback host. Whoever controls the network then picks the URL and the sha256, and the downloaded file passes verification. `plain_http_is_for_this_machine_only` does not cover this case.
|
||
Fix: parse the URL with `http::Uri` or `ureq::http::Uri`, reject userinfo, and decide by scheme plus the parsed host. Add the userinfo case to the test.
|
||
|
||
2. crates/ely-platform/src/update.rs:77, 232-246: `ensure_secure` checks only the first URL. Both agents use ureq's defaults (`max_redirects` 10, `https_only` false), so redirects to `http://` are followed for the manifest and for the download.
|
||
Scenario (probe A): `http://127.0.0.1:P/redirect` answered 302 to `http://192.168.31.221:P/latest.json`. `check` followed it and returned `Available`. An `https://` manifest URL that redirects to `http://` is followed the same way, so the manifest arrives over plain http.
|
||
Fix: check every hop. Either turn redirects off (`max_redirects(0)`) and follow `Location` manually through `ensure_secure`, or use `https_only(true)` for non-loopback URLs. Add a test where a redirect leaves loopback.
|
||
|
||
3. crates/ely-platform/src/update.rs:175-180, 239-246: The comment "the user can cancel" is not true. The download agent has no read timeout, and the cancel flag is checked only between `read` calls. A stalled connection blocks `read` forever: cancel does nothing, and no error is ever returned.
|
||
Scenario (probe C): the server sent the headers and 1000 of 1000000 bytes, then went silent. I set `cancel` to true 1 s in. `download` was still blocked 19 s later. In the field, a dropped Wi-Fi link or a hung CDN leaves the download hung for good.
|
||
Fix: put an idle-read timeout on the socket (for example a custom connector or transport with `set_read_timeout`) so that `read` returns, `cancel` is honoured, and a stall becomes an error. Add a test with a stalled server.
|
||
|
||
4. crates/ely-platform/src/update.rs:62, 66-73: `APPIMAGE` is an inherited environment variable, and it overrides the package-manager prefixes. A distro-installed binary launched from inside any AppImage is treated as `SelfManaged`.
|
||
Scenario: the user starts a terminal emulator or editor that ships as an AppImage, then runs `/usr/bin/ely-doc` (installed by pacman) from its terminal. `APPIMAGE` is set, so `install_policy()` returns `SelfManaged` and the app would update itself over files the package manager owns. This breaks PRD §4.2 ("Linux 包管理器安装的版本不绕过包管理器自行覆盖文件").
|
||
Fix: count it as an AppImage only when `current_exe` lies under `$APPDIR` (the mount of this AppImage), not just because `APPIMAGE` exists. Cover the inherited-variable case in the unit test.
|
||
|
||
5. crates/ely-platform/src/update.rs:142-147: The download's own error is lost when removing the `.part` file fails, because the `?` on `remove_file` returns the removal error instead.
|
||
Scenario: the hash does not match, and on Windows an antivirus scanner still holds `ElyDoc.exe.part`. The caller sees "cannot remove …part", and "the file has sha256 X, the release says Y" never reaches the user.
|
||
Fix: keep the original error and attach the removal failure to it, or log the removal failure and still return the original error.
|
||
|
||
6. crates/ely-platform/src/update.rs:76-102, 138-141: Rule 4 (key paths are logged) is not met. `check` makes a network request and logs neither the request nor the outcome (current, available, or which failure). A cancelled download is not logged either. Only a successful download logs anything.
|
||
Scenario: QA-25 asks for an audit of outgoing update requests, and a user reports "check for updates does nothing". The log has no line showing a check was made or what it returned.
|
||
Fix: log the manifest host and the result in `check`, and log a cancelled download (version only, no secrets).
|