feat: add Organization/Sub-Organization CRUD cmdlets and Get-InfisicalSANList
Adds 8 cmdlets for Organization and Sub-Organization CRUD (Get/New/Update/Remove for each), targeting /api/v2/organizations and /api/v1/sub-organizations. Get cmdlets default to List parameter set and switch to Single when -OrganizationId or -SubOrganizationId is supplied. New/Update/Remove honor -WhatIf/-Confirm; Remove defaults to High ConfirmImpact and supports -PassThru. No project context required. Adds Get-InfisicalSANList: emits a deduplicated SAN candidate set containing the local device name, the device name suffixed with each non-empty DNS suffix found across operational adapters and the system primary domain, every IPv4 unicast address falling within RFC 1918 or CGNAT, and the IPv4/IPv6 loopback addresses. Supports optional case-insensitive -InclusionExpression and -ExclusionExpression regex filters applied in fetch -> include -> exclude -> output order. Output is a single strongly-typed System.String[] array emitted non-enumerated so List<string>.AddRange consumes it directly. Registers 10 new endpoints, adds InfisicalOrganization/InfisicalSubOrganization models with DTOs, mappers, and clients, full MAML help for all 9 new cmdlets, mapper unit tests, EndpointRegistry inline-data coverage, and docs/DesignSpec.md sections 16.7 and 16.8. build.ps1 CmdletsToExport and Test-ModuleImports expected list now contain 51 cmdlets. README updated with Organization/Sub-Organization tables, the new Get-InfisicalSANList entry, and an end-to-end certificate request example using splatted OrderedDictionary blocks.
This commit is contained in:
@@ -75,6 +75,16 @@ namespace PSInfisicalAPI.Tests
|
||||
[InlineData(InfisicalEndpointNames.BulkUpdateSecret, "PATCH", "/api/v4/secrets/batch")]
|
||||
[InlineData(InfisicalEndpointNames.BulkDeleteSecret, "DELETE", "/api/v4/secrets/batch")]
|
||||
[InlineData(InfisicalEndpointNames.DuplicateSecret, "POST", "/api/v4/secrets/duplicate")]
|
||||
[InlineData(InfisicalEndpointNames.ListOrganizations, "GET", "/api/v2/organizations")]
|
||||
[InlineData(InfisicalEndpointNames.RetrieveOrganization, "GET", "/api/v1/organization/{organizationId}")]
|
||||
[InlineData(InfisicalEndpointNames.CreateOrganization, "POST", "/api/v2/organizations")]
|
||||
[InlineData(InfisicalEndpointNames.UpdateOrganization, "PATCH", "/api/v1/organization/{organizationId}")]
|
||||
[InlineData(InfisicalEndpointNames.DeleteOrganization, "DELETE", "/api/v1/organization/{organizationId}")]
|
||||
[InlineData(InfisicalEndpointNames.ListSubOrganizations, "GET", "/api/v1/sub-organizations")]
|
||||
[InlineData(InfisicalEndpointNames.RetrieveSubOrganization, "GET", "/api/v1/sub-organizations/{subOrgId}")]
|
||||
[InlineData(InfisicalEndpointNames.CreateSubOrganization, "POST", "/api/v1/sub-organizations")]
|
||||
[InlineData(InfisicalEndpointNames.UpdateSubOrganization, "PATCH", "/api/v1/sub-organizations/{subOrgId}")]
|
||||
[InlineData(InfisicalEndpointNames.DeleteSubOrganization, "DELETE", "/api/v1/sub-organizations/{subOrgId}")]
|
||||
public void Registered_Endpoints_Have_Expected_Shape(string name, string method, string template)
|
||||
{
|
||||
InfisicalEndpointDefinition definition = InfisicalEndpointRegistry.Get(name);
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
using System.Reflection;
|
||||
using PSInfisicalAPI.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace PSInfisicalAPI.Tests
|
||||
{
|
||||
public class OrganizationMapperTests
|
||||
{
|
||||
private static readonly System.Type MapperType = typeof(PSInfisicalAPI.Connections.InfisicalConnection).Assembly
|
||||
.GetType("PSInfisicalAPI.Organizations.InfisicalOrganizationMapper", true);
|
||||
|
||||
private static readonly System.Type DtoType = typeof(PSInfisicalAPI.Connections.InfisicalConnection).Assembly
|
||||
.GetType("PSInfisicalAPI.Organizations.InfisicalOrganizationResponseDto", true);
|
||||
|
||||
private static InfisicalOrganization InvokeMap(object dto)
|
||||
{
|
||||
MethodInfo map = MapperType.GetMethod("Map", BindingFlags.Public | BindingFlags.Static);
|
||||
return (InfisicalOrganization)map.Invoke(null, new[] { dto });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_Null_Dto_Returns_Null()
|
||||
{
|
||||
Assert.Null(InvokeMap(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_Populates_Core_Fields()
|
||||
{
|
||||
object dto = System.Activator.CreateInstance(DtoType);
|
||||
DtoType.GetProperty("Id").SetValue(dto, "org-001");
|
||||
DtoType.GetProperty("Name").SetValue(dto, "Acme");
|
||||
DtoType.GetProperty("Slug").SetValue(dto, "acme");
|
||||
DtoType.GetProperty("CustomerId").SetValue(dto, "cust-9");
|
||||
DtoType.GetProperty("AuthEnforced").SetValue(dto, true);
|
||||
DtoType.GetProperty("ScimEnabled").SetValue(dto, true);
|
||||
DtoType.GetProperty("CreatedAt").SetValue(dto, "2026-01-15T12:34:56Z");
|
||||
DtoType.GetProperty("UpdatedAt").SetValue(dto, "2026-02-20T09:00:00Z");
|
||||
|
||||
InfisicalOrganization organization = InvokeMap(dto);
|
||||
|
||||
Assert.Equal("org-001", organization.Id);
|
||||
Assert.Equal("Acme", organization.Name);
|
||||
Assert.Equal("acme", organization.Slug);
|
||||
Assert.Equal("cust-9", organization.CustomerId);
|
||||
Assert.True(organization.AuthEnforced);
|
||||
Assert.True(organization.ScimEnabled);
|
||||
Assert.NotNull(organization.CreatedAtUtc);
|
||||
Assert.NotNull(organization.UpdatedAtUtc);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_Falls_Back_To_InternalId()
|
||||
{
|
||||
object dto = System.Activator.CreateInstance(DtoType);
|
||||
DtoType.GetProperty("InternalId").SetValue(dto, "internal-id-1");
|
||||
|
||||
InfisicalOrganization organization = InvokeMap(dto);
|
||||
|
||||
Assert.Equal("internal-id-1", organization.Id);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MapMany_Null_Returns_Empty()
|
||||
{
|
||||
MethodInfo mapMany = MapperType.GetMethod("MapMany", BindingFlags.Public | BindingFlags.Static);
|
||||
InfisicalOrganization[] result = (InfisicalOrganization[])mapMany.Invoke(null, new object[] { null });
|
||||
Assert.NotNull(result);
|
||||
Assert.Empty(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
using System.Reflection;
|
||||
using PSInfisicalAPI.Models;
|
||||
using Xunit;
|
||||
|
||||
namespace PSInfisicalAPI.Tests
|
||||
{
|
||||
public class SubOrganizationMapperTests
|
||||
{
|
||||
private static readonly System.Type MapperType = typeof(PSInfisicalAPI.Connections.InfisicalConnection).Assembly
|
||||
.GetType("PSInfisicalAPI.SubOrganizations.InfisicalSubOrganizationMapper", true);
|
||||
|
||||
private static readonly System.Type DtoType = typeof(PSInfisicalAPI.Connections.InfisicalConnection).Assembly
|
||||
.GetType("PSInfisicalAPI.SubOrganizations.InfisicalSubOrganizationResponseDto", true);
|
||||
|
||||
private static InfisicalSubOrganization InvokeMap(object dto)
|
||||
{
|
||||
MethodInfo map = MapperType.GetMethod("Map", BindingFlags.Public | BindingFlags.Static);
|
||||
return (InfisicalSubOrganization)map.Invoke(null, new[] { dto });
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_Null_Dto_Returns_Null()
|
||||
{
|
||||
Assert.Null(InvokeMap(null));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_Populates_Core_Fields()
|
||||
{
|
||||
object dto = System.Activator.CreateInstance(DtoType);
|
||||
DtoType.GetProperty("Id").SetValue(dto, "sub-001");
|
||||
DtoType.GetProperty("Name").SetValue(dto, "Platform Engineering");
|
||||
DtoType.GetProperty("Slug").SetValue(dto, "platform-eng");
|
||||
DtoType.GetProperty("OrganizationId").SetValue(dto, "org-001");
|
||||
DtoType.GetProperty("IsAccessible").SetValue(dto, true);
|
||||
DtoType.GetProperty("CreatedAt").SetValue(dto, "2026-01-15T12:34:56Z");
|
||||
DtoType.GetProperty("UpdatedAt").SetValue(dto, "2026-02-20T09:00:00Z");
|
||||
|
||||
InfisicalSubOrganization subOrganization = InvokeMap(dto);
|
||||
|
||||
Assert.Equal("sub-001", subOrganization.Id);
|
||||
Assert.Equal("Platform Engineering", subOrganization.Name);
|
||||
Assert.Equal("platform-eng", subOrganization.Slug);
|
||||
Assert.Equal("org-001", subOrganization.OrganizationId);
|
||||
Assert.True(subOrganization.IsAccessible);
|
||||
Assert.NotNull(subOrganization.CreatedAtUtc);
|
||||
Assert.NotNull(subOrganization.UpdatedAtUtc);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Map_Falls_Back_To_InternalId_And_OrgId()
|
||||
{
|
||||
object dto = System.Activator.CreateInstance(DtoType);
|
||||
DtoType.GetProperty("InternalId").SetValue(dto, "internal-id-1");
|
||||
DtoType.GetProperty("OrgId").SetValue(dto, "org-fallback");
|
||||
|
||||
InfisicalSubOrganization subOrganization = InvokeMap(dto);
|
||||
|
||||
Assert.Equal("internal-id-1", subOrganization.Id);
|
||||
Assert.Equal("org-fallback", subOrganization.OrganizationId);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void MapMany_Null_Returns_Empty()
|
||||
{
|
||||
MethodInfo mapMany = MapperType.GetMethod("MapMany", BindingFlags.Public | BindingFlags.Static);
|
||||
InfisicalSubOrganization[] result = (InfisicalSubOrganization[])mapMany.Invoke(null, new object[] { null });
|
||||
Assert.NotNull(result);
|
||||
Assert.Empty(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using PSInfisicalAPI.Connections;
|
||||
using PSInfisicalAPI.Models;
|
||||
using PSInfisicalAPI.Organizations;
|
||||
|
||||
namespace PSInfisicalAPI.Cmdlets
|
||||
{
|
||||
[Cmdlet(VerbsCommon.Get, "InfisicalOrganization", DefaultParameterSetName = "List")]
|
||||
[OutputType(typeof(InfisicalOrganization))]
|
||||
public sealed class GetInfisicalOrganizationCmdlet : InfisicalCmdletBase
|
||||
{
|
||||
[Parameter(ParameterSetName = "Single", Mandatory = true, ValueFromPipelineByPropertyName = true, Position = 0)]
|
||||
[Alias("Id")]
|
||||
public string OrganizationId { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
InfisicalConnection connection = InfisicalSessionManager.RequireCurrent();
|
||||
InfisicalOrganizationClient client = new InfisicalOrganizationClient(HttpClient, Logger);
|
||||
|
||||
if (string.Equals(ParameterSetName, "Single", StringComparison.Ordinal))
|
||||
{
|
||||
InfisicalOrganization organization = client.Retrieve(connection, OrganizationId);
|
||||
if (organization != null)
|
||||
{
|
||||
WriteObject(organization);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
InfisicalOrganization[] organizations = client.List(connection);
|
||||
foreach (InfisicalOrganization organization in organizations)
|
||||
{
|
||||
WriteObject(organization);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
ThrowTerminatingForException("GetInfisicalOrganizationCmdlet", "GetOrganization", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Management.Automation;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace PSInfisicalAPI.Cmdlets
|
||||
{
|
||||
[Cmdlet(VerbsCommon.Get, "InfisicalSANList")]
|
||||
[OutputType(typeof(string[]))]
|
||||
public sealed class GetInfisicalSANListCmdlet : InfisicalCmdletBase
|
||||
{
|
||||
private const string Component = "GetInfisicalSANListCmdlet";
|
||||
|
||||
[Parameter]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string InclusionExpression { get; set; }
|
||||
|
||||
[Parameter]
|
||||
[ValidateNotNullOrEmpty]
|
||||
public string ExclusionExpression { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
Regex includeRegex = !string.IsNullOrEmpty(InclusionExpression) ? new Regex(InclusionExpression, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant) : null;
|
||||
Regex excludeRegex = !string.IsNullOrEmpty(ExclusionExpression) ? new Regex(ExclusionExpression, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant) : null;
|
||||
|
||||
List<string> sans = new List<string>();
|
||||
HashSet<string> seen = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
string deviceName = Dns.GetHostName();
|
||||
AddUnique(sans, seen, deviceName);
|
||||
|
||||
HashSet<string> suffixes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
string globalDomain = IPGlobalProperties.GetIPGlobalProperties().DomainName;
|
||||
if (!string.IsNullOrEmpty(globalDomain)) { suffixes.Add(globalDomain); }
|
||||
|
||||
NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
|
||||
foreach (NetworkInterface adapter in adapters)
|
||||
{
|
||||
if (adapter.OperationalStatus != OperationalStatus.Up) { continue; }
|
||||
if (adapter.NetworkInterfaceType == NetworkInterfaceType.Loopback) { continue; }
|
||||
|
||||
IPInterfaceProperties props = adapter.GetIPProperties();
|
||||
if (!string.IsNullOrEmpty(props.DnsSuffix)) { suffixes.Add(props.DnsSuffix); }
|
||||
|
||||
foreach (UnicastIPAddressInformation unicast in props.UnicastAddresses)
|
||||
{
|
||||
IPAddress ip = unicast.Address;
|
||||
if (ip.AddressFamily == AddressFamily.InterNetwork && IsRfc1918OrCgnat(ip))
|
||||
{
|
||||
AddUnique(sans, seen, ip.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string suffix in suffixes)
|
||||
{
|
||||
string trimmed = suffix.Trim().TrimStart('.');
|
||||
if (!string.IsNullOrEmpty(trimmed))
|
||||
{
|
||||
AddUnique(sans, seen, string.Concat(deviceName, ".", trimmed));
|
||||
}
|
||||
}
|
||||
|
||||
AddUnique(sans, seen, "127.0.0.1");
|
||||
AddUnique(sans, seen, "::1");
|
||||
|
||||
List<string> filtered = new List<string>(sans.Count);
|
||||
foreach (string san in sans)
|
||||
{
|
||||
if (includeRegex != null && !includeRegex.IsMatch(san)) { continue; }
|
||||
if (excludeRegex != null && excludeRegex.IsMatch(san)) { continue; }
|
||||
filtered.Add(san);
|
||||
}
|
||||
|
||||
WriteObject(filtered.ToArray(), false);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
ThrowTerminatingForException(Component, "GetSANList", exception);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsRfc1918OrCgnat(IPAddress ip)
|
||||
{
|
||||
byte[] bytes = ip.GetAddressBytes();
|
||||
if (bytes.Length != 4) { return false; }
|
||||
|
||||
if (bytes[0] == 10) { return true; }
|
||||
if (bytes[0] == 172 && bytes[1] >= 16 && bytes[1] <= 31) { return true; }
|
||||
if (bytes[0] == 192 && bytes[1] == 168) { return true; }
|
||||
if (bytes[0] == 100 && bytes[1] >= 64 && bytes[1] <= 127) { return true; }
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void AddUnique(List<string> list, HashSet<string> seen, string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value)) { return; }
|
||||
if (seen.Add(value)) { list.Add(value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using PSInfisicalAPI.Connections;
|
||||
using PSInfisicalAPI.Models;
|
||||
using PSInfisicalAPI.SubOrganizations;
|
||||
|
||||
namespace PSInfisicalAPI.Cmdlets
|
||||
{
|
||||
[Cmdlet(VerbsCommon.Get, "InfisicalSubOrganization", DefaultParameterSetName = "List")]
|
||||
[OutputType(typeof(InfisicalSubOrganization))]
|
||||
public sealed class GetInfisicalSubOrganizationCmdlet : InfisicalCmdletBase
|
||||
{
|
||||
[Parameter(ParameterSetName = "Single", Mandatory = true, ValueFromPipelineByPropertyName = true, Position = 0)]
|
||||
[Alias("Id")]
|
||||
public string SubOrganizationId { get; set; }
|
||||
|
||||
[Parameter(ParameterSetName = "List")] public int? Limit { get; set; }
|
||||
[Parameter(ParameterSetName = "List")] public int? Offset { get; set; }
|
||||
[Parameter(ParameterSetName = "List")] public string Search { get; set; }
|
||||
[Parameter(ParameterSetName = "List")] public string OrderBy { get; set; }
|
||||
|
||||
[Parameter(ParameterSetName = "List")]
|
||||
[ValidateSet("asc", "desc")]
|
||||
public string OrderDirection { get; set; }
|
||||
|
||||
[Parameter(ParameterSetName = "List")] public SwitchParameter IsAccessible { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
InfisicalConnection connection = InfisicalSessionManager.RequireCurrent();
|
||||
InfisicalSubOrganizationClient client = new InfisicalSubOrganizationClient(HttpClient, Logger);
|
||||
|
||||
if (string.Equals(ParameterSetName, "Single", StringComparison.Ordinal))
|
||||
{
|
||||
InfisicalSubOrganization subOrganization = client.Retrieve(connection, SubOrganizationId);
|
||||
if (subOrganization != null)
|
||||
{
|
||||
WriteObject(subOrganization);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool? isAccessible = MyInvocation.BoundParameters.ContainsKey("IsAccessible") ? (bool?)IsAccessible.IsPresent : null;
|
||||
InfisicalSubOrganization[] subOrganizations = client.List(connection, Limit, Offset, Search, OrderBy, OrderDirection, isAccessible);
|
||||
foreach (InfisicalSubOrganization subOrganization in subOrganizations)
|
||||
{
|
||||
WriteObject(subOrganization);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
ThrowTerminatingForException("GetInfisicalSubOrganizationCmdlet", "GetSubOrganization", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using PSInfisicalAPI.Connections;
|
||||
using PSInfisicalAPI.Models;
|
||||
using PSInfisicalAPI.Organizations;
|
||||
|
||||
namespace PSInfisicalAPI.Cmdlets
|
||||
{
|
||||
[Cmdlet(VerbsCommon.New, "InfisicalOrganization", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(InfisicalOrganization))]
|
||||
public sealed class NewInfisicalOrganizationCmdlet : InfisicalCmdletBase
|
||||
{
|
||||
[Parameter(Mandatory = true, Position = 0)] public string Name { get; set; }
|
||||
[Parameter] public string Slug { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!ShouldProcess(Name, "Create Infisical organization"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InfisicalConnection connection = InfisicalSessionManager.RequireCurrent();
|
||||
InfisicalOrganizationClient client = new InfisicalOrganizationClient(HttpClient, Logger);
|
||||
InfisicalOrganization organization = client.Create(connection, Name, Slug);
|
||||
if (organization != null)
|
||||
{
|
||||
WriteObject(organization);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
ThrowTerminatingForException("NewInfisicalOrganizationCmdlet", "CreateOrganization", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using PSInfisicalAPI.Connections;
|
||||
using PSInfisicalAPI.Models;
|
||||
using PSInfisicalAPI.SubOrganizations;
|
||||
|
||||
namespace PSInfisicalAPI.Cmdlets
|
||||
{
|
||||
[Cmdlet(VerbsCommon.New, "InfisicalSubOrganization", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(InfisicalSubOrganization))]
|
||||
public sealed class NewInfisicalSubOrganizationCmdlet : InfisicalCmdletBase
|
||||
{
|
||||
[Parameter(Mandatory = true, Position = 0)] public string Name { get; set; }
|
||||
[Parameter(Mandatory = true, Position = 1)] public string Slug { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!ShouldProcess(Name, "Create Infisical sub-organization"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InfisicalConnection connection = InfisicalSessionManager.RequireCurrent();
|
||||
InfisicalSubOrganizationClient client = new InfisicalSubOrganizationClient(HttpClient, Logger);
|
||||
InfisicalSubOrganization subOrganization = client.Create(connection, Name, Slug);
|
||||
if (subOrganization != null)
|
||||
{
|
||||
WriteObject(subOrganization);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
ThrowTerminatingForException("NewInfisicalSubOrganizationCmdlet", "CreateSubOrganization", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using PSInfisicalAPI.Connections;
|
||||
using PSInfisicalAPI.Organizations;
|
||||
|
||||
namespace PSInfisicalAPI.Cmdlets
|
||||
{
|
||||
[Cmdlet(VerbsCommon.Remove, "InfisicalOrganization", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
|
||||
public sealed class RemoveInfisicalOrganizationCmdlet : InfisicalCmdletBase
|
||||
{
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, Position = 0)]
|
||||
[Alias("Id")]
|
||||
public string OrganizationId { get; set; }
|
||||
|
||||
[Parameter] public SwitchParameter PassThru { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
InfisicalConnection connection = InfisicalSessionManager.RequireCurrent();
|
||||
|
||||
if (!ShouldProcess(OrganizationId, "Remove Infisical organization"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InfisicalOrganizationClient client = new InfisicalOrganizationClient(HttpClient, Logger);
|
||||
client.Delete(connection, OrganizationId);
|
||||
|
||||
if (PassThru.IsPresent)
|
||||
{
|
||||
WriteObject(OrganizationId);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
ThrowTerminatingForException("RemoveInfisicalOrganizationCmdlet", "DeleteOrganization", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using PSInfisicalAPI.Connections;
|
||||
using PSInfisicalAPI.SubOrganizations;
|
||||
|
||||
namespace PSInfisicalAPI.Cmdlets
|
||||
{
|
||||
[Cmdlet(VerbsCommon.Remove, "InfisicalSubOrganization", SupportsShouldProcess = true, ConfirmImpact = ConfirmImpact.High)]
|
||||
public sealed class RemoveInfisicalSubOrganizationCmdlet : InfisicalCmdletBase
|
||||
{
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, Position = 0)]
|
||||
[Alias("Id")]
|
||||
public string SubOrganizationId { get; set; }
|
||||
|
||||
[Parameter] public SwitchParameter PassThru { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
InfisicalConnection connection = InfisicalSessionManager.RequireCurrent();
|
||||
|
||||
if (!ShouldProcess(SubOrganizationId, "Remove Infisical sub-organization"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InfisicalSubOrganizationClient client = new InfisicalSubOrganizationClient(HttpClient, Logger);
|
||||
client.Delete(connection, SubOrganizationId);
|
||||
|
||||
if (PassThru.IsPresent)
|
||||
{
|
||||
WriteObject(SubOrganizationId);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
ThrowTerminatingForException("RemoveInfisicalSubOrganizationCmdlet", "DeleteSubOrganization", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using PSInfisicalAPI.Connections;
|
||||
using PSInfisicalAPI.Models;
|
||||
using PSInfisicalAPI.Organizations;
|
||||
|
||||
namespace PSInfisicalAPI.Cmdlets
|
||||
{
|
||||
[Cmdlet(VerbsData.Update, "InfisicalOrganization", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(InfisicalOrganization))]
|
||||
public sealed class UpdateInfisicalOrganizationCmdlet : InfisicalCmdletBase
|
||||
{
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, Position = 0)]
|
||||
[Alias("Id")]
|
||||
public string OrganizationId { get; set; }
|
||||
|
||||
[Parameter] public string Name { get; set; }
|
||||
[Parameter] public string Slug { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
InfisicalConnection connection = InfisicalSessionManager.RequireCurrent();
|
||||
|
||||
if (!ShouldProcess(OrganizationId, "Update Infisical organization"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InfisicalOrganizationClient client = new InfisicalOrganizationClient(HttpClient, Logger);
|
||||
InfisicalOrganization organization = client.Update(connection, OrganizationId, Name, Slug);
|
||||
if (organization != null)
|
||||
{
|
||||
WriteObject(organization);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
ThrowTerminatingForException("UpdateInfisicalOrganizationCmdlet", "UpdateOrganization", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Management.Automation;
|
||||
using PSInfisicalAPI.Connections;
|
||||
using PSInfisicalAPI.Models;
|
||||
using PSInfisicalAPI.SubOrganizations;
|
||||
|
||||
namespace PSInfisicalAPI.Cmdlets
|
||||
{
|
||||
[Cmdlet(VerbsData.Update, "InfisicalSubOrganization", SupportsShouldProcess = true)]
|
||||
[OutputType(typeof(InfisicalSubOrganization))]
|
||||
public sealed class UpdateInfisicalSubOrganizationCmdlet : InfisicalCmdletBase
|
||||
{
|
||||
[Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, Position = 0)]
|
||||
[Alias("Id")]
|
||||
public string SubOrganizationId { get; set; }
|
||||
|
||||
[Parameter] public string Name { get; set; }
|
||||
[Parameter] public string Slug { get; set; }
|
||||
|
||||
protected override void ProcessRecord()
|
||||
{
|
||||
try
|
||||
{
|
||||
InfisicalConnection connection = InfisicalSessionManager.RequireCurrent();
|
||||
|
||||
if (!ShouldProcess(SubOrganizationId, "Update Infisical sub-organization"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InfisicalSubOrganizationClient client = new InfisicalSubOrganizationClient(HttpClient, Logger);
|
||||
InfisicalSubOrganization subOrganization = client.Update(connection, SubOrganizationId, Name, Slug);
|
||||
if (subOrganization != null)
|
||||
{
|
||||
WriteObject(subOrganization);
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
ThrowTerminatingForException("UpdateInfisicalSubOrganizationCmdlet", "UpdateSubOrganization", exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,6 +44,18 @@ namespace PSInfisicalAPI.Endpoints
|
||||
public const string UpdateTag = "UpdateTag";
|
||||
public const string DeleteTag = "DeleteTag";
|
||||
|
||||
public const string ListOrganizations = "ListOrganizations";
|
||||
public const string RetrieveOrganization = "RetrieveOrganization";
|
||||
public const string CreateOrganization = "CreateOrganization";
|
||||
public const string UpdateOrganization = "UpdateOrganization";
|
||||
public const string DeleteOrganization = "DeleteOrganization";
|
||||
|
||||
public const string ListSubOrganizations = "ListSubOrganizations";
|
||||
public const string RetrieveSubOrganization = "RetrieveSubOrganization";
|
||||
public const string CreateSubOrganization = "CreateSubOrganization";
|
||||
public const string UpdateSubOrganization = "UpdateSubOrganization";
|
||||
public const string DeleteSubOrganization = "DeleteSubOrganization";
|
||||
|
||||
public const string ListInternalCertificateAuthorities = "ListInternalCertificateAuthorities";
|
||||
public const string RetrieveInternalCertificateAuthority = "RetrieveInternalCertificateAuthority";
|
||||
public const string SearchCertificates = "SearchCertificates";
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace PSInfisicalAPI.Endpoints
|
||||
RegisterEnvironments(Candidates);
|
||||
RegisterFolders(Candidates);
|
||||
RegisterTags(Candidates);
|
||||
RegisterOrganizations(Candidates);
|
||||
RegisterSubOrganizations(Candidates);
|
||||
RegisterPki(Candidates);
|
||||
}
|
||||
|
||||
@@ -496,6 +498,112 @@ namespace PSInfisicalAPI.Endpoints
|
||||
});
|
||||
}
|
||||
|
||||
private static void RegisterOrganizations(Dictionary<string, List<InfisicalEndpointDefinition>> map)
|
||||
{
|
||||
Add(map, new InfisicalEndpointDefinition
|
||||
{
|
||||
Name = InfisicalEndpointNames.ListOrganizations,
|
||||
Resource = "Organizations",
|
||||
Version = "v2",
|
||||
Method = "GET",
|
||||
Template = "/api/v2/organizations",
|
||||
RequiresAuthorization = true
|
||||
});
|
||||
|
||||
Add(map, new InfisicalEndpointDefinition
|
||||
{
|
||||
Name = InfisicalEndpointNames.RetrieveOrganization,
|
||||
Resource = "Organizations",
|
||||
Version = "v1",
|
||||
Method = "GET",
|
||||
Template = "/api/v1/organization/{organizationId}",
|
||||
RequiresAuthorization = true
|
||||
});
|
||||
|
||||
Add(map, new InfisicalEndpointDefinition
|
||||
{
|
||||
Name = InfisicalEndpointNames.CreateOrganization,
|
||||
Resource = "Organizations",
|
||||
Version = "v2",
|
||||
Method = "POST",
|
||||
Template = "/api/v2/organizations",
|
||||
RequiresAuthorization = true
|
||||
});
|
||||
|
||||
Add(map, new InfisicalEndpointDefinition
|
||||
{
|
||||
Name = InfisicalEndpointNames.UpdateOrganization,
|
||||
Resource = "Organizations",
|
||||
Version = "v1",
|
||||
Method = "PATCH",
|
||||
Template = "/api/v1/organization/{organizationId}",
|
||||
RequiresAuthorization = true
|
||||
});
|
||||
|
||||
Add(map, new InfisicalEndpointDefinition
|
||||
{
|
||||
Name = InfisicalEndpointNames.DeleteOrganization,
|
||||
Resource = "Organizations",
|
||||
Version = "v1",
|
||||
Method = "DELETE",
|
||||
Template = "/api/v1/organization/{organizationId}",
|
||||
RequiresAuthorization = true
|
||||
});
|
||||
}
|
||||
|
||||
private static void RegisterSubOrganizations(Dictionary<string, List<InfisicalEndpointDefinition>> map)
|
||||
{
|
||||
Add(map, new InfisicalEndpointDefinition
|
||||
{
|
||||
Name = InfisicalEndpointNames.ListSubOrganizations,
|
||||
Resource = "SubOrganizations",
|
||||
Version = "v1",
|
||||
Method = "GET",
|
||||
Template = "/api/v1/sub-organizations",
|
||||
RequiresAuthorization = true
|
||||
});
|
||||
|
||||
Add(map, new InfisicalEndpointDefinition
|
||||
{
|
||||
Name = InfisicalEndpointNames.RetrieveSubOrganization,
|
||||
Resource = "SubOrganizations",
|
||||
Version = "v1",
|
||||
Method = "GET",
|
||||
Template = "/api/v1/sub-organizations/{subOrgId}",
|
||||
RequiresAuthorization = true
|
||||
});
|
||||
|
||||
Add(map, new InfisicalEndpointDefinition
|
||||
{
|
||||
Name = InfisicalEndpointNames.CreateSubOrganization,
|
||||
Resource = "SubOrganizations",
|
||||
Version = "v1",
|
||||
Method = "POST",
|
||||
Template = "/api/v1/sub-organizations",
|
||||
RequiresAuthorization = true
|
||||
});
|
||||
|
||||
Add(map, new InfisicalEndpointDefinition
|
||||
{
|
||||
Name = InfisicalEndpointNames.UpdateSubOrganization,
|
||||
Resource = "SubOrganizations",
|
||||
Version = "v1",
|
||||
Method = "PATCH",
|
||||
Template = "/api/v1/sub-organizations/{subOrgId}",
|
||||
RequiresAuthorization = true
|
||||
});
|
||||
|
||||
Add(map, new InfisicalEndpointDefinition
|
||||
{
|
||||
Name = InfisicalEndpointNames.DeleteSubOrganization,
|
||||
Resource = "SubOrganizations",
|
||||
Version = "v1",
|
||||
Method = "DELETE",
|
||||
Template = "/api/v1/sub-organizations/{subOrgId}",
|
||||
RequiresAuthorization = true
|
||||
});
|
||||
}
|
||||
|
||||
private static void RegisterPki(Dictionary<string, List<InfisicalEndpointDefinition>> map)
|
||||
{
|
||||
Add(map, new InfisicalEndpointDefinition
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
|
||||
namespace PSInfisicalAPI.Models
|
||||
{
|
||||
public sealed class InfisicalOrganization
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public string CustomerId { get; set; }
|
||||
public bool AuthEnforced { get; set; }
|
||||
public bool ScimEnabled { get; set; }
|
||||
public DateTimeOffset? CreatedAtUtc { get; set; }
|
||||
public DateTimeOffset? UpdatedAtUtc { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.IsNullOrEmpty(Slug) ? (Name ?? Id) : Slug;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System;
|
||||
|
||||
namespace PSInfisicalAPI.Models
|
||||
{
|
||||
public sealed class InfisicalSubOrganization
|
||||
{
|
||||
public string Id { get; set; }
|
||||
public string Name { get; set; }
|
||||
public string Slug { get; set; }
|
||||
public string OrganizationId { get; set; }
|
||||
public bool IsAccessible { get; set; }
|
||||
public DateTimeOffset? CreatedAtUtc { get; set; }
|
||||
public DateTimeOffset? UpdatedAtUtc { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.IsNullOrEmpty(Slug) ? (Name ?? Id) : Slug;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using PSInfisicalAPI.Connections;
|
||||
using PSInfisicalAPI.Endpoints;
|
||||
using PSInfisicalAPI.Errors;
|
||||
using PSInfisicalAPI.Http;
|
||||
using PSInfisicalAPI.Logging;
|
||||
using PSInfisicalAPI.Models;
|
||||
using PSInfisicalAPI.Serialization;
|
||||
|
||||
namespace PSInfisicalAPI.Organizations
|
||||
{
|
||||
public sealed class InfisicalOrganizationClient
|
||||
{
|
||||
private const string Component = "OrganizationClient";
|
||||
|
||||
private readonly IInfisicalLogger _logger;
|
||||
private readonly JsonInfisicalSerializer _serializer;
|
||||
private readonly InfisicalApiInvoker _invoker;
|
||||
|
||||
public InfisicalOrganizationClient(IInfisicalHttpClient httpClient, IInfisicalLogger logger)
|
||||
{
|
||||
if (httpClient == null) { throw new ArgumentNullException(nameof(httpClient)); }
|
||||
_logger = logger ?? NullInfisicalLogger.Instance;
|
||||
_serializer = new JsonInfisicalSerializer();
|
||||
_invoker = new InfisicalApiInvoker(httpClient);
|
||||
}
|
||||
|
||||
public InfisicalOrganization[] List(InfisicalConnection connection)
|
||||
{
|
||||
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Information(Component, "Attempting to list Infisical organizations. Please Wait...");
|
||||
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.ListOrganizations, "ListOrganizations", null, null, null);
|
||||
InfisicalOrganizationListResponseDto dto = _serializer.Deserialize<InfisicalOrganizationListResponseDto>(response.Body);
|
||||
response.Clear();
|
||||
|
||||
InfisicalOrganization[] mapped = InfisicalOrganizationMapper.MapMany(dto != null ? dto.Organizations : null);
|
||||
_logger.Information(Component, "Infisical organization list retrieval was successful.");
|
||||
return mapped;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.Error(Component, "Infisical organization list retrieval failed.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public InfisicalOrganization Retrieve(InfisicalConnection connection, string organizationId)
|
||||
{
|
||||
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||
if (string.IsNullOrEmpty(organizationId)) { throw new InfisicalConfigurationException("OrganizationId is required."); }
|
||||
|
||||
Dictionary<string, string> pathParameters = new Dictionary<string, string> { { "organizationId", organizationId } };
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Information(Component, string.Concat("Attempting to retrieve Infisical organization '", organizationId, "'. Please Wait..."));
|
||||
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.RetrieveOrganization, "RetrieveOrganization", pathParameters, null, null);
|
||||
InfisicalOrganizationSingleResponseDto dto = _serializer.Deserialize<InfisicalOrganizationSingleResponseDto>(response.Body);
|
||||
response.Clear();
|
||||
|
||||
InfisicalOrganization mapped = InfisicalOrganizationMapper.Map(dto != null ? dto.Organization : null);
|
||||
_logger.Information(Component, "Infisical organization retrieval was successful.");
|
||||
return mapped;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.Error(Component, "Infisical organization retrieval failed.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public InfisicalOrganization Create(InfisicalConnection connection, string name, string slug)
|
||||
{
|
||||
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||
if (string.IsNullOrEmpty(name)) { throw new InfisicalConfigurationException("Name is required."); }
|
||||
|
||||
InfisicalOrganizationCreateRequestDto request = new InfisicalOrganizationCreateRequestDto { Name = name, Slug = slug };
|
||||
string body = _serializer.Serialize(request);
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Information(Component, string.Concat("Attempting to create Infisical organization '", name, "'. Please Wait..."));
|
||||
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.CreateOrganization, "CreateOrganization", null, null, body);
|
||||
InfisicalOrganizationSingleResponseDto dto = _serializer.Deserialize<InfisicalOrganizationSingleResponseDto>(response.Body);
|
||||
response.Clear();
|
||||
|
||||
InfisicalOrganization mapped = InfisicalOrganizationMapper.Map(dto != null ? dto.Organization : null);
|
||||
_logger.Information(Component, "Infisical organization creation was successful.");
|
||||
return mapped;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.Error(Component, "Infisical organization creation failed.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public InfisicalOrganization Update(InfisicalConnection connection, string organizationId, string name, string slug)
|
||||
{
|
||||
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||
if (string.IsNullOrEmpty(organizationId)) { throw new InfisicalConfigurationException("OrganizationId is required."); }
|
||||
|
||||
Dictionary<string, string> pathParameters = new Dictionary<string, string> { { "organizationId", organizationId } };
|
||||
InfisicalOrganizationUpdateRequestDto request = new InfisicalOrganizationUpdateRequestDto { Name = name, Slug = slug };
|
||||
string body = _serializer.Serialize(request);
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Information(Component, string.Concat("Attempting to update Infisical organization '", organizationId, "'. Please Wait..."));
|
||||
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.UpdateOrganization, "UpdateOrganization", pathParameters, null, body);
|
||||
InfisicalOrganizationSingleResponseDto dto = _serializer.Deserialize<InfisicalOrganizationSingleResponseDto>(response.Body);
|
||||
response.Clear();
|
||||
|
||||
InfisicalOrganization mapped = InfisicalOrganizationMapper.Map(dto != null ? dto.Organization : null);
|
||||
_logger.Information(Component, "Infisical organization update was successful.");
|
||||
return mapped;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.Error(Component, "Infisical organization update failed.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete(InfisicalConnection connection, string organizationId)
|
||||
{
|
||||
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||
if (string.IsNullOrEmpty(organizationId)) { throw new InfisicalConfigurationException("OrganizationId is required."); }
|
||||
|
||||
Dictionary<string, string> pathParameters = new Dictionary<string, string> { { "organizationId", organizationId } };
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Information(Component, string.Concat("Attempting to delete Infisical organization '", organizationId, "'. Please Wait..."));
|
||||
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.DeleteOrganization, "DeleteOrganization", pathParameters, null, null);
|
||||
response.Clear();
|
||||
_logger.Information(Component, "Infisical organization deletion was successful.");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.Error(Component, "Infisical organization deletion failed.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSInfisicalAPI.Organizations
|
||||
{
|
||||
internal sealed class InfisicalOrganizationResponseDto
|
||||
{
|
||||
[JsonProperty("id")] public string Id { get; set; }
|
||||
[JsonProperty("_id")] public string InternalId { get; set; }
|
||||
[JsonProperty("name")] public string Name { get; set; }
|
||||
[JsonProperty("slug")] public string Slug { get; set; }
|
||||
[JsonProperty("customerId")] public string CustomerId { get; set; }
|
||||
[JsonProperty("authEnforced")] public bool AuthEnforced { get; set; }
|
||||
[JsonProperty("scimEnabled")] public bool ScimEnabled { get; set; }
|
||||
[JsonProperty("createdAt")] public string CreatedAt { get; set; }
|
||||
[JsonProperty("updatedAt")] public string UpdatedAt { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class InfisicalOrganizationListResponseDto
|
||||
{
|
||||
[JsonProperty("organizations")] public List<InfisicalOrganizationResponseDto> Organizations { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class InfisicalOrganizationSingleResponseDto
|
||||
{
|
||||
[JsonProperty("organization")] public InfisicalOrganizationResponseDto Organization { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class InfisicalOrganizationCreateRequestDto
|
||||
{
|
||||
[JsonProperty("name")] public string Name { get; set; }
|
||||
[JsonProperty("slug", NullValueHandling = NullValueHandling.Ignore)] public string Slug { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class InfisicalOrganizationUpdateRequestDto
|
||||
{
|
||||
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name { get; set; }
|
||||
[JsonProperty("slug", NullValueHandling = NullValueHandling.Ignore)] public string Slug { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using PSInfisicalAPI.Models;
|
||||
|
||||
namespace PSInfisicalAPI.Organizations
|
||||
{
|
||||
internal static class InfisicalOrganizationMapper
|
||||
{
|
||||
public static InfisicalOrganization Map(InfisicalOrganizationResponseDto dto)
|
||||
{
|
||||
if (dto == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new InfisicalOrganization
|
||||
{
|
||||
Id = !string.IsNullOrEmpty(dto.Id) ? dto.Id : dto.InternalId,
|
||||
Name = dto.Name,
|
||||
Slug = dto.Slug,
|
||||
CustomerId = dto.CustomerId,
|
||||
AuthEnforced = dto.AuthEnforced,
|
||||
ScimEnabled = dto.ScimEnabled,
|
||||
CreatedAtUtc = ParseTimestamp(dto.CreatedAt),
|
||||
UpdatedAtUtc = ParseTimestamp(dto.UpdatedAt)
|
||||
};
|
||||
}
|
||||
|
||||
public static InfisicalOrganization[] MapMany(IEnumerable<InfisicalOrganizationResponseDto> items)
|
||||
{
|
||||
if (items == null)
|
||||
{
|
||||
return Array.Empty<InfisicalOrganization>();
|
||||
}
|
||||
|
||||
List<InfisicalOrganization> results = new List<InfisicalOrganization>();
|
||||
foreach (InfisicalOrganizationResponseDto dto in items)
|
||||
{
|
||||
InfisicalOrganization mapped = Map(dto);
|
||||
if (mapped != null)
|
||||
{
|
||||
results.Add(mapped);
|
||||
}
|
||||
}
|
||||
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
private static DateTimeOffset? ParseTimestamp(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
DateTimeOffset parsed;
|
||||
if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out parsed))
|
||||
{
|
||||
return parsed;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using PSInfisicalAPI.Connections;
|
||||
using PSInfisicalAPI.Endpoints;
|
||||
using PSInfisicalAPI.Errors;
|
||||
using PSInfisicalAPI.Http;
|
||||
using PSInfisicalAPI.Logging;
|
||||
using PSInfisicalAPI.Models;
|
||||
using PSInfisicalAPI.Serialization;
|
||||
|
||||
namespace PSInfisicalAPI.SubOrganizations
|
||||
{
|
||||
public sealed class InfisicalSubOrganizationClient
|
||||
{
|
||||
private const string Component = "SubOrganizationClient";
|
||||
|
||||
private readonly IInfisicalLogger _logger;
|
||||
private readonly JsonInfisicalSerializer _serializer;
|
||||
private readonly InfisicalApiInvoker _invoker;
|
||||
|
||||
public InfisicalSubOrganizationClient(IInfisicalHttpClient httpClient, IInfisicalLogger logger)
|
||||
{
|
||||
if (httpClient == null) { throw new ArgumentNullException(nameof(httpClient)); }
|
||||
_logger = logger ?? NullInfisicalLogger.Instance;
|
||||
_serializer = new JsonInfisicalSerializer();
|
||||
_invoker = new InfisicalApiInvoker(httpClient);
|
||||
}
|
||||
|
||||
public InfisicalSubOrganization[] List(InfisicalConnection connection, int? limit, int? offset, string search, string orderBy, string orderDirection, bool? isAccessible)
|
||||
{
|
||||
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||
|
||||
List<KeyValuePair<string, string>> queryParameters = new List<KeyValuePair<string, string>>();
|
||||
if (limit.HasValue) { queryParameters.Add(new KeyValuePair<string, string>("limit", limit.Value.ToString(CultureInfo.InvariantCulture))); }
|
||||
if (offset.HasValue) { queryParameters.Add(new KeyValuePair<string, string>("offset", offset.Value.ToString(CultureInfo.InvariantCulture))); }
|
||||
if (!string.IsNullOrEmpty(search)) { queryParameters.Add(new KeyValuePair<string, string>("search", search)); }
|
||||
if (!string.IsNullOrEmpty(orderBy)) { queryParameters.Add(new KeyValuePair<string, string>("orderBy", orderBy)); }
|
||||
if (!string.IsNullOrEmpty(orderDirection)) { queryParameters.Add(new KeyValuePair<string, string>("orderDirection", orderDirection)); }
|
||||
if (isAccessible.HasValue) { queryParameters.Add(new KeyValuePair<string, string>("isAccessible", isAccessible.Value ? "true" : "false")); }
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Information(Component, "Attempting to list Infisical sub-organizations. Please Wait...");
|
||||
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.ListSubOrganizations, "ListSubOrganizations", null, queryParameters, null);
|
||||
InfisicalSubOrganizationListResponseDto dto = _serializer.Deserialize<InfisicalSubOrganizationListResponseDto>(response.Body);
|
||||
response.Clear();
|
||||
|
||||
InfisicalSubOrganization[] mapped = InfisicalSubOrganizationMapper.MapMany(dto != null ? dto.SubOrganizations : null);
|
||||
_logger.Information(Component, "Infisical sub-organization list retrieval was successful.");
|
||||
return mapped;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.Error(Component, "Infisical sub-organization list retrieval failed.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public InfisicalSubOrganization Retrieve(InfisicalConnection connection, string subOrganizationId)
|
||||
{
|
||||
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||
if (string.IsNullOrEmpty(subOrganizationId)) { throw new InfisicalConfigurationException("SubOrganizationId is required."); }
|
||||
|
||||
Dictionary<string, string> pathParameters = new Dictionary<string, string> { { "subOrgId", subOrganizationId } };
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Information(Component, string.Concat("Attempting to retrieve Infisical sub-organization '", subOrganizationId, "'. Please Wait..."));
|
||||
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.RetrieveSubOrganization, "RetrieveSubOrganization", pathParameters, null, null);
|
||||
InfisicalSubOrganizationSingleResponseDto dto = _serializer.Deserialize<InfisicalSubOrganizationSingleResponseDto>(response.Body);
|
||||
response.Clear();
|
||||
|
||||
InfisicalSubOrganization mapped = InfisicalSubOrganizationMapper.Map(dto != null ? dto.SubOrganization : null);
|
||||
_logger.Information(Component, "Infisical sub-organization retrieval was successful.");
|
||||
return mapped;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.Error(Component, "Infisical sub-organization retrieval failed.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public InfisicalSubOrganization Create(InfisicalConnection connection, string name, string slug)
|
||||
{
|
||||
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||
if (string.IsNullOrEmpty(name)) { throw new InfisicalConfigurationException("Name is required."); }
|
||||
if (string.IsNullOrEmpty(slug)) { throw new InfisicalConfigurationException("Slug is required."); }
|
||||
|
||||
InfisicalSubOrganizationCreateRequestDto request = new InfisicalSubOrganizationCreateRequestDto { Name = name, Slug = slug };
|
||||
string body = _serializer.Serialize(request);
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Information(Component, string.Concat("Attempting to create Infisical sub-organization '", name, "'. Please Wait..."));
|
||||
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.CreateSubOrganization, "CreateSubOrganization", null, null, body);
|
||||
InfisicalSubOrganizationSingleResponseDto dto = _serializer.Deserialize<InfisicalSubOrganizationSingleResponseDto>(response.Body);
|
||||
response.Clear();
|
||||
|
||||
InfisicalSubOrganization mapped = InfisicalSubOrganizationMapper.Map(dto != null ? dto.SubOrganization : null);
|
||||
_logger.Information(Component, "Infisical sub-organization creation was successful.");
|
||||
return mapped;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.Error(Component, "Infisical sub-organization creation failed.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public InfisicalSubOrganization Update(InfisicalConnection connection, string subOrganizationId, string name, string slug)
|
||||
{
|
||||
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||
if (string.IsNullOrEmpty(subOrganizationId)) { throw new InfisicalConfigurationException("SubOrganizationId is required."); }
|
||||
|
||||
Dictionary<string, string> pathParameters = new Dictionary<string, string> { { "subOrgId", subOrganizationId } };
|
||||
InfisicalSubOrganizationUpdateRequestDto request = new InfisicalSubOrganizationUpdateRequestDto { Name = name, Slug = slug };
|
||||
string body = _serializer.Serialize(request);
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Information(Component, string.Concat("Attempting to update Infisical sub-organization '", subOrganizationId, "'. Please Wait..."));
|
||||
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.UpdateSubOrganization, "UpdateSubOrganization", pathParameters, null, body);
|
||||
InfisicalSubOrganizationSingleResponseDto dto = _serializer.Deserialize<InfisicalSubOrganizationSingleResponseDto>(response.Body);
|
||||
response.Clear();
|
||||
|
||||
InfisicalSubOrganization mapped = InfisicalSubOrganizationMapper.Map(dto != null ? dto.SubOrganization : null);
|
||||
_logger.Information(Component, "Infisical sub-organization update was successful.");
|
||||
return mapped;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.Error(Component, "Infisical sub-organization update failed.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete(InfisicalConnection connection, string subOrganizationId)
|
||||
{
|
||||
if (connection == null) { throw new ArgumentNullException(nameof(connection)); }
|
||||
if (string.IsNullOrEmpty(subOrganizationId)) { throw new InfisicalConfigurationException("SubOrganizationId is required."); }
|
||||
|
||||
Dictionary<string, string> pathParameters = new Dictionary<string, string> { { "subOrgId", subOrganizationId } };
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Information(Component, string.Concat("Attempting to delete Infisical sub-organization '", subOrganizationId, "'. Please Wait..."));
|
||||
InfisicalHttpResponse response = _invoker.Invoke(connection, InfisicalEndpointNames.DeleteSubOrganization, "DeleteSubOrganization", pathParameters, null, null);
|
||||
response.Clear();
|
||||
_logger.Information(Component, "Infisical sub-organization deletion was successful.");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_logger.Error(Component, "Infisical sub-organization deletion failed.");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace PSInfisicalAPI.SubOrganizations
|
||||
{
|
||||
internal sealed class InfisicalSubOrganizationResponseDto
|
||||
{
|
||||
[JsonProperty("id")] public string Id { get; set; }
|
||||
[JsonProperty("_id")] public string InternalId { get; set; }
|
||||
[JsonProperty("name")] public string Name { get; set; }
|
||||
[JsonProperty("slug")] public string Slug { get; set; }
|
||||
[JsonProperty("organizationId")] public string OrganizationId { get; set; }
|
||||
[JsonProperty("orgId")] public string OrgId { get; set; }
|
||||
[JsonProperty("isAccessible")] public bool IsAccessible { get; set; }
|
||||
[JsonProperty("createdAt")] public string CreatedAt { get; set; }
|
||||
[JsonProperty("updatedAt")] public string UpdatedAt { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class InfisicalSubOrganizationListResponseDto
|
||||
{
|
||||
[JsonProperty("subOrganizations")] public List<InfisicalSubOrganizationResponseDto> SubOrganizations { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class InfisicalSubOrganizationSingleResponseDto
|
||||
{
|
||||
[JsonProperty("subOrganization")] public InfisicalSubOrganizationResponseDto SubOrganization { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class InfisicalSubOrganizationCreateRequestDto
|
||||
{
|
||||
[JsonProperty("name")] public string Name { get; set; }
|
||||
[JsonProperty("slug")] public string Slug { get; set; }
|
||||
}
|
||||
|
||||
internal sealed class InfisicalSubOrganizationUpdateRequestDto
|
||||
{
|
||||
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name { get; set; }
|
||||
[JsonProperty("slug", NullValueHandling = NullValueHandling.Ignore)] public string Slug { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using PSInfisicalAPI.Models;
|
||||
|
||||
namespace PSInfisicalAPI.SubOrganizations
|
||||
{
|
||||
internal static class InfisicalSubOrganizationMapper
|
||||
{
|
||||
public static InfisicalSubOrganization Map(InfisicalSubOrganizationResponseDto dto)
|
||||
{
|
||||
if (dto == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new InfisicalSubOrganization
|
||||
{
|
||||
Id = !string.IsNullOrEmpty(dto.Id) ? dto.Id : dto.InternalId,
|
||||
Name = dto.Name,
|
||||
Slug = dto.Slug,
|
||||
OrganizationId = !string.IsNullOrEmpty(dto.OrganizationId) ? dto.OrganizationId : dto.OrgId,
|
||||
IsAccessible = dto.IsAccessible,
|
||||
CreatedAtUtc = ParseTimestamp(dto.CreatedAt),
|
||||
UpdatedAtUtc = ParseTimestamp(dto.UpdatedAt)
|
||||
};
|
||||
}
|
||||
|
||||
public static InfisicalSubOrganization[] MapMany(IEnumerable<InfisicalSubOrganizationResponseDto> items)
|
||||
{
|
||||
if (items == null)
|
||||
{
|
||||
return Array.Empty<InfisicalSubOrganization>();
|
||||
}
|
||||
|
||||
List<InfisicalSubOrganization> results = new List<InfisicalSubOrganization>();
|
||||
foreach (InfisicalSubOrganizationResponseDto dto in items)
|
||||
{
|
||||
InfisicalSubOrganization mapped = Map(dto);
|
||||
if (mapped != null)
|
||||
{
|
||||
results.Add(mapped);
|
||||
}
|
||||
}
|
||||
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
private static DateTimeOffset? ParseTimestamp(string value)
|
||||
{
|
||||
if (string.IsNullOrEmpty(value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
DateTimeOffset parsed;
|
||||
if (DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out parsed))
|
||||
{
|
||||
return parsed;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user