Treat profile pending-approval as warning instead of throw

Issuance via Request-InfisicalCertificate -CertificateProfileId no longer throws when the API responds without a certificate body (e.g. status pending_approval / pending_validation). InfisicalPkiClient.IssueCertificateByProfile now logs a warning and returns an InfisicalSignedCertificate populated only with Status, StatusMessage, and CertificateRequestId. New Status, StatusMessage, CertificateRequestId properties on InfisicalSignedCertificate and InfisicalCertificateResult propagate the lifecycle state. The cmdlet short-circuits when CertificatePem is empty: it skips key build, install, chain install, and private-key write, scrubs PrivateKeyPem, and emits a status-only result so callers can poll or trigger approval. Whether issuance is immediate is dictated by the certificate policy bound to the profile.
This commit is contained in:
GraceSolutions
2026-06-04 17:11:56 -04:00
parent ebabd6cf26
commit 3754de74f6
6 changed files with 31 additions and 3 deletions
@@ -121,6 +121,15 @@ namespace PSInfisicalAPI.Cmdlets
InfisicalSignedCertificate signed = SignCertificate(client, connection, resolvedProjectId, csr.CsrPem);
signed.PrivateKeyPem = csr.PrivateKeyPem;
if (string.IsNullOrEmpty(signed.CertificatePem))
{
Logger.Warning(Component, string.Concat("Issuance returned without a certificate (status='", signed.Status ?? "unknown", "'", string.IsNullOrEmpty(signed.StatusMessage) ? "" : string.Concat(", message='", signed.StatusMessage, "'"), string.IsNullOrEmpty(signed.CertificateRequestId) ? "" : string.Concat(", certificateRequestId='", signed.CertificateRequestId, "'"), "). Install / chain / key-write steps are skipped; emitting status-only result."));
InfisicalCertificateResult pending = InfisicalCertificateRequestHelpers.BuildResult(null, signed);
pending.PrivateKeyPem = null;
WriteObject(pending);
return;
}
X509KeyStorageFlags resolvedFlags = ResolveEffectiveKeyStorageFlags();
X509Certificate2 cert = PemCertificateBuilder.Build(signed.CertificatePem, signed.PrivateKeyPem, signed.CertificateChainPem, resolvedFlags);
@@ -13,6 +13,9 @@ namespace PSInfisicalAPI.Models
public string CertificatePem { get; set; }
public string CertificateChainPem { get; set; }
public string PrivateKeyPem { get; set; }
public string Status { get; set; }
public string StatusMessage { get; set; }
public string CertificateRequestId { get; set; }
public override string ToString()
{
@@ -7,6 +7,9 @@ namespace PSInfisicalAPI.Models
public string CertificateChainPem { get; set; }
public string IssuingCaCertificatePem { get; set; }
public string PrivateKeyPem { get; set; }
public string Status { get; set; }
public string StatusMessage { get; set; }
public string CertificateRequestId { get; set; }
public override string ToString()
{
@@ -220,6 +220,9 @@ namespace PSInfisicalAPI.Pki
result.CertificatePem = signed.CertificatePem;
result.CertificateChainPem = signed.CertificateChainPem;
result.PrivateKeyPem = signed.PrivateKeyPem;
result.Status = signed.Status;
result.StatusMessage = signed.StatusMessage;
result.CertificateRequestId = signed.CertificateRequestId;
}
List<X509Certificate2> chainCerts = signed != null ? CollectChainCertificates(signed) : new List<X509Certificate2>();
+12 -2
View File
@@ -340,7 +340,14 @@ namespace PSInfisicalAPI.Pki
{
string status = dto != null ? dto.Status : "unknown";
string message = dto != null ? dto.Message : null;
throw new InfisicalConfigurationException(string.Concat("Certificate was not issued (status='", status ?? "unknown", "'", string.IsNullOrEmpty(message) ? "" : string.Concat(", message='", message, "'"), "). The certificate profile may require manual approval or additional validation."));
string requestId = dto != null ? dto.CertificateRequestId : null;
_logger.Warning(Component, string.Concat("Profile issuance did not return a certificate (status='", status ?? "unknown", "'", string.IsNullOrEmpty(message) ? "" : string.Concat(", message='", message, "'"), string.IsNullOrEmpty(requestId) ? "" : string.Concat(", certificateRequestId='", requestId, "'"), "). The profile may require manual approval or additional validation; returning a status-only result."));
return new InfisicalSignedCertificate
{
Status = status,
StatusMessage = message,
CertificateRequestId = requestId
};
}
InfisicalSignedCertificate signed = new InfisicalSignedCertificate
@@ -348,7 +355,10 @@ namespace PSInfisicalAPI.Pki
SerialNumber = dto.Certificate.SerialNumber,
CertificatePem = dto.Certificate.Certificate,
CertificateChainPem = dto.Certificate.CertificateChain,
IssuingCaCertificatePem = dto.Certificate.IssuingCaCertificate
IssuingCaCertificatePem = dto.Certificate.IssuingCaCertificate,
Status = dto.Status,
StatusMessage = dto.Message,
CertificateRequestId = dto.CertificateRequestId
};
_logger.Information(Component, "Infisical certificate issuance (profile) was successful.");
return signed;