Skip to content

Commit 68c33e4

Browse files
committed
build: target IAnyCAPlugin 3.2.0 (no-DCV variant for 25.5.0 hosts)
Gateway hosts on anygateway-rest 25.5.0 ship IAnyCAPlugin 3.2.0; a plugin built against 3.3.0-PRERELEASE loads but its AnyCAPluginCertificate records are not persisted by the 3.2 host (issue 0003). This branch builds against 3.2.0 so the contract matches, at the cost of DCV (the v3.3-only IDomainValidatorFactory). - CERTInext.csproj: IAnyCAPlugin 3.3.0-PRERELEASE -> 3.2.0; SUPPORTS_DCV define documented (left undefined). - CERTInextCAPlugin.cs: fence all DCV/IDomainValidator(Factory) code with #if SUPPORTS_DCV — the factory ctor, DomainValidatorFactory property, the Enroll DCV block, PerformDcvIfNeededAsync. TryRunDcvDuringSyncAsync no-ops (returns false) so the 0001 body-refetch + 0002 gate keep working; SetDomainValidatorFactory(object) stays as a logged no-op for host compatibility. - Test csprojs: exclude DCV-only files (DcvTests, FakeDomainValidator, integration DCV lifecycle + DNS validators) unless SUPPORTS_DCV is defined. - SmokeTests: use the (client, config) ctor instead of the fenced factory ctor. Solution builds clean (0 warnings); 172 unit tests pass (23 DCV tests excluded).
1 parent 6c2e0cb commit 68c33e4

5 files changed

Lines changed: 63 additions & 4 deletions

File tree

CERTInext.IntegrationTests/CERTInext.IntegrationTests.csproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@
1212
<ProjectReference Include="..\CERTInext\CERTInext.csproj" />
1313
</ItemGroup>
1414

15+
<!-- DCV integration tests + the DNS validator implementations use the v3.3-only
16+
IDomainValidator / IDomainValidatorFactory and the factory constructor. On the
17+
IAnyCAPlugin 3.2.0 (no-DCV) build those don't exist, so exclude these files unless
18+
SUPPORTS_DCV is defined. See issue 0003. -->
19+
<ItemGroup Condition="!$(DefineConstants.Contains('SUPPORTS_DCV'))">
20+
<Compile Remove="DcvLifecycleTests.cs" />
21+
<Compile Remove="CloudflareDomainValidator.cs" />
22+
<Compile Remove="StubDomainValidator.cs" />
23+
</ItemGroup>
24+
1525
<ItemGroup>
1626
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
1727
<PackageReference Include="xunit" Version="2.9.0" />

CERTInext.IntegrationTests/SmokeTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ public async Task GetSingleRecord_ReturnsRecord()
109109
Skip.If(string.IsNullOrWhiteSpace(orderId),
110110
"Set CERTINEXT_ORDER_ID in ~/.env_certinext to run this test.");
111111

112-
var plugin = new CERTInextCAPlugin(_fixture.Client, new StubDomainValidatorFactory(), _fixture.Config);
112+
var plugin = new CERTInextCAPlugin(_fixture.Client, _fixture.Config);
113113
var record = await plugin.GetSingleRecord(orderId);
114114

