diff --git a/.gitignore b/.gitignore index 9a08aaea9f..20731ec899 100644 --- a/.gitignore +++ b/.gitignore @@ -136,3 +136,6 @@ custom-gcl # dibble (the seed slinger) — binary lives next to source tools/dibble/dibble + +# osv-processor binary built from cmd/osv-processor +/osv-processor diff --git a/ee/server/googleworkspace/google_workspace.go b/ee/server/googleworkspace/google_workspace.go index 293d7df9fc..2a29fba14f 100644 --- a/ee/server/googleworkspace/google_workspace.go +++ b/ee/server/googleworkspace/google_workspace.go @@ -209,8 +209,8 @@ func groupDisplayName(g *directory.Group) string { // (case-insensitive) and guaranteeing the primary email is present and flagged // primary — the host↔user linking matches on the primary email. func mapEmails(primaryEmail string, raw []directoryEmail) []fleet.ScimUserEmail { - seen := make(map[string]int, len(raw)+1) - out := make([]fleet.ScimUserEmail, 0, len(raw)+1) + seen := make(map[string]int, len(raw)) + out := make([]fleet.ScimUserEmail, 0, len(raw)) for _, e := range raw { addr := strings.TrimSpace(e.Address) if addr == "" { diff --git a/osv-processor b/osv-processor deleted file mode 100755 index 60fcbbfac4..0000000000 Binary files a/osv-processor and /dev/null differ diff --git a/server/fleet/fleet_vars.go b/server/fleet/fleet_vars.go index bf8910c411..4bece1d261 100644 --- a/server/fleet/fleet_vars.go +++ b/server/fleet/fleet_vars.go @@ -55,7 +55,7 @@ func MaybeExpand(s string, mapping func(string, int, int) (string, bool)) string for j := 0; j < len(s); j++ { if s[j] == '$' && j+1 < len(s) { if buf == nil { - buf = make([]byte, 0, 2*len(s)) + buf = make([]byte, 0, len(s)) } buf = append(buf, s[i:j]...) name, w := getShellName(s[j+1:]) diff --git a/server/mdm/apple/profile_processor.go b/server/mdm/apple/profile_processor.go index 52f79f85d4..07eccb3e8a 100644 --- a/server/mdm/apple/profile_processor.go +++ b/server/mdm/apple/profile_processor.go @@ -453,7 +453,7 @@ func preprocessProfileContents( ca, ok := smallstepCAs[caName] if !ok { logger.ErrorContext(ctx, "Smallstep SCEP CA not found. "+ - "This error should never happen since we validated/populated CAs earlier", "ca_name", caName) + "This error should never happen since we validated/populated CAs earlier", "known_cas", profiles.KnownCANames(smallstepCAs)) continue } logger.DebugContext(ctx, "fetching Smallstep SCEP challenge", "host_uuid", hostUUID, "profile_uuid", profUUID) @@ -571,7 +571,7 @@ func preprocessProfileContents( ca, ok := digiCertCAs[caName] if !ok { logger.ErrorContext(ctx, "Custom DigiCert CA not found. "+ - "This error should never happen since we validated/populated CAs earlier", "ca_name", caName) + "This error should never happen since we validated/populated CAs earlier", "known_cas", profiles.KnownCANames(digiCertCAs)) continue } caCopy := *ca diff --git a/server/mdm/profiles/profile_variables.go b/server/mdm/profiles/profile_variables.go index 5baa8e41a2..9e0dd876c4 100644 --- a/server/mdm/profiles/profile_variables.go +++ b/server/mdm/profiles/profile_variables.go @@ -6,8 +6,10 @@ import ( "encoding/xml" "fmt" "log/slog" + "maps" "net/url" "regexp" + "slices" "strings" "github.com/fleetdm/fleet/v4/server/contexts/ctxerr" @@ -29,12 +31,20 @@ Once more is needed it should be placed here, and the main replacement logic can under server/service folder. Inside the `preprocessProfileContents` under the `fleetVarLoop` loop. */ +// KnownCANames returns the configured CA names for logging. Names extracted +// from profile contents must not be logged: after variable substitution the +// contents can embed secrets (e.g. certificate passwords), so a malformed +// variable name derived from them could leak secret fragments into logs. +func KnownCANames[T any](cas map[string]T) string { + return strings.Join(slices.Sorted(maps.Keys(cas)), ",") +} + func ReplaceCustomSCEPChallengeVariable(ctx context.Context, logger *slog.Logger, fleetVariable string, customSCEPCAs map[string]*fleet.CustomSCEPProxyCA, profileContents string) (contents string, replacedVariable bool, err error) { caName := strings.TrimPrefix(fleetVariable, string(fleet.FleetVarCustomSCEPChallengePrefix)) ca, ok := customSCEPCAs[caName] if !ok { logger.ErrorContext(ctx, "Custom SCEP CA not found. This error should never happen since we validated/populated CAs earlier", - "ca_name", caName) + "known_cas", KnownCANames(customSCEPCAs)) return "", false, nil } contents, err = ReplaceExactFleetPrefixVariableInXML(string(fleet.FleetVarCustomSCEPChallengePrefix), ca.Name, profileContents, ca.Challenge) @@ -52,7 +62,7 @@ func ReplaceCustomSCEPProxyURLVariable(ctx context.Context, logger *slog.Logger, ca, ok := customSCEPCAs[caName] if !ok { logger.ErrorContext(ctx, "Custom SCEP CA not found. This error should never happen since we validated/populated CAs earlier", - "ca_name", caName) + "known_cas", KnownCANames(customSCEPCAs)) return "", nil, false, nil } // Generate a new SCEP challenge for the profile diff --git a/server/mdm/profiles/profile_variables_test.go b/server/mdm/profiles/profile_variables_test.go new file mode 100644 index 0000000000..b8c06b598c --- /dev/null +++ b/server/mdm/profiles/profile_variables_test.go @@ -0,0 +1,14 @@ +package profiles + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestKnownCANames(t *testing.T) { + assert.Empty(t, KnownCANames[int](nil)) + assert.Empty(t, KnownCANames(map[string]int{})) + assert.Equal(t, "one", KnownCANames(map[string]int{"one": 1})) + assert.Equal(t, "a,b,c", KnownCANames(map[string]struct{}{"c": {}, "a": {}, "b": {}})) +}