From f5c59ae3b403bdc33df34f69ebd8b34a2c1faa2b Mon Sep 17 00:00:00 2001 From: Scott Gress Date: Mon, 11 May 2026 11:41:28 -0700 Subject: [PATCH] Fix google calendar key validation (#44556) **Related issue:** Resolves #42886 # Checklist for submitter If some of the following don't apply, delete the relevant line. - [X] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. ## Testing - [X] Added/updated automated tests - [X] QA'd all new/changed functionality manually - [X] gitops run with extra keys (besides `client_email` and `private_key` in `api_key_json` fails on main, passes on this branch - [X] gitops run with missing `client_email` or `private_key` in `api_key_json` still fails gitops (including dry run) - [X] gitops run with extra keys sibling to api_key_json still fails as expected ## Summary by CodeRabbit * **Bug Fixes** * Corrected GitOps validation so Google Calendar API key JSON no longer rejects valid nested keys; required-field validation for the integration still enforced. * **Tests** * Added test coverage to ensure nested unknown keys are accepted while sibling-level unknown fields are reported as validation errors. [![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/44556) --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Tim Lee --- .../42886-fix-google-cal-gitops-validation | 1 + pkg/spec/gitops_validate_test.go | 33 +++++++++++-------- server/fleet/integrations.go | 16 +++------ 3 files changed, 26 insertions(+), 24 deletions(-) create mode 100644 changes/42886-fix-google-cal-gitops-validation diff --git a/changes/42886-fix-google-cal-gitops-validation b/changes/42886-fix-google-cal-gitops-validation new file mode 100644 index 0000000000..5a163142e6 --- /dev/null +++ b/changes/42886-fix-google-cal-gitops-validation @@ -0,0 +1 @@ +- Fixed issue where GitOps would incorrectly reject keys in Google Calendar API key JSON diff --git a/pkg/spec/gitops_validate_test.go b/pkg/spec/gitops_validate_test.go index 238e451cb2..4bf39946a6 100644 --- a/pkg/spec/gitops_validate_test.go +++ b/pkg/spec/gitops_validate_test.go @@ -129,16 +129,25 @@ func TestValidateUnknownKeys(t *testing.T) { assert.Len(t, errs, 2) }) - t.Run("ValidKeysProvider accepts declared keys", func(t *testing.T) { - // GoogleCalendarApiKey implements ValidKeysProvider to declare accepted - // keys for its custom JSON marshaling. + t.Run("api_key_json keys are not validated", func(t *testing.T) { + // GoogleCalendarApiKey accepts the full Google service-account JSON blob, + // so unknown-key validation is intentionally skipped for its contents. data := map[string]any{ "google_calendar": []any{ map[string]any{ "domain": "example.com", "api_key_json": map[string]any{ - "client_email": "test@example.com", - "private_key": "some value", + "client_email": "test@example.com", + "private_key": "some value", + "type": "service_account", + "project_id": "fleet-dogfood", + "private_key_id": "abc123", + "client_id": "1234567890", + "auth_uri": "https://accounts.google.com/o/oauth2/auth", + "token_uri": "https://oauth2.googleapis.com/token", + "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", + "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/foo", + "universe_domain": "googleapis.com", }, }, }, @@ -147,22 +156,20 @@ func TestValidateUnknownKeys(t *testing.T) { assert.Empty(t, errs) }) - t.Run("ValidKeysProvider rejects undeclared keys", func(t *testing.T) { + t.Run("unknown keys at google_calendar entry level are rejected", func(t *testing.T) { + // Skipping validation for api_key_json must not leak into siblings. data := map[string]any{ "google_calendar": []any{ map[string]any{ - "domain": "example.com", - "api_key_json": map[string]any{ - "client_email": "test@example.com", - "private_key": "nothing to see here", - "bad_field": "unknown", - }, + "domain": "example.com", + "api_key_json": map[string]any{"client_email": "x", "private_key": "y"}, + "bad_sibling": true, }, }, } errs := validateUnknownKeys(data, reflect.TypeFor[fleet.Integrations](), []string{"org_settings", "integrations"}, "test.yml") require.Len(t, errs, 1) - assert.Contains(t, errs[0].Error(), "bad_field") + assert.Contains(t, errs[0].Error(), "bad_sibling") }) t.Run("scalar data no errors", func(t *testing.T) { diff --git a/server/fleet/integrations.go b/server/fleet/integrations.go index d9ea478cc9..2027b34ae8 100644 --- a/server/fleet/integrations.go +++ b/server/fleet/integrations.go @@ -389,14 +389,15 @@ const ( GoogleCalendarPrivateKey = "private_key" ) -// googleCalendarKeyNames lists all valid JSON keys for GoogleCalendarApiKey, -// used by ValidKeys() for gitops unknown-key validation. -var googleCalendarKeyNames = []string{GoogleCalendarEmail, GoogleCalendarPrivateKey} - // GoogleCalendarApiKey is a custom type for the Google Calendar API key JSON. // It handles JSON marshaling/unmarshaling with support for masking sensitive data. // When marshaled in masked state, it serializes to just "********". // When unmarshaled, it accepts either "********" (indicating masked/preserve) or a JSON object. +// +// GitOps unknown-key validation is intentionally skipped for this type: users +// typically paste the full Google service-account JSON blob (which contains many +// keys beyond the two Fleet uses), and ValidateGoogleCalendarIntegrations still +// enforces that client_email and private_key are present. type GoogleCalendarApiKey struct { // Values contains the actual API key fields when not masked Values map[string]string @@ -404,13 +405,6 @@ type GoogleCalendarApiKey struct { masked bool } -// ValidKeys returns the set of accepted JSON keys for this type. -// This is used by gitops validation to check for unknown keys in types -// with custom JSON marshaling. -func (GoogleCalendarApiKey) ValidKeys() []string { - return googleCalendarKeyNames -} - // MarshalJSON implements json.Marshaler. When masked, returns "********". // Otherwise, returns the JSON object representation of the values. func (k GoogleCalendarApiKey) MarshalJSON() ([]byte, error) {