Skip to content

Don't resend pending certificates - #43820

Merged
dantecatalfamo merged 1 commit into
mainfrom
37556-android-cert-no-resend-pending
Apr 22, 2026
Merged

Don't resend pending certificates#43820
dantecatalfamo merged 1 commit into
mainfrom
37556-android-cert-no-resend-pending

Conversation

@dantecatalfamo

@dantecatalfamo dantecatalfamo commented Apr 20, 2026

Copy link
Copy Markdown
Member

Related issue: Resolves #37556

Fixes an issue caught in QA where a pending certificate could get resent using the API

Checklist for submitter

Testing

  • Added/updated automated tests
  • QA'd all new/changed functionality manually

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed certificate template resending to prevent invalid operations on pending templates. Users attempting to resend a pending template will now receive a clear error message.
  • Tests

    • Added test coverage for certificate template resending with pending status validation.

@dantecatalfamo
dantecatalfamo marked this pull request as ready for review April 20, 2026 21:07
@dantecatalfamo
dantecatalfamo requested a review from a team as a code owner April 20, 2026 21:07
Copilot AI review requested due to automatic review settings April 20, 2026 21:07

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai

coderabbitai Bot commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR adds validation to the ResendHostCertificateTemplate operation to prevent resending Android certificates when the host-specific template is in a pending status. The implementation retrieves the certificate template record for the specific host and checks if its status equals CertificateTemplatePending. If pending, the operation rejects the request with a 400 BadRequest error. A test case verifies that the pending-status check prevents the datastore resend operation and activity log creation.

Possibly related PRs

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is largely incomplete. While it references the related issue and checks testing boxes, it omits many template sections including security validations, database migrations, and changelog requirements. Add a changes file entry for user-visible changes and complete other relevant checklist items from the template, or explicitly document why sections are not applicable.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Don't resend pending certificates' clearly and concisely summarizes the main change—preventing resending of pending certificates—which matches the core functionality implemented.
Linked Issues check ✅ Passed The code changes successfully implement the requirement to prevent resending pending certificates via API by returning a 400 error, with appropriate test coverage validating this behavior.
Out of Scope Changes check ✅ Passed All code changes are directly scoped to the linked issue's engineering requirements: preventing pending certificate resends and validating this behavior with tests. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 37556-android-cert-no-resend-pending

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.

🧹 Nitpick comments (1)
server/service/certificates.go (1)

784-809: Optional: the follow-up GetCertificateTemplateById call is now redundant.

GetCertificateTemplateByIdForHost at line 784 already returns the template's ID and Name (via the embedded CertificateTemplateResponseCertificateTemplateResponseSummary), which are the only fields consumed by the activity payload below. The subsequent svc.ds.GetCertificateTemplateById(ctx, templateID) at line 797 is an extra DB round-trip that can be eliminated.

