Skip to content

Merge 2.2.0 to main#45

Merged
indrora merged 22 commits intomainfrom
release-2.2
Feb 17, 2026
Merged

Merge 2.2.0 to main#45
indrora merged 22 commits intomainfrom
release-2.2

Conversation

@indrora
Copy link
Member

@indrora indrora commented Feb 17, 2026

Merge release-2.2 to main - Automated PR

dgaley and others added 22 commits October 8, 2025 11:29
change default start sync date for first incremental sync
removing caching of product type list
change default incremental sync range
shorten incremental sync if it is too long
* add duplicate support

* Update generated docs

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>
Copilot AI review requested due to automatic review settings February 17, 2026 20:41
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR merges the release-2.2 branch to main, incorporating changes from three releases (2.1.1, 2.1.2, and 2.2.0). The primary purpose is to add certificate duplication functionality to the DigiCert CertCentral plugin, along with several bug fixes and enhancements.

Changes:

  • Added certificate duplication support allowing users to duplicate existing certificate orders via an enrollment field
  • Added temporary support for including Client Authentication EKU in SSL certificates (planned for deprecation by DigiCert in May 2026)
  • Improved SMIME certificate profile type handling to use DigiCert product defaults instead of hardcoded 'strict' value
  • Fixed incremental sync to use a 6-day window when no previous sync exists
  • Removed caching of product ID lookups and added workaround for DigiCert API duplicate PEM issue

Reviewed changes

Copilot reviewed 11 out of 11 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
integration-manifest.json Added IncludeClientAuthEKU parameter and updated ProfileType description
docsource/configuration.md Added documentation for certificate duplication feature
README.md Added IncludeClientAuthEKU parameter documentation and certificate duplication instructions
CHANGELOG.md Added version history for 2.1.1, 2.1.2, and 2.2.0 releases
digicert-certcentral-caplugin.csproj Updated assembly version to 2.1.2 and file encoding
Constants.cs Added DUPLICATE and INCLUDE_CLIENT_AUTH constants
CertCentralCertType.cs Removed static caching of certificate types
OrderCertificate.cs Added ProfileOption property for client auth EKU support
Duplicate.cs New file implementing duplicate certificate request/response models
CertCentralClient.cs Added DuplicateCertificate method
CertCentralCAPlugin.cs Implemented duplicate functionality, client auth EKU support, sync window fix, and duplicate PEM handling

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}
orderRequest.Certificate.ProfileType = profileType;
orderRequest.Certificate.ProfileType = profile;
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line has trailing whitespace after the closing brace. Consider removing the trailing whitespace to maintain code cleanliness and consistency.

Suggested change
}
}

