mirror of
https://github.com/GoodOlClint/PSProxmoxVE.git
synced 2026-09-03 18:55:33 +00:00
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.
This commit is contained in:
committed by
GitHub
parent
c3f051bba5
commit
b90791e2bf
@@ -0,0 +1,48 @@
|
||||
# ADR 0002 — Password parameters must use SecureString
|
||||
|
||||
- **Status:** Accepted
|
||||
- **Date:** 2026-03-22
|
||||
- **Deciders:** unrecorded; adopted during review scan 2026-03-22
|
||||
- **Context source:** `docs/review/findings.json` F051
|
||||
|
||||
## Context
|
||||
|
||||
`Set-PveVmGuestPassword` accepted a plain `string` password parameter, leaving the credential in managed memory indefinitely.
|
||||
|
||||
`Connect-PveServer` already took a `PSCredential`, so the module was inconsistent with itself about how sensitive input arrives.
|
||||
|
||||
## Decision
|
||||
|
||||
Every cmdlet parameter that accepts a password is a `SecureString`, extracted with `Marshal.SecureStringToGlobalAllocUnicode` and freed with `ZeroFreeGlobalAllocUnicode` in a `finally`.
|
||||
|
||||
```csharp
|
||||
[Parameter(Mandatory = true)]
|
||||
public SecureString Password { get; set; }
|
||||
|
||||
IntPtr ptr = IntPtr.Zero;
|
||||
try
|
||||
{
|
||||
ptr = Marshal.SecureStringToGlobalAllocUnicode(Password);
|
||||
string plainText = Marshal.PtrToStringUni(ptr);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (ptr != IntPtr.Zero)
|
||||
Marshal.ZeroFreeGlobalAllocUnicode(ptr);
|
||||
}
|
||||
```
|
||||
|
||||
## Rejected alternatives
|
||||
|
||||
A plain `string` parameter. It is simpler to write and to test, and it leaves the credential recoverable from a memory dump for the lifetime of the process:
|
||||
|
||||
```csharp
|
||||
[Parameter(Mandatory = true)]
|
||||
public string Password { get; set; }
|
||||
```
|
||||
|
||||
## Consequences
|
||||
|
||||
The service layer below the cmdlet still receives a plain `string` — the conversion happens at the cmdlet boundary, and `ClusterConfigService.JoinCluster` documents that it expects the converted value. The guarantee is about the module's public surface and the window of exposure, not about the credential never existing in managed memory.
|
||||
|
||||
A TLS private key is at least as sensitive as a password; anything accepting one is covered by the same rule.
|
||||
Reference in New Issue
Block a user