Commit Graph

311 Commits

Author SHA1 Message Date
GoodOlClint 59327a1329 Merge pull request #29 from GoodOlClint/fix/emit-native-types
feat: emit native types instead of Newtonsoft JObject/JArray in public APIs
2026-03-25 11:46:57 -05:00
GoodOlClint 298294b687 Merge pull request #30 from GoodOlClint/copilot/sub-pr-29
chore: remove stale D013 compliance report and fix JsonHelper XML doc nullability
2026-03-25 11:45:14 -05:00
copilot-swe-agent[bot] 4a63055c10 chore: remove pre-correction D013-compliance.md and fix JsonHelper XML doc comment nullability
Co-authored-by: GoodOlClint <151449+GoodOlClint@users.noreply.github.com>
Agent-Logs-Url: https://github.com/GoodOlClint/PSProxmoxVE/sessions/2feecd30-2ba1-40bc-b1b5-c1fcc485a319
2026-03-25 16:42:29 +00:00
copilot-swe-agent[bot] 9e22036abd Initial plan 2026-03-25 16:38:23 +00:00
Clint Branham 10c277af10 fix: resolve F085 — PveClusterJoinInfo Nodelist/Totem D013 violations
D013 compliance scan found 2 remaining Newtonsoft type exposures:
- PveClusterJoinInfo.Nodelist: JArray → List<Dictionary<string, object?>>
- PveClusterJoinInfo.Totem: JObject → Dictionary<string, object?>

Both now use NativeListConverter/NativeDictionaryConverter for
deserialization. Full D013 compliance report added.

Updated findings.json: F085 status open with scan evidence.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:31:05 -05:00
Clint Branham 3ce19a721c feat: emit native types instead of Newtonsoft JObject/JArray in public APIs
Replace all Newtonsoft.Json.Linq types (JObject, JArray, JToken) exposed
in public service methods, model properties, and cmdlet OutputTypes with
native .NET types (Dictionary<string, object?>, List<Dictionary<string,
object?>>, PSObject).

New utilities:
- JsonHelper: ToNative, ToDictionary, ToListOfDictionaries for recursive
  JToken→native conversion
- NativeListConverter / NativeDictionaryConverter: JsonConverters for
  model properties that deserialize JArray/JObject to native types

Services updated (8 methods):
- NodeService: GetNodeConfig, GetNodeDns → Dictionary<string, object?>
- BackupService: GetNotBackedUp → List<Dictionary<string, object?>>
- ClusterConfigService: GetClusterConfig, GetTotem, GetQdevice → Dictionary
- HaService: GetManagerStatus → Dictionary<string, object?>
- VmService: GetGuestExecStatus → Dictionary<string, object?>

Models updated (2 properties):
- PvePool.Members: JArray → List<Dictionary<string, object?>>
- PveHaRule.Properties: JObject → Dictionary<string, object?>

Cmdlets updated (5):
- GetPveClusterConfigCmdlet: OutputType JToken → Dictionary<string, object>
- GetPveNodeConfigCmdlet: iteration updated for Dictionary
- GetPveNodeDnsCmdlet: iteration updated for Dictionary
- GetPveBackupInfoCmdlet: iteration updated for List<Dictionary>
- InvokePveVmGuestExecCmdlet: polling updated for Dictionary

Added D013 to DECISIONS.md: cmdlets must emit only native or module-defined types.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 11:12:57 -05:00
GoodOlClint 20ed5de69e Merge pull request #27 from GoodOlClint/feat/cluster-config-ha
feat: add cluster config and HA management cmdlets
2026-03-24 18:50:07 -05:00
Clint Branham 51b51354ef fix: address second round of Copilot review feedback
- Replace null-forgiving operator on Marshal.PtrToStringUni with
  null-coalescing fallback (AddPveClusterMemberCmdlet.cs:64)
- GetNextId now throws InvalidOperationException instead of silently
  returning 0 when API response cannot be parsed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:47:43 -05:00
GoodOlClint e54f9fb749 Merge branch 'main' into feat/cluster-config-ha 2026-03-24 18:41:20 -05:00
GoodOlClint 358e104db2 Merge pull request #26 from GoodOlClint/fix/f039-f084-quick-fixes
fix: resolve F039 bare catches and F084 session secret exposure
2026-03-24 18:41:01 -05:00
Clint Branham f1a3676723 fix: address Copilot review feedback on PR #27
- Extract ParseLinks helper to PveCmdletBase for shared link parsing
  with WriteWarning on malformed entries (was duplicated in 3 cmdlets)
- Fix GetClusterConfig to return data payload, not full API envelope
- Fix OutputType on GetPveClusterConfigCmdlet to JObject
- Fix link doc comments to use correct key format (link0..link7)
- Add null-safe Properties hashtable conversion in HA rule cmdlets
- Use case-insensitive Mode comparison in MovePveHaResourceCmdlet
- Remove unused using directives

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:40:10 -05:00
GoodOlClint b646a611e6 Merge pull request #28 from GoodOlClint/copilot/sub-pr-26
fix: narrow exception catches in PingGuestAgent and ImportPveOvaCmdlet
2026-03-24 18:37:22 -05:00
copilot-swe-agent[bot] f400336803 fix: narrow exception catches in PingGuestAgent and ImportPveOvaCmdlet
Co-authored-by: GoodOlClint <151449+GoodOlClint@users.noreply.github.com>
Agent-Logs-Url: https://github.com/GoodOlClint/PSProxmoxVE/sessions/e7930807-5536-4c55-96f8-0712aee44e00
2026-03-24 23:35:27 +00:00
copilot-swe-agent[bot] d91c93aca2 Initial plan 2026-03-24 23:31:32 +00:00
Clint Branham da2037d0c5 feat: add cluster config and HA management cmdlets (F060, F053)
Cluster Config (F060) — 11 new cmdlets:
- Get-PveClusterStatus, Get-PveClusterNextId
- Get/Set-PveClusterOption (datacenter settings)
- Get-PveClusterConfig, Get-PveClusterConfigNode
- Add/Remove-PveClusterConfigNode (cluster membership)
- Get-PveClusterJoinInfo, Add-PveClusterMember (join workflow)
- New-PveCluster (create cluster)

HA Management (F053) — 14 new cmdlets:
- Get/New/Set/Remove-PveHaResource (HA managed VMs/CTs)
- Move-PveHaResource (migrate/relocate via HA manager)
- Get/New/Set/Remove-PveHaGroup (node groups + priorities)
- Get-PveHaStatus (HA manager status)
- Get/New/Set/Remove-PveHaRule (PVE 9.0+ version-gated)

All cmdlets follow established conventions:
- sealed classes with [OutputType]
- ConfirmImpact.High on destructive operations (D006)
- SecureString for password parameter in Add-PveClusterMember (D002)
- Uri.EscapeDataString on all path segments (D003)
- Verb class constants (D011)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:28:11 -05:00
GoodOlClint c33ef930c8 Merge branch 'main' into fix/f039-f084-quick-fixes 2026-03-24 18:25:06 -05:00
GoodOlClint 6f74db10ed Merge pull request #25 from GoodOlClint/docs/review-scan-8
docs: review scan-8 findings update
2026-03-24 18:24:52 -05:00
Clint Branham c0a37d5ef3 fix: resolve F039 bare catches and F084 session secret exposure
F039 (regressed): Replace bare catch blocks with filtered catches that
exclude OutOfMemoryException and StackOverflowException, per D004.
- VmService.PingGuestAgent: catch now filters fatal exceptions
- ImportPveOvaCmdlet: catch now filters fatal exceptions + WriteVerbose

F084 (new): Add PveSession format view to PSProxmoxVE.format.ps1xml
that shows only Hostname, Port, AuthMode, IsExpired, and ServerVersion
in default table output. Sensitive properties (Ticket, ApiToken,
CsrfToken) are hidden from default display but remain accessible
via Select-Object * or direct property access.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:18:56 -05:00
Clint Branham f311c738b4 docs: review scan-8 findings update
Scan-8 full re-scan of PSProxmoxVE module (2026-03-24).

New findings:
- F084 [medium/security]: PveSession exposes auth secrets in pipeline output

Regressed:
- F039 [medium]: Bare catch blocks in VmService.PingGuestAgent and
  ImportPveOvaCmdlet (D004 violation)

Resolved:
- F059: VM/CT-level firewall was already supported via Level parameter

Findings DB: F001-F084, 10 open + 1 regressed + 72 resolved + 1 wont_fix

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 18:15:46 -05:00
GoodOlClint 0789601e33 Merge pull request #24 from GoodOlClint/fix/ci-concurrency
Add concurrency group to integration tests workflow
2026-03-24 15:57:25 -05:00
Clint Branham fb5d00aad0 fix(ci): add concurrency group to queue integration test runs
Prevents overlapping integration test runs on the self-hosted runner.
Uses cancel-in-progress: false so each run completes its full
lifecycle (including cleanup) before the next one starts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 15:53:11 -05:00
GoodOlClint 0f3e2c16d9 Merge pull request #23 from GoodOlClint/copilot/set-up-copilot-instructions
chore: add .github/copilot-instructions.md
2026-03-24 15:42:54 -05:00
GoodOlClint 5a27baa96a Merge branch 'main' into copilot/set-up-copilot-instructions 2026-03-24 15:41:29 -05:00
GoodOlClint 80652cbe92 Merge pull request #20 from GoodOlClint/feat/storage-iscsi-nfs-params
Add iSCSI/NFS parameters to New-PveStorage and shared storage integration tests
2026-03-24 15:41:09 -05:00
GoodOlClint a0c0b84323 Merge pull request #21 from GoodOlClint/copilot/sub-pr-20
fix(storage): iSCSI portal defaulting, Pool/CephPool selection, NFS format validation
2026-03-24 15:39:47 -05:00
copilot-swe-agent[bot] efc3e3a8e0 chore: add .github/copilot-instructions.md
Co-authored-by: GoodOlClint <151449+GoodOlClint@users.noreply.github.com>
Agent-Logs-Url: https://github.com/GoodOlClint/PSProxmoxVE/sessions/45c5e8bb-c3e5-461c-9064-6cdafab4daa0
2026-03-24 20:38:49 +00:00
copilot-swe-agent[bot] 3cd5400695 Initial plan 2026-03-24 20:37:18 +00:00
copilot-swe-agent[bot] f76ff513e9 fix(storage): implement Portal defaulting for iSCSI, fix Pool/CephPool selection, add NFS format validation
Co-authored-by: GoodOlClint <151449+GoodOlClint@users.noreply.github.com>
Agent-Logs-Url: https://github.com/GoodOlClint/PSProxmoxVE/sessions/d84722e4-409e-4ced-bfbc-f323715b8bdc
2026-03-24 20:36:46 +00:00
copilot-swe-agent[bot] 79c227f131 Initial plan 2026-03-24 20:30:56 +00:00
Clint Branham 2bf7f45ebf fix(ci): mount /lib/modules into NFS container for automatic kernel module loading
The NFS server image already has modprobe logic built in but needs
access to host kernel modules. Avoids requiring manual modprobe on
the runner host.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 15:24:06 -05:00
Clint Branham c385f4a620 fix(tests): correct NFS and iSCSI storage test parameters
NFS and iSCSI are implicitly shared in PVE — the API rejects an
explicit 'shared' parameter. iSCSI uses 'portal' (not 'server') for
the target address.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 14:57:45 -05:00
Clint Branham 064cc372cf feat(storage): add -Target and -Portal parameters to New-PveStorage for iSCSI
New-PveStorage now supports configuring iSCSI storage backends natively:
  -Target: iSCSI target IQN (e.g. iqn.2024-01.com.example:storage)
  -Portal: iSCSI portal address (host:port, defaults to server:3260)

Also refactored ProcessRecord to use AddIfNotEmpty helper, reducing
cognitive complexity.

Added unit tests for all iSCSI/NFS parameter metadata and a new
SharedStorage.Tests.ps1 integration test file that tests NFS and iSCSI
storage create/verify/status/delete lifecycle against the Docker-based
storage containers.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 14:43:33 -05:00
GoodOlClint ab768e114a Merge pull request #18 from GoodOlClint/feat/multi-node-storage-vm
Multi-node PVE provisioning and Docker-based shared storage
2026-03-24 14:09:31 -05:00
GoodOlClint b3481e259b Merge pull request #19 from GoodOlClint/copilot/sub-pr-18
fix(ci): address PR #18 review feedback on Docker storage reliability and security
2026-03-24 14:02:54 -05:00
copilot-swe-agent[bot] 6a63dea923 fix: apply review feedback on Docker storage and security documentation
- Fix storage_ip derivation to use default route first, not Swarm RemoteManagers
- Make iSCSI container entrypoint idempotent (check before create for target/LUN/bind)
- Pin erichough/nfs-server from 'latest' to '2.2.1' for reproducibility
- Replace curl|sh Docker install with apt repo in Dockerfile.test
- Add docker.sock security warnings in docker-compose.test.yml and CI workflow
- Update stale 'storage VM' references in comments and .env.test.example"

Co-authored-by: GoodOlClint <151449+GoodOlClint@users.noreply.github.com>
Agent-Logs-Url: https://github.com/GoodOlClint/PSProxmoxVE/sessions/534c0a63-2988-496c-b0ae-e291fcfa050b
2026-03-24 18:53:30 +00:00
copilot-swe-agent[bot] 8acd04c272 Initial plan 2026-03-24 18:47:58 +00:00
Clint Branham 9817d30a11 feat(ci): multi-node PVE provisioning and Docker-based shared storage
Provision two PVE nodes per version (a/b) for future cluster testing,
plus Docker-based iSCSI target and NFS server for shared storage tests.

Multi-node changes:
- Each PVE version gets two nodes: 9a/9b and 8a/8b (4 VMs total)
- Parameterized answer.toml FQDN for unique hostnames per node
- Per-node auto-install ISOs with unique answer files
- Node name discovered from FQDN and included in test config
- API token creation handles pre-existing tokens (delete + recreate)
- New test env vars: PVETEST_HOST_B, PVETEST_APITOKEN_B
- Removed preflight cleanup from provision (use explicit cleanup instead)

Docker storage services:
- New docker-compose.storage.yml with iSCSI (tgt) and NFS containers
- Host networking so PVE nodes can reach storage services
- Docker socket mounted into dev-infra container for host Docker access
- Docker CLI added to dev-infra Dockerfile stage
- New test env vars: PVETEST_STORAGE_VM_IP, PVETEST_ISCSI_IQN, PVETEST_NFS_EXPORT

