Skip to content

Feature/discovery job#14

Merged
indrora merged 32 commits into
release-1.2from
feature/discovery-job
May 21, 2026
Merged

Feature/discovery job#14
indrora merged 32 commits into
release-1.2from
feature/discovery-job

Conversation

@bhillkeyfactor

Copy link
Copy Markdown
Contributor

No description provided.

bhillkeyfactor and others added 30 commits May 4, 2026 15:39
Adds CertStores.GcpCertMgr.Discovery (IDiscoveryJobExtension) that lists
every active GCP project the orchestrator's service account can see via
Cloud Resource Manager v3 projects.search and emits one candidate store
per (project, location) pair in canonical projects/{p}/locations/{l}
form. Discovery scope is bounded by IAM (service account permissioned
at the org root, per customer setup), not by query filtering.

Also brings the orchestrator up to the canonical hardening pattern:
ports FlowLogger.cs from the reference repo, adds JobBase.cs with
IPAMSecretResolver injection + GoogleApiException unwrapping, and
retrofits Inventory and Management onto the shared base. Job result
FailureMessage now carries the flow summary on every path so operators
can see what happened from job history alone. Bumps
Keyfactor.Orchestrators.IOrchestratorJobExtensions 0.6.0 -> 0.7.0 to
pick up IPAMSecretResolver.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Inventory and Management built the GCP resource path from
ClientMachine + the Location custom property, ignoring whatever was in
the store's StorePath. Discovery-approved stores arrive in Command with
StorePath="projects/{id}/locations/{loc}" but ClientMachine defaulting
to whatever Command auto-fills (often the orchestrator hostname), so
inventory failed with HTTP 403 CONSUMER_INVALID against
"projects/<orchestrator-hostname>/locations/global".

ResolveGcpResourcePath now trusts StorePath when it is in canonical
"projects/X/locations/Y" form. Manually-created v1.1-shaped stores
(StorePath="n/a") continue to build the path from ClientMachine + the
Location custom property, so existing stores keep working without
intervention. Discovery-approved stores no longer require operators to
retype the project ID into ClientMachine after approval.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Make Store Path the single source of truth for the GCP resource path on
both manually-created and Discovery-approved stores. Repurpose Client
Machine as a display label (recommended value: GCP Organization ID).
Deprecate the standalone Location custom property; the location is now
parsed out of Store Path. Existing v1.1 stores keep working via a
deprecation-logged fallback in JobBase.ResolveGcpResourcePath - every
inventory/management run against a v1.1-shape store emits one
LogWarning naming the migration step. Fallback removal scheduled for
v2.0.

Updates integration-manifest.json: clears StorePathValue's "n/a"
default, marks Location property Required:false with a deprecation
description, rewrites Client Machine and Store Path descriptions.
Doctool will regenerate the README's Manual Creation table from these.

Updates docsource/gcpcertmgr.md and content.md with one unified
configuration narrative covering both manual and Discovery-approved
flows, plus an explicit v1.1 migration section.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Management/Add was doing CheckForDuplicate + LoadPkcs12 + ExtractPrivateKey
before calling GCP, only to have GCP reject the request with HTTP 400 if
the alias contained capital letters or other illegal characters. Now we
validate against [a-z]([-a-z0-9]*[a-z0-9])? (max 63 chars) immediately on
entry to PerformAddition and produce a clear flow-step failure with a
suggested normalized alias (e.g. 'Cert1' -> 'cert1'). No API calls or
PFX work happen on a non-conforming alias.

Operator workflow when validation fails: rename the certificate in
Keyfactor Command to the suggested form and re-run Management/Add.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a "Design rationale: why Store Path is the source of truth"
section to docsource/gcpcertmgr.md covering: the IDiscoveryJobExtension
contract constraint that forced the schema change, the alternatives
considered (manual edits per approval, one job per project, posting to
Command's REST API directly), and the trade-offs accepted (Client
Machine repurposed as display label, Location property deprecated not
removed). CHANGELOG entry now points readers at the docs section for
the long form.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hots

Authentication now consolidates around Application Default Credentials.
The Service Account Key File Path custom store property is deprecated
because Keyfactor Command's discovery-job UI does not surface store-type
custom properties, so file-based auth never worked uniformly across all
four job types. ADC works via workload identity (GCE / GKE) or via the
GOOGLE_APPLICATION_CREDENTIALS environment variable on the orchestrator
host. v1.1 stores with the property populated continue to work via a
deprecation-logged fallback in GcpCertificateManagerClient.LoadCredentials;
the property is scheduled for removal in v2.0.

