Skip to content

recreate certificate templates when CA or subject name change - #36772

Merged
ksykulev merged 2 commits into
mainfrom
36717-recreate-certs
Dec 5, 2025
Merged

recreate certificate templates when CA or subject name change#36772
ksykulev merged 2 commits into
mainfrom
36717-recreate-certs

Conversation

@ksykulev

@ksykulev ksykulev commented Dec 5, 2025

Copy link
Copy Markdown
Contributor

Related issue: Resolves #36717

When gitops runs and the yml for a certificate template includes a change to a certificate authority or a subject name for an existing certificate template. Do not update the certificate template, delete the old one and create a new one. This will aid in ensuring the new certificate is sent to the android device.

Checklist for submitter

If some of the following don't apply, delete the relevant line.

  • Input data is properly validated, SELECT * is avoided, SQL injection is prevented (using placeholders for values in statements)

Testing

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced certificate template comparison logic to properly detect changes in certificate authority associations and subject names, ensuring certificates are recreated when needed.
  • Tests

    • Expanded test coverage for certificate template management scenarios, including updates to certificate authorities and subject name modifications.
    • Added validation for certificate deletion and recreation workflows under various configuration changes.

✏️ Tip: You can customize this high-level summary in your review settings.

@ksykulev
ksykulev requested a review from a team as a code owner December 5, 2025 18:10
@codecov

codecov Bot commented Dec 5, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 81.81818% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 65.91%. Comparing base (b57469e) to head (e23763e).
⚠️ Report is 47 commits behind head on main.

Files with missing lines Patch % Lines
server/service/client.go 80.00% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #36772      +/-   ##
==========================================
+ Coverage   65.89%   65.91%   +0.01%     
==========================================
  Files        2248     2248              
  Lines      183935   184047     +112     
  Branches     7647     7647              
==========================================
+ Hits       121200   121308     +108     
+ Misses      51660    51657       -3     
- Partials    11075    11082       +7     
Flag Coverage Δ
backend 67.70% <81.81%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@getvictor getvictor self-assigned this Dec 5, 2025
@getvictor

Copy link
Copy Markdown
Member

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Dec 5, 2025

Copy link
Copy Markdown
Contributor
✅ Actions performed

Full review triggered.

@coderabbitai

coderabbitai Bot commented Dec 5, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

This PR fixes certificate template management during GitOps flows: when a certificate's subjectName or certificate authority changes, the old certificate is marked for deletion and a new one is created rather than updating the existing record. The datastore now skips updating these fields on upsert conflicts, and the service layer compares full certificate specifications to detect when deletion and recreation are required.

Changes

Cohort / File(s) Summary
Datastore: Certificate template upsert behavior
server/datastore/mysql/certificate_templates.go
Modified BatchUpsertCertificateTemplates to only update name and team_id on duplicate key conflicts; certificate_authority_id and subject_name are no longer updated, forcing deletion/recreation workflows when these fields change.
Datastore: Certificate template tests
server/datastore/mysql/certificate_templates_test.go
Updated testBatchUpsertCertificates to verify that subject_name remains unchanged after upserting an existing certificate template, validating the new upsert behavior.
Service layer: Certificate reconciliation
server/service/client.go
Enhanced certificate comparison logic: certsToBeAdded now stores full CertificateRequestSpec objects instead of placeholder structs; when a certificate with the same name exists, fetches full certificate details and compares SubjectName and CertificateAuthorityId against the desired spec; marks certificates for deletion if either field differs.
GitOps test scaffolding
cmd/fleetctl/fleetctl/gitops_test.go
Extended test coverage to simulate and verify certificate deletion and recreation scenarios: added deletion tracking, mock functions for fetching certificate details by ID, test flows validating deletion/recreation on SubjectName changes, CA rebindings, and no-op scenarios.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20–25 minutes

  • Service layer comparison logic (client.go): Verify the SubjectName and CertificateAuthorityId comparison correctly identifies when deletion/recreation is needed; confirm error handling for failed certificate detail fetches.
  • Datastore upsert behavior change (certificate_templates.go): Ensure the reduced update scope (omitting certificate_authority_id and subject_name) doesn't inadvertently break other upsert operations or leave stale data.
  • Test coverage expansion (gitops_test.go): Confirm new mock functions and deletion/recreation test scenarios comprehensively cover the updated control flow.

Possibly related PRs

