Skip to content

41542 android cert resend backend#42099

Merged
dantecatalfamo merged 10 commits intomainfrom
41542-android-cert-resend-backend
Mar 23, 2026
Merged

41542 android cert resend backend#42099
dantecatalfamo merged 10 commits intomainfrom
41542-android-cert-resend-backend

Conversation

@dantecatalfamo
Copy link
Copy Markdown
Member

@dantecatalfamo dantecatalfamo commented Mar 19, 2026

Related issue: Resolves #41542

Checklist for submitter

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

  • Changes file added for user-visible changes in changes/, orbit/changes/ or ee/fleetd-chrome/changes.
    See Changes files for more information.
  • Input data is properly validated, SELECT * is avoided, SQL injection is prevented (using placeholders for values in statements), JS inline code is prevented especially for url redirects, and untrusted data interpolated into shell scripts/commands is validated against shell metacharacters.

Testing

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

Summary by CodeRabbit

  • New Features
    • Added support for resending Android certificate templates. Users can now resend certificates to specific hosts. When resent, the certificate template status resets to pending and a new UUID is generated for re-delivery. All resend actions are automatically tracked in activity logs.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 19, 2026

Codecov Report

❌ Patch coverage is 82.00000% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.51%. Comparing base (5a266bf) to head (4741498).
⚠️ Report is 215 commits behind head on main.

Files with missing lines Patch % Lines
server/service/certificates.go 77.77% 3 Missing and 3 partials ⚠️
server/datastore/mysql/certificate_templates.go 90.00% 1 Missing and 1 partial ⚠️
server/service/hosts.go 50.00% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #42099      +/-   ##
==========================================
+ Coverage   66.41%   66.51%   +0.10%     
==========================================
  Files        2509     2517       +8     
  Lines      200777   202300    +1523     
  Branches     9048     9048              
==========================================
+ Hits       133344   134565    +1221     
- Misses      55370    55579     +209     
- Partials    12063    12156      +93     
Flag Coverage Δ
backend 68.30% <82.00%> (+0.10%) ⬆️

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 marked this pull request as ready for review March 20, 2026 15:12
@dantecatalfamo dantecatalfamo requested a review from a team as a code owner March 20, 2026 15:12
Copy link
Copy Markdown

@claude claude bot left a comment

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.

@mostlikelee
Copy link
Copy Markdown
Contributor

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 20, 2026

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 20, 2026

Walkthrough

This pull request implements backend functionality to support resending Android host certificates. It adds a datastore method that updates host certificate template records by regenerating their UUID and resetting the status to pending. A corresponding service layer method handles authorization checks, retrieves template metadata for activity logging, and creates an activity record. A new HTTP POST endpoint is registered at /api/_version_/fleet/hosts/{id}/certificates/{template_id}/resend. A new activity type ActivityTypeResentCertificate is introduced for audit logging. The changes include unit tests for datastore and service layers, as well as an integration test validating the full workflow.