Drops the dead ServiceAccountKey JobProperty handling from Discovery.cs
since it was never reachable from Keyfactor Command's UI.

Removes three Google Cloud Console screenshot GIFs from docsource/
(ServiceAccountSettings.gif, ApiAccessNeeded.gif, GoogleKeyJsonDownload.gif)
and replaces them with verbal step-by-step instructions and gcloud
commands in docsource/content.md. Google's Console UI changes regularly
and screenshots go stale; gcloud commands and the underlying APIs are
the stable interface. The Keyfactor Command store-type dialog screenshots
are doctool-managed and remain.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GCP region names appear in three distinct places across the
orchestrator: the {location} segment of Store Path (load-bearing for
new stores), the deprecated Location custom property (v1.1 fallback
only), and Discovery's "Directories to search" form field (operator
input to Discovery, does not propagate to resulting stores). The
relationships were not obvious from the field semantics table - this
adds a "Location semantics: where the GCP region lives" subsection
that walks through each place, what reads it, and how they relate
across the discovery and creation flows. Includes a quick-reference
that maps common operator questions to the right field.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The store type's SupportedOperations advertised Create: true since v1.0,
but Management.cs has only ever switched on Add and Remove - a Create
job from Keyfactor Command's UI fell through to the default branch and
returned 'Invalid Management Operation'. There is no meaningful semantic
for Create on a GCP Certificate Manager store anyway: the (project,
location) container is implicit in the GCP project, so there is nothing
the orchestrator can usefully provision. Flip the manifest claim to
match the code rather than implement a no-op.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Keyfactor Command's Discovery UI requires "Directories to search" to
be non-empty, so prior advice to "leave blank to default to global"
doesn't actually work for operators - the form rejects submission.
The recommended value is to type 'global' explicitly. The orchestrator
still defaults to 'global' defensively if it ever receives a blank
value via a non-UI submission path, but that should be treated as a
safety net rather than the documented flow.

Also expanded the surrounding guidance to explain why the label says
"Directories" (it's a Command UI convention inherited from filesystem
store types), why 'global' is the right answer for ~95 percent of
deployments, and the rare cases where adding regional locations makes
sense (regional external Application Load Balancers, data-residency
constraints).

Server Username / Server Password guidance updated similarly: although
the orchestrator does not use them, the form may require non-empty
values, so the recommendation is to type any placeholder.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Empirical observation of the Schedule Discovery dialog in Keyfactor
Command shows the form does NOT include Client Machine, Server
Username, Server Password, or a Create Certificate Store If Missing
checkbox - those were claims I made without verifying. The form has
the standard Command Discovery layout (Category, Orchestrator,
Schedule, Directories to search, Directories to ignore, Extensions,
File name patterns to match, Follow SymLinks, Include PKCS12 Files)
and most fields don't apply to GCP at all.

Corrections in this commit:

- Replace the discovery-job form table with the actual fields visible
  on the Schedule Discovery dialog, marking each filesystem-store
  field as not-applicable-to-GCP.
- Move Create Certificate Store If Missing to its actual location -
  the per-candidate edit dialog when MANAGEing a discovered store -
  and document what to do with the other fields on that approval
  dialog (Store Path comes pre-filled from Discovery; deprecated
  custom properties get left blank).
- CHANGELOG: clarify that the discovery-job ClientMachine value is
  auto-populated by Command (typically the orchestrator hostname)
  rather than something the operator types into the form. The
  orchestrator still logs it for traceability but it isn't load-bearing.
- Design rationale section: drop the misattribution of "auto-approval
  enabled via Create Certificate Store If Missing checkbox" - that
  checkbox is on the per-candidate approval dialog, not the discovery
  job. Keep the underlying observation that Client Machine is shared
  across all candidates and not per-candidate-settable, which is the
  actual constraint that drove the StorePath-as-canonical-source
  decision.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GCP Certificate Manager's `scope` field is create-only and immutable.
Previous releases hard-coded `Scope = "DEFAULT"` on every certificate
created, which made the orchestrator unusable for environments running
cross-region internal Application Load Balancers (`ALL_REGIONS`), Media
CDN (`EDGE_CACHE`), or mTLS trust configs (`CLIENT_AUTH`). Affected
customers had to pre-create empty placeholder certificate resources in
GCP via Terraform with the right scope, then point Keyfactor at the
shell - breaking the single-pane-of-glass workflow.