Suggested reviewers

  • sgress454
  • JordanMontgomery
  • georgekarrv

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'recreate certificate templates when CA or subject name change' directly and clearly describes the main change: recreating certificate templates when certificate authority or subject name changes.
Description check ✅ Passed The PR description covers the key aspects: the linked issue is referenced (#36717), the problem and solution are explained, and relevant checklist items are completed (input validation, automated tests, host isolation tests, manual QA).
Linked Issues check ✅ Passed The code changes implement the requirement from #36717: instead of updating existing certificate templates when CA or subject_name changes, the system now deletes the old template and creates a new one through modified comparison logic in client.go and updated upsert behavior in certificate_templates.go.
Out of Scope Changes check ✅ Passed All changes are directly related to the linked issue objectives: test expansions verify deletion/recreation behavior, upsert logic changes reflect the deletion strategy, and client logic implements the comparison logic needed to identify when deletion is required.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 36717-recreate-certs

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 30d3a50 and b9149c9.

📒 Files selected for processing (4)
  • cmd/fleetctl/fleetctl/gitops_test.go (5 hunks)
  • server/datastore/mysql/certificate_templates.go (1 hunks)
  • server/datastore/mysql/certificate_templates_test.go (1 hunks)
  • server/service/client.go (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

⚙️ CodeRabbit configuration file

When reviewing SQL queries that are added or modified, ensure that appropriate filtering criteria are applied—especially when a query is intended to return data for a specific entity (e.g., a single host). Check for missing WHERE clauses or incorrect filtering that could lead to incorrect or non-deterministic results (e.g., returning the first row instead of the correct one). Flag any queries that may return unintended results due to lack of precise scoping.

Files:

  • server/datastore/mysql/certificate_templates.go
  • server/service/client.go
  • cmd/fleetctl/fleetctl/gitops_test.go
  • server/datastore/mysql/certificate_templates_test.go
🧠 Learnings (1)
📚 Learning: 2025-07-08T16:06:54.576Z
Learnt from: getvictor
Repo: fleetdm/fleet PR: 30589
File: ee/server/service/hostidentity/depot/depot.go:104-119
Timestamp: 2025-07-08T16:06:54.576Z
Learning: In ee/server/service/hostidentity/depot/depot.go, the security concern where shared challenges allow certificate revocation (lines 104-119) is a known issue that will be addressed in a later feature, not an immediate concern to fix.

Applied to files:

  • server/service/client.go
🧬 Code graph analysis (1)
server/service/client.go (1)
server/fleet/certificate_templates.go (1)
  • CertificateRequestSpec (3-8)
🔇 Additional comments (8)
server/datastore/mysql/certificate_templates.go (1)

163-166: LGTM - Upsert now preserves immutable fields as intended.

The ON DUPLICATE KEY UPDATE clause now correctly excludes certificate_authority_id and subject_name, which aligns with the PR objective to treat these as immutable fields. When either changes, the service layer will delete and recreate the certificate template rather than updating in place.

server/service/client.go (1)

2920-2960: LGTM - Data structure change enables proper certificate comparison.

Changing certsToBeAdded from map[string]struct{} to map[string]*fleet.CertificateRequestSpec correctly enables comparing the full spec (SubjectName, CertificateAuthorityId) against existing certificates to determine when recreation is needed.

server/datastore/mysql/certificate_templates_test.go (1)

720-731: LGTM - Test correctly validates new upsert semantics.

The test now properly verifies that BatchUpsertCertificateTemplates preserves the original subject_name on duplicate key conflicts, which aligns with the updated upsert behavior in certificate_templates.go.

cmd/fleetctl/fleetctl/gitops_test.go (5)

7-7: LGTM!

The errors import is correctly added to support the errors.New usage in the new mock functions.


3892-3950: LGTM!

The test scaffolding properly tracks deleted certificate IDs and adds the GetCertificateTemplateByIdFunc mock to return full certificate details (including SubjectName) for comparing existing vs. new certificate specifications. The mock correctly handles the expected IDs and returns an appropriate error for unknown IDs.


4014-4076: Verify mock state consistency for the CA swap scenario.

In the second test scenario (swapped CAs), the GetCertificateTemplateByIdFunc mock still returns the original subject names ("CN=Original Subject 1" and "CN=Original Subject 2"). The test config at lines 4044-4050 uses the same original subject names but with swapped CAs. This is correct for testing CA-only changes.

However, after the first test run (lines 3998-4012) deletes and recreates certificates with "CN=Updated Subject 1/2", the mock doesn't reflect this state change. The test relies on the mock returning stale data. While this works because the mock is static, consider whether this accurately simulates production behavior where the database would reflect the updated state.

If the intent is to test CA changes in isolation (without prior SubjectName changes), consider either:

  1. Documenting this is intentional (mock returns original state for each scenario), or
  2. Restructuring as separate sub-tests with isolated mock state.

4077-4130: LGTM!

The no-change scenario correctly validates that certificates with unchanged SubjectName and CA are not deleted and recreated. State is properly reset before this test run, and assertions verify the expected behavior (0 deletions, 2 certificates remain).


4171-4195: LGTM!

The GetCertificateTemplateByIdFunc mock is correctly added to return full certificate details. The subject names ("CN=Device Certificate 1" and "CN=Device Certificate 2") are consistent with the test configuration, enabling proper comparison during the deletion scenario.

Comment thread server/service/client.go Outdated
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

@getvictor getvictor left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@ksykulev
ksykulev merged commit fc3fd7d into main Dec 5, 2025
47 checks passed
@ksykulev
ksykulev deleted the 36717-recreate-certs branch December 5, 2025 22:46
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.

Do not update subjectName/CA on existing certificate

2 participants