Skip to content

Comments

feat(client): improve .rdp merge support and startup sizing#1115

Open
Marc-André Moreau (mamoreau-devolutions) wants to merge 2 commits intomasterfrom
rdp-file
Open

feat(client): improve .rdp merge support and startup sizing#1115
Marc-André Moreau (mamoreau-devolutions) wants to merge 2 commits intomasterfrom
rdp-file

Conversation

@mamoreau-devolutions

Summary

  • add broader .rdp -> native client config mapping for currently supported options
  • keep .rdp parsing tolerant by ignoring unsupported properties and redacting sensitive logged values
  • initialize native client startup window size from configured desktop dimensions
  • add regression tests for .rdp merge precedence and mapping behavior
  • document currently supported .rdp properties in client/parser READMEs

Validation

  • cargo xtask check fmt -v
  • cargo xtask check typos -v
  • cargo xtask check lints -v
  • cargo xtask check tests --no-run -v

- map additional supported .rdp properties into native client config

- ignore unsupported properties safely and redact sensitive values in logs

- initialize startup window from configured desktop size

- add regression tests for .rdp merge precedence and mapping
Pass --no-cfg-coverage to cargo llvm-cov in xtask coverage commands to avoid dependency breakage on crates using cfg_attr(coverage, no_coverage).
@github-actions
Copy link

Coverage Report 🤖 ⚙️

Past:
Total lines: 36458
Covered lines: 23733 (65.10%)

New:
Total lines: 37586
Covered lines: 23789 (63.29%)

Diff: -1.80%

[this comment will be updated automatically]

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This pull request enhances .rdp file support in the native IronRDP client by adding comprehensive property mapping, improving error handling, and initializing the client window from configured desktop dimensions.

Changes:

  • Expanded .rdp property support with 20+ properties including gateway, Kerberos, desktop sizing, audio, and clipboard configuration
  • Made .rdp parsing tolerant by logging unsupported properties at debug level with redaction of sensitive values
  • Fixed client window initialization to use configured desktop dimensions instead of hardcoded values

Reviewed changes

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

Show a summary per file
File Description
xtask/src/cov.rs Added --no-cfg-coverage flag to llvm-cov commands for improved coverage reporting
crates/ironrdp-rdpfile/README.md Added documentation clarifying that property support depends on consumers
crates/ironrdp-client/tests/config_rdp_merge.rs Added 8 integration tests verifying .rdp merge precedence and property mapping behavior
crates/ironrdp-client/src/rdp.rs Updated connection functions to pass Kerberos config and simplified debug logging
crates/ironrdp-client/src/main.rs Changed to use configured desktop size for initial window dimensions instead of hardcoded values
crates/ironrdp-client/src/config.rs Implemented comprehensive .rdp property parsing with validation, redaction, and CLI precedence
crates/ironrdp-client/src/app.rs Updated App to accept and use initial window size from configuration
crates/ironrdp-client/README.md Documented all 22 currently supported .rdp properties with precedence rules
crates/ironrdp-cfg/src/lib.rs Extended PropertySetExt trait with 14 new accessor methods for .rdp properties

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +9 to +27
fn write_rdp_file(content: &str) -> PathBuf {
let path = std::env::temp_dir().join(format!("ironrdp-client-rdp-{}.rdp", Uuid::new_v4()));
fs::write(&path, content).expect("failed to write temporary .rdp file");
path
}