Adds a `Scope` custom store property honored by Management/Add. Values
are case-normalized and validated against the four-value enum GCP
accepts; an unsupported value fails the `ResolveScope` flow step before
any API call. Blank resolves to `DEFAULT` so existing stores keep
working with no operator action.

Replace (overwrite) intentionally does not propagate scope: the patch
UpdateMask is "SelfManaged", and GCP would reject a scope change
anyway. The recommended pattern is one store per (project, location,
scope) tuple.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Scope is per-certificate in GCP's data model - a single (project,
location) container can hold certs at different scopes - so modeling it
as a store property forced operators into one-store-per-scope and
required toggling the property between adds. Entry parameter matches
the actual semantics and lets a single store hold mixed-scope certs.

Changes:
- Move Scope from manifest Properties[] to EntryParameters[] as a
  MultipleChoice dropdown (DEFAULT/ALL_REGIONS/EDGE_CACHE/CLIENT_AUTH).
  Operators pick at Add time; the dropdown prevents typos reaching the
  orchestrator (ResolveScope still validates as defence-in-depth).
- Remove Scope from StoreProperties.cs.
- Management.cs now reads Scope from config.JobProperties["Scope"]
  rather than the store-properties bag.
- Inventory.cs reads c.Scope from each certificates.list response and
  writes it into CurrentInventoryItem.Parameters["Scope"]. GCP omits
  the field when the cert is at DEFAULT, so null/blank normalizes to
  "DEFAULT" here. This makes renewals/reenrollments carry scope
  forward automatically - Keyfactor replays the inventoried value
  back into JobProperties on the next Management/Add cycle.
- Regenerate scripts/store_types/{bash,powershell} so operators
  applying the store type from the branch get the EntryParameter
  shape without waiting for doctool CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
RestSharp 107.2.1 was a dead PackageReference - no using directive or
type reference exists anywhere in the source. Removing it eliminates
the GHSA-4rr6-2v9v-wcpc moderate-severity NU1902 warning without
needing a runtime upgrade.

Add net10.0 alongside net6.0 and net8.0 so the orchestrator can run
on .NET 10 hosts; build verified locally across all three TFMs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
System.Management.Automation 7.0.5 was dead weight - zero usages in the
source, and the manifest already declares "PowerShell": false. The
package also drove the NETSDK1206 RID warning (legacy win10-x64 etc.
RIDs in Microsoft.Management.Infrastructure.Runtime.Win) on net8/net10
builds.

Note: removing SMA does *not* eliminate the System.Drawing.Common
critical-severity warning (NU1904 / GHSA-rxg9-xrhp-64gj). That dep is
pulled in transitively by Keyfactor.Logging 1.1.1 via
System.DirectoryServices 5.0.0 -> System.Security.Permissions 5.0.0 ->
System.Windows.Extensions 5.0.0 -> System.Drawing.Common 5.0.0. The
fix path is either an explicit PackageReference override or a
Keyfactor.Logging upgrade upstream - both out of scope for this commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…p-64gj)

Pins System.Drawing.Common to 8.0.10 directly so the transitive 5.0.0
pulled in by Keyfactor.Logging -> System.DirectoryServices ->
System.Security.Permissions -> System.Windows.Extensions cannot resolve.
The 5.0.0 version has a critical-severity remote-code-execution CVE
(GHSA-rxg9-xrhp-64gj); 8.0.10 carries the patch.

Direct PackageReference outranks transitive resolution, so no other
csproj changes are needed. Override should be removed once Keyfactor
publishes a Keyfactor.Logging release that bumps System.DirectoryServices
to 8.x upstream.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@indrora indrora merged commit ac2b6ae into release-1.2 May 21, 2026
indrora added a commit that referenced this pull request May 21, 2026
* feat: add Discovery job for org-wide GCP cert manager enumeration

Adds CertStores.GcpCertMgr.Discovery (IDiscoveryJobExtension) that lists
every active GCP project the orchestrator's service account can see via
Cloud Resource Manager v3 projects.search and emits one candidate store
per (project, location) pair in canonical projects/{p}/locations/{l}
form. Discovery scope is bounded by IAM (service account permissioned
at the org root, per customer setup), not by query filtering.