Copilot uses AI. Check for mistakes.
Comment on lines +298 to +302
if (typeOfCert.Equals("ssl") && Convert.ToBoolean(productInfo.ProductParameters[CertCentralConstants.Config.INCLUDE_CLIENT_AUTH]))
{
orderRequest.Certificate.ProfileOption = "server_client_auth_eku";
_logger.LogWarning($"{CertCentralConstants.Config.INCLUDE_CLIENT_AUTH}: Ability to include client auth EKU in SSL certs is currently planned to cease in May 2026. Make sure any workflows that depend on this feature are updated before then to avoid interruptions.");
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code calls 'Convert.ToBoolean(productInfo.ProductParameters[CertCentralConstants.Config.INCLUDE_CLIENT_AUTH])' without first checking if the key exists in the dictionary. This will throw a KeyNotFoundException if the INCLUDE_CLIENT_AUTH parameter is not present. Since this is an OPTIONAL parameter (as documented), consider using 'ContainsKey' to check for existence first, or use 'TryGetValue', before attempting the conversion.

Copilot uses AI. Check for mistakes.
Comment on lines +1490 to +1492
/// <param name="request">The <see cref="OrderRequest"/>.</param>
/// <param name="enrollmentProductInfo">Information about the DigiCert product this certificate uses.</param>
/// <returns></returns>
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The parameter documentation mentions 'request' with type 'OrderRequest', but this parameter does not exist in the method signature. The method actually has individual parameters like 'enrollmentProductInfo', 'caRequestId', 'commonName', etc. Update the documentation to accurately reflect the actual parameters or remove the incorrect parameter reference.

Suggested change
/// <param name="request">The <see cref="OrderRequest"/>.</param>
/// <param name="enrollmentProductInfo">Information about the DigiCert product this certificate uses.</param>
/// <returns></returns>
/// <param name="enrollmentProductInfo">Information about the DigiCert product this certificate uses.</param>
/// <param name="caRequestId">The CA request identifier from which to derive the original order ID.</param>
/// <param name="commonName">The common name (CN) for the certificate.</param>
/// <param name="csr">The certificate signing request (CSR) for the new duplicate certificate.</param>
/// <param name="dnsNames">Additional DNS names (SANs) to include in the duplicate certificate.</param>
/// <param name="signatureHash">The signature hash algorithm to use.</param>
/// <param name="caCertId">The DigiCert CA certificate identifier to use for issuance.</param>
/// <returns>The result of the duplicate enrollment operation.</returns>

Copilot uses AI. Check for mistakes.
Comment on lines +1510 to +1520
DuplicateRequest duplicateRequest = new DuplicateRequest(orderId)
{
Certificate = new CertificateDuplicateRequest
{
CommonName = commonName,
CSR = csr,
DnsNames = dnsNames,
SignatureHash = signatureHash,
CACertID = caCertId
}
};
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DuplicateRequest is created without setting 'SkipApproval', which will default to false. The similar Reissue method explicitly sets 'SkipApproval = true' with a comment explaining it allows the certificate ID to return a value (see line 1479). Consider whether the Duplicate method should also set 'SkipApproval = true' for consistency and to ensure the certificate ID is returned, unless there's a specific reason for the different behavior.

Copilot uses AI. Check for mistakes.
Comment on lines +1652 to +1658
//Another check for duplicate PEMs to get arround issue with DigiCert API returning incorrect data sometimes on reissued/duplicate certs
if (pemList.Contains(certificate))
{
_logger.LogWarning($"Found duplicate PEM for ID {caReqId}. Skipping...");
continue;
}
pemList.Add(certificate);
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'certificate' variable could be null if the certificate status is not GENERATED or REVOKED (line 1639-1650), but it's added to 'pemList' unconditionally at line 1658. This means null values could be added to the list, and the duplicate check at line 1653 would match multiple null values incorrectly. Consider only adding to pemList when certificate is not null, or restructure the logic to handle null certificates appropriately.

Suggested change
//Another check for duplicate PEMs to get arround issue with DigiCert API returning incorrect data sometimes on reissued/duplicate certs
if (pemList.Contains(certificate))
{
_logger.LogWarning($"Found duplicate PEM for ID {caReqId}. Skipping...");
continue;
}
pemList.Add(certificate);
//Another check for duplicate PEMs to get around issue with DigiCert API returning incorrect data sometimes on reissued/duplicate certs
if (certificate != null)
{
if (pemList.Contains(certificate))
{
_logger.LogWarning($"Found duplicate PEM for ID {caReqId}. Skipping...");
continue;
}
pemList.Add(certificate);
}

Copilot uses AI. Check for mistakes.
using Newtonsoft.Json;

using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Pqc.Crypto.Falcon;
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import 'using Org.BouncyCastle.Pqc.Crypto.Falcon;' appears to be unused. This namespace is typically used for post-quantum cryptography (Falcon signature scheme), but there are no references to Falcon types anywhere in this file. This unused import should be removed to keep the code clean and avoid confusion.

Suggested change
using Org.BouncyCastle.Pqc.Crypto.Falcon;

Copilot uses AI. Check for mistakes.
_logger.MethodEntry(LogLevel.Trace);

lastSync = lastSync.HasValue ? lastSync.Value.AddHours(-7) : DateTime.MinValue; // DigiCert issue with treating the timezone as mountain time. -7 to accomodate DST
// DigiCert issue with treating the timezone as mountain time. -7 hours to accomodate DST
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains a spelling error: 'accomodate' should be spelled 'accommodate' (with two 'm's).

Suggested change
// DigiCert issue with treating the timezone as mountain time. -7 hours to accomodate DST
// DigiCert issue with treating the timezone as mountain time. -7 hours to accommodate DST

Copilot uses AI. Check for mistakes.
throw new Exception($"Unexpected error downloading certificate {certId} for order {orderId}: {certificateChainResponse.Errors.FirstOrDefault()?.message}");
}
}
//Another check for duplicate PEMs to get arround issue with DigiCert API returning incorrect data sometimes on reissued/duplicate certs
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment contains a spelling error: 'arround' should be spelled 'around' (with one 'r').

Suggested change
//Another check for duplicate PEMs to get arround issue with DigiCert API returning incorrect data sometimes on reissued/duplicate certs
//Another check for duplicate PEMs to get around issue with DigiCert API returning incorrect data sometimes on reissued/duplicate certs

Copilot uses AI. Check for mistakes.
// If no last sync, use a 6 day window for the sync range (only relevant for incremental syncs)
lastSync = lastSync.HasValue ? lastSync.Value.AddHours(-7) : DateTime.UtcNow.AddDays(-5);
DateTime? utcDate = DateTime.UtcNow.AddDays(1);
if ((utcDate.Value - lastSync.Value).Days > 6)
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The date calculation uses '.Days' property which returns only the whole number of days in the TimeSpan, potentially losing precision. For example, if the difference is 6.5 days, this will evaluate to 6 and the condition won't trigger. Consider using '.TotalDays' instead and comparing with a double value, or ensure this behavior is intentional for the sync window logic.

Suggested change
if ((utcDate.Value - lastSync.Value).Days > 6)
if ((utcDate.Value - lastSync.Value).TotalDays > 6.0)

Copilot uses AI. Check for mistakes.
Comment on lines +1788 to +1791
else
{
profile = null;
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The else block at lines 1788-1791 that sets 'profile = null' is redundant. The variable 'profile' is already initialized to null at line 1774, and the only assignment inside the if block (line 1777) converts the parameter to a string. If that string is empty, it won't pass the validation at line 1780-1786 and profile would remain as set. This else block appears unnecessary and could be removed for clarity.

Suggested change
else
{
profile = null;
}

Copilot uses AI. Check for mistakes.
@indrora indrora merged commit 665bf3d into main Feb 17, 2026
32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments