Skip to content

fix: resolve merge conflict markers committed in 1.3.3 merge - #27

Merged
indrora merged 1 commit into
mainfrom
fix/resolve-1.3.3-merge-markers
Jul 23, 2026
Merged

fix: resolve merge conflict markers committed in 1.3.3 merge#27
indrora merged 1 commit into
mainfrom
fix/resolve-1.3.3-merge-markers

Conversation

@spbsoluble

Copy link
Copy Markdown
Contributor

Problem

main does not compile: dotnet build GCPCAS.sln fails with 27 errors, mostly CS8300: Merge conflict marker encountered.

Commit f4fbf10 ("Merge branch 'main' into release-1.3") was committed with unresolved conflict markers in CHANGELOG.md and GCPCAS/Client/GCPCASClient.cs. PR #26 then squash-merged that onto main as df8c241, carrying the markers with it.

Triage

git diff 1.3.3 main is exactly the 13 marker lines — nothing else. Every conflict block resolves to the release-1.3 side:

Block Location Verdict
1 CHANGELOG.md:1 Keep 1.3.3 changelog entry
2 GCPCASClient.cs:274 Keep skip-unparseable-subject sync logic — this is the 1.3.3 feature; its helper method and skippedCertificates counter already live in the non-conflicted region
3 GCPCASClient.cs:320 Keep [SYNC-DIAG] summary log — dropping it orphans skippedCertificates
4 GCPCASClient.cs:383 Keep caRequestId/pem locals + diagnostics call — the return below already references those locals, so the main side cannot compile

Fix

Restore both files from the 1.3.3 tag, whose content is byte-identical to the intended resolution. Diff is 13 deletions (the marker lines only).

Verification

  • git grep '<<<<<<<' — no markers remain
  • dotnet build GCPCAS.sln — 0 errors (was 27)
  • dotnet test — 4 skipped (integration tests, gated on GCP env vars), 0 failed

Note

origin/release-1.3 still carries the markers at its tip (f4fbf10). It should get the same fix or be reset before anything else merges from it, or the markers will come back.

PR #26 squash-merged release-1.3 commit f4fbf10, which had been
committed with unresolved conflict markers in CHANGELOG.md and
GCPCASClient.cs, leaving main uncompilable (CS8300 x27).

The intended resolution of every conflict block is the release-1.3
side, whose content is byte-identical to the 1.3.3 tag. Restore both
files from the 1.3.3 tag.
spbsoluble added a commit that referenced this pull request Jul 23, 2026
The 1.3.3 guard ran new X509Name(true, netCert.Subject), which does not
throw on a CN containing an odd-length run of literal backslash bytes.
Such subjects were admitted, persisted with backslashes escape-doubled,
and then aborted Command's Full Scan with 'badly formatted directory
string' when the gateway un-escaped one level and re-parsed the dangling
escape on its /v2/certificate/search response.

Replace the fragile mirror-the-gateway-parse approach with a structural,
version-independent check: reject any subject whose literal backslash run
has odd length (HasOddBackslashRun), keeping a defensive local X509Name
parse as a second net. Even-length runs round-trip cleanly, matching the
lab reproduction's abort/no-abort split (shape1 vs shape2/shape3).

Add pure unit regression tests (no GCP required) via InternalsVisibleTo.

