Files
PSInfisicalAPI/src/PSInfisicalAPI/Endpoints/InfisicalEndpointRegistry.cs
T
GraceSolutions 09c577ebd0 Add lazy API version negotiation (v4 -> v3 fallback) with -ApiVersion override
- Endpoint registry now stores ordered candidate lists per logical operation; Get/TryGet preserve prior behavior, new GetCandidates(name) exposes the ladder. Added v3 fallbacks (/api/v3/secrets/raw and /api/v3/secrets/raw/{secretName}) after v4. - InfisicalConnection gains PinnedApiVersion and a ResolvedEndpointVersions cache so the chosen version sticks for the session. - InfisicalSecretsClient.SendWithVersionFallback walks candidates in pin -> cached -> registry order, falls back on routing-style failures (404 without an Infisical JSON envelope, 405, or 400 mentioning workspaceId/projectSlug) when no version is pinned, and surfaces real application errors immediately. - Get-InfisicalSecret(s) expose -ApiVersion; Connect-Infisical sets PinnedApiVersion only when -ApiVersion is explicitly bound on the command line (env-var/default values do not pin). - Logger.Error routes via WriteWarning to avoid premature terminating errors that masked InfisicalApiException details; EnsureSuccess no longer redacts non-2xx bodies so server error envelopes are visible. - InfisicalSecretsClient sends both projectId and workspaceId so it works against both new and legacy server-side validators.
2026-06-02 21:01:37 -04:00

147 lines
5.7 KiB
C#

using System.Collections.Generic;
using PSInfisicalAPI.Errors;
namespace PSInfisicalAPI.Endpoints
{
public static class InfisicalEndpointRegistry
{
private static readonly Dictionary<string, List<InfisicalEndpointDefinition>> Candidates =
new Dictionary<string, List<InfisicalEndpointDefinition>>
{
{
InfisicalEndpointNames.UniversalAuthLogin,
new List<InfisicalEndpointDefinition>
{
new InfisicalEndpointDefinition
{
Name = InfisicalEndpointNames.UniversalAuthLogin,
Resource = "Authentication",
Version = "v1",
Method = "POST",
Template = "/api/v1/auth/universal-auth/login",
RequiresAuthorization = false,
ContainsSecretMaterialInRequest = true,
ContainsSecretMaterialInResponse = true
}
}
},
{
InfisicalEndpointNames.ListSecrets,
new List<InfisicalEndpointDefinition>
{
new InfisicalEndpointDefinition
{
Name = InfisicalEndpointNames.ListSecrets,
Resource = "Secrets",
Version = "v4",
Method = "GET",
Template = "/api/v4/secrets",
RequiresAuthorization = true,
ContainsSecretMaterialInRequest = false,
ContainsSecretMaterialInResponse = true
},
new InfisicalEndpointDefinition
{
Name = InfisicalEndpointNames.ListSecrets,
Resource = "Secrets",
Version = "v3",
Method = "GET",
Template = "/api/v3/secrets/raw",
RequiresAuthorization = true,
ContainsSecretMaterialInRequest = false,
ContainsSecretMaterialInResponse = true
}
}
},
{
InfisicalEndpointNames.RetrieveSecret,
new List<InfisicalEndpointDefinition>
{
new InfisicalEndpointDefinition
{
Name = InfisicalEndpointNames.RetrieveSecret,
Resource = "Secrets",
Version = "v4",
Method = "GET",
Template = "/api/v4/secrets/{secretName}",
RequiresAuthorization = true,
ContainsSecretMaterialInRequest = false,
ContainsSecretMaterialInResponse = true
},
new InfisicalEndpointDefinition
{
Name = InfisicalEndpointNames.RetrieveSecret,
Resource = "Secrets",
Version = "v3",
Method = "GET",
Template = "/api/v3/secrets/raw/{secretName}",
RequiresAuthorization = true,
ContainsSecretMaterialInRequest = false,
ContainsSecretMaterialInResponse = true
}
}
}
};
public static InfisicalEndpointDefinition Get(string name)
{
List<InfisicalEndpointDefinition> list = GetCandidatesInternal(name);
return list[0];
}
public static bool TryGet(string name, out InfisicalEndpointDefinition definition)
{
if (string.IsNullOrEmpty(name))
{
definition = null;
return false;
}
List<InfisicalEndpointDefinition> list;
if (!Candidates.TryGetValue(name, out list) || list == null || list.Count == 0)
{
definition = null;
return false;
}
definition = list[0];
return true;
}
public static IReadOnlyList<InfisicalEndpointDefinition> GetCandidates(string name)
{
return GetCandidatesInternal(name);
}
public static IEnumerable<InfisicalEndpointDefinition> All()
{
List<InfisicalEndpointDefinition> result = new List<InfisicalEndpointDefinition>();
foreach (List<InfisicalEndpointDefinition> list in Candidates.Values)
{
foreach (InfisicalEndpointDefinition definition in list)
{
result.Add(definition);
}
}
return result;
}
private static List<InfisicalEndpointDefinition> GetCandidatesInternal(string name)
{
if (string.IsNullOrEmpty(name))
{
throw new InfisicalConfigurationException("Endpoint name must be provided.");
}
List<InfisicalEndpointDefinition> list;
if (!Candidates.TryGetValue(name, out list) || list == null || list.Count == 0)
{
throw new InfisicalConfigurationException(string.Concat("Unknown endpoint name: ", name));
}
return list;
}
}
}