Merge 1.3.0 to main#79
Conversation
* feat: `x509certificate2` removal (#71) * Update generated docs * chore(lint): Fix PR review lint. * Update generated docs * test: unit tests for SeparateChain/IncludeCertChain conflict resolution in JobBase Adds StorePropertiesParsingTests covering the four flag combinations so that the override logic (SeparateChain forced to false when IncludeCertChain=false) is caught at the unit level, not only by integration tests. * Update generated docs --------- Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io>
Dependency ReviewThe following issues were found:
Snapshot WarningsEnsure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice. License Issues.github/workflows/dotnet-security-scan.yml
.github/workflows/secret-scanning.yml
.github/workflows/unit-tests.yml
OpenSSF ScorecardScorecard details
Scanned Files
|
Integration Test Results (K8s v1.29.0)152 tests 152 ✅ 3m 19s ⏱️ Results for commit c2edf79. |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Merges release 1.3.0 changes into main, adding a comprehensive test suite (unit + integration), expanding docs/manifests for updated store behaviors, and introducing CI/security GitHub workflows to validate and scan the repo.
Changes:
- Added extensive unit/integration tests plus test helpers for certificate/key-format scenarios and K8S CSR inventory modes.
- Updated manifests and documentation to reflect K8SCert cluster-wide CSR inventory, IncludeCertChain limitations, and deprecated properties.
- Added GitHub Actions workflows for tests, quality gates, dependency/security scanning, SBOM generation, and issue templates.
Reviewed changes
Copilot reviewed 65 out of 114 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| kubernetes-orchestrator-extension.Tests/K8SCertStoreTests.cs | Adds unit tests around CSR status handling, parsing, and inventory mode logic. |
| kubernetes-orchestrator-extension.Tests/Jobs/StorePropertiesParsingTests.cs | Adds tests validating SeparateChain/IncludeCertChain conflict resolution behavior. |
| kubernetes-orchestrator-extension.Tests/Jobs/CertificateFormatTests.cs | Adds certificate format/key/chain parsing tests (DER/PEM/PKCS12). |
| kubernetes-orchestrator-extension.Tests/Integration/K8SCertStoreIntegrationTests.cs | Adds K8SCert integration tests for single vs cluster-wide CSR inventory and discovery. |
| kubernetes-orchestrator-extension.Tests/Integration/IntegrationTestBase.cs | Introduces shared integration base with namespace isolation and cleanup helpers. |
| kubernetes-orchestrator-extension.Tests/Integration/Fixtures/IntegrationTestFixture.cs | Adds integration fixture for kubeconfig loading, client creation, and PAM resolver mocking. |
| kubernetes-orchestrator-extension.Tests/Integration/Collections/K8STLSSecrCollection.cs | Adds xUnit collection fixture for K8STLSSecr integration tests. |
| kubernetes-orchestrator-extension.Tests/Integration/Collections/K8SSecretCollection.cs | Adds xUnit collection fixture for K8SSecret integration tests. |
| kubernetes-orchestrator-extension.Tests/Integration/Collections/K8SPKCS12Collection.cs | Adds xUnit collection fixture for K8SPKCS12 integration tests. |
| kubernetes-orchestrator-extension.Tests/Integration/Collections/K8SNSCollection.cs | Adds xUnit collection fixture for K8SNS integration tests. |
| kubernetes-orchestrator-extension.Tests/Integration/Collections/K8SJKSCollection.cs | Adds xUnit collection fixture for K8SJKS integration tests. |
| kubernetes-orchestrator-extension.Tests/Integration/Collections/K8SClusterCollection.cs | Adds xUnit collection fixture for K8SCluster integration tests. |
| kubernetes-orchestrator-extension.Tests/Integration/Collections/K8SCertCollection.cs | Adds xUnit collection fixture for K8SCert integration tests. |
| kubernetes-orchestrator-extension.Tests/Helpers/KeyTypeTestData.cs | Provides shared Theory test data for supported key types to reduce duplication. |
| kubernetes-orchestrator-extension.Tests/Helpers/CertificateTestHelper.cs | Adds certificate/key/keystore/CSR generation helpers for tests. |
| kubernetes-orchestrator-extension.Tests/Helpers/CachedCertificateProvider.cs | Adds thread-safe caching for expensive certificate generation during tests. |
| kubernetes-orchestrator-extension.Tests/Attributes/SkipUnlessTheoryAttribute.cs | Adds env-var-gated Theory attribute for integration/conditional tests. |
| kubernetes-orchestrator-extension.Tests/Attributes/SkipUnlessAttribute.cs | Adds env-var-gated Fact attribute for integration/conditional tests. |
| integration-manifest.json | Updates store property metadata (K8SCert inventory modes, deprecations, IncludeCertChain notes). |
| docsource/k8stlssecr.md | Fixes naming references and documents storepath/alias patterns. |
| docsource/k8ssecret.md | Fixes naming references and documents storepath/alias patterns. |
| docsource/k8spkcs12.md | Documents supported key types and updates default discovery patterns. |
| docsource/k8sns.md | Clarifies K8SNS overview and improves discovery/config sections. |
| docsource/k8sjks.md | Documents supported key types and corrects discovery text. |
| docsource/k8scluster.md | Clarifies K8SCluster overview wording. |
| docsource/k8scert.md | Adds detailed K8SCert inventory modes, config matrix, and limitations. |
| docsource/content.md | Updates overall docs and adds supported key type matrix. |
| TestConsole/Program.cs | Comments out sample serialization XML snippet (keeps as reference). |
| TESTING_QUICKSTART.md | Adds a quickstart guide for running tests/coverage and CI expectations. |
| TESTING.md | Adds a comprehensive testing guide covering unit/integration/coverage/limitations. |
| MAKEFILE_GUIDE.md | Documents Makefile targets for testing, debugging, and workflow parity. |
| Keyfactor.Orchestrators.K8S.sln | Adds test project and solution folders; expands configuration platforms. |
| CHANGELOG.md | Adds 1.3.0 release notes (features/fixes/chores). |
| .github/workflows/unit-tests.yml | Adds unit test workflow with matrix (.NET 8/10), coverage, and artifacts. |
| .github/workflows/secret-scanning.yml | Adds TruffleHog secret scanning workflow. |
| .github/workflows/sbom-generation.yml | Adds CycloneDX SBOM generation workflow and release attachment. |
| .github/workflows/pr-quality-gate.yml | Adds PR quality gate including semantic title validation and keyword scans. |
| .github/workflows/license-compliance.yml | Adds dependency license reporting workflow. |
| .github/workflows/integration-tests.yml | Adds kind-based integration test workflow and cleanup/diagnostics. |
| .github/workflows/dotnet-security-scan.yml | Adds NuGet vulnerability checks and outdated package reporting. |
| .github/workflows/dependency-submission.yml | Adds dependency graph submission workflow. |
| .github/workflows/dependency-review.yml | Adds PR dependency review workflow (vulns + license checks). |
| .github/workflows/code-quality.yml | Adds format/analyzer-based code quality checks. |
| .github/workflows/autochangelog.yml | Removes disabled/legacy autochangelog workflow stub. |
| .github/workflows/README.md | Adds documentation for CI workflows and artifacts/troubleshooting. |
| .github/labeler.yml | Adds PR auto-labeling rules by file patterns/branch naming. |
| .github/kind-config.yaml | Adds minimal kind cluster config for integration tests. |
| .github/dependabot.yml | Expands dependabot config (actions, gomod, nuget + grouping/labels). |
| .github/WORKFLOWS_SUMMARY.md | Adds high-level summary of security/quality workflows and settings. |
| .github/SETUP_COMPLETE.md | Adds “setup complete” checklist/details for GHAS + templates/workflows. |
| .github/SECURITY_WORKFLOWS.md | Adds detailed documentation for security/quality workflows. |
| .github/ISSUE_TEMPLATE/security_vulnerability.yml | Adds security vulnerability issue form template. |
| .github/ISSUE_TEMPLATE/feature_request.yml | Adds feature request issue form template. |
| .github/ISSUE_TEMPLATE/documentation.yml | Adds documentation/question issue form template. |
| .github/ISSUE_TEMPLATE/config.yml | Configures issue templates and support/security contact links. |
| .github/ISSUE_TEMPLATE/bug_report.yml | Adds bug report issue form template. |
Comments suppressed due to low confidence (1)
docsource/k8sjks.md:1
- Correct typo: 'toy' → 'you'.
## Overview
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| - name: Validate PR title | ||
| uses: amannn/action-semantic-pull-request@v5 | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| with: | ||
| types: | | ||
| feat | ||
| fix | ||
| docs | ||
| style | ||
| refactor | ||
| perf | ||
| test | ||
| chore | ||
| ci | ||
| requireScope: false | ||
| subjectPattern: ^[A-Z].+$ |
There was a problem hiding this comment.
This workflow enforces Conventional Commit PR titles, but the current PR title ("Merge 1.3.0 to main") will fail the check, which can block release-merge PRs. Consider exempting merge/release PRs (e.g., guard the step with an if: that skips titles starting with "Merge" or skips for PRs created by automation/bots), or broaden the allowed title patterns to include your release merge convention.
| - name: Check for prohibited keywords | ||
| run: | | ||
| # Check for common placeholder/debug keywords that shouldn't be committed | ||
| prohibited_keywords=( | ||
| "TODO" | ||
| "FIXME" | ||
| "HACK" | ||
| "XXX" | ||
| "debugger" | ||
| "console.log" | ||
| ) | ||
|
|
||
| found_issues=false | ||
| for keyword in "${prohibited_keywords[@]}"; do | ||
| if git diff origin/main...HEAD | grep -i "$keyword"; then | ||
| echo "::warning::Found prohibited keyword: $keyword" | ||
| found_issues=true | ||
| fi | ||
| done |
There was a problem hiding this comment.
git diff origin/main...HEAD assumes origin/main is present in the checkout. On PR workflows, actions/checkout may not fetch the base branch ref, which can cause this step to fail or behave unexpectedly. Prefer diffing against the PR base SHA/ref provided by GitHub (e.g., ${{ github.event.pull_request.base.sha }}) or explicitly git fetch origin ${{ github.base_ref }} before diffing.
| try { job.PublicInitializeStore(config); } catch { /* expected */ } | ||
|
|
||
| // Assert |
There was a problem hiding this comment.
Catching all exceptions here can mask unexpected failures (and also makes it unclear whether an exception was actually thrown as intended). Prefer using Record.Exception(...) and asserting it is non-null (or asserting a specific exception type/message), or catching only the expected exception type(s) from kubeconfig parsing/client creation.
| try { job.PublicInitializeStore(config); } catch { /* expected */ } | |
| // Assert | |
| var exception = Record.Exception(() => job.PublicInitializeStore(config)); | |
| // Assert | |
| Assert.NotNull(exception); |
| // Arrange | ||
| var csrName = $"test-single-approved-{Guid.NewGuid():N}"; | ||
| await CreateTestCsr(csrName, approve: true); | ||
| await Task.Delay(2000); // Wait for certificate to be issued |
There was a problem hiding this comment.
Fixed delays in integration tests are prone to CI flakiness (clusters vary in how quickly CSRs become issued). A more reliable approach is to poll the CSR resource until Status.Certificate is populated (or a timeout is reached), which reduces intermittent failures and unnecessary waiting when issuance is fast.
| await CreateTestCsr(approvedCsr1, approve: true); | ||
| await CreateTestCsr(approvedCsr2, approve: true); | ||
| await CreateTestCsr(pendingCsr, approve: false); | ||
| await Task.Delay(2000); // Wait for certificates to be issued |
There was a problem hiding this comment.
Fixed delays in integration tests are prone to CI flakiness (clusters vary in how quickly CSRs become issued). A more reliable approach is to poll the CSR resource until Status.Certificate is populated (or a timeout is reached), which reduces intermittent failures and unnecessary waiting when issuance is fast.
| // Arrange | ||
| var csrName = $"test-no-pk-cw-{Guid.NewGuid():N}"; | ||
| await CreateTestCsr(csrName, approve: true); | ||
| await Task.Delay(2000); |
There was a problem hiding this comment.
Fixed delays in integration tests are prone to CI flakiness (clusters vary in how quickly CSRs become issued). A more reliable approach is to poll the CSR resource until Status.Certificate is populated (or a timeout is reached), which reduces intermittent failures and unnecessary waiting when issuance is fast.
| /// <summary> | ||
| /// Gets or sets the name of the environment variable to check. | ||
| /// </summary> | ||
| public string EnvironmentVariable { get; set; } |
There was a problem hiding this comment.
With nullable reference types enabled, EnvironmentVariable being non-nullable but uninitialized will produce warnings, and returning null from Skip can also produce nullability warnings depending on xUnit's annotations. Consider initializing EnvironmentVariable to string.Empty (matching SkipUnlessTheoryAttribute), and align the Skip override's nullability with the base property (or use return null!; explicitly if the base signature is non-nullable but xUnit treats null as 'do not skip').
| { | ||
| } | ||
|
|
||
| public override string Skip |
There was a problem hiding this comment.
With nullable reference types enabled, EnvironmentVariable being non-nullable but uninitialized will produce warnings, and returning null from Skip can also produce nullability warnings depending on xUnit's annotations. Consider initializing EnvironmentVariable to string.Empty (matching SkipUnlessTheoryAttribute), and align the Skip override's nullability with the base property (or use return null!; explicitly if the base signature is non-nullable but xUnit treats null as 'do not skip').
| **Purpose:** Comprehensive unit testing across .NET versions | ||
|
|
||
| **What it does:** | ||
| - Runs all 134 unit tests |
There was a problem hiding this comment.
These hard-coded test counts appear inconsistent with the counts documented elsewhere in this PR (e.g., TESTING.md / TESTING_QUICKSTART.md). Consider removing exact numbers, deriving them from dotnet test --list-tests, or wording this as 'runs all unit tests / integration tests' to avoid the docs going stale.
|
|
||
| **What it does:** | ||
| - Creates kind (Kubernetes in Docker) cluster with K8s v1.29 | ||
| - Runs all 55 integration tests |
There was a problem hiding this comment.
These hard-coded test counts appear inconsistent with the counts documented elsewhere in this PR (e.g., TESTING.md / TESTING_QUICKSTART.md). Consider removing exact numbers, deriving them from dotnet test --list-tests, or wording this as 'runs all unit tests / integration tests' to avoid the docs going stale.
* feat: `x509certificate2` removal (#73) (#79) * feat: `x509certificate2` removal (#71) * Update generated docs * chore(lint): Fix PR review lint. * Update generated docs * test: unit tests for SeparateChain/IncludeCertChain conflict resolution in JobBase Adds StorePropertiesParsingTests covering the four flag combinations so that the override logic (SeparateChain forced to false when IncludeCertChain=false) is caught at the unit level, not only by integration tests. * Update generated docs --------- Co-authored-by: spb <1661003+spbsoluble@users.noreply.github.com> Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io> * refactor: extract service layer from monolithic JobBase Break domain logic out of JobBase into focused, testable services: - StoreConfigurationParser: parses CertificateStoreDetails.Properties JSON into a typed StoreConfiguration, eliminating dynamic dispatch - StorePathResolver: resolves StorePath strings (namespace/secret-name) into structured PathResolutionResult for all store type patterns - JobCertificateParser: extracts certificate/key/chain from ManagementJobConfiguration with explicit format detection - PasswordResolver: resolves passwords from inline values or K8S secret references, centralising the "buddy password" pattern - CertificateChainExtractor: parses PEM chains into leaf + intermediates, handling both bundled and pre-separated chain formats - KeystoreOperations: JKS/PKCS12 read/write operations moved out of handlers into a standalone service None of these services require a Kubernetes client, making them fully unit-testable without network access. * refactor: introduce handler strategy pattern for secret operations Replace inline switch/if chains in JobBase with a proper Strategy pattern: - ISecretHandler: contract for Inventory, Management, Discovery, and Reenrollment operations on a specific secret/store type - SecretHandlerBase: shared infrastructure (client, logging, result helpers) - SecretHandlerFactory: creates the correct handler from SecretType enum - Per-type handlers: TlsSecretHandler, OpaqueSecretHandler, JksSecretHandler, Pkcs12SecretHandler, ClusterSecretHandler, NamespaceSecretHandler, CertificateSecretHandler (read-only) Supporting additions: - SecretTypes enum: typed representation of Kubernetes secret types with normalisation and IsTlsType/IsOpaqueType helpers - K8SJobCertificate model: replaces ad-hoc certificate data passing - Exceptions: StoreNotFoundException, InvalidK8SSecretException, JkSisPkcs12Exception — typed errors replace bare Exception throws - ICertificateStoreSerializer + JKS/PKCS12 serializer implementations moved from StoreTypes/ to Serializers/ (interface renamed for clarity) * refactor: split monolithic KubeClient into focused client components KubeClient.cs was a 3000+ line file mixing authentication, kubeconfig parsing, secret CRUD, and CSR operations. Split into: - KubeconfigParser: parses kubeconfig JSON into typed configuration, validates required fields, provides clear error messages - SecretOperations: Kubernetes secret CRUD (create, read, update, delete, list) with retry logic and structured logging - CertificateOperations: CSR-specific operations (list, read, approve, inject certificate status) - KubeClient (KubeCertificateManagerClient): now a thin coordinator that initialises the authenticated client and delegates to the above Also removes unreachable code branches, converts string interpolation log calls to structured logging throughout, and adds retry logic with configurable backoff. * refactor: restructure job classes by store type, remove X509Certificate2 Job structure (flat → per-store-type): - Remove Jobs/Inventory.cs, Management.cs, Discovery.cs, Reenrollment.cs (monolithic files with large switch statements on store type) - Add Jobs/Base/: K8SJobBase, InventoryBase, ManagementBase, DiscoveryBase, ReenrollmentBase — shared logic each job type delegates to its handler - Add Jobs/StoreTypes/<Type>/: one class per operation per store type (7 store types × up to 4 operations = 26 concrete job classes) - manifest.json updated to route each capability to its dedicated class X509Certificate2 removal: - Replace X509Certificate2 usage throughout with BouncyCastle types - K8SCertificateContext replaces X509Certificate2-based SerializedStoreInfo - LoggingUtilities updated: GetCertificateSummary now accepts BouncyCastle X509Certificate; RedactPassword no longer leaks password length Version logging: - JobBase reads AssemblyInformationalVersionAttribute at startup and logs "K8S Orchestrator Extension version: {Version}" on every job execution (baked in at build time by GitHub Actions via -p:Version=<tag>) Also removes TestConsole (superseded by integration test suite) and store_types.json (superseded by integration-manifest.json). * feat: add CachedCertificateProvider and comprehensive test suite Test infrastructure: - CachedCertificateProvider: thread-safe cache for generated certificates; eliminates redundant RSA key generation across test collections (RSA 8192 takes 30+ seconds per key — this alone cut full-suite runtime by ~60%) - IntegrationTestFixture: shared kubeconfig loading, K8S client creation, namespace setup/teardown for all integration test collections - SkipUnless attribute: skips integration tests when RUN_INTEGRATION_TESTS is not set, keeping unit test runs fast New unit tests (zero network access): - Services: StoreConfigurationParser, StorePathResolver, PasswordResolver, CertificateChainExtractor, JobCertificateParser, KeystoreOperations - Handlers: SecretHandlerBase, SecretHandlerFactory, all handler types (no-network paths), alias routing regression - Clients: KubeconfigParser, SecretOperations, CertificateOperations, KubeCertificateManagerClient - Jobs: ManagementBase, DiscoveryBase, PAMUtilities, exception paths, K8SJobCertificate, K8SCertificateContext - Utilities: LoggingUtilities (60 cases including DoesNotRevealLength), CertificateUtilities, LoggingSafetyTests - Enums: SecretTypes Updated integration tests: migrated all 7 store-type integration test files to use IntegrationTestFixture and new job class namespaces. Also adds scripts/analyze-coverage.py for coverage gap analysis. * docs: update CHANGELOG, ARCHITECTURE.md, Development.md, README for v2.0.0 - CHANGELOG.md: document v2.0.0 breaking changes — new store type routing via per-store-type job classes, removed X509Certificate2 dependency, updated job configuration model - docs/ARCHITECTURE.md: new file documenting the service/handler/job architecture, authentication flow, and extension points - Development.md: updated testing guide with CachedCertificateProvider guidance, integration test setup, coverage targets - README.md: regenerated from docsource/ with updated store type dialogs - docsource/: updated content and added SVG store type dialog images for all 7 store types - .github/workflows: add test-doctool workflow, update starter workflow - scripts/store_types/: updated kfutil helper scripts - terraform/: add Terraform module examples for all store types * docs(architecture): remove incorrect reenrollment references Reenrollment is not a supported operation. Remove it from the overview sentence, fix the store type operations table (K8SJKS and K8SPKCS12 were incorrectly listed as 'All + Reenrollment'), and remove ReenrollmentBase.cs from the base class directory listing. * docs: auto-generate README and documentation [skip ci] * docs: update compatibility to include Command 24.x and 25.x Update the compatibility statement and UO version matrix to explicitly call out support for Keyfactor Command platform versions 24.x and 25.x, and add a net10.0 row for Command 25.x and newer. * docs: auto-generate README and documentation [skip ci] * docs: call out .NET 8 and .NET 10 compatibility in README Add explicit mention of net8.0/net10.0 dual-targeting to the Compatibility section so users know which build to download without having to dig into the installation table. * docs: auto-generate README and documentation [skip ci] * docs(changelog): add v2.0.0 entry * docs(changelog): merge pre-rebase content into v2.0.0 and 1.3.0 entries Add missing breaking changes (JobBase dead property removal, KeystoreManager removal), terraform feature, and richer 1.3.0 bug fixes (create-if-missing, buddy-secret password, alias routing) and refactor/test chores from the break/major_refactor branch changelog. * fix: add missing Serializers directory to fix build The Serializers/ directory containing JKS and PKCS12 store serializers was never committed, causing build failures when handler files attempted to reference the Keyfactor.Extensions.Orchestrator.K8S.Serializers namespace. * docs(auth): add client certificate auth as alternative to SA token - Fix fragile grep/awk token lookup in get_service_account_creds.sh and create_service_account.sh — now uses direct jsonpath lookup with a clear error message if the token Secret is missing (k8s v1.22+) - Add generate_client_cert_creds.sh: end-to-end script that applies RBAC, generates an RSA key, submits and approves a k8s CSR, and builds a client-cert kubeconfig in one step - Add kubernetes_svc_account_cert_auth.yaml: ClusterRole + ClusterRoleBinding for cert-based auth (kind: User subject, no ServiceAccount required) - Add example_kubeconfig_cert.json showing client-certificate-data layout - Rewrite scripts/kubernetes/README.md to present both auth options equally with comparison table, quickstart, config reference, and manual steps - Update docsource/content.md Requirements section to document both methods * docs: auto-generate README and documentation [skip ci] * feat(auth): add in-cluster pod identity as third authentication option Plugin changes: - KubeClient.GetKubeClient(): detect KUBERNETES_SERVICE_HOST and call InClusterConfig() when no kubeconfig is provided, using the projected service account token mounted by kubelet (auto-rotated every hour) - JobBase.InitializeProperties(): allow empty KubeSvcCreds when running in-cluster instead of throwing ConfigurationException Scripts/docs: - Add keyfactor-orchestrator-deployment.yaml: Deployment manifest that runs the UO as a pod using the keyfactor-orchestrator-sa ServiceAccount - Update scripts/kubernetes/README.md: add Option 3 to comparison table and full setup section (apply SA YAML, deploy, leave Server Password blank) - Update docsource/content.md: document all three auth options equally * docs: auto-generate README and documentation [skip ci] * docs(auth): clarify in-cluster requires "No value" for Server Password in Command UI * docs: auto-generate README and documentation [skip ci] * fix(security): SOX/SOC2 compliance remediations and UseSSL bug fix Compliance remediations (all findings were pre-existing on branch): - Redact certificate bytes in UpdateOpaqueSecret log traces (CRIT-1) - Log CSR certificate length only, not content preview (CRIT-2) - Add structured AUDIT log entries (store_access, secret_read/write/delete) to ManagementBase, InventoryBase, DiscoveryBase, SecretOperations (CRIT-3) - ValidateK8SName throws ArgumentException instead of warning; 5+ segment paths return Success=false and fail the job (CRIT-4) - Zero KubeSvcCreds and ServerPassword after KubeClient construction (HIGH-1) - RedactKubeconfig validates JSON structure before applying label; non-JSON returns POSSIBLY_MALFORMED_CREDENTIAL (HIGH-2) - Silent catch blocks in JKS/PKCS12 serializers now log exception type (HIGH-3) - PAM resolution outcome promoted from LogTrace to LogInformation (HIGH-4) - TLS skip override promoted from LogWarning to LogError with structured SECURITY_CONFIG_OVERRIDE field (HIGH-5) - ReadBuddyPass: make passwordSecretName discard explicit with _ (HIGH-6) - HandleRemove returns Warning (not Success) when store not found so job history distinguishes no-op from actual removal (HIGH-7) - Remove KubeSvcCreds from storeProperties dict after client construction (MED-1) - StorePathResolver rejects 5+ segment paths (MED-4) - Handler NotFound catch blocks use HttpOperationException status code comparison instead of ex.Message string matching (MED-5) - Discovery InitializeStore wrapped in try/catch matching Inventory/Management pattern (MED-6) Bug fix: - UseSSL value from job config (config.UseSSL) was never forwarded to KubeCertificateManagerClient — TLS verification was always defaulting to true regardless of the store's Use SSL checkbox. Now captured in each InitializeStore overload and passed through InitializeKubeClient. * security: remove GetPasswordCorrelationId and update changelog Removes SHA-256 password correlation ID (MED-2) — low-entropy passwords are reversible via dictionary attack and RedactPassword is already present at all call sites. Updates CHANGELOG.md with all v2.0.0 changes from this session including client cert auth, in-cluster auth, UseSSL fix, audit logging, and compliance remediations. * docs: remove duplicate content sections from generated README Regenerated with fixed doctooldotnet (Keyfactor/doctooldotnet#9). Named content.md sections were being emitted twice due to title mutation before the custom-sections filter ran. NOTE: Actions will revert this until doctooldotnet PR #9 is merged. * docs: auto-generate README and documentation [skip ci] * chore(ci): revert to old doctool * fix(k8scert): ignore storepath for csr mode and add regression coverage * fix(inventory): sanitize URL cluster names in discovery location strings (#88) --------- Co-authored-by: Morgan Gangwere <470584+indrora@users.noreply.github.com> Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* feat: `x509certificate2` removal (#73) (#79) * feat: `x509certificate2` removal (#71) * Update generated docs * chore(lint): Fix PR review lint. * Update generated docs * test: unit tests for SeparateChain/IncludeCertChain conflict resolution in JobBase Adds StorePropertiesParsingTests covering the four flag combinations so that the override logic (SeparateChain forced to false when IncludeCertChain=false) is caught at the unit level, not only by integration tests. * Update generated docs --------- * refactor: extract service layer from monolithic JobBase Break domain logic out of JobBase into focused, testable services: - StoreConfigurationParser: parses CertificateStoreDetails.Properties JSON into a typed StoreConfiguration, eliminating dynamic dispatch - StorePathResolver: resolves StorePath strings (namespace/secret-name) into structured PathResolutionResult for all store type patterns - JobCertificateParser: extracts certificate/key/chain from ManagementJobConfiguration with explicit format detection - PasswordResolver: resolves passwords from inline values or K8S secret references, centralising the "buddy password" pattern - CertificateChainExtractor: parses PEM chains into leaf + intermediates, handling both bundled and pre-separated chain formats - KeystoreOperations: JKS/PKCS12 read/write operations moved out of handlers into a standalone service None of these services require a Kubernetes client, making them fully unit-testable without network access. * refactor: introduce handler strategy pattern for secret operations Replace inline switch/if chains in JobBase with a proper Strategy pattern: - ISecretHandler: contract for Inventory, Management, Discovery, and Reenrollment operations on a specific secret/store type - SecretHandlerBase: shared infrastructure (client, logging, result helpers) - SecretHandlerFactory: creates the correct handler from SecretType enum - Per-type handlers: TlsSecretHandler, OpaqueSecretHandler, JksSecretHandler, Pkcs12SecretHandler, ClusterSecretHandler, NamespaceSecretHandler, CertificateSecretHandler (read-only) Supporting additions: - SecretTypes enum: typed representation of Kubernetes secret types with normalisation and IsTlsType/IsOpaqueType helpers - K8SJobCertificate model: replaces ad-hoc certificate data passing - Exceptions: StoreNotFoundException, InvalidK8SSecretException, JkSisPkcs12Exception — typed errors replace bare Exception throws - ICertificateStoreSerializer + JKS/PKCS12 serializer implementations moved from StoreTypes/ to Serializers/ (interface renamed for clarity) * refactor: split monolithic KubeClient into focused client components KubeClient.cs was a 3000+ line file mixing authentication, kubeconfig parsing, secret CRUD, and CSR operations. Split into: - KubeconfigParser: parses kubeconfig JSON into typed configuration, validates required fields, provides clear error messages - SecretOperations: Kubernetes secret CRUD (create, read, update, delete, list) with retry logic and structured logging - CertificateOperations: CSR-specific operations (list, read, approve, inject certificate status) - KubeClient (KubeCertificateManagerClient): now a thin coordinator that initialises the authenticated client and delegates to the above Also removes unreachable code branches, converts string interpolation log calls to structured logging throughout, and adds retry logic with configurable backoff. * refactor: restructure job classes by store type, remove X509Certificate2 Job structure (flat → per-store-type): - Remove Jobs/Inventory.cs, Management.cs, Discovery.cs, Reenrollment.cs (monolithic files with large switch statements on store type) - Add Jobs/Base/: K8SJobBase, InventoryBase, ManagementBase, DiscoveryBase, ReenrollmentBase — shared logic each job type delegates to its handler - Add Jobs/StoreTypes/<Type>/: one class per operation per store type (7 store types × up to 4 operations = 26 concrete job classes) - manifest.json updated to route each capability to its dedicated class X509Certificate2 removal: - Replace X509Certificate2 usage throughout with BouncyCastle types - K8SCertificateContext replaces X509Certificate2-based SerializedStoreInfo - LoggingUtilities updated: GetCertificateSummary now accepts BouncyCastle X509Certificate; RedactPassword no longer leaks password length Version logging: - JobBase reads AssemblyInformationalVersionAttribute at startup and logs "K8S Orchestrator Extension version: {Version}" on every job execution (baked in at build time by GitHub Actions via -p:Version=<tag>) Also removes TestConsole (superseded by integration test suite) and store_types.json (superseded by integration-manifest.json). * feat: add CachedCertificateProvider and comprehensive test suite Test infrastructure: - CachedCertificateProvider: thread-safe cache for generated certificates; eliminates redundant RSA key generation across test collections (RSA 8192 takes 30+ seconds per key — this alone cut full-suite runtime by ~60%) - IntegrationTestFixture: shared kubeconfig loading, K8S client creation, namespace setup/teardown for all integration test collections - SkipUnless attribute: skips integration tests when RUN_INTEGRATION_TESTS is not set, keeping unit test runs fast New unit tests (zero network access): - Services: StoreConfigurationParser, StorePathResolver, PasswordResolver, CertificateChainExtractor, JobCertificateParser, KeystoreOperations - Handlers: SecretHandlerBase, SecretHandlerFactory, all handler types (no-network paths), alias routing regression - Clients: KubeconfigParser, SecretOperations, CertificateOperations, KubeCertificateManagerClient - Jobs: ManagementBase, DiscoveryBase, PAMUtilities, exception paths, K8SJobCertificate, K8SCertificateContext - Utilities: LoggingUtilities (60 cases including DoesNotRevealLength), CertificateUtilities, LoggingSafetyTests - Enums: SecretTypes Updated integration tests: migrated all 7 store-type integration test files to use IntegrationTestFixture and new job class namespaces. Also adds scripts/analyze-coverage.py for coverage gap analysis. * docs: update CHANGELOG, ARCHITECTURE.md, Development.md, README for v2.0.0 - CHANGELOG.md: document v2.0.0 breaking changes — new store type routing via per-store-type job classes, removed X509Certificate2 dependency, updated job configuration model - docs/ARCHITECTURE.md: new file documenting the service/handler/job architecture, authentication flow, and extension points - Development.md: updated testing guide with CachedCertificateProvider guidance, integration test setup, coverage targets - README.md: regenerated from docsource/ with updated store type dialogs - docsource/: updated content and added SVG store type dialog images for all 7 store types - .github/workflows: add test-doctool workflow, update starter workflow - scripts/store_types/: updated kfutil helper scripts - terraform/: add Terraform module examples for all store types * docs(architecture): remove incorrect reenrollment references Reenrollment is not a supported operation. Remove it from the overview sentence, fix the store type operations table (K8SJKS and K8SPKCS12 were incorrectly listed as 'All + Reenrollment'), and remove ReenrollmentBase.cs from the base class directory listing. * docs: auto-generate README and documentation [skip ci] * docs: update compatibility to include Command 24.x and 25.x Update the compatibility statement and UO version matrix to explicitly call out support for Keyfactor Command platform versions 24.x and 25.x, and add a net10.0 row for Command 25.x and newer. * docs: auto-generate README and documentation [skip ci] * docs: call out .NET 8 and .NET 10 compatibility in README Add explicit mention of net8.0/net10.0 dual-targeting to the Compatibility section so users know which build to download without having to dig into the installation table. * docs: auto-generate README and documentation [skip ci] * docs(changelog): add v2.0.0 entry * docs(changelog): merge pre-rebase content into v2.0.0 and 1.3.0 entries Add missing breaking changes (JobBase dead property removal, KeystoreManager removal), terraform feature, and richer 1.3.0 bug fixes (create-if-missing, buddy-secret password, alias routing) and refactor/test chores from the break/major_refactor branch changelog. * fix: add missing Serializers directory to fix build The Serializers/ directory containing JKS and PKCS12 store serializers was never committed, causing build failures when handler files attempted to reference the Keyfactor.Extensions.Orchestrator.K8S.Serializers namespace. * docs(auth): add client certificate auth as alternative to SA token - Fix fragile grep/awk token lookup in get_service_account_creds.sh and create_service_account.sh — now uses direct jsonpath lookup with a clear error message if the token Secret is missing (k8s v1.22+) - Add generate_client_cert_creds.sh: end-to-end script that applies RBAC, generates an RSA key, submits and approves a k8s CSR, and builds a client-cert kubeconfig in one step - Add kubernetes_svc_account_cert_auth.yaml: ClusterRole + ClusterRoleBinding for cert-based auth (kind: User subject, no ServiceAccount required) - Add example_kubeconfig_cert.json showing client-certificate-data layout - Rewrite scripts/kubernetes/README.md to present both auth options equally with comparison table, quickstart, config reference, and manual steps - Update docsource/content.md Requirements section to document both methods * docs: auto-generate README and documentation [skip ci] * feat(auth): add in-cluster pod identity as third authentication option Plugin changes: - KubeClient.GetKubeClient(): detect KUBERNETES_SERVICE_HOST and call InClusterConfig() when no kubeconfig is provided, using the projected service account token mounted by kubelet (auto-rotated every hour) - JobBase.InitializeProperties(): allow empty KubeSvcCreds when running in-cluster instead of throwing ConfigurationException Scripts/docs: - Add keyfactor-orchestrator-deployment.yaml: Deployment manifest that runs the UO as a pod using the keyfactor-orchestrator-sa ServiceAccount - Update scripts/kubernetes/README.md: add Option 3 to comparison table and full setup section (apply SA YAML, deploy, leave Server Password blank) - Update docsource/content.md: document all three auth options equally * docs: auto-generate README and documentation [skip ci] * docs(auth): clarify in-cluster requires "No value" for Server Password in Command UI * docs: auto-generate README and documentation [skip ci] * fix(security): SOX/SOC2 compliance remediations and UseSSL bug fix Compliance remediations (all findings were pre-existing on branch): - Redact certificate bytes in UpdateOpaqueSecret log traces (CRIT-1) - Log CSR certificate length only, not content preview (CRIT-2) - Add structured AUDIT log entries (store_access, secret_read/write/delete) to ManagementBase, InventoryBase, DiscoveryBase, SecretOperations (CRIT-3) - ValidateK8SName throws ArgumentException instead of warning; 5+ segment paths return Success=false and fail the job (CRIT-4) - Zero KubeSvcCreds and ServerPassword after KubeClient construction (HIGH-1) - RedactKubeconfig validates JSON structure before applying label; non-JSON returns POSSIBLY_MALFORMED_CREDENTIAL (HIGH-2) - Silent catch blocks in JKS/PKCS12 serializers now log exception type (HIGH-3) - PAM resolution outcome promoted from LogTrace to LogInformation (HIGH-4) - TLS skip override promoted from LogWarning to LogError with structured SECURITY_CONFIG_OVERRIDE field (HIGH-5) - ReadBuddyPass: make passwordSecretName discard explicit with _ (HIGH-6) - HandleRemove returns Warning (not Success) when store not found so job history distinguishes no-op from actual removal (HIGH-7) - Remove KubeSvcCreds from storeProperties dict after client construction (MED-1) - StorePathResolver rejects 5+ segment paths (MED-4) - Handler NotFound catch blocks use HttpOperationException status code comparison instead of ex.Message string matching (MED-5) - Discovery InitializeStore wrapped in try/catch matching Inventory/Management pattern (MED-6) Bug fix: - UseSSL value from job config (config.UseSSL) was never forwarded to KubeCertificateManagerClient — TLS verification was always defaulting to true regardless of the store's Use SSL checkbox. Now captured in each InitializeStore overload and passed through InitializeKubeClient. * security: remove GetPasswordCorrelationId and update changelog Removes SHA-256 password correlation ID (MED-2) — low-entropy passwords are reversible via dictionary attack and RedactPassword is already present at all call sites. Updates CHANGELOG.md with all v2.0.0 changes from this session including client cert auth, in-cluster auth, UseSSL fix, audit logging, and compliance remediations. * docs: remove duplicate content sections from generated README Regenerated with fixed doctooldotnet (Keyfactor/doctooldotnet#9). Named content.md sections were being emitted twice due to title mutation before the custom-sections filter ran. NOTE: Actions will revert this until doctooldotnet PR #9 is merged. * docs: auto-generate README and documentation [skip ci] * chore(ci): revert to old doctool * fix(k8scert): ignore storepath for csr mode and add regression coverage * fix(inventory): sanitize URL cluster names in discovery location strings (#88) --------- Co-authored-by: spb <1661003+spbsoluble@users.noreply.github.com> Co-authored-by: Keyfactor <keyfactor@keyfactor.github.io> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Merge release-1.3 to main - Automated PR