Also brings the orchestrator up to the canonical hardening pattern:
ports FlowLogger.cs from the reference repo, adds JobBase.cs with
IPAMSecretResolver injection + GoogleApiException unwrapping, and
retrofits Inventory and Management onto the shared base. Job result
FailureMessage now carries the flow summary on every path so operators
can see what happened from job history alone. Bumps
Keyfactor.Orchestrators.IOrchestratorJobExtensions 0.6.0 -> 0.7.0 to
pick up IPAMSecretResolver.



* Update generated docs

* fix: prefer canonical StorePath over ClientMachine for GCP resource path

Inventory and Management built the GCP resource path from
ClientMachine + the Location custom property, ignoring whatever was in
the store's StorePath. Discovery-approved stores arrive in Command with
StorePath="projects/{id}/locations/{loc}" but ClientMachine defaulting
to whatever Command auto-fills (often the orchestrator hostname), so
inventory failed with HTTP 403 CONSUMER_INVALID against
"projects/<orchestrator-hostname>/locations/global".

ResolveGcpResourcePath now trusts StorePath when it is in canonical
"projects/X/locations/Y" form. Manually-created v1.1-shaped stores
(StorePath="n/a") continue to build the path from ClientMachine + the
Location custom property, so existing stores keep working without
intervention. Discovery-approved stores no longer require operators to
retype the project ID into ClientMachine after approval.



* Update generated docs

* refactor: unify store-type schema around canonical Store Path

Make Store Path the single source of truth for the GCP resource path on
both manually-created and Discovery-approved stores. Repurpose Client
Machine as a display label (recommended value: GCP Organization ID).
Deprecate the standalone Location custom property; the location is now
parsed out of Store Path. Existing v1.1 stores keep working via a
deprecation-logged fallback in JobBase.ResolveGcpResourcePath - every
inventory/management run against a v1.1-shape store emits one
LogWarning naming the migration step. Fallback removal scheduled for
v2.0.

Updates integration-manifest.json: clears StorePathValue's "n/a"
default, marks Location property Required:false with a deprecation
description, rewrites Client Machine and Store Path descriptions.
Doctool will regenerate the README's Manual Creation table from these.

Updates docsource/gcpcertmgr.md and content.md with one unified
configuration narrative covering both manual and Discovery-approved
flows, plus an explicit v1.1 migration section.



* Update generated docs

* feat: pre-flight alias validation against GCP resource-ID rules

Management/Add was doing CheckForDuplicate + LoadPkcs12 + ExtractPrivateKey
before calling GCP, only to have GCP reject the request with HTTP 400 if
the alias contained capital letters or other illegal characters. Now we
validate against [a-z]([-a-z0-9]*[a-z0-9])? (max 63 chars) immediately on
entry to PerformAddition and produce a clear flow-step failure with a
suggested normalized alias (e.g. 'Cert1' -> 'cert1'). No API calls or
PFX work happen on a non-conforming alias.

Operator workflow when validation fails: rename the certificate in
Keyfactor Command to the suggested form and re-run Management/Add.



* Update generated docs

* docs: explain why Store Path became the canonical source

Adds a "Design rationale: why Store Path is the source of truth"
section to docsource/gcpcertmgr.md covering: the IDiscoveryJobExtension
contract constraint that forced the schema change, the alternatives
considered (manual edits per approval, one job per project, posting to
Command's REST API directly), and the trade-offs accepted (Client
Machine repurposed as display label, Location property deprecated not
removed). CHANGELOG entry now points readers at the docs section for
the long form.



* Update generated docs

* refactor: consolidate authentication around ADC, ditch Google screenshots

Authentication now consolidates around Application Default Credentials.
The Service Account Key File Path custom store property is deprecated
because Keyfactor Command's discovery-job UI does not surface store-type
custom properties, so file-based auth never worked uniformly across all
four job types. ADC works via workload identity (GCE / GKE) or via the
GOOGLE_APPLICATION_CREDENTIALS environment variable on the orchestrator
host. v1.1 stores with the property populated continue to work via a
deprecation-logged fallback in GcpCertificateManagerClient.LoadCredentials;
the property is scheduled for removal in v2.0.

Drops the dead ServiceAccountKey JobProperty handling from Discovery.cs
since it was never reachable from Keyfactor Command's UI.

