Skip to content

fix(upgrade): correct appendData params to {"length": N} (hardware-validated) - #3

Merged
widgetii merged 3 commits into
masterfrom
fix/upgrader-appenddata-params
Sep 26, 2026
Merged

widgetii merged 3 commits into
masterfrom
fix/upgrader-appenddata-params

Conversation

@widgetii

Copy link
Copy Markdown
Member

The upgrader.appendData RPC (used by DahuaClient.upgrade_firmware) was sending params {"Offset": ..., "Length": ...}, which the device rejects with 400 "param error".

Reversed the hunter daemons CUpgradeService::appendData handler on a Goke **GK7205V510** and confirmed with a live flash: the handler reads **params.length** and rejects the call unless it equals the actual trailing binary length. prepare ({"Type":"System"}) and execute` params are ignored.

State machine (unchanged): prepare(0→2) → appendData(2/4, repeatable) → execute(4→0), ~60s idle timeout.

Fix

# before — rejected 400 "param error"
self.request(const.UPGRADER_APPEND, {"Offset": sent, "Length": len(chunk)}, data=chunk)
# after — accepted
self.request(const.UPGRADER_APPEND, {"length": len(chunk)}, data=chunk)

Validation

End-to-end on hardware (not a mock): upgrade_firmware() streamed an ~11 MB OpenIPC package over DHIP, execute returned {"result": true}, the device burned the kernel+rootfs partitions and rebooted into the new firmware. const.py comment updated to record the byte-proven param shape.

pytest tests/ — 30 passed.

…lidated)

Reversed from the hunter CUpgradeService::appendData handler and confirmed by a
live UART-free flash on a GK7205V510: appendData expects params {"length": N}
with an N-byte binary payload (the handler checks params.length == actual binary
length), NOT {"Offset","Length"} — which returned 400 "param error". prepare
({"Type":"System"}) and execute params are ignored. State machine: prepare(0->2)
-> appendData(2/4, repeatable) -> execute(4->0), with a ~60s idle timeout.

With this, DahuaClient.upgrade_firmware() successfully flashed an OpenIPC package
over DHIP end-to-end (device rebooted into the new firmware). const comment
updated to record the byte-proven param shape.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown

PR Summary by Qodo

Fix firmware appendData length parameter

🐞 Bug fix 📝 Documentation 🕐 Less than 10 minutes

Grey Divider

AI Description

• Sends appendData the required lowercase length parameter for each firmware chunk.
• Documents hardware-validated upgrader parameters, state transitions, and timeout behavior.
Diagram

sequenceDiagram
    actor Caller
    participant Client as DahuaClient
    participant File as Firmware File
    participant Device as Upgrader RPC
    Caller->>Client: Start upgrade
    Client->>Device: prepare
    loop Firmware chunks
        Client->>File: Read chunk
        File-->>Client: N bytes
        Client->>Device: appendData length N
    end
    Client->>Device: execute
    Device-->>Client: Upgrade result
Loading
High-Level Assessment

The direct contract correction is optimal because the reversed handler validates params.length against the trailing binary payload size. Retaining Offset/Length or sending both shapes would not match the hardware-validated RPC contract and could continue producing parameter errors.

Files changed (2) +5 / -5

Bug fix (1) +1 / -1
client.pySend hardware-compatible appendData parameters +1/-1

Send hardware-compatible appendData parameters

• Changes firmware chunk uploads to send '{"length": len(chunk)}' instead of unsupported 'Offset' and capitalized 'Length' fields. This aligns requests with the device handler’s payload-length validation.

dahua/client.py

Documentation (1) +4 / -4
const.pyDocument validated firmware upgrade protocol +4/-4

Document validated firmware upgrade protocol

• Records the hardware-validated 'appendData' parameter shape, binary payload requirement, upgrader state transitions, and approximate idle timeout.

dahua/const.py

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 26, 2026 •

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Users get false upgrade safety guidance ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
The newly validated {"length": N} request in upgrade_firmware leaves that method's docstring and
confirmation ValueError saying parameter names are not byte-proven and the upgrade has never run
on hardware. Every caller reading the API docs or omitting confirm=True, plus README readers,
receives guidance that directly contradicts the new hardware-validation comment and implemented
behavior.
Code

dahua/const.py[R72-74]

+# are the same handlers the web /cgi-bin/upgrader.cgi bridges to. Validated on a
+# GK7205V510 (hunter decompile + live flash): appendData takes params {"length": N}
+# with an N-byte binary payload; prepare/execute params are ignored. State machine:
Evidence
The added constant comment explicitly records a decompile and live flash, while the method
documentation, user-facing exception, support table, and status section still state that the
operation is unproven or intentionally never run on hardware.

dahua/const.py[72-75]
dahua/client.py[467-484]
README.md[159-159]
README.md[207-233]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The firmware upgrade documentation and confirmation error still claim the operation has never been tested on hardware, contradicting the newly added hardware-validation record.
## Fix Focus Areas
- dahua/client.py[467-484]
- README.md[159-159]
- README.md[207-233]
## Recommended Fix
Update the docstring, confirmation error, support table, and device-status section to record the GK7205V510 hardware validation while retaining the destructive-operation warning, model-specific qualification, and `confirm=True` requirement.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Broken upgrade parameters pass tests ✓ Resolved 🐞 Bug ⚙ Maintainability
Description
test_upgrade_streams_file_in_chunks supplies an append handler that returns success for every
request and only asserts method counts, without inspecting the changed params object. Reverting
line 497 to the rejected Offset/Length shape, changing the key's case, or sending an incorrect
value therefore leaves this upgrade test green.
Code

dahua/client.py[497]

+                                       {"length": len(chunk)},
Evidence
The firmware test's handler receives the full request but ignores it, and its assertions cover only
the number and order of RPC methods; the fake server passes each decoded request directly to that
handler.

tests/test_dahua.py[319-345]
tests/fake_server.py[105-116]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The firmware streaming test does not distinguish the newly fixed append parameters from the rejected parameter shape, so it cannot prevent this exact regression.
## Fix Focus Areas
- tests/test_dahua.py[319-345]
## Recommended Fix
Have the append handler collect each request's `params`, then assert that the three requests contain only `{"length": 4096}`, `{"length": 4096}`, and `{"length": 1808}` respectively.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can type 'qodo, fix this' on a finding and the fix lands right on your PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread dahua/const.py
Comment thread dahua/client.py
…rams in test

Addresses Qodo review on #3:
- upgrade_firmware docstring + confirm ValueError no longer claim the path is
  byte-unproven / never run on hardware (it is validated end-to-end on a
  GK7205V510); docstring now states the {"length":N}+binary contract and the
  prepare/appendData/execute state machine.
- test_upgrade_streams_file_in_chunks now records each appendData params and the
  real trailing-binary length and asserts params == {"length": N} with N equal
  to the payload for every chunk. FakeDHIPServer exposes the binary payload
  (__data__) so handlers can verify it. A revert to {"Offset","Length"} now
  fails the test (previously it passed).
Finding 1 (Qodo) also pointed at README: the API table said 'mock-validated
only' and the device-support section said upgrade_firmware is 'intentionally
never run against a device' — both now contradicted the validated flow. Moved
firmware upgrade into 'Verified on hardware' (flashed OpenIPC on a GK7205V510
end-to-end), kept the destructive/confirm=True warning.
@widgetii
widgetii merged commit 51082cc into master Sep 26, 2026
6 checks passed
@widgetii
widgetii deleted the fix/upgrader-appenddata-params branch September 26, 2026 14:11
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.

1 participant