Files
PSProxmoxVE/REVIEW_REPORT.md
T
Clint Branham 0fa92d689f docs(review): scan-4 review report and findings update
Add scan-4 full review: 1 resolved (F040), 6 new findings (F071-F076).
27 open findings, 49 resolved. No regressions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 09:07:51 -05:00

48 KiB
Raw Blame History

PSProxmoxVE Module Review Report

Scan date:           2026-03-22
Prior report date:   2026-03-21
PVE API spec date:   2026-03-21T15:04:50.641Z
PVE API spec SHA256: 4af79be30166209a4714b771f65e1e9540c5b738f414ff30c98454402e29d030
PVE version hint:    (not set in spec)
Total API endpoints: 646

Reviewer: Claude Code (Opus 4.6) Module Version: 0.1.0-preview Repository: PSProxmoxVE (C# binary PowerShell module)


Executive Summary

Delta since last scan: 16 fixed | 5 new findings | 0 regressed | 9 still open

API drift: 194 endpoints with version_changes | 466 PVE endpoints unimplemented (72.1% uncovered) | 42 🆕 PVE 9.0 endpoints

  1. 169 cmdlets (up from 148) — all fully exported, sealed, with OutputType attributes. New: 21 additional cmdlets since prior scan.
  2. 14 prior findings resolved: All 4 infinite-loop WaitForTask methods (CQ1CQ4) now use TaskService.WaitForTask. Guest exec timeout added (CQ5). OutputType on all cmdlets (CQ9). Firewall VmId nullable (CQ10). Bare catches replaced with filtered exceptions (CQ11CQ14). RemovePveRole/SuspendPveVm/RestartPveVm ConfirmImpact fixed (CQ17/CQ19/CQ20). Cmdlets sealed (CQ18). Dual JSON attrs removed (CQ21). Magic strings extracted to constants (CQ22). Guest password now SecureString (S1). Debug script secrets redacted (S2).
  3. Remaining Critical: 5 cmdlets still have while(true) task-polling loops with no timeout — 3 container snapshot cmdlets plus InvokePveStorageDownloadCmdlet and SendPveFileCmdlet.
  4. 100% Pester unit test coverage maintained across all 169 cmdlets. Integration test coverage is ~62% (105 of 169).
  5. 27.9% API endpoint coverage (180 of 646 endpoints). Major uncovered areas unchanged: Ceph (40), HA (21), cluster config (10), disks (18), ACME (15), certificates (8).
  6. Security posture solid: All prior security findings resolved (S1S3). URL encoding now consistent across all services. HTTPS enforced, SecureString used consistently.
  7. PSGallery-ready: No publication blockers. IconUri still missing (cosmetic). Manifest CmdletsToExport fully enumerates all 169 cmdlets.
  8. net9.0 target is EOL (May 2025) — should upgrade to net10.0.
  9. Pool/CephPool parameter conflict in New-PveStorage resolved: runtime validation now throws if both specified.
  10. 42 new PVE 9.0 endpoints available (HA rules, SDN fabrics, bulk actions, OCI registry). None yet implemented.

Phase 1 — Repository Inventory & Structure

Directory Tree (depth ≤ 4)

PSProxmoxVE/
├── PSProxmoxVE.sln
├── README.md
├── LICENSE (MIT)
├── CHANGELOG.md
├── CONTRIBUTING.md
├── CODE_OF_CONDUCT.md
├── SECURITY.md
├── .editorconfig
├── .gitignore
├── .gitattributes
├── REVIEW_REPORT.md
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── bug_report.yml
│   │   └── feature_request.yml
│   ├── pull_request_template.md
│   └── workflows/
│       ├── build.yml
│       ├── unit-tests.yml
│       ├── integration-tests.yml
│       └── publish.yml
├── docs/
│   ├── PVE_API_COVERAGE.md
│   └── cmdlets/                      (75 cmdlet documentation files)
├── src/
│   ├── PSProxmoxVE/
│   │   ├── PSProxmoxVE.csproj
│   │   ├── PSProxmoxVE.psd1
│   │   ├── PSProxmoxVE.format.ps1xml
│   │   ├── PSProxmoxVE.dll-Help.xml
│   │   ├── ModuleState.cs
│   │   └── Cmdlets/
│   │       ├── PveCmdletBase.cs
│   │       ├── Backup/              (6 cmdlets)
│   │       ├── CloudInit/           (3 cmdlets)
│   │       ├── Cluster/             (1 cmdlet)
│   │       ├── Connection/          (3 cmdlets)
│   │       ├── Containers/          (20 cmdlets)
│   │       ├── Firewall/            (21 cmdlets)
│   │       ├── Network/             (5 + 22 SDN cmdlets)
│   │       ├── Nodes/               (8 cmdlets)
│   │       ├── Pools/               (4 cmdlets)
│   │       ├── Snapshots/           (4 cmdlets)
│   │       ├── Storage/             (11 cmdlets)
│   │       ├── Tasks/               (4 cmdlets)
│   │       ├── Templates/           (4 cmdlets)
│   │       ├── Users/               (23 cmdlets)
│   │       └── Vms/                 (30 cmdlets)
│   └── PSProxmoxVE.Core/
│       ├── PSProxmoxVE.Core.csproj
│       ├── Authentication/           (PveAuthenticator, PveAuthMode, PveSession, PveVersion)
│       ├── Client/                   (PveHttpClient)
│       ├── Exceptions/               (7 exception types)
│       ├── Models/                   (25+ model classes across 9 areas)
│       └── Services/                 (14 service classes)
├── tests/
│   ├── PSProxmoxVE.Core.Tests/       (xUnit)
│   │   ├── Authentication/           (3 test files)
│   │   ├── Fixtures/                 (28 JSON fixtures)
│   │   ├── Models/                   (12 test files)
│   │   └── TestHelper.cs
│   ├── PSProxmoxVE.Tests/            (Pester 5)
│   │   ├── _TestHelper.ps1
│   │   ├── Backup/                   (2 test files)
│   │   ├── CloudInit/                (1 test file)
│   │   ├── Cluster/                  (1 test file)
│   │   ├── Connection/               (3 test files)
│   │   ├── Containers/               (5 test files)
│   │   ├── Firewall/                 (5 test files)
│   │   ├── Network/                  (5 test files)
│   │   ├── Nodes/                    (2 test files)
│   │   ├── Pools/                    (1 test file)
│   │   ├── Snapshots/                (1 test file)
│   │   ├── Storage/                  (4 test files)
│   │   ├── Tasks/                    (2 test files)
│   │   ├── Templates/                (1 test file)
│   │   ├── Users/                    (4 test files)
│   │   ├── Vms/                      (12 test files)
│   │   └── Integration/              (1 comprehensive test file)
│   └── infrastructure/               (Terraform, Dockerfile, scripts for CI)
├── publish/                          (netstandard2.0 build output)
├── debug/                            (debug/analysis scripts)
└── tools/
    └── Invoke-Tests.ps1

Project Layout

Item Value
Solution PSProxmoxVE.sln
Main project src/PSProxmoxVE/PSProxmoxVE.csproj
Core library src/PSProxmoxVE.Core/PSProxmoxVE.Core.csproj
Test project (xUnit) tests/PSProxmoxVE.Core.Tests/PSProxmoxVE.Core.Tests.csproj
Test project (Pester) tests/PSProxmoxVE.Tests/
Target Frameworks netstandard2.0, net9.0, net48
Language Version C# 10.0
Nullable Enabled
Assembly Names PSProxmoxVE, PSProxmoxVE.Core

CI/CD Workflows

Workflow Purpose
build.yml Build + xUnit tests on net48 (Windows) and net9.0 (Windows + Ubuntu)
unit-tests.yml Build + Pester tests across PS 5.1/7.5 on Windows/Ubuntu/macOS
integration-tests.yml Full integration tests against nested PVE 8 + PVE 9 instances
publish.yml Tag-triggered publish to PSGallery + GitHub Release creation

Inventory Checklist

Item Present Prior Status
Solution file (.sln) Yes Open
Module manifest (.psd1) Yes Open
Format definitions (.format.ps1xml) Yes Open
MAML help (.dll-Help.xml) Yes Open
.editorconfig Yes Open
.gitignore Yes Open
.gitattributes Yes Open
LICENSE (MIT) Yes Open
CHANGELOG.md Yes Open
README.md Yes Open
CONTRIBUTING.md Yes Open
CODE_OF_CONDUCT.md Yes Open
SECURITY.md Yes Open
.github/ISSUE_TEMPLATE/ Yes Open
.github/pull_request_template.md Yes Open
PSGallery publish workflow Yes Open
docs/PVE_API_COVERAGE.md Yes Open
docs/cmdlets/ (75 files) Yes Open

What's Missing

  • IconUri in manifest PSData (cosmetic)
  • .github/ISSUE_TEMPLATE/config.yml (controls blank issue creation)
  • CODEOWNERS file (low priority for single-maintainer)

Phase 2 — PVE API Coverage Audit

Source of truth: ~/Source/pve_api/pve-api.json (646 endpoints). Spec generated 2026-03-21. Latest tracked PVE version: 9.0 (42 new endpoints, 56 changed endpoints)

Implemented Cmdlets (169 total)

Connection (3)

Cmdlet API Endpoint Method Prior Status
Connect-PveServer /access/ticket POST Open
Disconnect-PveServer (session teardown) Open
Test-PveConnection /version GET Open

Nodes (8)

Cmdlet API Endpoint Method Prior Status
Get-PveNode /nodes GET Open
Get-PveNodeStatus /nodes/{node}/status GET Open
Get-PveNodeConfig /nodes/{node}/config GET Open
Set-PveNodeConfig /nodes/{node}/config PUT Open
Get-PveNodeDns /nodes/{node}/dns GET Open
Set-PveNodeDns /nodes/{node}/dns PUT Open
Start-PveNodeVms /nodes/{node}/startall POST Open
Stop-PveNodeVms /nodes/{node}/stopall POST Open

VMs / QEMU (19)

Cmdlet API Endpoint Method Prior Status
Get-PveVm /nodes/{node}/qemu GET Open
New-PveVm /nodes/{node}/qemu POST Open
Remove-PveVm /nodes/{node}/qemu/{vmid} DELETE Open
Start-PveVm /nodes/{node}/qemu/{vmid}/status/start POST Open
Stop-PveVm /nodes/{node}/qemu/{vmid}/status/stop POST Open
Restart-PveVm /nodes/{node}/qemu/{vmid}/status/reboot POST Open
Suspend-PveVm /nodes/{node}/qemu/{vmid}/status/suspend POST Open
Resume-PveVm /nodes/{node}/qemu/{vmid}/status/resume POST Open
Reset-PveVm /nodes/{node}/qemu/{vmid}/status/reset POST Open
Copy-PveVm /nodes/{node}/qemu/{vmid}/clone POST Open
Move-PveVm /nodes/{node}/qemu/{vmid}/migrate POST Open
Get-PveVmConfig /nodes/{node}/qemu/{vmid}/config GET Open
Set-PveVmConfig /nodes/{node}/qemu/{vmid}/config PUT Open
Resize-PveVmDisk /nodes/{node}/qemu/{vmid}/resize PUT Open
Import-PveVmDisk /nodes/{node}/storage/{storage}/upload POST Open
Import-PveOva Multiple (upload + config + import) POST Open
Move-PveVmDisk /nodes/{node}/qemu/{vmid}/move_disk POST Open
Remove-PveVmDisk /nodes/{node}/qemu/{vmid}/unlink PUT Open
New-PveVmFromTemplate /nodes/{node}/qemu/{vmid}/clone POST Open

Guest Agent (9)

Cmdlet API Endpoint Method Prior Status
Test-PveVmGuestAgent /nodes/{node}/qemu/{vmid}/agent/ping POST Open
Get-PveVmGuestNetwork /nodes/{node}/qemu/{vmid}/agent/network-get-interfaces GET Open
Invoke-PveVmGuestExec /nodes/{node}/qemu/{vmid}/agent/exec + .../exec-status POST/GET Open
Get-PveVmGuestOsInfo /nodes/{node}/qemu/{vmid}/agent/get-osinfo GET Open
Get-PveVmGuestFsInfo /nodes/{node}/qemu/{vmid}/agent/get-fsinfo GET Open
Read-PveVmGuestFile /nodes/{node}/qemu/{vmid}/agent/file-read GET Open
Write-PveVmGuestFile /nodes/{node}/qemu/{vmid}/agent/file-write POST Open
Set-PveVmGuestPassword /nodes/{node}/qemu/{vmid}/agent/set-user-password POST Open
Invoke-PveVmGuestFsTrim /nodes/{node}/qemu/{vmid}/agent/fstrim POST Open

Containers / LXC (20)

Cmdlet API Endpoint Method Prior Status
Get-PveContainer /nodes/{node}/lxc GET Open
New-PveContainer /nodes/{node}/lxc POST Open
Remove-PveContainer /nodes/{node}/lxc/{vmid} DELETE Open
Start-PveContainer /nodes/{node}/lxc/{vmid}/status/start POST Open
Stop-PveContainer /nodes/{node}/lxc/{vmid}/status/stop POST Open
Restart-PveContainer /nodes/{node}/lxc/{vmid}/status/shutdown POST Open
Copy-PveContainer /nodes/{node}/lxc/{vmid}/clone POST Open
Move-PveContainer /nodes/{node}/lxc/{vmid}/migrate POST Open
Get-PveContainerConfig /nodes/{node}/lxc/{vmid}/config GET Open
Set-PveContainerConfig /nodes/{node}/lxc/{vmid}/config PUT Open
Suspend-PveContainer /nodes/{node}/lxc/{vmid}/status/suspend POST Open
Resume-PveContainer /nodes/{node}/lxc/{vmid}/status/resume POST Open
Resize-PveContainerDisk /nodes/{node}/lxc/{vmid}/resize PUT Open
New-PveContainerTemplate /nodes/{node}/lxc/{vmid}/template POST Open
Move-PveContainerVolume /nodes/{node}/lxc/{vmid}/move_volume POST Open
Get-PveContainerInterface /nodes/{node}/lxc/{vmid}/interfaces GET Open
Get-PveContainerSnapshot /nodes/{node}/lxc/{vmid}/snapshot GET Open
New-PveContainerSnapshot /nodes/{node}/lxc/{vmid}/snapshot POST Open
Remove-PveContainerSnapshot /nodes/{node}/lxc/{vmid}/snapshot/{name} DELETE Open
Restore-PveContainerSnapshot /nodes/{node}/lxc/{vmid}/snapshot/{name}/rollback POST Open

Storage (11)

Cmdlet API Endpoint Method Prior Status
Get-PveStorage /storage or /nodes/{node}/storage GET Open
Get-PveStorageContent /nodes/{node}/storage/{storage}/content GET Open
Send-PveFile /nodes/{node}/storage/{storage}/upload POST Open
Invoke-PveStorageDownload /nodes/{node}/storage/{storage}/download-url POST Open
New-PveStorage /storage POST Open
Remove-PveStorage /storage/{storage} DELETE Open
Set-PveStorage /storage/{storage} PUT Open
Get-PveStorageStatus /nodes/{node}/storage/{storage}/status GET Open
Remove-PveStorageContent /nodes/{node}/storage/{storage}/content/{volume} DELETE Open
Set-PveStorageContent /nodes/{node}/storage/{storage}/content/{volume} PUT Open
New-PveStorageDisk /nodes/{node}/storage/{storage}/content POST Open

VM Snapshots (4)

Cmdlet API Endpoint Method Prior Status
Get-PveSnapshot /nodes/{node}/qemu/{vmid}/snapshot GET Open
New-PveSnapshot /nodes/{node}/qemu/{vmid}/snapshot POST Open
Remove-PveSnapshot /nodes/{node}/qemu/{vmid}/snapshot/{name} DELETE Open
Restore-PveSnapshot /nodes/{node}/qemu/{vmid}/snapshot/{name}/rollback POST Open

Networking (5)

Cmdlet API Endpoint Method Prior Status
Get-PveNetwork /nodes/{node}/network GET Open
New-PveNetwork /nodes/{node}/network POST Open
Set-PveNetwork /nodes/{node}/network/{iface} PUT Open
Remove-PveNetwork /nodes/{node}/network/{iface} DELETE Open
Invoke-PveNetworkApply /nodes/{node}/network PUT Open

SDN (25)

Cmdlet API Endpoint Method Prior Status
Get-PveSdnZone /cluster/sdn/zones GET Open
New-PveSdnZone /cluster/sdn/zones POST Open
Remove-PveSdnZone /cluster/sdn/zones/{zone} DELETE Open
Set-PveSdnZone /cluster/sdn/zones/{zone} PUT Open
Get-PveSdnVnet /cluster/sdn/vnets GET Open
New-PveSdnVnet /cluster/sdn/vnets POST Open
Remove-PveSdnVnet /cluster/sdn/vnets/{vnet} DELETE Open
Set-PveSdnVnet /cluster/sdn/vnets/{vnet} PUT Open
Get-PveSdnSubnet /cluster/sdn/vnets/{vnet}/subnets GET Open
New-PveSdnSubnet /cluster/sdn/vnets/{vnet}/subnets POST Open
Remove-PveSdnSubnet /cluster/sdn/vnets/{vnet}/subnets/{subnet} DELETE Open
Set-PveSdnSubnet /cluster/sdn/vnets/{vnet}/subnets/{subnet} PUT Open
Get-PveSdnIpam /cluster/sdn/ipams GET Open
New-PveSdnIpam /cluster/sdn/ipams POST Open
Remove-PveSdnIpam /cluster/sdn/ipams/{ipam} DELETE Open
Set-PveSdnIpam /cluster/sdn/ipams/{ipam} PUT Open
Get-PveSdnDns /cluster/sdn/dns GET Open
New-PveSdnDns /cluster/sdn/dns POST Open
Remove-PveSdnDns /cluster/sdn/dns/{dns} DELETE Open
Set-PveSdnDns /cluster/sdn/dns/{dns} PUT Open
Get-PveSdnController /cluster/sdn/controllers GET Open
New-PveSdnController /cluster/sdn/controllers POST Open
Remove-PveSdnController /cluster/sdn/controllers/{controller} DELETE Open
Set-PveSdnController /cluster/sdn/controllers/{controller} PUT Open
Invoke-PveSdnApply /cluster/sdn PUT Open

Firewall (21)

Cmdlet API Endpoint Method Prior Status
Get-PveFirewallRule /cluster/firewall/rules GET Open
New-PveFirewallRule /cluster/firewall/rules POST Open
Set-PveFirewallRule /cluster/firewall/rules/{pos} PUT Open
Remove-PveFirewallRule /cluster/firewall/rules/{pos} DELETE Open
Get-PveFirewallGroup /cluster/firewall/groups GET Open
New-PveFirewallGroup /cluster/firewall/groups POST Open
Remove-PveFirewallGroup /cluster/firewall/groups/{group} DELETE Open
Get-PveFirewallAlias /cluster/firewall/aliases GET Open
New-PveFirewallAlias /cluster/firewall/aliases POST Open
Set-PveFirewallAlias /cluster/firewall/aliases/{name} PUT Open
Remove-PveFirewallAlias /cluster/firewall/aliases/{name} DELETE Open
Get-PveFirewallIpSet /cluster/firewall/ipset GET Open
New-PveFirewallIpSet /cluster/firewall/ipset POST Open
Remove-PveFirewallIpSet /cluster/firewall/ipset/{name} DELETE Open
Get-PveFirewallIpSetEntry /cluster/firewall/ipset/{name} GET Open
New-PveFirewallIpSetEntry /cluster/firewall/ipset/{name} POST Open
Set-PveFirewallIpSetEntry /cluster/firewall/ipset/{name}/{cidr} PUT Open
Remove-PveFirewallIpSetEntry /cluster/firewall/ipset/{name}/{cidr} DELETE Open
Get-PveFirewallOptions /cluster/firewall/options GET Open
Set-PveFirewallOptions /cluster/firewall/options PUT Open
Get-PveFirewallRef /cluster/firewall/refs GET Open

Backup (6)

Cmdlet API Endpoint Method Prior Status
New-PveBackup /nodes/{node}/vzdump POST Open
Get-PveBackupJob /cluster/backup GET Open
New-PveBackupJob /cluster/backup POST Open
Set-PveBackupJob /cluster/backup/{id} PUT Open
Remove-PveBackupJob /cluster/backup/{id} DELETE Open
Get-PveBackupInfo /cluster/backup-info/not-backed-up GET Open

Users / Access (23)

Cmdlet API Endpoint Method Prior Status
Get-PveUser /access/users GET Open
New-PveUser /access/users POST Open
Remove-PveUser /access/users/{userid} DELETE Open
Set-PveUser /access/users/{userid} PUT Open
Get-PveRole /access/roles GET Open
New-PveRole /access/roles POST Open
Remove-PveRole /access/roles/{roleid} DELETE Open
Set-PveRole /access/roles/{roleid} PUT Open
Get-PvePermission /access/acl GET Open
Set-PvePermission /access/acl PUT Open
Get-PveApiToken /access/users/{userid}/token GET Open
New-PveApiToken /access/users/{userid}/token/{tokenid} POST Open
Remove-PveApiToken /access/users/{userid}/token/{tokenid} DELETE Open
Set-PveApiToken /access/users/{userid}/token/{tokenid} PUT Open
Get-PveGroup /access/groups GET Open
New-PveGroup /access/groups POST Open
Set-PveGroup /access/groups/{groupid} PUT Open
Remove-PveGroup /access/groups/{groupid} DELETE Open
Get-PveDomain /access/domains GET Open
New-PveDomain /access/domains POST Open
Set-PveDomain /access/domains/{realm} PUT Open
Remove-PveDomain /access/domains/{realm} DELETE Open
Set-PvePassword /access/password PUT Open

Pools (4)

Cmdlet API Endpoint Method Prior Status
Get-PvePool /pools GET Open
New-PvePool /pools POST Open
Set-PvePool /pools/{poolid} PUT Open
Remove-PvePool /pools/{poolid} DELETE Open

Templates (4)

Cmdlet API Endpoint Method Prior Status
Get-PveTemplate /nodes/{node}/qemu (filtered) GET Open
New-PveTemplate /nodes/{node}/qemu/{vmid}/template POST Open
Remove-PveTemplate /nodes/{node}/qemu/{vmid} DELETE Open
New-PveVmFromTemplate /nodes/{node}/qemu/{vmid}/clone POST Open

Cloud-Init (3)

Cmdlet API Endpoint Method Prior Status
Get-PveCloudInitConfig /nodes/{node}/qemu/{vmid}/config GET Open
Set-PveCloudInitConfig /nodes/{node}/qemu/{vmid}/config PUT Open
Invoke-PveCloudInitRegenerate /nodes/{node}/qemu/{vmid}/cloudinit PUT Open

Tasks (4)

Cmdlet API Endpoint Method Prior Status
Get-PveTask /nodes/{node}/tasks/{upid}/status GET Open
Wait-PveTask /nodes/{node}/tasks/{upid}/status (polling) GET Open
Get-PveTaskList /nodes/{node}/tasks GET Open
Stop-PveTask /nodes/{node}/tasks/{upid} DELETE Open

Cluster (1)

Cmdlet API Endpoint Method Prior Status
Get-PveClusterResource /cluster/resources GET Open

Coverage Summary Per Functional Area

Area Total Endpoints Covered % 🆕 PVE 9.0 New Prior Status
acl 2 2 100% 0 Open
version 1 1 100% 0 Open
backup 6 5 83% 0 Open
access_groups 5 4 80% 0 Open
roles 5 4 80% 0 Open
tasks 5 4 80% 0 Open
firewall 40 31 78% 0 Open
users 12 9 75% 0 Open
networking 7 5 71% 0 Open
pools 7 5 71% 0 Open
access_domains 6 4 67% 0 Open
storage_config 5 3 60% 0 Open
storage 19 8 42% 1 Open
sdn 60 25 42% 16 Open
vms 97 35 36% 1 Open
containers 62 21 34% 1 Open
access 15 2 13% 1 Open
nodes 75 8 11% 11 Open
cluster 77 3 4% 6 Open
ceph 40 0 0% 0 Open
ha 21 0 0% 5 Open
disks 18 0 0% 0 Open
acme 15 0 0% 0 Open
cluster_config 10 0 0% 0 Open
certificates 8 0 0% 0 Open
apt 8 0 0% 0 Open
services 7 0 0% 0 Open
metrics 7 0 0% 0 Open
replication 5 0 0% 0 Open
TOTAL 646 180 27.9% 42

API Drift — Changed Endpoints (Covered Cmdlets)

Cmdlet Endpoint Change Description Risk Prior Status
Set-PveBackupJob PUT /cluster/backup/{id} Removed notification-policy, notification-target params Breaking Open
Set-PveNetwork PUT /nodes/{node}/network Added regenerate-frr, removed skip_frr Breaking Open
Get-PveVmConfig GET .../qemu/{vmid}/config Returns changed in latest version Cosmetic Open
Move-PveVm POST .../qemu/{vmid}/migrate Added with-conntrack-state parameter Additive Open

PVE 9.0 New Endpoints (42 total, 0 implemented)

Area Endpoint Method Description
ha /cluster/ha/rules GET/POST HA rules system (new in PVE 9.0)
ha /cluster/ha/rules/{rule} GET/PUT/DELETE Individual HA rule management
cluster /cluster/bulk-action/guest/* POST Bulk guest start/shutdown/suspend/migrate
sdn /cluster/sdn/fabrics/* GET/POST/PUT/DELETE SDN fabrics (13 endpoints)
sdn /cluster/sdn/lock / rollback POST/DELETE SDN lock and rollback
nodes /nodes/{node}/capabilities/qemu/cpu-flags GET CPU flags query
nodes /nodes/{node}/capabilities/qemu/migration GET Migration capabilities
nodes /nodes/{node}/sdn/fabrics/* GET Node SDN fabric status
nodes /nodes/{node}/query-oci-repo-tags GET OCI repo tag query
storage /nodes/{node}/storage/{storage}/oci-registry-pull POST OCI registry pull
vms /nodes/{node}/qemu/{vmid}/dbus-vmstate POST D-Bus VM state
containers GET /nodes/{node}/lxc/{vmid}/migrate GET Container migration pre-check
access POST /access/vncticket POST VNC ticket creation

High-Value Gaps

Tier 1 — Most impactful for users:

  1. HA (High Availability) — 21 endpoints, 0% covered. Essential for production clusters. Resources, groups, status, and the new PVE 9.0 rules system (5 🆕 endpoints).
  2. Cluster configuration — 10 endpoints, 0%. Cluster create/join/node management is fundamental for multi-node setups.
  3. Ceph — 40 endpoints, 0%. Critical for hyperconverged infrastructure (OSD, MON, pools, status).
  4. Notifications — 32 cluster endpoints, 0%. New in PVE 8.1+, essential for monitoring/alerting automation.
  5. Disk management — 18 endpoints, 0%. LVM, ZFS, SMART, wipe — needed for storage provisioning.

Tier 2 — Important operational gaps:

  1. VM/CT-level firewall — ~44 combined endpoints. Cluster-level IS covered, but per-VM/CT rules are not.
  2. SDN Fabrics (🆕 PVE 9.0) — 13 new endpoints. Key for advanced SDN.
  3. Resource mappings (PCI/USB passthrough) — 15 endpoints. Key for GPU passthrough.
  4. Certificates/ACME — 23 combined endpoints. TLS certificate management.
  5. GET /cluster/nextid — Trivial but frequently needed to allocate VM IDs programmatically.

Phase 3 — Code Quality & Best Practices

3a. PowerShell Module Design

  • All cmdlets use approved PowerShell verbs via verb class constants.
  • Noun prefix Pve is consistent across all 169 cmdlets.
  • HelpMessage present on virtually all parameters.
  • ShouldProcess on all destructive/mutating cmdlets.
  • Pipeline support via ProcessRecord and ValueFromPipelineByPropertyName.
  • ValidateRange/ValidateNotNullOrEmpty/ValidateSet used appropriately.
  • OutputType on all 169 cmdlets (previously ~54 were missing — now all have it).
  • All cmdlets are sealed (previously ~95 were not).

3b. C# Code Quality

  • Nullable annotations: <Nullable>enable</Nullable> in both projects.
  • IDisposable: PveHttpClient correctly implements IDisposable.
  • Logging: WriteVerbose used extensively; WriteProgress in file uploads and task waiting.
  • Exception hierarchy: 7 custom exception types with context properties.
  • Bare catches eliminated: All catch { } blocks replaced with filtered catch (Exception ex) when (...).
  • Magic strings extracted: Auth header names are now const string fields.
  • Zero TODO/FIXME/HACK markers.
  • No commented-out code or dead code.
  • Clean code style matching .editorconfig.
  • Dual JSON attributes removed: Only [JsonProperty] (Newtonsoft) remains; [JsonPropertyName] removed.

Code Quality Findings

ID File Line Severity Description Prior Status
CQ1 NewPveContainerSnapshotCmdlet.cs 75 Critical Infinite loop with no timeout in private WaitForTask. while (true) with no timeout or cancellation. If task never completes, cmdlet hangs forever. Should use TaskService.WaitForTask (same pattern that was fixed in VM snapshot cmdlets). New
CQ2 RemovePveContainerSnapshotCmdlet.cs 67 Critical Identical infinite loop — same while(true) no-timeout pattern as CQ1. New
CQ3 RestorePveContainerSnapshotCmdlet.cs 70 Critical Identical infinite loop — same pattern as CQ1. New
CQ4 InvokePveStorageDownloadCmdlet.cs 83 Critical Infinite loop in download task polling. while(true) with no timeout. Should use TaskService.WaitForTask. New
CQ5 SendPveFileCmdlet.cs 143 Critical Infinite loop in upload task polling. while(true) with no timeout. Should use TaskService.WaitForTask. New
CQ6 Both .csproj files 4 Medium net9.0 target is EOL (May 2025). Should upgrade to net10.0 (LTS). Open
CQ7 PveHttpClient.cs ~154 sites Medium Sync-over-async via .GetAwaiter().GetResult() across ~216 call sites. Standard for PS binary modules but carries deadlock risk. Open
CQ8 PveCmdletBase.cs 149 Medium Broad catch in status polling. catch (Exception ex) when (...) is filtered but still catches broadly. Improvement over bare catch but could be more specific. Open
CQ9 RestartPveContainerCmdlet.cs 15 Medium Missing ConfirmImpact.HighRestartPveVmCmdlet has it but container counterpart does not. Inconsistent. New
CQ10 SuspendPveContainerCmdlet.cs 14 Medium Missing ConfirmImpact.HighSuspendPveVmCmdlet has it but container counterpart does not. Inconsistent. New
CQ11 38 cmdlet files varies Medium new PveHttpClient per-operation. 38 cmdlets create their own PveHttpClient instance instead of going through services. Bypasses connection pooling. Open
CQ12 PSProxmoxVE.csproj 22 Low System.Management.Automation pinned to 7.4.0. Consider updating if targeting .NET 10. Open

Fixed Since Prior Scan

Prior ID Description Status
CQ1CQ4 Infinite loop WaitForTask in InvokePveNetworkApply, NewPveSnapshot, RestorePveSnapshot, RemovePveSnapshot Fixed — now uses TaskService.WaitForTask
CQ5 Infinite poll loop in InvokePveVmGuestExec Fixed — added Timeout parameter with Stopwatch + TimeoutException
CQ7 Duplicated WaitForTask methods (4 VM/network cmdlets) Fixed — uses TaskService
CQ9 ~54 cmdlets missing OutputType Fixed — all 169 cmdlets now have [OutputType]
CQ10 Firewall VmId defaults to 0 instead of nullable Fixed — no longer int default 0 pattern
CQ11 Bare catch in PveHttpClient.ExtractErrorMessage Fixed — proper exception handling
CQ12 Bare catch in PveCmdletBase status polling Fixed — filtered when clause excludes OOM/SOE
CQ13 Bare catch in VmService + ContainerService Fixed — filtered to PveApiException/HttpRequestException
CQ14 Bare catch in GetPveVmCmdlet Fixed — proper exception handling
CQ17 RemovePveRoleCmdlet missing ConfirmImpact.High Fixed — now has ConfirmImpact = ConfirmImpact.High
CQ18 ~95 cmdlets not sealed Fixed — all 169 cmdlets are now sealed
CQ19 SuspendPveVmCmdlet missing ConfirmImpact.High Fixed — now has ConfirmImpact.High
CQ20 RestartPveVmCmdlet missing ConfirmImpact Fixed — now has ConfirmImpact.High
CQ21 Dual JSON serialization attributes Fixed[JsonPropertyName] removed, only [JsonProperty] remains
CQ22 Auth header magic strings Fixed — extracted to const string ApiTokenPrefix and CsrfHeaderName
CQ6 (prior) Pool/CephPool parameter conflict in NewPveStorageCmdlet Fixed — runtime validation with ThrowTerminatingError if both specified

Phase 4 — Testing Coverage Analysis

Test Projects

Project Framework Type Runner
PSProxmoxVE.Core.Tests xUnit 2.7 + Moq 4.20 Unit tests (models, auth) dotnet test
PSProxmoxVE.Tests Pester 5 Cmdlet + Integration tests Invoke-Pester

xUnit Tests (Core Library)

15 test files covering authentication (PveSession, PveAuthenticator, PveVersion) and model deserialization (12 model areas including backup, cluster, firewall, SDN) with PVE 8 and PVE 9 JSON fixtures. ~180+ xUnit tests total.

Pester Tests

100% of 169 cmdlets have Pester unit tests covering: command existence, parameter metadata, mandatory checks, parameter types, ShouldProcess presence, ConfirmImpact declarations, and "no session" error behavior.

Integration Tests

  • Self-hosted runner provisions nested PVE 8 and PVE 9 via Terraform + auto-install ISO
  • Tests check for PVETEST_* environment variables, skip gracefully when unavailable
  • Robust AfterAll cleanup of VMs, containers, users, roles, firewall rules, backup jobs
  • CRUD patterns: create → verify → update → verify → delete → verify
  • SDN tests check PVE version and skip if older

Test Coverage Gap List (cmdlets lacking integration tests)

Cmdlet Unit Test Integration Test Prior Status
Nodes
Get-PveNodeConfig Yes No Open
Set-PveNodeConfig Yes No Open
Get-PveNodeDns Yes No Open
Set-PveNodeDns Yes No Open
Start-PveNodeVms Yes No Open
Stop-PveNodeVms Yes No Open
VMs
Move-PveVm Yes No Open
Move-PveVmDisk Yes No Open
Remove-PveVmDisk Yes No Open
Guest Agent
Get-PveVmGuestOsInfo Yes No Open
Get-PveVmGuestFsInfo Yes No Open
Read-PveVmGuestFile Yes No Open
Write-PveVmGuestFile Yes No Open
Set-PveVmGuestPassword Yes No Open
Invoke-PveVmGuestFsTrim Yes No Open
Containers
Move-PveContainer Yes No Open
Suspend-PveContainer Yes No Open
Resume-PveContainer Yes No Open
Resize-PveContainerDisk Yes No Open
New-PveContainerTemplate Yes No Open
Move-PveContainerVolume Yes No Open
Get-PveContainerInterface Yes No Open
Storage
Set-PveStorage Yes No Open
Get-PveStorageStatus Yes No Open
Remove-PveStorageContent Yes No Open
Set-PveStorageContent Yes No Open
New-PveStorageDisk Yes No Open
SDN
Set-PveSdnZone Yes No Open
Set-PveSdnVnet Yes No Open
Set-PveSdnSubnet Yes No Open
New-PveSdnIpam Yes No Open
Remove-PveSdnIpam Yes No Open
Set-PveSdnIpam Yes No Open
New-PveSdnDns Yes No Open
Remove-PveSdnDns Yes No Open
Set-PveSdnDns Yes No Open
New-PveSdnController Yes No Open
Remove-PveSdnController Yes No Open
Set-PveSdnController Yes No Open
Invoke-PveSdnApply Yes No Open
Users / Access
Set-PveRole Yes No Open
Set-PveApiToken Yes No Open
Get-PveGroup Yes No Open
New-PveGroup Yes No Open
Set-PveGroup Yes No Open
Remove-PveGroup Yes No Open
Get-PveDomain Yes No Open
New-PveDomain Yes No Open
Set-PveDomain Yes No Open
Remove-PveDomain Yes No Open
Set-PvePassword Yes No Open
Pools
Get-PvePool Yes No Open
New-PvePool Yes No Open
Set-PvePool Yes No Open
Remove-PvePool Yes No Open
Templates
New-PveTemplate Yes No Open
Remove-PveTemplate Yes No Open
Tasks
Get-PveTaskList Yes No Open
Stop-PveTask Yes No Open
Firewall
Get-PveFirewallGroup Yes No Open
New-PveFirewallGroup Yes No Open
Remove-PveFirewallGroup Yes No Open
Set-PveFirewallAlias Yes No Open
Set-PveFirewallIpSetEntry Yes No Open
Set-PveFirewallOptions Yes No Open
Get-PveFirewallRef Yes No Open
Backup
New-PveBackup Yes No Open
Get-PveBackupInfo Yes No Open
Cluster
Get-PveClusterResource Yes No Open

Summary: 169/169 unit tested (100%), ~105/169 integration tested (~62%).


Phase 5 — Security Review

5.1 Credential Handling

Aspect Status Details Prior Status
PSCredential usage Good Connect-PveServer accepts PSCredential Open
SecureString pattern Good Consistent Marshal.SecureStringToGlobalAllocUnicode + ZeroFreeGlobalAllocUnicode in try/finally Open
Set-PveVmGuestPassword Good Now uses SecureString (was plain string) Fixed
API token in memory Acceptable Stored as plain string in PveSession.ApiToken Open
Credential logging Good No WriteVerbose/WriteDebug includes credentials Open
Ticket storage Good In PveSession only, not written to disk Open
Session expiry Good 2-hour expiry via IsExpired property Open

5.2 TLS/HTTPS

Aspect Status Details Prior Status
HTTPS enforced Good BaseUrl always https://, no HTTP fallback Open
SkipCertificateCheck Good Explicit opt-in with WriteWarning advisory Open
TLS version Good OS/runtime negotiation (no pinning) Open
CSRF protection Good Token included on all POST/PUT/DELETE with ticket auth Open

5.3 Input Validation

Aspect Status Details Prior Status
VMID validation Good [ValidateRange(100, 999999999)] on all VmId params Open
URL encoding Good Uri.EscapeDataString() applied consistently across all services (VmService, ContainerService, StorageService, NetworkService, FirewallService, UserService, BackupService, PoolService, TaskService, SnapshotService, ClusterService) Fixed
API token format Good Regex validation in PveAuthenticator Open
Port validation Good [ValidateRange(1, 65535)] on port parameter Open

5.4 Dependency Security

Package Version Pinned Notes Prior Status
Newtonsoft.Json 13.0.3 Yes Latest stable Open
System.Text.Json 8.0.5 Yes Latest 8.x patch Open
SharpCompress 0.38.0 Yes OVA/tar extraction Open
PowerShellStandard.Library 5.1.1 Yes PrivateAssets=all Open
System.Management.Automation 7.4.0 Yes PrivateAssets=all Open

Security Findings

ID Area File Severity Description Prior Status
S1 Hardcoded password integration-tests.yml:42 Low PVE_PASSWORD: "Testpass123!" in workflow env. Masked via ::add-mask::. Disposable test VM. Open
S2 Hardcoded password variables.tf:80 Low Default "Testpass123!" for test VM password. Disposable nested VM. Open

Fixed Since Prior Scan

Prior ID Description Status
S1 SetPveVmGuestPasswordCmdlet.cs Password is string, not SecureString Fixed — now uses SecureString
S2 debug/Capture-UploadDiff.ps1 hardcoded API token and IP Fixed — replaced with placeholder tokens <PVE_HOST>, <USER>@<REALM>!<TOKENID>=<TOKEN_UUID>
S3 URL encoding missing in VmService, ContainerService, StorageService FixedUri.EscapeDataString() now used consistently across all services

Phase 6 — PSGallery Publication Readiness

# Check Pass/Fail Notes Prior Status
1 ModuleVersion is SemVer Pass 0.1.0 Open
2 GUID present and stable Pass a3f7c2d1-84e5-4b9f-a061-3e2d8c5f1a7b Open
3 Author Pass goodolclint Open
4 CompanyName Pass Worklab Open
5 Copyright Pass (c) 2026 goodolclint. All rights reserved. Open
6 Description (meaningful) Pass Mentions PVE 8.x/9.x and feature areas Open
7 PowerShellVersion minimum Pass 5.1 Open
8 RequiredAssemblies Pass PSProxmoxVE.Core.dll, Newtonsoft.Json.dll Open
9 CmdletsToExport explicit list Pass Fully enumerated (169 cmdlets), no wildcards Open
10 FunctionsToExport Pass Explicitly @() Open
11 Tags for discoverability Pass 8 tags incl. Proxmox, PVE, Virtualization, IaC Open
12 ProjectUri Pass GitHub repo URL Open
13 LicenseUri Pass Points to LICENSE Open
14 IconUri Fail Not set — cosmetic Open
15 ReleaseNotes Pass In PSData Open
16 Prerelease string Pass 'preview' Open
17 LICENSE (OSI-approved) Pass MIT Open
18 README: Install-Module Pass Install-Module -Name PSProxmoxVE documented Open
19 README: Quick-start examples Pass Multiple scenarios Open
20 README: Authentication guide Pass Ticket + API token Open
21 README: Badges Pass Build, Unit Tests, License, PSGallery Open
22 Publish workflow Pass Tag-triggered via publish.yml Open
23 Publish: version stamping Pass Extracts from git tag Open
24 Publish: smoke test Pass Loads module, asserts cmdlet count Open
25 Publish: API key as secret Pass secrets.PSGALLERY_API_KEY Open
26 Publish: GitHub Release Pass Auto-created via softprops/action-gh-release Open
27 CHANGELOG Pass Keep a Changelog format + Conventional Commits Open
28 Publish: single netstandard2.0 Warning Only builds netstandard2.0. Verify it loads under Win PS 5.1 since manifest declares DotNetFrameworkVersion = '4.8'. Open

Phase 7 — Community & Repo Maintenance Standards

# Check Pass/Fail Notes Prior Status
1 Bug report issue template Pass YAML form with module/PVE/PS version fields Open
2 Feature request template Pass Description, use case, API endpoints Open
3 PR template Pass Summary, type checkboxes, testing checklist Open
4 CONTRIBUTING.md Pass Prerequisites, building, tests, coding standards, PR process Open
5 CODE_OF_CONDUCT.md Pass Contributor Covenant 2.1 Open
6 SECURITY.md Pass Vulnerability disclosure, 48h SLA Open
7 Conventional commits Pass Consistent feat:, fix:, fix(test): in history Open
8 .gitattributes Pass Comprehensive: csharp diff, binary markers, LF for .sh Open
9 Issue template config.yml Fail No config.yml to control blank issues Open
10 CODEOWNERS Fail Not present. Low priority for single maintainer. Open
11 FUNDING.yml / community links Fail No Discussions/Discord/Funding references Open
12 Default branch main Pass Confirmed Open
  • Require PR reviews before merge
  • Require status checks (build + unit tests + integration tests)
  • Require linear history or squash merging

Phase 8 — Prioritized Recommendations

🔴 Critical (blocks PSGallery publication or is a security risk)

# What Where Why Fix Prior Status
C1 Infinite loop in 5 cmdlets' WaitForTask methods NewPveContainerSnapshotCmdlet.cs, RemovePveContainerSnapshotCmdlet.cs, RestorePveContainerSnapshotCmdlet.cs, InvokePveStorageDownloadCmdlet.cs, SendPveFileCmdlet.cs while(true) with no timeout — cmdlet hangs forever if task stalls. Same pattern that was fixed in VM snapshot cmdlets. Replace private WaitForTask with TaskService.WaitForTask (identical fix to CQ1CQ4 from prior scan) New

🟠 High (significantly impacts quality or community adoption)

# What Where Why Fix Prior Status
H1 HA subsystem (0% coverage) Module 21 endpoints + 5 🆕 PVE 9.0, essential for production clusters Implement HA resources, groups, status, and PVE 9.0 rules Open
H2 Ceph subsystem (0% coverage) Module 40 endpoints, critical for hyperconverged infrastructure Implement Ceph OSD, MON, pool, status operations Open
H3 net9.0 target is EOL Both .csproj files .NET 9.0 EOL was May 2025. Should use LTS release. Upgrade to net10.0 Open

🟡 Medium (best practice gaps, test coverage holes)

# What Where Why Fix Prior Status
M1 HttpClient per-call pattern 38 cmdlet files + services 38 cmdlets create new PveHttpClient per operation, bypassing connection pooling Refactor to client-per-session or use IHttpClientFactory pattern Open
M2 64 cmdlets lack integration tests Integration tests 38% of cmdlets untested end-to-end Prioritize pools, groups, domains, node ops, container gaps, guest agent extensions Open
M3 VM/CT-level firewall (0% coverage) Module ~44 endpoints. Cluster/node-level covered but per-VM/CT rules are not. Add VM/CT firewall cmdlets using existing firewall service patterns Open
M4 Cluster config (0% coverage) Module 10 endpoints for cluster create/join/node management Implement for multi-node cluster automation Open
M5 PVE 9.0 endpoints (0% coverage) Module 42 new endpoints in latest PVE version. Users on PVE 9 will expect support. Prioritize HA rules, bulk actions, SDN fabrics New
M6 Broad exception catches PveCmdletBase.cs, VmService.cs, ContainerService.cs Filtered when clauses are better than bare catches but still catch broadly Consider more specific exception types Open

🟢 Low / Nice-to-have (polish, discoverability, stretch goals)

# What Where Why Fix Prior Status
L1 No IconUri in manifest PSProxmoxVE.psd1 Improves PSGallery listing appearance Create icon, host it, add URI Open
L2 System.Management.Automation pinned to 7.4.0 PSProxmoxVE.csproj Consider updating when targeting .NET 10 Update with TFM migration Open
L3 No config.yml for issue templates .github/ISSUE_TEMPLATE/ Controls blank issue creation Add simple config.yml Open
L4 No CODEOWNERS Repo root Documents ownership for PR auto-assignment Add CODEOWNERS with maintainer Open
L5 Disk management (0% coverage) Module 18 endpoints — LVM, ZFS, SMART, wipe Implement as demand grows Open
L6 Notifications (0% coverage) Module 32 endpoints — new in PVE 8.1+ Implement for monitoring automation Open
L7 ACME/Certificates (0% coverage) Module 23 endpoints — TLS cert management Implement as demand grows Open
L8 Verify netstandard2.0 loads on PS 5.1 Publish workflow Manifest says Desktop compatible Add PS 5.1 smoke test to publish workflow Open

Summary Statistics

Metric This Scan Prior Scan Delta
Total cmdlets 169 148 +21
Cmdlets with ShouldProcess All mutating All mutating
Cmdlets with OutputType 169 (100%) ~94 (~64%) +36%
Cmdlets sealed 169 (100%) ~60 (~40%) +60%
Cmdlets with HelpMessage 169 (100%) 148 (100%)
xUnit test files 15 15
Pester test files ~48 ~45 +3
Integration test coverage ~62% (105/169) ~57% (85/148) +5%
PVE API areas with >0% coverage 17 of 30 17 of 29
PVE API total coverage 27.9% (180/646) 27.9% (180/646)
Critical issues 1 2 -1
High issues 3 5 -2
Medium issues 7 10 -3
Low issues 7 11 -4
Total issues 18 28 -10
Issues fixed from prior 16 9 +7
New issues found 5 16 -11
NuGet dependencies (runtime) 3 3
Security vulnerabilities 0 0
Community files present 9/9 9/9

* Integration test coverage improved both in absolute count (+20 cmdlets) and percentage (+5%).