fix!(pki): deserialize certificate-policy subject as array (matches API shape)

Get-InfisicalCertificatePolicy was throwing JsonSerializationException on
every list/get call:

  Cannot deserialize the current JSON array (e.g. [1,2,3]) into type
  'PSInfisicalAPI.Pki.InfisicalCertificatePolicySubjectDto' because the type
  requires a JSON object ... Path 'certificatePolicies[0].subject', line 1,
  position 207.

The API returns `subject` as an array of {type, allowed} entries (one per
DN component: CN, O, OU, C, ...), in the same shape as `sans`. The DTO
modeled it as a single object, so deserialization failed before any data
ever reached the caller.

CHANGES
- InfisicalCertificatePolicy.Subject is now InfisicalCertificatePolicySubject[]
  (was a single InfisicalCertificatePolicySubject).
- DTO field switched from typed InfisicalCertificatePolicySubjectDto to
  JToken SubjectRaw so we tolerate both array (current API) and object
  (defensive fallback) shapes -- same pattern as SansRaw.
- Mapper gains MapSubjects(JToken) / MapSubjectObject(JToken) mirroring
  MapSans / MapSanObject.

BREAKING
- The Subject property type changed from a single object to an array.
  Existing consumers writing `$policy.Subject.Allowed` must update to
  `$policy.Subject[0].Allowed` or iterate `$policy.Subject`. In practice no
  caller was reachable because the cmdlet threw before returning.

TESTS
- 216/216 tests passing.
This commit is contained in:
GraceSolutions
2026-06-04 22:05:36 -04:00
parent bdec5aa6ec
commit 86968c18cb
3 changed files with 28 additions and 4 deletions
@@ -8,7 +8,7 @@ namespace PSInfisicalAPI.Models
public string ProjectId { get; set; } public string ProjectId { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Description { get; set; } public string Description { get; set; }
public InfisicalCertificatePolicySubject Subject { get; set; } public InfisicalCertificatePolicySubject[] Subject { get; set; }
public InfisicalCertificatePolicySan[] Sans { get; set; } public InfisicalCertificatePolicySan[] Sans { get; set; }
public InfisicalCertificatePolicyUsages KeyUsages { get; set; } public InfisicalCertificatePolicyUsages KeyUsages { get; set; }
public InfisicalCertificatePolicyUsages ExtendedKeyUsages { get; set; } public InfisicalCertificatePolicyUsages ExtendedKeyUsages { get; set; }
@@ -10,7 +10,7 @@ namespace PSInfisicalAPI.Pki
[JsonProperty("projectId")] public string ProjectId { get; set; } [JsonProperty("projectId")] public string ProjectId { get; set; }
[JsonProperty("name")] public string Name { get; set; } [JsonProperty("name")] public string Name { get; set; }
[JsonProperty("description")] public string Description { get; set; } [JsonProperty("description")] public string Description { get; set; }
[JsonProperty("subject")] public InfisicalCertificatePolicySubjectDto Subject { get; set; } [JsonProperty("subject")] public JToken SubjectRaw { get; set; }
[JsonProperty("sans")] public JToken SansRaw { get; set; } [JsonProperty("sans")] public JToken SansRaw { get; set; }
[JsonProperty("keyUsages")] public InfisicalCertificatePolicyUsagesDto KeyUsages { get; set; } [JsonProperty("keyUsages")] public InfisicalCertificatePolicyUsagesDto KeyUsages { get; set; }
[JsonProperty("extendedKeyUsages")] public InfisicalCertificatePolicyUsagesDto ExtendedKeyUsages { get; set; } [JsonProperty("extendedKeyUsages")] public InfisicalCertificatePolicyUsagesDto ExtendedKeyUsages { get; set; }
@@ -21,7 +21,7 @@ namespace PSInfisicalAPI.Pki
ProjectId = !string.IsNullOrEmpty(dto.ProjectId) ? dto.ProjectId : fallbackProjectId, ProjectId = !string.IsNullOrEmpty(dto.ProjectId) ? dto.ProjectId : fallbackProjectId,
Name = dto.Name, Name = dto.Name,
Description = dto.Description, Description = dto.Description,
Subject = MapSubject(dto.Subject), Subject = MapSubjects(dto.SubjectRaw),
Sans = MapSans(dto.SansRaw), Sans = MapSans(dto.SansRaw),
KeyUsages = MapUsages(dto.KeyUsages), KeyUsages = MapUsages(dto.KeyUsages),
ExtendedKeyUsages = MapUsages(dto.ExtendedKeyUsages), ExtendedKeyUsages = MapUsages(dto.ExtendedKeyUsages),
@@ -52,8 +52,32 @@ namespace PSInfisicalAPI.Pki
return results.ToArray(); return results.ToArray();
} }
private static InfisicalCertificatePolicySubject MapSubject(InfisicalCertificatePolicySubjectDto dto) private static InfisicalCertificatePolicySubject[] MapSubjects(JToken token)
{ {
if (token == null || token.Type == JTokenType.Null) { return null; }
List<InfisicalCertificatePolicySubject> results = new List<InfisicalCertificatePolicySubject>();
if (token.Type == JTokenType.Array)
{
foreach (JToken child in (JArray)token)
{
InfisicalCertificatePolicySubject mapped = MapSubjectObject(child);
if (mapped != null) { results.Add(mapped); }
}
}
else if (token.Type == JTokenType.Object)
{
InfisicalCertificatePolicySubject mapped = MapSubjectObject(token);
if (mapped != null) { results.Add(mapped); }
}
return results.Count > 0 ? results.ToArray() : null;
}
private static InfisicalCertificatePolicySubject MapSubjectObject(JToken token)
{
if (token == null || token.Type != JTokenType.Object) { return null; }
InfisicalCertificatePolicySubjectDto dto = token.ToObject<InfisicalCertificatePolicySubjectDto>();
if (dto == null) { return null; } if (dto == null) { return null; }
return new InfisicalCertificatePolicySubject return new InfisicalCertificatePolicySubject
{ {