Removes three Google Cloud Console screenshot GIFs from docsource/
(ServiceAccountSettings.gif, ApiAccessNeeded.gif, GoogleKeyJsonDownload.gif)
and replaces them with verbal step-by-step instructions and gcloud
commands in docsource/content.md. Google's Console UI changes regularly
and screenshots go stale; gcloud commands and the underlying APIs are
the stable interface. The Keyfactor Command store-type dialog screenshots
are doctool-managed and remain.



* Update generated docs

* docs: clarify Location semantics across the three places it appears

GCP region names appear in three distinct places across the
orchestrator: the {location} segment of Store Path (load-bearing for
new stores), the deprecated Location custom property (v1.1 fallback
only), and Discovery's "Directories to search" form field (operator
input to Discovery, does not propagate to resulting stores). The
relationships were not obvious from the field semantics table - this
adds a "Location semantics: where the GCP region lives" subsection
that walks through each place, what reads it, and how they relate
across the discovery and creation flows. Includes a quick-reference
that maps common operator questions to the right field.



* fix: stop claiming Create is supported in SupportedOperations

The store type's SupportedOperations advertised Create: true since v1.0,
but Management.cs has only ever switched on Add and Remove - a Create
job from Keyfactor Command's UI fell through to the default branch and
returned 'Invalid Management Operation'. There is no meaningful semantic
for Create on a GCP Certificate Manager store anyway: the (project,
location) container is implicit in the GCP project, so there is nothing
the orchestrator can usefully provision. Flip the manifest claim to
match the code rather than implement a no-op.



* Update generated docs

* docs: correct Directories to search guidance - field is required

Keyfactor Command's Discovery UI requires "Directories to search" to
be non-empty, so prior advice to "leave blank to default to global"
doesn't actually work for operators - the form rejects submission.
The recommended value is to type 'global' explicitly. The orchestrator
still defaults to 'global' defensively if it ever receives a blank
value via a non-UI submission path, but that should be treated as a
safety net rather than the documented flow.

Also expanded the surrounding guidance to explain why the label says
"Directories" (it's a Command UI convention inherited from filesystem
store types), why 'global' is the right answer for ~95 percent of
deployments, and the rare cases where adding regional locations makes
sense (regional external Application Load Balancers, data-residency
constraints).

Server Username / Server Password guidance updated similarly: although
the orchestrator does not use them, the form may require non-empty
values, so the recommendation is to type any placeholder.



* docs: correct false claims about the Schedule Discovery form fields

Empirical observation of the Schedule Discovery dialog in Keyfactor
Command shows the form does NOT include Client Machine, Server
Username, Server Password, or a Create Certificate Store If Missing
checkbox - those were claims I made without verifying. The form has
the standard Command Discovery layout (Category, Orchestrator,
Schedule, Directories to search, Directories to ignore, Extensions,
File name patterns to match, Follow SymLinks, Include PKCS12 Files)
and most fields don't apply to GCP at all.

Corrections in this commit:

- Replace the discovery-job form table with the actual fields visible
  on the Schedule Discovery dialog, marking each filesystem-store
  field as not-applicable-to-GCP.
- Move Create Certificate Store If Missing to its actual location -
  the per-candidate edit dialog when MANAGEing a discovered store -
  and document what to do with the other fields on that approval
  dialog (Store Path comes pre-filled from Discovery; deprecated
  custom properties get left blank).
- CHANGELOG: clarify that the discovery-job ClientMachine value is
  auto-populated by Command (typically the orchestrator hostname)
  rather than something the operator types into the form. The
  orchestrator still logs it for traceability but it isn't load-bearing.
- Design rationale section: drop the misattribution of "auto-approval
  enabled via Create Certificate Store If Missing checkbox" - that
  checkbox is on the per-candidate approval dialog, not the discovery
  job. Keep the underlying observation that Client Machine is shared
  across all candidates and not per-candidate-settable, which is the
  actual constraint that drove the StorePath-as-canonical-source
  decision.



* Update generated docs

* Update keyfactor-starter-workflow.yml

* Update keyfactor-starter-workflow.yml

* docs: auto-generate README and documentation [skip ci]

* Update CHANGELOG.md

* feat: add Scope custom store property for GCP Certificate Manager

GCP Certificate Manager's `scope` field is create-only and immutable.
Previous releases hard-coded `Scope = "DEFAULT"` on every certificate
created, which made the orchestrator unusable for environments running
cross-region internal Application Load Balancers (`ALL_REGIONS`), Media
CDN (`EDGE_CACHE`), or mTLS trust configs (`CLIENT_AUTH`). Affected
customers had to pre-create empty placeholder certificate resources in
GCP via Terraform with the right scope, then point Keyfactor at the
shell - breaking the single-pane-of-glass workflow.