Possibly related PRs

  • Add Android cert immediate statuses #36978 – Introduced certificate template statuses (pending/delivering/delivered/failed) and datastore methods to manage those statuses; the resend functionality builds directly upon this status management infrastructure.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
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 (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'android cert resend backend' accurately summarizes the main change: adding backend implementation for Android certificate resend functionality.
Description check ✅ Passed PR description covers the required checklist items: changes file added, input validation confirmed, and automated tests added, aligning with the template requirements.
Linked Issues check ✅ Passed The PR fully implements all required objectives: new API endpoint added (handler.go, certificates.go), UUID management for cert configs (certificate_templates.go), and activity logging (activities.go, certificates_test.go).
Out of Scope Changes check ✅ Passed All changes directly support the three objectives: endpoint implementation, database resend logic, activity creation, and comprehensive testing. Minor formatting in hosts.go is auxiliary.

✏️ 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 41542-android-cert-resend-backend

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.

Tip

CodeRabbit can suggest fixes for GitHub Check annotations.

Configure the reviews.tools.github-checks setting to adjust the time to wait for GitHub Checks to complete.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
server/service/integration_android_certificate_templates_test.go (1)

1467-1473: Add a case for “template exists but not for this host.”

Current negative coverage only uses non-existent IDs. Please add a case where the certificate template exists (belongs to another host/team) and assert the resend endpoint returns 404 for that host/template pair. This will lock down the no-row-updated path.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/service/integration_android_certificate_templates_test.go` around
lines 1467 - 1473, Add a test case where the certificate template exists but is
associated with a different host/team: create a second host (e.g., otherHost)
and a certificate template for that host to obtain otherCertTemplateID, then
call s.DoJSON("POST",
fmt.Sprintf("/api/latest/fleet/hosts/%d/certificates/%d/resend", host.ID,
otherCertTemplateID), nil, http.StatusNotFound, &struct{}{}) to assert the
resend endpoint returns 404 for a template that exists but not for the given
host; reference certTemplateID and host.ID to place this new case alongside the
existing negative tests.
server/service/certificate_templates_test.go (1)

448-457: Add a failure-path test for certificate lookup errors.

ResendHostCertificateTemplate also fails when GetCertificateTemplateById errors; adding that case would complete coverage for all pre-activity failure branches and assert no activity is emitted.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@server/service/certificate_templates_test.go` around lines 448 - 457, Add a
new unit test that mirrors the existing "returns error when datastore fails"
case but mocks datastore.GetCertificateTemplateById to return an error (e.g.,
errors.New("db error")) before calling svc.ResendHostCertificateTemplate(ctx,
hostID, templateID), then assert that an error is returned and its message
contains the db error and that opts.ActivityMock.NewActivityFuncInvoked is false
to ensure no activity was emitted; reference the ResendHostCertificateTemplate
method, the GetCertificateTemplateById datastore mock, and the
ActivityMock.NewActivityFuncInvoked flag when implementing the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@server/datastore/mysql/certificate_templates.go`:
- Around line 423-426: Handle the error returned by results.RowsAffected() and
preserve the not-found semantic: call affected, err := results.RowsAffected()
and if err != nil return a wrapped DB error (e.g., ctxerr.Errorf(ctx, "checking
rows affected for template %d host %d: %v", templateID, hostID, err)); otherwise
if affected == 0 return a typed not-found error (use the project’s not-found
helper, e.g., ctxerr.NotFoundf(ctx, "template %d does not exist for host %d",
templateID, hostID)) so that DB failures surface as errors and missing templates
remain a 404 path.

In `@server/service/certificates.go`:
- Around line 737-744: The code currently calls
svc.ds.GetCertificateTemplateById before proving the template belongs to the
host; to avoid exposing template existence, call
svc.ds.ResendHostCertificateTemplate(ctx, hostID, templateID) first (or replace
GetCertificateTemplateById with a host-scoped lookup like
GetHostCertificateTemplateById if available) and only fetch certificate details
via svc.ds.GetCertificateTemplateById after ResendHostCertificateTemplate
succeeds, so the template existence is validated through the host relationship
before any detailed lookup or logging.

---

Nitpick comments:
In `@server/service/certificate_templates_test.go`:
- Around line 448-457: Add a new unit test that mirrors the existing "returns
error when datastore fails" case but mocks datastore.GetCertificateTemplateById
to return an error (e.g., errors.New("db error")) before calling
svc.ResendHostCertificateTemplate(ctx, hostID, templateID), then assert that an
error is returned and its message contains the db error and that
opts.ActivityMock.NewActivityFuncInvoked is false to ensure no activity was
emitted; reference the ResendHostCertificateTemplate method, the
GetCertificateTemplateById datastore mock, and the
ActivityMock.NewActivityFuncInvoked flag when implementing the test.

In `@server/service/integration_android_certificate_templates_test.go`:
- Around line 1467-1473: Add a test case where the certificate template exists
but is associated with a different host/team: create a second host (e.g.,
otherHost) and a certificate template for that host to obtain
otherCertTemplateID, then call s.DoJSON("POST",
fmt.Sprintf("/api/latest/fleet/hosts/%d/certificates/%d/resend", host.ID,
otherCertTemplateID), nil, http.StatusNotFound, &struct{}{}) to assert the
resend endpoint returns 404 for a template that exists but not for the given
host; reference certTemplateID and host.ID to place this new case alongside the
existing negative tests.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 450d5a5a-6664-4a37-b05e-903e7b063099

📥 Commits

Reviewing files that changed from the base of the PR and between 99f8639 and b5fff31.

📒 Files selected for processing (13)
  • changes/41542-android-cert-resend-backend
  • server/datastore/mysql/certificate_templates.go
  • server/datastore/mysql/certificate_templates_test.go
  • server/fleet/activities.go
  • server/fleet/datastore.go
  • server/fleet/service.go
  • server/mock/datastore_mock.go
  • server/mock/service/service_mock.go
  • server/service/certificate_templates_test.go
  • server/service/certificates.go
  • server/service/handler.go
  • server/service/hosts.go
  • server/service/integration_android_certificate_templates_test.go

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
}{
{"from verified", fleet.CertificateTemplateVerified},
{"from delivered", fleet.CertificateTemplateDelivered},
{"from failed", fleet.CertificateTemplateFailed},
Copy link
Copy Markdown
Contributor

@ksykulev ksykulev Mar 23, 2026

Choose a reason for hiding this comment

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

What if someone tries to resend a certificate that's already pending? Just thinking about a race condition that could occur.

Certificate is in pending status
cron starts delivery (transitions to delivering)
User calls resend (resets to pending with new UUID)

The delivery cron might have already fetched the old UUID

I forget how the UUID works in the delivery process. might not be a concern.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Was thinking about it more, and even if it was allowed to happen, either the cron would just pick it up again next run, or mark it as delivered and then the UUID in the DB wouldn't match what's on the device but that wouldn't really matter since it's only used to re-install a cert and if it's mismatched on the first install it still accomplished the goal of installing the certificate

@dantecatalfamo dantecatalfamo merged commit 4df9ae0 into main Mar 23, 2026
47 of 51 checks passed
@dantecatalfamo dantecatalfamo deleted the 41542-android-cert-resend-backend branch March 23, 2026 21:01
dnplkndll pushed a commit to ledoent/fleet that referenced this pull request Mar 25, 2026
<!-- Add the related story/sub-task/bug number, like Resolves fleetdm#123, or
remove if NA -->
**Related issue:** Resolves fleetdm#41542
dnplkndll pushed a commit to ledoent/fleet that referenced this pull request Mar 25, 2026
<!-- Add the related story/sub-task/bug number, like Resolves fleetdm#123, or
remove if NA -->
**Related issue:** Resolves fleetdm#41542
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.

Android cert resend: Backend

3 participants