Closes #45969 ## Summary The `List certificate templates` API endpoint returned `null` for certificates because the **API docs documented the wrong query parameter name**. The docs said `fleet` but the code accepts `fleet_id` (or the deprecated `team_id`). Customers following the docs used `?fleet=11`, which was silently ignored, causing the endpoint to default to team 0 (unassigned) -- which typically has no certificates. - **Docs fix**: Changed the parameter name from `fleet` (string) to `fleet_id` (integer) in the REST API docs, matching how all other list endpoints document this parameter. - **API quality fix**: Initialize the `templates` slice in `GetCertificateTemplatesByTeamID` so that when no templates exist, the JSON response returns `"certificates": []` instead of `"certificates": null`. ## Root cause In `docs/REST API/rest-api.md`, the "List certificate templates" endpoint documented the query parameter as `fleet` (string), but the request struct accepts `fleet_id` or `team_id`: ```go type listCertificateTemplatesRequest struct { TeamID uint `query:"team_id,optional" renameto:"fleet_id"` } ``` When the customer used `?fleet=11` (as documented), the parameter was unrecognized and silently ignored. The endpoint defaulted to `team_id=0` (unassigned), which had no certificates. The nil Go slice then serialized to JSON `null`. Credit to Andrey Kizimenko for identifying the docs mismatch. ## Changes - `docs/REST API/rest-api.md` -- Fix parameter name from `fleet` (string) to `fleet_id` (integer) - `server/datastore/mysql/certificate_templates.go:174` -- Initialize slice to avoid `null` in JSON - `server/datastore/mysql/certificate_templates_test.go:489` -- Add `require.NotNil` regression test ## Testing All tests run locally against a real MySQL (Docker) and Redis instance: | Test suite | Command | Result | |---|---|---| | Datastore integration (all certificate tests) | `MYSQL_TEST=1 go test -run TestCertificates ./server/datastore/mysql/...` | 11 suites, 33 subtests, all PASS | | Service unit tests | `go test -run "TestCreateCertificateTemplate\|TestApplyCertificateTemplateSpecs\|..."` | 4 suites, all PASS | | Enterprise integration (full HTTP) | `MYSQL_TEST=1 REDIS_TEST=1 go test -run "TestIntegrationsEnterprise/TestCertificatesSpecs"` | PASS | | Enterprise integration (team delete) | `MYSQL_TEST=1 REDIS_TEST=1 go test -run "TestIntegrationsEnterprise/TestDeleteTeamCertificateTemplates"` | PASS | | Static analysis | `go build`, `go vet` | Clean | Andrey's reproduction confirmed via screenshots: - `?fleet_id=11` returns certificates correctly - `?fleet=11` (the documented param) returns `null` -- the bug - No param returns results when "unassigned" team has certificates ## QA steps 1. Follow the API docs to list certificate templates using `?fleet_id=<id>` 2. Verify the response contains `"certificates": [...]` with the correct data 3. Call without `fleet_id` and verify `"certificates": []` (not `null`) for a team with no templates <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Fixed the "List certificate templates" API documentation with the correct query parameter name, enabling proper filtering of results. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/45978?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -0,0 +1 @@
|
||||
- Fixed `List certificate templates` API docs: query parameter was incorrectly documented as `fleet` instead of `fleet_id`, causing the parameter to be silently ignored and returning no results.
|
||||
@@ -936,7 +936,7 @@ List certificate added to Fleet. Currently, they can only be added via GitOps.
|
||||
|
||||
| Name | Type | In | Description |
|
||||
| ----------| ------- | ---- | -------------------------------------------------------------- |
|
||||
| fleet | string | query | _Available in Fleet Premium_. The fleet ID to filter profiles. |
|
||||
| fleet_id | integer | query | _Available in Fleet Premium_. The fleet ID to filter certificate templates. |
|
||||
| page | integer | query | Page number of the results to fetch. |
|
||||
| per_page | integer | query | Results per page. |
|
||||
| order_key | string | query | What to order results by. Allowed field is `id`. |
|
||||
|
||||
@@ -171,7 +171,7 @@ func (ds *Datastore) GetCertificateTemplatesByTeamID(ctx context.Context, teamID
|
||||
return nil, nil, ctxerr.Wrap(ctx, err, "apply list options")
|
||||
}
|
||||
|
||||
var templates []*fleet.CertificateTemplateResponseSummary
|
||||
templates := []*fleet.CertificateTemplateResponseSummary{}
|
||||
if err := sqlx.SelectContext(ctx, ds.reader(ctx), &templates, stmtPaged, args...); err != nil {
|
||||
return nil, nil, ctxerr.Wrap(ctx, err, "getting certificate_templates by team_id")
|
||||
}
|
||||
|
||||
@@ -488,6 +488,7 @@ func testGetCertificateTemplatesByTeamID(t *testing.T, ds *Datastore) {
|
||||
func(t *testing.T, ds *Datastore) {
|
||||
templates, _, err := ds.GetCertificateTemplatesByTeamID(ctx, 1, fleet.ListOptions{Page: 0, PerPage: 10})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, templates, "expected empty slice, not nil (nil marshals to JSON null)")
|
||||
require.Len(t, templates, 0)
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user