Adds a `Scope` custom store property honored by Management/Add. Values
are case-normalized and validated against the four-value enum GCP
accepts; an unsupported value fails the `ResolveScope` flow step before
any API call. Blank resolves to `DEFAULT` so existing stores keep
working with no operator action.

Replace (overwrite) intentionally does not propagate scope: the patch
UpdateMask is "SelfManaged", and GCP would reject a scope change
anyway. The recommended pattern is one store per (project, location,
scope) tuple.



* docs: auto-generate README and documentation [skip ci]

* refactor: model Scope as entry parameter, persist via Inventory

Scope is per-certificate in GCP's data model - a single (project,
location) container can hold certs at different scopes - so modeling it
as a store property forced operators into one-store-per-scope and
required toggling the property between adds. Entry parameter matches
the actual semantics and lets a single store hold mixed-scope certs.

Changes:
- Move Scope from manifest Properties[] to EntryParameters[] as a
  MultipleChoice dropdown (DEFAULT/ALL_REGIONS/EDGE_CACHE/CLIENT_AUTH).
  Operators pick at Add time; the dropdown prevents typos reaching the
  orchestrator (ResolveScope still validates as defence-in-depth).
- Remove Scope from StoreProperties.cs.
- Management.cs now reads Scope from config.JobProperties["Scope"]
  rather than the store-properties bag.
- Inventory.cs reads c.Scope from each certificates.list response and
  writes it into CurrentInventoryItem.Parameters["Scope"]. GCP omits
  the field when the cert is at DEFAULT, so null/blank normalizes to
  "DEFAULT" here. This makes renewals/reenrollments carry scope
  forward automatically - Keyfactor replays the inventoried value
  back into JobProperties on the next Management/Add cycle.
- Regenerate scripts/store_types/{bash,powershell} so operators
  applying the store type from the branch get the EntryParameter
  shape without waiting for doctool CI.



* docs: auto-generate README and documentation [skip ci]

* chore(build): drop unused RestSharp dep, add net10.0 TFM

RestSharp 107.2.1 was a dead PackageReference - no using directive or
type reference exists anywhere in the source. Removing it eliminates
the GHSA-4rr6-2v9v-wcpc moderate-severity NU1902 warning without
needing a runtime upgrade.

Add net10.0 alongside net6.0 and net8.0 so the orchestrator can run
on .NET 10 hosts; build verified locally across all three TFMs.



* chore(build): drop unused System.Management.Automation dep

System.Management.Automation 7.0.5 was dead weight - zero usages in the
source, and the manifest already declares "PowerShell": false. The
package also drove the NETSDK1206 RID warning (legacy win10-x64 etc.
RIDs in Microsoft.Management.Infrastructure.Runtime.Win) on net8/net10
builds.

Note: removing SMA does *not* eliminate the System.Drawing.Common
critical-severity warning (NU1904 / GHSA-rxg9-xrhp-64gj). That dep is
pulled in transitively by Keyfactor.Logging 1.1.1 via
System.DirectoryServices 5.0.0 -> System.Security.Permissions 5.0.0 ->
System.Windows.Extensions 5.0.0 -> System.Drawing.Common 5.0.0. The
fix path is either an explicit PackageReference override or a
Keyfactor.Logging upgrade upstream - both out of scope for this commit.



* chore(deps): override transitive System.Drawing.Common (GHSA-rxg9-xrhp-64gj)

Pins System.Drawing.Common to 8.0.10 directly so the transitive 5.0.0
pulled in by Keyfactor.Logging -> System.DirectoryServices ->
System.Security.Permissions -> System.Windows.Extensions cannot resolve.
The 5.0.0 version has a critical-severity remote-code-execution CVE
(GHSA-rxg9-xrhp-64gj); 8.0.10 carries the patch.

Direct PackageReference outranks transitive resolution, so no other
csproj changes are needed. Override should be removed once Keyfactor
publishes a Keyfactor.Logging release that bumps System.DirectoryServices
to 8.x upstream.



* Update CHANGELOG.md

* docs: auto-generate README and documentation [skip ci]

---------

Co-authored-by: Brian Hill <76450501+bhillkeyfactor@users.noreply.github.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>
Co-authored-by: github-actions[bot] <github-actions[bot]@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