Other fixes:
- first-boot.sh installs open-iscsi on PVE nodes
- preflight-cleanup.sh handles empty ISO filename gracefully
- TMPDIR set to work dir to avoid /tmp overflow during ISO uploads

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 13:34:15 -05:00
GoodOlClint 105bf4b2ba Merge pull request #17 from GoodOlClint/feat/local-integration-runner
fix(ci): add .dockerignore to prevent sending 250MB build context
2026-03-24 10:55:35 -05:00
GoodOlClint da0591c84c Merge branch 'main' into feat/local-integration-runner 2026-03-24 10:53:17 -05:00
Clint Branham 8d5df62b41 fix(ci): add .dockerignore to prevent sending 250MB build context
The Dockerfile.test stages only install packages (no COPY), but the
build context changed from tests/infrastructure/ to repo root. Without
a .dockerignore, Docker sends the entire repo (250MB) to the daemon
before building, causing CI to hang.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 10:51:27 -05:00
GoodOlClint cc07e110f9 Merge pull request #16 from GoodOlClint/feat/local-integration-runner
Unify CI and local integration test infrastructure
2026-03-24 10:44:32 -05:00
Clint Branham f21c7f84b7 feat(ci): unify CI and local integration test infrastructure
- Replace tests/infrastructure/Dockerfile with tests/Dockerfile.test
  (single multi-stage Dockerfile for both CI and local dev)
- CI container-image job now builds from Dockerfile.test target dev-infra
- Add ARM support: PowerShell installed via dotnet tool on arm64,
  APT package on amd64
- Replace tests/dev.sh (bash) with tests/dev.ps1 (PowerShell) for
  cross-platform support (Windows, macOS, Linux)
- Add -DockerHost parameter for running x86 containers on a remote
  Docker host from ARM Macs (rsyncs repo, uses SSH Docker transport)
- Add -NoCleanup switch to keep nested PVE VMs after integration tests
- integration command now provisions nested PVE VMs instead of testing
  against a pre-existing PVE directly
- Share /opt/pve-isos host path between CI and local dev (was separate
  Docker named volume)
- Delete tools/Invoke-Tests.ps1 (unused, overlapped with run-integration.sh)
- Add .gitignore entries for Terraform state/artifacts
- Update all documentation references

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 10:41:28 -05:00
GoodOlClint 629551021c Merge pull request #15 from GoodOlClint/fix/unmask-target-node
fix(ci): move PVE_TARGET_NODE from secret to variable to stop log masking
2026-03-24 09:55:15 -05:00
Clint Branham c1e1442155 fix(ci): move PVE_TARGET_NODE from secret to variable
The node name "pve" was being masked in all CI logs because GitHub
Actions auto-masks secret values. Since the node name is not sensitive,
use vars.PVE_TARGET_NODE instead of secrets.PVE_TARGET_NODE.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:49:21 -05:00
GoodOlClint da9e553683 Merge pull request #13 from GoodOlClint/refactor/integration-test-orchestration
refactor: extract integration test orchestration, add dev container
2026-03-24 09:44:19 -05:00
GoodOlClint cddb3ef71a Merge pull request #14 from GoodOlClint/copilot/sub-pr-13
fix: harden run-integration.sh against special chars, token leakage, and ARM
2026-03-24 09:40:06 -05:00
copilot-swe-agent[bot] 2291379040 fix: apply security and correctness fixes from PR #13 review
Co-authored-by: GoodOlClint <151449+GoodOlClint@users.noreply.github.com>
Agent-Logs-Url: https://github.com/GoodOlClint/PSProxmoxVE/sessions/677fba6b-906d-4cf6-82fa-3b7ab6afc648
2026-03-24 14:36:51 +00:00
copilot-swe-agent[bot] bdb62a3fbf Initial plan 2026-03-24 14:34:00 +00:00
Clint Branham ee717cccd1 docs: update CLAUDE.md with PR workflow and dev container instructions
All changes now go through pull requests. Branch protection is enabled
on main (required build checks, required review, admin enforced).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-24 09:21:59 -05:00
Clint Branham fc092ea5b3 feat: add dev container for local build, test, and provisioning
- Dockerfile.test: multi-stage build with dev (ARM+x86) and dev-infra
  (x86 only, adds Terraform + PVE provisioning tools) targets
- docker-compose.test.yml: services for both targets, .env.test support
- dev.sh: helper script wrapping container lifecycle and run-integration.sh
- .env.test.example: template for integration test configuration
- .gitignore: exclude .env.test, whitelist .env.*.example

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