115115
record.Should().NotBeNull();
@@ -130,7 +130,7 @@ public async Task GetSingleRecord_ForAllOrders_AllSucceed()
130130
{
131131
IntegrationSkip.IfNotConfigured(_fixture);
132132

133-
var plugin = new CERTInextCAPlugin(_fixture.Client, new StubDomainValidatorFactory(), _fixture.Config);
133+
var plugin = new CERTInextCAPlugin(_fixture.Client, _fixture.Config);
134134

135135
var orderNumbers = new List<string>();
136136
await foreach (var entry in _fixture.Client.ListOrdersAsync())
@@ -170,7 +170,7 @@ public async Task Synchronize_DumpsAllRecords()
170170
{
171171
IntegrationSkip.IfNotConfigured(_fixture);
172172

173-
var plugin = new CERTInextCAPlugin(_fixture.Client, new StubDomainValidatorFactory(), _fixture.Config);
173+
var plugin = new CERTInextCAPlugin(_fixture.Client, _fixture.Config);
174174

175175
var records = new List<Keyfactor.AnyGateway.Extensions.AnyCAPluginCertificate>();
176176
var blockingCollection = new System.Collections.Concurrent.BlockingCollection<Keyfactor.AnyGateway.Extensions.AnyCAPluginCertificate>();

CERTInext.Tests/CERTInext.Tests.csproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@
1212
<ProjectReference Include="..\CERTInext\CERTInext.csproj" />
1313
</ItemGroup>
1414

15+
<!-- DCV unit tests + the fake DNS validator implement the v3.3-only IDomainValidator /
16+
IDomainValidatorFactory. On the IAnyCAPlugin 3.2.0 (no-DCV) build those types don't
17+
exist, so exclude these files unless SUPPORTS_DCV is defined. See issue 0003. -->
18+
<ItemGroup Condition="!$(DefineConstants.Contains('SUPPORTS_DCV'))">
19+
<Compile Remove="CERTInextCAPluginDcvTests.cs" />
20+
<Compile Remove="FakeDomainValidator.cs" />
21+
</ItemGroup>
22+
1523
<ItemGroup>
1624
<PackageReference Include="coverlet.collector" Version="6.0.2" />
1725
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />

CERTInext/CERTInext.csproj

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,19 @@
66
<ImplicitUsings>disable</ImplicitUsings>
77
<Nullable>warnings</Nullable>
88
<LangVersion>12.0</LangVersion>
9+
<!-- DCV requires the v3.3-only IDomainValidatorFactory. This branch targets
10+
IAnyCAPlugin 3.2.0 (for 25.5.0 hosts), so SUPPORTS_DCV is intentionally NOT
11+
defined and all DCV code is fenced out with #if SUPPORTS_DCV. See issue 0003. -->
12+
<!-- <DefineConstants>SUPPORTS_DCV</DefineConstants> -->
913
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
1014
</PropertyGroup>
1115

1216
<ItemGroup>
13-
<PackageReference Include="Keyfactor.AnyGateway.IAnyCAPlugin" Version="3.3.0-PRERELEASE-78770-979f582005" />
17+
<!-- 3.2.0 (NOT 3.3) so the plugin's AnyCAPluginCertificate contract matches gateway
18+
hosts shipping IAnyCAPlugin 3.2.0 (e.g. anygateway-rest 25.5.0). DCV requires the
19+
3.3-only IDomainValidatorFactory, so the DCV code is disabled on this branch.
20+
See issue 0003. -->
21+
<PackageReference Include="Keyfactor.AnyGateway.IAnyCAPlugin" Version="3.2.0" />
1422
<PackageReference Include="Keyfactor.Logging" Version="1.1.2" />
1523
<PackageReference Include="Keyfactor.PKI" Version="5.5.0" />
1624
<PackageReference Include="RestSharp" Version="112.1.0" />

CERTInext/CERTInextCAPlugin.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
using Keyfactor.Logging;
2020
using Keyfactor.PKI.Enums.EJBCA;
2121
using Microsoft.Extensions.Logging;
22+
#if SUPPORTS_DCV
2223
using IDomainValidatorFactory = Keyfactor.AnyGateway.Extensions.IDomainValidatorFactory;
24+
#endif
2325

2426
namespace Keyfactor.Extensions.CAPlugin.CERTInext
2527
{
@@ -51,7 +53,14 @@ public class CERTInextCAPlugin : IAnyCAPlugin, IDisposable
5153
// `volatile` because the field is written by SetDomainValidatorFactory and read
5254
// by EnrollNewAsync / TryRunDcvDuringSyncAsync, which can run on different threads.
5355
// See GitHub issue #7 for the full reasoning.
56+
// On the no-DCV build (IAnyCAPlugin 3.2.0, SUPPORTS_DCV undefined) this field is
57+
// intentionally never assigned — its assignment sites (the factory ctor and
58+
// SetDomainValidatorFactory) are fenced out, so it stays null and the Initialize
59+
// DCV-wiring check reports "not wired". Suppress CS0649 for that case; on the
60+
// SUPPORTS_DCV build it is assigned normally and the pragma is a no-op.
61+
#pragma warning disable CS0649
5462
private volatile object _domainValidatorFactory;
63+
#pragma warning restore CS0649
5564

5665
/// <summary>
5766
/// Returns the injected <see cref="IDomainValidatorFactory"/> when one is
@@ -60,8 +69,10 @@ public class CERTInextCAPlugin : IAnyCAPlugin, IDisposable
6069
/// gateway host stays compileable and never triggers <c>TypeLoadException</c>
6170
/// at runtime. All read sites in this class go through this property.
6271
/// </summary>
72+
#if SUPPORTS_DCV
6373
private IDomainValidatorFactory DomainValidatorFactory =>
6474
_domainValidatorFactory as IDomainValidatorFactory;
75+
#endif
6576

6677
// True when the client was passed in via a test-injection constructor and therefore
6778
// should not be disposed by this class (the test owns the mock's lifetime).
@@ -141,13 +152,15 @@ internal CERTInextCAPlugin(ICERTInextClient client, CERTInextConfig config)
141152
/// <c>CERTInext.IntegrationTests</c> can still reach it via
142153
/// <c>[InternalsVisibleTo]</c>. See issue #7.
143154
/// </summary>
155+
#if SUPPORTS_DCV
144156
internal CERTInextCAPlugin(ICERTInextClient client, IDomainValidatorFactory domainValidatorFactory, CERTInextConfig config = null)
145157
{
146158
_client = client;
147159
_clientWasInjected = true;
148160
_domainValidatorFactory = domainValidatorFactory;
149161
_config = config ?? new CERTInextConfig();
150162
}
163+
#endif
151164

152165
/// <summary>
153166
/// Injects an <see cref="IDomainValidatorFactory"/> after construction. Intended
@@ -162,6 +175,7 @@ internal CERTInextCAPlugin(ICERTInextClient client, IDomainValidatorFactory doma
162175
/// </summary>
163176
public void SetDomainValidatorFactory(object factory)
164177
{
178+
#if SUPPORTS_DCV
165179
var typed = factory as IDomainValidatorFactory;
166180
// SOX change-management / SOC2 CC6.1: log every factory injection so an auditor
167181
// can confirm which DNS provider plugin is being used to publish TXT records.
@@ -173,6 +187,14 @@ public void SetDomainValidatorFactory(object factory)
173187
"OfferedType={OfferedType}, Accepted={Accepted}",
174188
factory?.GetType().FullName ?? "(null)", typed != null);
175189
_domainValidatorFactory = typed;
190+
#else
191+
// DCV is not supported on this build (IAnyCAPlugin 3.2.0 — no IDomainValidatorFactory).
192+
// Accept the call for host compatibility but leave DCV disabled. See issue 0003.
193+
_logger.LogInformation(
194+
"Domain validator factory offered but DCV is not supported on this build " +
195+
"(IAnyCAPlugin 3.2.0). OfferedType={OfferedType}",
196+
factory?.GetType().FullName ?? "(null)");
197+
#endif
176198
}
177199

178200
// ---------------------------------------------------------------------------
@@ -1024,6 +1046,7 @@ private async Task<EnrollmentResult> EnrollNewAsync(
10241046

10251047
var enrollResp = await _client.EnrollCertificateAsync(enrollReq);
10261048

1049+
#if SUPPORTS_DCV
10271050
// DCV: run domain validation if enabled, the factory was injected, and the
10281051
// order was accepted (not immediately failed).
10291052
string orderNumber = enrollResp.Id;
@@ -1086,6 +1109,7 @@ private async Task<EnrollmentResult> EnrollNewAsync(
10861109
}
10871110
}
10881111
}
1112+
#endif
10891113

10901114
return BuildEnrollmentResult(enrollResp, ep.AutoApprove);
10911115
}
@@ -1285,6 +1309,7 @@ private static bool IsDcvNotYetReady(Exception ex)
12851309
/// </summary>
12861310
private async Task<bool> TryRunDcvDuringSyncAsync(string orderNumber, CancellationToken ct, bool fastSync = false)
12871311
{
1312+
#if SUPPORTS_DCV
12881313
if (_domainValidatorFactory == null || !_config.DcvEnabled || string.IsNullOrEmpty(orderNumber))
12891314
return false;
12901315

@@ -1330,6 +1355,12 @@ private async Task<bool> TryRunDcvDuringSyncAsync(string orderNumber, Cancellati
13301355
{
13311356
_dcvInFlight.TryRemove(orderNumber, out _);
13321357
}
1358+
#else
1359+
// DCV is not supported on this build (IAnyCAPlugin 3.2.0). No-op: pending orders
1360+
// are reported as EXTERNALVALIDATION and not advanced during sync. See issue 0003.
1361+
await Task.CompletedTask;
1362+
return false;
1363+
#endif
13331364
}
13341365

13351366
/// <summary>
@@ -1347,6 +1378,7 @@ private async Task<bool> TryRunDcvDuringSyncAsync(string orderNumber, Cancellati
13471378
/// on the next cycle instead. Enroll passes <c>null</c> to keep the full configured
13481379
/// budget (user-visible latency benefits from a one-shot end-to-end finish).
13491380
/// </summary>
1381+
#if SUPPORTS_DCV
13501382
private async Task<bool> PerformDcvIfNeededAsync(
13511383
string orderNumber,
13521384
CancellationToken ct,
@@ -1608,6 +1640,7 @@ private async Task<bool> PerformDcvIfNeededAsync(
16081640

16091641
return true;
16101642
}
1643+
#endif
16111644

16121645
/// <summary>
16131646
/// Polls <c>GetCertificateAsync</c> until either (a) the certificate reaches a terminal

0 commit comments

Comments
 (0)