fix(local-windows-rdp): escape special characters in credentials - #1056
Conversation
…ers in credentials The password was interpolated into a PowerShell double-quoted string, where $, backtick, and " are all interpreted, so the setup script aborted with a parser error and never set the admin password. The same value went into the coder:// app URL unencoded, where it truncates at the first &. - pass credentials to the setup script as PowerShell single-quoted strings, with single quotes doubled - urlencode both credentials in the app URL - add a .tftest.hcl covering a password with backslash, quotes, backtick, dollar, ampersand, angle brackets, pipe, hash, percent and plus
Module Scorecard Check
|
| Theme | Before | After |
|---|---|---|
| Presentation & Onboarding | 17.5 / 25 | 20 / 25 |
| Integration | — | — |
| Credential Hygiene | 18 / 20 | 18 / 20 |
| Restricted-Environment | N/A | N/A |
| Engineering Quality | 10 / 10 | 10 / 10 |
| Overall | 83 / 100 | 87 / 100 |
Full scorecard for this PR
| Presentation & Onboarding | Credential Hygiene | Restricted-Environment Readiness | Engineering Quality | Overall |
|---|---|---|---|---|
| 20 / 25 | 18 / 20 | N/A | 10 / 10 | 87 / 100 |
Drilldown
Presentation & Onboarding — 20 / 25
| Criterion | Max | Score | Notes |
|---|---|---|---|
| Configuration-mode examples | 12 | 12 | README provides three distinct examples: basic usage with defaults, custom display name with ordering, and generated credentials pattern. Each demonstrates a different configuration approach with sensible defaults. |
| Coder-context framing | 8 | 8 | README clearly explains this module "enables Remote Desktop Protocol (RDP) on Windows workspaces and adds a one-click button to launch RDP sessions directly through Coder Desktop." Names both Coder and RDP, explains the module eliminates manual configuration, and shows Coder Desktop as the entry point. |
| Visual preview | 5 | 0 | No image, GIF, or video present in README. Only an icon reference exists. |
Credential Hygiene — 18 / 20
| Criterion | Max | Score | Notes |
|---|---|---|---|
| Secrets marked sensitive | 16 | 16 | The password variable is marked sensitive = true in main.tf. README examples avoid inline secrets: basic example uses the default (not a literal secret paste), custom example shows random_password.rdp.result reference rather than hardcoded value. |
| Non-hardcoded auth path | 4 | 2 | README shows random_password resource pattern to generate credentials per workspace, avoiding template-embedded secrets. However, this is still a credential management workaround rather than a true external auth mechanism like OAuth, IAM, or ServiceAccount integration. Earns half credit for the documented pattern. |
Restricted-Environment Readiness — N/A
| Criterion | Max | Score | Notes |
|---|---|---|---|
| Mirrorable artifact source | 10 | N/A | Module downloads nothing; it only configures Windows RDP via PowerShell script and creates a coder_app. No external artifacts are fetched. |
| Bring-your-own binary | 5 | N/A | Module uses built-in Windows RDP functionality; no binary installation occurs. |
| Egress transparency | 3 | N/A | Module makes no external network calls beyond Coder API interactions inherent to coder_app and coder_script resources. |
| Runs without sudo | 2 | N/A | Module targets Windows and uses PowerShell; sudo is not applicable to Windows environments. |
Engineering Quality — 10 / 10
| Criterion | Max | Score | Notes |
|---|---|---|---|
| Input quality | 6 | 6 | All inputs have clear descriptions. Sensible defaults provided (username="Administrator", display_name="RDP Desktop"). The password variable is marked sensitive. Variables include appropriate types and descriptions for agent_id, agent_name, username, password, display_name, order, and group. |
| Test coverage | 4 | 4 | Comprehensive testing story: .tftest.hcl covers password escaping and URL encoding logic with special characters. TypeScript tests in main.test.ts provide end-to-end coverage including app creation, script generation, custom values, credential handling, and URI format validation. Tests verify both business logic and integration behavior. |
Overall — 87 / 100
Raw 48 / 55 → round(48 / 55 × 100) = 87
Track: Utility (RDP configuration module; not an AI agent or IDE)
Scored against SCORECARD.md with claude-sonnet-4-5. Language-model scores are advisory.
…edentials Show the per-workspace random_password pattern so the credential never has to live in the template, and note that special characters now survive.
|
On the scorecard regression: the Credential Hygiene drop is scoring noise, not something this PR introduced. The only README change in the original diff was the version bump, Presentation moved 17.5 → 20 in the same run with no README content change either, which is the same variance in the other direction. The footer notes these are advisory language-model scores. That said, the underlying point about the non-hardcoded auth path is fair, so I've added a The remaining criteria I'm deliberately not addressing here:
|
Problem
The password was interpolated into two places without escaping it for the target syntax.
1. PowerShell double-quoted string —
configure-rdp.ps1$, backtick, and"are all interpreted there. Reproduced on a live AWS Windows workspace withpassword = "Te\st$Pa\"ss'word&<>|1!": the entireConfigure RDPscript aborts before doing anything, and the workspace reportsstart_error`.2. Unencoded URL query parameter —
main.tfThe same value went into the
coder://app URL raw, so the rendered URL on that workspace was:Coder Desktop receives everything up to the first
&. A#drops the remainder,+decodes as a space, and a bare%is an invalid escape.Fix
'doubledurlencode()on both username and passwordSame approach as #1036 for
amazon-dcv-windowsand #1034 forwindows-rdp.Changes
configure-rdp.ps1: pass credentials as PowerShell single-quoted stringsmain.tf:urlencode()both credentials in the app URLlocal-windows-rdp.tftest.hclcovering a password with\ " ' ```` $ & < > | # % +`main.test.tsthat were pinning the old behavior, for examplepassword=CustomPass123!unencodedModule bumped to
1.0.5.Validation
The new Terraform tests fail without the source fix and pass with it, so they are not vacuous:
With the fix:
2 passed, 0 failed,bun test main.test.ts10/10, prettier andterraform fmtclean.Note
Third and last module in this bug class, after #20 / #1034 (
windows-rdp) and #1035 / #1036 (amazon-dcv-windows). Found while dogfooding #1034 on a real AWS Windows workspace, where this module's script was the one that actually crashed.Closes #1043