fix: remove defunct DELETE /access/ticket call and gain -Session parameter

Disconnect-PveServer was calling DELETE /access/ticket, an endpoint that does
not exist in the PVE API spec. The call always failed but errors were swallowed,
so the cmdlet succeeded while claiming server-side invalidation occurred.

Rebase on PveCmdletBase to gain the -Session parameter, making explicit session
disconnection possible (the cmdlet previously only worked with the active
session). Update help text to clarify that PVE tickets expire server-side after
two hours and cannot be revoked.

Remove the DELETE call entirely — tickets are stateless and expire on their own.
Clear ModuleState.ActiveSession only when disconnecting the active session
(no -Session given) or when explicitly disconnecting the active session.
This commit is contained in:
goodolclint-claude[bot]
2026-09-02 16:32:00 +00:00
committed by GitHub
parent 68f953075d
commit e4a667e7fc
2 changed files with 22 additions and 27 deletions
@@ -1,56 +1,39 @@
using System;
using System.Management.Automation;
using PSProxmoxVE.Core.Authentication;
using PSProxmoxVE.Core.Client;
namespace PSProxmoxVE.Cmdlets.Connection
{
/// <summary>
/// <para type="synopsis">Closes the active Proxmox VE session.</para>
/// <para type="synopsis">Discards the local Proxmox VE session.</para>
/// <para type="description">
/// Disconnect-PveServer invalidates the module-level session. For ticket-based
/// sessions it additionally attempts a best-effort DELETE against the
/// /access/ticket endpoint to invalidate the server-side ticket. Errors from
/// that request are silently ignored so that the local session is always cleared.
/// Disconnect-PveServer discards the module-level session from memory. PVE tickets cannot be
/// revoked server-side and expire on their own (typically two hours).
/// </para>
/// </summary>
[Cmdlet(VerbsCommunications.Disconnect, "PveServer",
SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.Low)]
[OutputType(typeof(void))]
[Alias("dpve")]
public sealed class DisconnectPveServerCmdlet : PSCmdlet
public sealed class DisconnectPveServerCmdlet : PveCmdletBase
{
protected override void ProcessRecord()
{
var session = ModuleState.ActiveSession;
var sessionToDisconnect = Session ?? ModuleState.ActiveSession;
if (session is null)
if (sessionToDisconnect is null)
{
WriteWarning("No active Proxmox VE session to disconnect.");
return;
}
if (!ShouldProcess($"{session.Hostname}:{session.Port}", "Disconnect"))
if (!ShouldProcess($"{sessionToDisconnect.Hostname}:{sessionToDisconnect.Port}", "Disconnect"))
return;
// Best-effort server-side ticket invalidation for ticket-based auth.
if (session.AuthMode == PveAuthMode.Ticket)
if (Session is null || sessionToDisconnect == ModuleState.ActiveSession)
{
try
{
using var client = new PveHttpClient(session);
client.DeleteAsync("access/ticket").GetAwaiter().GetResult();
}
catch (Exception ex)
{
// Non-fatal — we still clear the local session below.
WriteVerbose($"Server-side ticket invalidation failed (ignored): {ex.Message}");
}
ModuleState.ActiveSession = null;
}
ModuleState.ActiveSession = null;
WriteVerbose($"Disconnected from {session.Hostname}:{session.Port}.");
WriteVerbose($"Disconnected from {sessionToDisconnect.Hostname}:{sessionToDisconnect.Port}.");
}
}
}
@@ -38,6 +38,10 @@ Describe 'Disconnect-PveServer' {
# attribute is present by confirming ShouldProcess support is enabled.
$script:Cmd.Parameters.ContainsKey('WhatIf') | Should -BeTrue
}
It 'Should expose -Session parameter' {
$script:Cmd.Parameters.ContainsKey('Session') | Should -BeTrue
}
}
Context 'Behaviour when no session is active' {
@@ -53,4 +57,12 @@ Describe 'Disconnect-PveServer' {
{ Disconnect-PveServer -WhatIf -ErrorAction Stop } | Should -Not -Throw
}
}
Context 'Active session lifecycle' {
It 'Should clear active session when disconnected without explicit -Session' {
Disconnect-PveServer -Confirm:$false -ErrorAction SilentlyContinue
$Module = Get-Module PSProxmoxVE
$Module.PrivateData.ModuleState.ActiveSession | Should -BeNullOrEmpty
}
}
}