Files
PSProxmoxVE/docs/decisions/0003-url-encoding-required-for-all-path-parameters.md
T
goodolclint-claude[bot] b90791e2bf docs: migrate DECISIONS.md to house-format ADRs, and retire the review folder (#131)
D001-D021 become ADR 0001-0021 in docs/decisions/, one decision per file.
D017's PESTER_VERSION amendment was a second decision in one entry and becomes
ADR 0022. ADR 0023 records the migration and reverses the lane2-change-plan
ruling that deliberately kept DECISIONS.md until the CI lane work landed.

DECISIONS.md is reduced to a stub with a D-to-ADR redirect table, so the four
released CHANGELOG entries and older issue bodies that cite it degrade to a
redirect rather than a dead reference.

docs/review/ and docs/lane2-change-plan.md are deleted (ADR 0024). Of 91
findings, 83 were resolved and six of the seven still open were already GitHub
issues; F021 was the exception and is now #130.

CLAUDE.md's Key Conventions list gains the two rules it was missing and becomes
the checklist, with the ADRs carrying rationale.
2026-09-02 14:49:07 +00:00

1.4 KiB

ADR 0003 — URL encoding required for all path parameters

  • Status: Accepted
  • Date: 2026-03-22
  • Deciders: unrecorded; adopted during review scan 2026-03-22
  • Context source: docs/review/findings.json F050

Context

Snapshot names, node names, user IDs and similar identifiers were interpolated raw into API URL paths. Most reach the module from validated sources, but nothing in the code enforced that, and a value carrying / or ? would silently change which endpoint was called.

Decision

Every user-supplied or dynamic value interpolated into an API URL path is wrapped in Uri.EscapeDataString(). This applies to all service classes without exception.

var resource = $"nodes/{Uri.EscapeDataString(node)}/qemu/{vmid}/snapshot/{Uri.EscapeDataString(snapshotName)}";

Rejected alternatives

Encoding only the parameters that can plausibly carry a separator, and trusting validation upstream for the rest. Rejected because the audit then has to be redone on every new call site, and the reader cannot tell a deliberate omission from an oversight:

var resource = $"nodes/{node}/qemu/{vmid}/snapshot/{snapshotName}";

Consequences

Applied across all 14 service classes at the time of the decision. Form-encoded bodies are a separate matter — PVE does not URL-decode form values in some internal consumers, so the cluster-join path deliberately sends minimally encoded values.