♻️ Proposed refactor
-	if err := svc.ds.ResendHostCertificateTemplate(ctx, hostID, templateID); err != nil {
-		return ctxerr.Wrap(ctx, err, "resending certificate template")
-	}
-
-	certificate, err := svc.ds.GetCertificateTemplateById(ctx, templateID)
-	if err != nil {
-		return ctxerr.Wrap(ctx, err, "getting certificate details")
-	}
-
-	if err := svc.NewActivity(ctx, authz.UserFromContext(ctx), fleet.ActivityTypeResentCertificate{
-		HostID:                host.ID,
-		HostDisplayName:       host.DisplayName(),
-		CertificateTemplateID: certificate.ID,
-		CertificateName:       certificate.Name,
-	}); err != nil {
+	if err := svc.ds.ResendHostCertificateTemplate(ctx, hostID, templateID); err != nil {
+		return ctxerr.Wrap(ctx, err, "resending certificate template")
+	}
+
+	if err := svc.NewActivity(ctx, authz.UserFromContext(ctx), fleet.ActivityTypeResentCertificate{
+		HostID:                host.ID,
+		HostDisplayName:       host.DisplayName(),
+		CertificateTemplateID: template.ID,
+		CertificateName:       template.Name,
+	}); err != nil {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/service/certificates.go` around lines 784 - 809, Remove the redundant
DB round-trip by dropping the svc.ds.GetCertificateTemplateById call and use the
already-fetched template from GetCertificateTemplateByIdForHost (the local
variable template) when building the ActivityTypeResentCertificate payload;
i.e., after successful svc.ds.ResendHostCertificateTemplate return to creating
the activity using template.ID and template.Name (and existing
host.ID/host.DisplayName()), and delete the extra certificate variable and its
error-handling block.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@server/service/certificates.go`:
- Around line 784-809: Remove the redundant DB round-trip by dropping the
svc.ds.GetCertificateTemplateById call and use the already-fetched template from
GetCertificateTemplateByIdForHost (the local variable template) when building
the ActivityTypeResentCertificate payload; i.e., after successful
svc.ds.ResendHostCertificateTemplate return to creating the activity using
template.ID and template.Name (and existing host.ID/host.DisplayName()), and
delete the extra certificate variable and its error-handling block.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d52052c3-ffc8-480f-8f49-33563c5305bb

📥 Commits

Reviewing files that changed from the base of the PR and between b2b8254 and b58f5e0.

📒 Files selected for processing (2)
  • server/service/certificate_templates_test.go
  • server/service/certificates.go

Copilot AI 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.

Pull request overview

Prevents resending an Android host certificate template when it’s already in a pending state, returning a client error instead of resetting the delivery.

Changes:

  • Add a host-specific template status lookup before resend and return HTTP 400 if status is pending.
  • Add unit coverage to ensure pending templates cannot be resent (and no activity/resend is triggered).
  • Import net/http to use http.StatusBadRequest.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
server/service/certificates.go Adds a pre-check to block resending pending certificate templates with a 400 user-message error.
server/service/certificate_templates_test.go Adds/updates tests to cover the new 400 behavior and ensure no resend/activity occurs.
Comments suppressed due to low confidence (1)

server/service/certificates.go:800

  • This adds an extra datastore read (GetCertificateTemplateByIdForHost) before the resend, and the function later fetches the certificate again via GetCertificateTemplateById just to populate activity fields. Since the host-specific template response already includes the template ID/name, consider reusing template for the activity payload to avoid the additional query.
	template, err := svc.ds.GetCertificateTemplateByIdForHost(ctx, templateID, host.UUID)
	if err != nil {
		return ctxerr.Wrap(ctx, err, "checking host certificate template")
	}

	if template.Status == fleet.CertificateTemplatePending {
		return fleet.NewUserMessageError(errors.New("Couldn't resend pending certificate template."), http.StatusBadRequest)
	}

	if err := svc.ds.ResendHostCertificateTemplate(ctx, hostID, templateID); err != nil {
		return ctxerr.Wrap(ctx, err, "resending certificate template")
	}

	certificate, err := svc.ds.GetCertificateTemplateById(ctx, templateID)
	if err != nil {
		return ctxerr.Wrap(ctx, err, "getting certificate details")
	}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread server/service/certificate_templates_test.go
Comment thread server/service/certificates.go
@codecov

codecov Bot commented Apr 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 66.91%. Comparing base (308e5f3) to head (b58f5e0).
⚠️ Report is 75 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main   #43820   +/-   ##
=======================================
  Coverage   66.91%   66.91%           
=======================================
  Files        2600     2600           
  Lines      208985   208995   +10     
  Branches     9305     9305           
=======================================
+ Hits       139846   139857   +11     
+ Misses      56397    56394    -3     
- Partials    12742    12744    +2     
Flag Coverage Δ
backend 68.70% <100.00%> (+<0.01%) ⬆️

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.

@dantecatalfamo
dantecatalfamo merged commit 2d3a790 into main Apr 22, 2026
55 checks passed
@dantecatalfamo
dantecatalfamo deleted the 37556-android-cert-no-resend-pending branch April 22, 2026 17:09
AndreyKizimenko pushed a commit that referenced this pull request Apr 22, 2026
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.

Allow IT admin to resend Android certificate to a specific host

3 participants