fn parse_config_from_rdp(content: &str, extra_args: &[&str]) -> Config {
let rdp_file = write_rdp_file(content);

let mut args = vec![
"ironrdp-client".to_owned(),
"--rdp-file".to_owned(),
rdp_file.display().to_string(),
];

args.extend(extra_args.iter().map(|arg| (*arg).to_owned()));

let result = Config::parse_from(args);
let _ = fs::remove_file(rdp_file);
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

The temporary .rdp test file is not guaranteed to be cleaned up if Config::parse_from panics or if the test is interrupted. Consider using a RAII-style guard or implementing Drop for cleanup to ensure files are removed even on panic.

Suggested change
fn write_rdp_file(content: &str) -> PathBuf {
let path = std::env::temp_dir().join(format!("ironrdp-client-rdp-{}.rdp", Uuid::new_v4()));
fs::write(&path, content).expect("failed to write temporary .rdp file");
path
}
fn parse_config_from_rdp(content: &str, extra_args: &[&str]) -> Config {
let rdp_file = write_rdp_file(content);
let mut args = vec![
"ironrdp-client".to_owned(),
"--rdp-file".to_owned(),
rdp_file.display().to_string(),
];
args.extend(extra_args.iter().map(|arg| (*arg).to_owned()));
let result = Config::parse_from(args);
let _ = fs::remove_file(rdp_file);
struct TempRdpFile {
path: PathBuf,
}
impl TempRdpFile {
fn new(content: &str) -> Self {
let path =
std::env::temp_dir().join(format!("ironrdp-client-rdp-{}.rdp", Uuid::new_v4()));
fs::write(&path, content).expect("failed to write temporary .rdp file");
TempRdpFile { path }
}
fn path(&self) -> &PathBuf {
&self.path
}
}
impl Drop for TempRdpFile {
fn drop(&mut self) {
let _ = fs::remove_file(&self.path);
}
}
fn write_rdp_file(content: &str) -> TempRdpFile {
TempRdpFile::new(content)
}
fn parse_config_from_rdp(content: &str, extra_args: &[&str]) -> Config {
let rdp_file = write_rdp_file(content);
let mut args = vec![
"ironrdp-client".to_owned(),
"--rdp-file".to_owned(),
rdp_file.path().display().to_string(),
];
args.extend(extra_args.iter().map(|arg| (*arg).to_owned()));
let result = Config::parse_from(args);

Copilot uses AI. Check for mistakes.
);

assert!(config.connector.enable_audio_playback);
}
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Consider adding test coverage for the desktop dimension properties (desktopwidth, desktopheight, desktopscalefactor) to verify they are correctly parsed from RDP files and applied to the client configuration, including edge cases like out-of-range values.

Suggested change
}
}
#[test]
fn desktop_dimensions_are_parsed_from_rdp_file() {
let config = parse_config_from_rdp(
"full address:s:rdp.example.com\n\
username:s:test-user\n\
ClearTextPassword:s:test-pass\n\
desktopwidth:i:1024\n\
desktopheight:i:768\n\
desktopscalefactor:i:125\n",
&[],
);
assert_eq!(config.connector.desktop_width, 1024);
assert_eq!(config.connector.desktop_height, 768);
assert_eq!(config.connector.desktop_scale_factor, 125);
}
#[test]
fn out_of_range_desktop_dimensions_fall_back_to_defaults() {
let default_config = parse_config_from_rdp(
"full address:s:rdp.example.com\n\
username:s:test-user\n\
ClearTextPassword:s:test-pass\n",
&[],
);
let invalid_config = parse_config_from_rdp(
"full address:s:rdp.example.com\n\
username:s:test-user\n\
ClearTextPassword:s:test-pass\n\
desktopwidth:i:0\n\
desktopheight:i:0\n\
desktopscalefactor:i:1000\n",
&[],
);
assert_eq!(
invalid_config.connector.desktop_width,
default_config.connector.desktop_width
);
assert_eq!(
invalid_config.connector.desktop_height,
default_config.connector.desktop_height
);
assert_eq!(
invalid_config.connector.desktop_scale_factor,
default_config.connector.desktop_scale_factor
);
}

Copilot uses AI. Check for mistakes.

if html_report {
cmd!(sh, "{CARGO} llvm-cov --html")
.arg("--no-cfg-coverage")

Choose a reason for hiding this comment

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

question: Why this modification? I think this should be reverted.

.await?;

debug!(?connection_result);
debug!("Connection finalized");
Copy link
Member

@CBenoit Benoît Cortier (CBenoit) Feb 19, 2026

Choose a reason for hiding this comment

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

question: Why this change? It seems we are losing the ability to see the debug representation of the connection result when enabling debug logs

Copy link
Member

@CBenoit Benoît Cortier (CBenoit) Feb 19, 2026

Choose a reason for hiding this comment

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

I’m not sure why it’s named with the "_merge" suffix since there is nothing related to merging in here. Seems to be solely about verifying the resulting Config based on various .RDP files. I would put these tests in the testsuite-extra crate.

Comment on lines -357 to +467
for e in errors {
#[expect(clippy::print_stderr)]
{
eprintln!("Error when reading {}: {e}", rdp_file.display())
for error in errors {
match &error.kind {
ironrdp_rdpfile::ErrorKind::UnknownType { ty } => {
debug!(
rdp_file = %rdp_file.display(),
line = error.line,
%ty,
"Skipped .RDP property with unsupported type"
);
}

Choose a reason for hiding this comment

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

issue:  I think the initial code was good and correct as-is. This is basically re-implementing the existing logic but using debug!. It also does not make sense to use debug! at this point, the logger is not yet initialized.

@CBenoit Benoît Cortier (CBenoit) changed the title client: improve .rdp merge support and startup sizing feat(client): improve .rdp merge support and startup sizing Feb 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants