Skip to content

RemoteID: restore operator ID validation and sanitizing - #14262

Closed
Junior00619 wants to merge 3 commits into
mavlink:masterfrom
Junior00619:fix/issue-14204-operator-id-validation
Closed

RemoteID: restore operator ID validation and sanitizing#14262
Junior00619 wants to merge 3 commits into
mavlink:masterfrom
Junior00619:fix/issue-14204-operator-id-validation

Conversation

@Junior00619

Copy link
Copy Markdown

Fixes #14204.

Summary

  • restore Operator ID validation inside RemoteIDManager so the generated settings UI no longer bypasses the EU checksum path
  • sanitize validated EU Operator IDs back down to the public 16-character form before they are stored or reused
  • add RemoteIDManagerTest coverage for valid EU IDs, invalid EU IDs, and switching from FAA to EU after entering a validated full ID

Verification

  • configured QGroundControl in the repo's Ubuntu/Qt Docker build environment with -DQGC_BUILD_TESTING=ON
  • generated MAVLink headers and MAVLinkEnums.h in the build tree
  • compiled the touched translation units directly from compile_commands.json inside the container:
    • src/Vehicle/RemoteIDManager.cc
    • test/Vehicle/RemoteIDManagerTest.cc

I did not finish a full QGroundControl --unittest:RemoteIDManagerTest run locally because the complete application build is much larger than the changed scope here, so the remaining end-to-end validation should come from CI.

@Junior00619
Junior00619 requested a review from HTRamsey as a code owner April 3, 2026 18:36
@github-actions

github-actions Bot commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Thanks for your first pull request! 🎉

A maintainer will review this soon. Please ensure:

  • CI checks pass
  • Code follows coding standards
  • Changes tested on relevant platforms

We appreciate your contribution to QGroundControl!

@github-actions

github-actions Bot commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Build Results

Platform Status

Platform Status Details
Linux Passed View
Windows Passed View
MacOS Passed View
Android Passed View

All builds passed.

Pre-commit

Check Status Details
pre-commit Failed (non-blocking) View

Pre-commit hooks: 4 passed, 32 failed, 7 skipped.

Test Results

linux-sanitizers: 68 passed, 0 skipped
linux_gcc_64: 68 passed, 0 skipped
Total: 136 passed, 0 skipped

Artifact Sizes

Artifact Size
QGroundControl 248.05 MB
QGroundControl 338.23 MB
QGroundControl-aarch64 177.21 MB
QGroundControl-installer-AMD64 135.10 MB
QGroundControl-installer-AMD64-ARM64 77.74 MB
QGroundControl-installer-ARM64 106.48 MB
QGroundControl-mac 188.68 MB
QGroundControl-windows 188.71 MB
QGroundControl-x86_64 163.45 MB
No baseline available for comparison---
Updated: 2026-04-04 03:37:25 UTC • Triggered by: Android

@DonLakeFlyer

Copy link
Copy Markdown
Contributor

@Davidsastresas Can you look at this and verify this is a correct thing to do?

@Davidsastresas

Copy link
Copy Markdown
Member

Thanks for tackling this, wiring validation to the Fact signals is the right approach, since the generated settings UI writes the operatorID Fact directly and never went through the old checkOperatorID()/setOperatorID() path. The reentrancy guard around the sanitizing write-back looks correct, and _setOperatorIDGood only emitting on change is a nice touch.

A couple of things before merge:

1. The PR description doesn't match the tests that shipped. The summary lists coverage for "switching from FAA to EU after entering a validated full ID," but that case isn't in the diff, there are only _validEUOperatorIDIsSanitized and _invalidEUOperatorIDClearsTrustedState, and neither switches region. Looks like narrow validation coverage to issue path dropped it. Since validation is region-independent (a valid full ID entered under FAA sets operatorIDValid=true, then switching to EU strips it), that transition is probably the most valuable case to keep, could we restore it, or at least update the description?

2. checkOperatorID() and setOperatorID() are now dead code. They're Q_INVOKABLE but have no callers anywhere in the repo after this change. checkOperatorID() now duplicates _handleOperatorIDChanged's validation, and setOperatorID() is just _refreshOperatorIDState(). Could we delete them (or have them delegate) rather than leave two parallel validation paths?

Minor:

  • length() > 16 is redundant with _isEUOperatorIDValid, which already requires exactly 19/20 chars. A named constant for the 16-char public length would also read better than the repeated literal.
  • operatorIDType >= 0 is always true (uint8, default 0). Pre-existing, just noting it's carried forward.

Copilot AI 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

This PR restores Remote ID Operator ID validation/sanitization within RemoteIDManager so EU Operator IDs are checksum-validated and any validated “full” Operator ID is sanitized back to the public 16-character form before being stored/broadcast. It also adds integration test scaffolding and CMake registration for RemoteIDManagerTest.

Changes:

  • Reconnect Operator ID validation to RemoteIDSettings::operatorID changes and centralize state refresh to prevent the settings UI from bypassing EU checksum validation.
  • Sanitize validated EU Operator IDs down to the public 16-character value when stored.
  • Add initial RemoteIDManagerTest coverage and wire it into the test build.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/Vehicle/RemoteIDManager.h Adds private helpers/guard for Operator ID change handling and state refresh.
src/Vehicle/RemoteIDManager.cc Implements Operator ID validation on Fact changes and sanitizes validated EU IDs to 16 chars.
test/Vehicle/RemoteIDManagerTest.h Introduces a new vehicle integration test class for Remote ID operator ID behavior.
test/Vehicle/RemoteIDManagerTest.cc Adds tests for EU Operator ID sanitization and invalid-ID trusted-state clearing.
test/Vehicle/CMakeLists.txt Adds the new RemoteID test sources to the vehicle test target.
test/CMakeLists.txt Registers RemoteIDManagerTest as an integration/vehicle test.

// We check whether it actually changed to avoid triggering this on startup.
if (operatorID != _settings->operatorID()->rawValueString()) {
_settings->operatorIDValid()->setRawValue(_isEUOperatorIDValid(operatorID));
const bool operatorIDValid = (operatorID.length() > 16) && _isEUOperatorIDValid(operatorID);
Comment on lines +408 to +412
const QString operatorID = value.toString();
const bool operatorIDValid = (operatorID.length() > 16) && _isEUOperatorIDValid(operatorID);
if (_settings->operatorIDValid()->rawValue().toBool() != operatorIDValid) {
_settings->operatorIDValid()->setRawValue(operatorIDValid);
}
Comment on lines +17 to +23
private slots:
void init() override;
void cleanup() override;

void _validEUOperatorIDIsSanitized();
void _invalidEUOperatorIDClearsTrustedState();

@DonLakeFlyer

Copy link
Copy Markdown
Contributor

This is still out of whack. This may validate the id internally and not send crap, but it doesn't tell the user through the ui that the id is bad like it used to. The other part of this got screwed up with the change the json settings page definitions. I'll take a look at taking this and also in combination fixing up the UI in a replacement pull that is a superset of this.

@DonLakeFlyer

Copy link
Copy Markdown
Contributor

@Davidsastresas Questions on stored settings: The current/original code allows storage of invalid operator ids into settings. Is there some specific spec/usage need for that? If instead it showed you the validation error and didn't persist bad values would that be a bad thing?

@DonLakeFlyer

Copy link
Copy Markdown
Contributor

@Junior00619 @Davidsastresas Can you try a new daily sometime after today?

@Davidsastresas

Copy link
Copy Markdown
Member

Sorry for the late response @DonLakeFlyer. I don't have anymore access to remote ID hardware so I can not help with testing at the moment.

On the stored-settings question — no, there's no spec or usage requirement to persist invalid operator IDs. Looking back at the original code it's really just a side effect of two things:

  • The text field writes the fact on every keystroke (onTextChanged → checkOperatorID() + operatorIDFact.value = text) so the validation could run live as you type.
  • For EU we need the full 19/20-char string (public part + the 3 secret chars) around just long enough to compute the Luhn checksum, and only once it validates do we strip it down to the 16-char public portion (sliced(0,16) in setOperatorID()).

So an invalid value only lingers in settings because nothing overwrites it until you type a valid one. In practice it's harmless — the send path is already gated on _operatorIDGood, so an invalid ID is never broadcast — but there's no reason it has to persist.

So showing the validation error and not persisting bad values wouldn't break anything, and it's cleaner. The only constraint to keep is that the field still needs the full value (incl. the secret) transiently to validate, while only the 16-char public part is what actually gets stored/sent. Your superset approach sounds right to me.

@DonLakeFlyer

Copy link
Copy Markdown
Contributor

Great, thanks for the info @Davidsastresas

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remote ID Operator ID not validated

4 participants