This branch is based on release-1.3 and also drops the committed
merge-conflict markers that release-1.3 carried in CHANGELOG.md and
GCPCAS/Client/GCPCASClient.cs (same resolution as #27).
spbsoluble added a commit that referenced this pull request Jul 23, 2026
The 1.3.3 guard ran new X509Name(true, netCert.Subject), which does not
throw on a CN containing an odd-length run of literal backslash bytes.
Such subjects were admitted, persisted with backslashes escape-doubled,
and then aborted Command's Full Scan with 'badly formatted directory
string' when the gateway un-escaped one level and re-parsed the dangling
escape on its /v2/certificate/search response.

Replace the fragile mirror-the-gateway-parse approach with a structural,
version-independent check: reject any subject whose literal backslash run
has odd length (HasOddBackslashRun), keeping a defensive local X509Name
parse as a second net. Even-length runs round-trip cleanly, matching the
lab reproduction's abort/no-abort split (shape1 vs shape2/shape3).

Add pure unit regression tests (no GCP required) via InternalsVisibleTo.

This branch is based on release-1.3 and also drops the committed
merge-conflict markers that release-1.3 carried in CHANGELOG.md and
GCPCAS/Client/GCPCASClient.cs (same resolution as #27).
spbsoluble added a commit that referenced this pull request Jul 23, 2026
The 1.3.3 guard ran new X509Name(true, netCert.Subject), which does not
throw on a CN containing an odd-length run of literal backslash bytes.
Such subjects were admitted, persisted with backslashes escape-doubled,
and then aborted Command's Full Scan with 'badly formatted directory
string' when the gateway un-escaped one level and re-parsed the dangling
escape on its /v2/certificate/search response.

Replace the fragile mirror-the-gateway-parse approach with a structural,
version-independent check: reject any subject whose literal backslash run
has odd length (HasOddBackslashRun), keeping a defensive local X509Name
parse as a second net. Even-length runs round-trip cleanly, matching the
lab reproduction's abort/no-abort split (shape1 vs shape2/shape3).

Add pure unit regression tests (no GCP required) via InternalsVisibleTo.

This branch is based on release-1.3 and also drops the committed
merge-conflict markers that release-1.3 carried in CHANGELOG.md and
GCPCAS/Client/GCPCASClient.cs (same resolution as #27).
spbsoluble added a commit that referenced this pull request Jul 23, 2026
The 1.3.3 guard ran new X509Name(true, netCert.Subject), which does not
throw on a CN containing an odd-length run of literal backslash bytes.
Such subjects were admitted, persisted with backslashes escape-doubled,
and then aborted Command's Full Scan with 'badly formatted directory
string' when the gateway un-escaped one level and re-parsed the dangling
escape on its /v2/certificate/search response.

Replace the fragile mirror-the-gateway-parse approach with a structural,
version-independent check: reject any subject whose literal backslash run
has odd length (HasOddBackslashRun), keeping a defensive local X509Name
parse as a second net. Even-length runs round-trip cleanly, matching the
lab reproduction's abort/no-abort split (shape1 vs shape2/shape3).

Add pure unit regression tests (no GCP required) via InternalsVisibleTo.

This branch is based on release-1.3 and also drops the committed
merge-conflict markers that release-1.3 carried in CHANGELOG.md and
GCPCAS/Client/GCPCASClient.cs (same resolution as #27).
@indrora
indrora merged commit 03efcc9 into main Jul 23, 2026
45 checks passed
@indrora
indrora deleted the fix/resolve-1.3.3-merge-markers branch July 23, 2026 18:17
spbsoluble added a commit that referenced this pull request Jul 23, 2026
The 1.3.3 guard ran new X509Name(true, netCert.Subject), which does not
throw on a CN containing an odd-length run of literal backslash bytes.
Such subjects were admitted, persisted with backslashes escape-doubled,
and then aborted Command's Full Scan with 'badly formatted directory
string' when the gateway un-escaped one level and re-parsed the dangling
escape on its /v2/certificate/search response.

Replace the fragile mirror-the-gateway-parse approach with a structural,
version-independent check: reject any subject whose literal backslash run
has odd length (HasOddBackslashRun), keeping a defensive local X509Name
parse as a second net. Even-length runs round-trip cleanly, matching the
lab reproduction's abort/no-abort split (shape1 vs shape2/shape3).

Add pure unit regression tests (no GCP required) via InternalsVisibleTo.

This branch is based on release-1.3 and also drops the committed
merge-conflict markers that release-1.3 carried in CHANGELOG.md and
GCPCAS/Client/GCPCASClient.cs (same resolution as #27).
spbsoluble added a commit that referenced this pull request Jul 23, 2026
GCP CAS will issue certificates whose subject is not valid RFC 4514 (e.g.
a CN ending in a dangling backslash). The AnyCA Gateway parses the subject
with BouncyCastle's X509Name on its /v2/certificate/search response; on
such a subject that call throws 'badly formatted directory string', the
search page 500s, and Command's Full Scan aborts.

The 1.3.3 guard tried to pre-empt this by running the same X509Name parse
locally, but the plugin bundled BouncyCastle 2.0.0, whose parser is lenient
and never throws on these shapes - so they were admitted and still broke
the downstream sync.

Fix: pin BouncyCastle.Cryptography to 2.6.2, the same strict build the
gateway uses (verified: it throws on exactly the shapes the gateway
rejects, with the identical message spelling, and accepts valid escapes
such as \HH hex and \, that the gateway accepts). The guard now
faithfully reproduces the gateway's accept/reject decision - no structural
heuristic and no assumptions about .NET escaping - so it skips only certs
the gateway genuinely cannot parse and stops dropping valid ones. Skips are
logged at error level and sync continues. The upgrade also clears the known
BouncyCastle 2.0.0 security advisories.

This branch is based on release-1.3 and also drops the committed
merge-conflict markers that release-1.3 carried in CHANGELOG.md and
GCPCAS/Client/GCPCASClient.cs (same resolution as #27).
spbsoluble added a commit that referenced this pull request Jul 23, 2026
GCP CAS will issue certificates whose subject is not valid RFC 4514 (e.g.
a CN ending in a dangling backslash). The AnyCA Gateway parses the subject
with BouncyCastle's X509Name on its /v2/certificate/search response; on
such a subject that call throws 'badly formatted directory string', the
search page 500s, and Command's Full Scan aborts.

The 1.3.3 guard tried to pre-empt this by running the same X509Name parse
locally, but the plugin bundled BouncyCastle 2.0.0, whose parser is lenient
and never throws on these shapes - so they were admitted and still broke
the downstream sync.

Fix: pin BouncyCastle.Cryptography to 2.6.2, the same strict build the
gateway uses (verified: it throws on exactly the shapes the gateway
rejects, with the identical message spelling, and accepts valid escapes
such as \HH hex and \, that the gateway accepts). The guard now
faithfully reproduces the gateway's accept/reject decision - no structural
heuristic and no assumptions about .NET escaping - so it skips only certs
the gateway genuinely cannot parse and stops dropping valid ones. Skips are
logged at error level and sync continues. The upgrade also clears the known
BouncyCastle 2.0.0 security advisories.

Tests: pure unit regression tests for the guard predicate, plus a sync-loop
test (SyncSkipContinuationTests) that streams good/bad/good pages through
DownloadAllIssuedCertificates via a fake CertificateAuthorityServiceClient
and asserts the bad cert is skipped while the rest are buffered and the sync
completes. Adds an internal test-only GCPCASClient constructor to inject the
fake client, and a GCPCAS.Tests/README.md describing every test.

This branch is based on release-1.3 and also drops the committed
merge-conflict markers that release-1.3 carried in CHANGELOG.md and
GCPCAS/Client/GCPCASClient.cs (same resolution as #27).
spbsoluble added a commit that referenced this pull request Jul 23, 2026
GCP CAS will issue certificates whose subject is not valid RFC 4514 (e.g.
a CN ending in a dangling backslash). The AnyCA Gateway parses the subject
with BouncyCastle's X509Name on its /v2/certificate/search response; on
such a subject that call throws 'badly formatted directory string', the
search page 500s, and Command's Full Scan aborts.

The 1.3.3 guard tried to pre-empt this by running the same X509Name parse
locally, but the plugin bundled BouncyCastle 2.0.0, whose parser is lenient
and never throws on these shapes - so they were admitted and still broke
the downstream sync.

Fix: pin BouncyCastle.Cryptography to 2.6.2, the same strict build the
gateway uses (verified: it throws on exactly the shapes the gateway
rejects, with the identical message spelling, and accepts valid escapes
such as \HH hex and \, that the gateway accepts). The guard now
faithfully reproduces the gateway's accept/reject decision - no structural
heuristic and no assumptions about .NET escaping - so it skips only certs
the gateway genuinely cannot parse and stops dropping valid ones. Skips are
logged at error level and sync continues. The upgrade also clears the known
BouncyCastle 2.0.0 security advisories.

Tests: pure unit regression tests for the guard predicate, plus a sync-loop
test (SyncSkipContinuationTests) that streams good/bad/good pages through
DownloadAllIssuedCertificates via a fake CertificateAuthorityServiceClient
and asserts the bad cert is skipped while the rest are buffered and the sync
completes. Adds an internal test-only GCPCASClient constructor to inject the
fake client, and a GCPCAS.Tests/README.md describing every test.

This branch is based on release-1.3 and also drops the committed
merge-conflict markers that release-1.3 carried in CHANGELOG.md and
GCPCAS/Client/GCPCASClient.cs (same resolution as #27).
indrora added a commit that referenced this pull request Jul 30, 2026
…#31)

* Merge 1.3.3 to main (#26)

* chore: Update integration-manifest.json (#16)

* Update integration-manifest.json

* Update generated docs

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* release: 1.3.0

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* fixed sans issue passed to extension data (#23)

* fixed sans issue passed to extension data

* fixed change log

---------

Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>

* 200dayfixes (#25)

* chore: Update integration-manifest.json

* Update integration-manifest.json

* Update generated docs

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* Merge 1.3.1 to main


Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* Merge 1.3.2 to main (#24)

* chore: Update integration-manifest.json (#16)

* Update integration-manifest.json

* Update generated docs

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* release: 1.3.0

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* fixed sans issue passed to extension data (#23)

* fixed sans issue passed to extension data

* fixed change log

---------

Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* Add FlowLogger and sync diagnostics for certificate metadata troubleshooting

Port the FlowLogger workflow-tracing utility from the cscglobal-caplugin
200dayfixes branch and wire it into the plugin's Synchronize, Enroll, and
GetSingleRecord operations to render step-by-step, timed flow diagrams to
Trace logs.

Add [SYNC-DIAG] instrumentation in GCPCASClient that, for every certificate
handed to the AnyCA Gateway during sync, parses the PEM content and logs the
fingerprint (thumbprint), NotBefore (as epoch ms), NotAfter, serial number,
and subject - i.e. the exact metadata the Gateway must surface to Command on
/v2/certificate/search and that the incremental sync gates on. Records whose
content is null/empty or unparseable are flagged, pinpointing whether empty
fingerprint / notBefore=0 values originate in the plugin.

* Add net10.0 to target frameworks

* Skip certs with gateway-unparseable subjects during sync

During Synchronize, mirror the subject parsing the AnyCA Gateway performs
when building its /v2/certificate/search response
(new X509Name(true, netCert.Subject)). That call throws on subjects
BouncyCastle cannot re-parse from .NET's string representation, which returns
a 500 for the entire search page and aborts Command's CA sync.

GatewayCanParseSubject runs the same parse on each certificate before it is
added to the sync buffer. Certificates that would throw are skipped with a
[SYNC-SKIP] warning and counted, so a single unparseable subject never lands
in the gateway database and can never break the downstream Command sync. The
gateway-side fix (try/catch or reading the subject from DER) will be handled
separately.

* update changelog

---------

Co-authored-by: Sean <1661003+spbsoluble@users.noreply.github.com>
Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>
Co-authored-by: Sean <1661003+spbsoluble@users.noreply.github.com>

* fix: resolve merge conflict markers committed in 1.3.3 merge (#27)

PR #26 squash-merged release-1.3 commit f4fbf10, which had been
committed with unresolved conflict markers in CHANGELOG.md and
GCPCASClient.cs, leaving main uncompilable (CS8300 x27).

The intended resolution of every conflict block is the release-1.3
side, whose content is byte-identical to the 1.3.3 tag. Restore both
files from the 1.3.3 tag.

* fix: skip subjects the AnyCA Gateway cannot parse in sync guard (#30)

GCP CAS will issue certificates whose subject is not valid RFC 4514 (e.g.
a CN ending in a dangling backslash). The AnyCA Gateway parses the subject
with BouncyCastle's X509Name on its /v2/certificate/search response; on
such a subject that call throws 'badly formatted directory string', the
search page 500s, and Command's Full Scan aborts.

The 1.3.3 guard tried to pre-empt this by running the same X509Name parse
locally, but the plugin bundled BouncyCastle 2.0.0, whose parser is lenient
and never throws on these shapes - so they were admitted and still broke
the downstream sync.

Fix: pin BouncyCastle.Cryptography to 2.6.2, the same strict build the
gateway uses (verified: it throws on exactly the shapes the gateway
rejects, with the identical message spelling, and accepts valid escapes
such as \HH hex and \, that the gateway accepts). The guard now
faithfully reproduces the gateway's accept/reject decision - no structural
heuristic and no assumptions about .NET escaping - so it skips only certs
the gateway genuinely cannot parse and stops dropping valid ones. Skips are
logged at error level and sync continues. The upgrade also clears the known
BouncyCastle 2.0.0 security advisories.

Tests: pure unit regression tests for the guard predicate, plus a sync-loop
test (SyncSkipContinuationTests) that streams good/bad/good pages through
DownloadAllIssuedCertificates via a fake CertificateAuthorityServiceClient
and asserts the bad cert is skipped while the rest are buffered and the sync
completes. Adds an internal test-only GCPCASClient constructor to inject the
fake client, and a GCPCAS.Tests/README.md describing every test.

This branch is based on release-1.3 and also drops the committed
merge-conflict markers that release-1.3 carried in CHANGELOG.md and
GCPCAS/Client/GCPCASClient.cs (same resolution as #27).

---------

Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>
Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>
indrora added a commit that referenced this pull request Jul 30, 2026
* chore: Update integration-manifest.json (#16)

* Update integration-manifest.json

* Update generated docs

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* release: 1.3.0

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* fixed sans issue passed to extension data (#23)

* fixed sans issue passed to extension data

* fixed change log

---------

Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>

* 200dayfixes (#25)

* chore: Update integration-manifest.json

* Update integration-manifest.json

* Update generated docs

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* Merge 1.3.1 to main


Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* Merge 1.3.2 to main (#24)

* chore: Update integration-manifest.json (#16)

* Update integration-manifest.json

* Update generated docs

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* release: 1.3.0

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* fixed sans issue passed to extension data (#23)

* fixed sans issue passed to extension data

* fixed change log

---------

Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* Add FlowLogger and sync diagnostics for certificate metadata troubleshooting

Port the FlowLogger workflow-tracing utility from the cscglobal-caplugin
200dayfixes branch and wire it into the plugin's Synchronize, Enroll, and
GetSingleRecord operations to render step-by-step, timed flow diagrams to
Trace logs.

Add [SYNC-DIAG] instrumentation in GCPCASClient that, for every certificate
handed to the AnyCA Gateway during sync, parses the PEM content and logs the
fingerprint (thumbprint), NotBefore (as epoch ms), NotAfter, serial number,
and subject - i.e. the exact metadata the Gateway must surface to Command on
/v2/certificate/search and that the incremental sync gates on. Records whose
content is null/empty or unparseable are flagged, pinpointing whether empty
fingerprint / notBefore=0 values originate in the plugin.

* Add net10.0 to target frameworks

* Skip certs with gateway-unparseable subjects during sync

During Synchronize, mirror the subject parsing the AnyCA Gateway performs
when building its /v2/certificate/search response
(new X509Name(true, netCert.Subject)). That call throws on subjects
BouncyCastle cannot re-parse from .NET's string representation, which returns
a 500 for the entire search page and aborts Command's CA sync.

GatewayCanParseSubject runs the same parse on each certificate before it is
added to the sync buffer. Certificates that would throw are skipped with a
[SYNC-SKIP] warning and counted, so a single unparseable subject never lands
in the gateway database and can never break the downstream Command sync. The
gateway-side fix (try/catch or reading the subject from DER) will be handled
separately.

* update changelog

---------

Co-authored-by: Sean <1661003+spbsoluble@users.noreply.github.com>
Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* fix: skip subjects with odd-length backslash runs in sync guard (#30) (#31)

* Merge 1.3.3 to main (#26)

* chore: Update integration-manifest.json (#16)

* Update integration-manifest.json

* Update generated docs

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* release: 1.3.0

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* fixed sans issue passed to extension data (#23)

* fixed sans issue passed to extension data

* fixed change log

---------

Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>

* 200dayfixes (#25)

* chore: Update integration-manifest.json

* Update integration-manifest.json

* Update generated docs

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* Merge 1.3.1 to main


Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* Merge 1.3.2 to main (#24)

* chore: Update integration-manifest.json (#16)

* Update integration-manifest.json

* Update generated docs

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* release: 1.3.0

---------

Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* fixed sans issue passed to extension data (#23)

* fixed sans issue passed to extension data

* fixed change log

---------

Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

* Add FlowLogger and sync diagnostics for certificate metadata troubleshooting

Port the FlowLogger workflow-tracing utility from the cscglobal-caplugin
200dayfixes branch and wire it into the plugin's Synchronize, Enroll, and
GetSingleRecord operations to render step-by-step, timed flow diagrams to
Trace logs.

Add [SYNC-DIAG] instrumentation in GCPCASClient that, for every certificate
handed to the AnyCA Gateway during sync, parses the PEM content and logs the
fingerprint (thumbprint), NotBefore (as epoch ms), NotAfter, serial number,
and subject - i.e. the exact metadata the Gateway must surface to Command on
/v2/certificate/search and that the incremental sync gates on. Records whose
content is null/empty or unparseable are flagged, pinpointing whether empty
fingerprint / notBefore=0 values originate in the plugin.

* Add net10.0 to target frameworks

* Skip certs with gateway-unparseable subjects during sync

During Synchronize, mirror the subject parsing the AnyCA Gateway performs
when building its /v2/certificate/search response
(new X509Name(true, netCert.Subject)). That call throws on subjects
BouncyCastle cannot re-parse from .NET's string representation, which returns
a 500 for the entire search page and aborts Command's CA sync.

GatewayCanParseSubject runs the same parse on each certificate before it is
added to the sync buffer. Certificates that would throw are skipped with a
[SYNC-SKIP] warning and counted, so a single unparseable subject never lands
in the gateway database and can never break the downstream Command sync. The
gateway-side fix (try/catch or reading the subject from DER) will be handled
separately.

* update changelog

---------

Co-authored-by: Sean <1661003+spbsoluble@users.noreply.github.com>
Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>
Co-authored-by: Sean <1661003+spbsoluble@users.noreply.github.com>

* fix: resolve merge conflict markers committed in 1.3.3 merge (#27)

PR #26 squash-merged release-1.3 commit f4fbf10, which had been
committed with unresolved conflict markers in CHANGELOG.md and
GCPCASClient.cs, leaving main uncompilable (CS8300 x27).

The intended resolution of every conflict block is the release-1.3
side, whose content is byte-identical to the 1.3.3 tag. Restore both
files from the 1.3.3 tag.

* fix: skip subjects the AnyCA Gateway cannot parse in sync guard (#30)

GCP CAS will issue certificates whose subject is not valid RFC 4514 (e.g.
a CN ending in a dangling backslash). The AnyCA Gateway parses the subject
with BouncyCastle's X509Name on its /v2/certificate/search response; on
such a subject that call throws 'badly formatted directory string', the
search page 500s, and Command's Full Scan aborts.

The 1.3.3 guard tried to pre-empt this by running the same X509Name parse
locally, but the plugin bundled BouncyCastle 2.0.0, whose parser is lenient
and never throws on these shapes - so they were admitted and still broke
the downstream sync.

Fix: pin BouncyCastle.Cryptography to 2.6.2, the same strict build the
gateway uses (verified: it throws on exactly the shapes the gateway
rejects, with the identical message spelling, and accepts valid escapes
such as \HH hex and \, that the gateway accepts). The guard now
faithfully reproduces the gateway's accept/reject decision - no structural
heuristic and no assumptions about .NET escaping - so it skips only certs
the gateway genuinely cannot parse and stops dropping valid ones. Skips are
logged at error level and sync continues. The upgrade also clears the known
BouncyCastle 2.0.0 security advisories.

Tests: pure unit regression tests for the guard predicate, plus a sync-loop
test (SyncSkipContinuationTests) that streams good/bad/good pages through
DownloadAllIssuedCertificates via a fake CertificateAuthorityServiceClient
and asserts the bad cert is skipped while the rest are buffered and the sync
completes. Adds an internal test-only GCPCASClient constructor to inject the
fake client, and a GCPCAS.Tests/README.md describing every test.

This branch is based on release-1.3 and also drops the committed
merge-conflict markers that release-1.3 carried in CHANGELOG.md and
GCPCAS/Client/GCPCASClient.cs (same resolution as #27).

---------

Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com>
Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>
Co-authored-by: Sean <1661003+spbsoluble@users.noreply.github.com>
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.

2 participants