Add "No Team" integration configurations for Jira and Zendesk (#32387)
- Added Jira and Zendesk integrations for "No team". (These are not supported by GitOps for teams) # 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 ## New Fleet configuration settings - [x] Setting(s) is/are explicitly excluded from GitOps <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - New Features - Default (No Team) responses now include limited integrations (Jira, Zendesk). - You can configure or clear Jira/Zendesk integrations for the Default (No Team) settings. - Bug Fixes - More consistent handling of the Default (No Team) when fetching team details. - Improved validation to prevent conflicting automation settings between webhooks and integrations. - Documentation - Clarified that Jira/Zendesk integrations aren’t supported via GitOps or at the team level (including No Team). - Noted that certain options (e.g., Google Calendar, Conditional Access) aren’t supported for the Default (No Team). <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
coderabbitai[bot]
parent
a867d2ba5a
commit
31f36a6314
@@ -1 +1 @@
|
||||
Allow configuring webhook and ticket policy automations for "No team"
|
||||
* Allow configuring webhook and ticket policy (Jira/Zendesk) automations for "No team"
|
||||
|
||||
@@ -707,6 +707,7 @@ func (cmd *GenerateGitopsCommand) generateIntegrations(filePath string, integrat
|
||||
result = result["team_integrations"].(map[string]interface{})
|
||||
|
||||
// We currently don't support configuring Jira and Zendesk integrations on the team.
|
||||
// https://github.com/fleetdm/fleet/issues/20287
|
||||
delete(result, "jira")
|
||||
delete(result, "zendesk")
|
||||
|
||||
@@ -863,11 +864,13 @@ func (cmd *GenerateGitopsCommand) generateTeamSettings(filePath string, team *fl
|
||||
t := reflect.TypeOf(fleet.TeamConfig{})
|
||||
|
||||
// For "No Team" (team ID 0), only include webhook settings
|
||||
// Note: Jira/Zendesk integrations are not supported at the team level (including No Team)
|
||||
// See https://github.com/fleetdm/fleet/issues/20287
|
||||
if team.ID == 0 {
|
||||
webhookSettings := map[string]interface{}{
|
||||
webhookSettings := map[string]any{
|
||||
"failing_policies_webhook": team.Config.WebhookSettings.FailingPoliciesWebhook,
|
||||
}
|
||||
teamSettings = map[string]interface{}{
|
||||
teamSettings = map[string]any{
|
||||
jsonFieldName(t, "WebhookSettings"): webhookSettings,
|
||||
}
|
||||
return teamSettings, nil
|
||||
|
||||
@@ -1826,8 +1826,53 @@ func (svc *Service) modifyDefaultTeamConfig(ctx context.Context, payload fleet.T
|
||||
config.WebhookSettings = *payload.WebhookSettings
|
||||
}
|
||||
|
||||
// Apply other team config settings if needed in the future
|
||||
// For now, only webhook settings are supported for default team config
|
||||
// Apply integrations if provided
|
||||
if payload.Integrations != nil {
|
||||
// Note: GoogleCalendar and ConditionalAccessEnabled are currently not supported for "No team"
|
||||
// Reject unsupported fields for "No team"
|
||||
if payload.Integrations.GoogleCalendar != nil ||
|
||||
payload.Integrations.ConditionalAccessEnabled.Set {
|
||||
return nil, fleet.NewInvalidArgumentError("integrations",
|
||||
"google_calendar and conditional_access_enabled are not supported for \"No team\"")
|
||||
}
|
||||
|
||||
// Get app config for integration validation (needed even if clearing integrations)
|
||||
appCfg, err := svc.ds.AppConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if payload.Integrations.Jira != nil || payload.Integrations.Zendesk != nil {
|
||||
// the team integrations must reference an existing global config integration.
|
||||
if _, err := payload.Integrations.MatchWithIntegrations(appCfg.Integrations); err != nil {
|
||||
return nil, fleet.NewInvalidArgumentError("integrations", err.Error())
|
||||
}
|
||||
|
||||
// integrations must be unique
|
||||
if err := payload.Integrations.Validate(); err != nil {
|
||||
return nil, fleet.NewInvalidArgumentError("integrations", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Always update integrations when provided (even if empty arrays to clear them)
|
||||
config.Integrations.Jira = payload.Integrations.Jira
|
||||
config.Integrations.Zendesk = payload.Integrations.Zendesk
|
||||
}
|
||||
|
||||
// Validate mutual exclusivity of automations if either webhooks or integrations were updated
|
||||
if payload.WebhookSettings != nil || payload.Integrations != nil {
|
||||
// must validate that at most only one automation is enabled for each
|
||||
// supported feature - by now the updated payload has been applied to config.
|
||||
invalid := &fleet.InvalidArgumentError{}
|
||||
fleet.ValidateEnabledFailingPoliciesTeamIntegrations(
|
||||
config.WebhookSettings.FailingPoliciesWebhook,
|
||||
config.Integrations,
|
||||
invalid,
|
||||
)
|
||||
if invalid.HasErrors() {
|
||||
return nil, ctxerr.Wrap(ctx, invalid)
|
||||
}
|
||||
}
|
||||
|
||||
// Save the configuration
|
||||
if err := svc.ds.SaveDefaultTeamConfig(ctx, config); err != nil {
|
||||
|
||||
@@ -465,6 +465,7 @@ func parseNoTeamSettings(raw json.RawMessage, result *GitOps, filePath string, m
|
||||
}
|
||||
|
||||
// For No Team, only webhook_settings is allowed in team_settings
|
||||
// Jira/Zendesk integrations are not supported in gitops: https://github.com/fleetdm/fleet/issues/20287
|
||||
// Check for any other keys and error if found
|
||||
for key := range teamSettingsMap {
|
||||
if key != "webhook_settings" {
|
||||
|
||||
+26
-3
@@ -182,11 +182,15 @@ type TeamWebhookSettings struct {
|
||||
}
|
||||
|
||||
// DefaultTeam represents the limited team information returned for team ID 0
|
||||
// Structure matches Team to be JSON-compatible with existing tests
|
||||
type DefaultTeam struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
DefaultTeamConfig // Embedded struct - fields appear at top level in JSON
|
||||
}
|
||||
|
||||
type DefaultTeamConfig struct {
|
||||
WebhookSettings DefaultTeamWebhookSettings `json:"webhook_settings"`
|
||||
Integrations DefaultTeamIntegrations `json:"integrations"`
|
||||
}
|
||||
|
||||
// DefaultTeamWebhookSettings contains webhook settings for team ID 0
|
||||
@@ -194,6 +198,12 @@ type DefaultTeamWebhookSettings struct {
|
||||
FailingPoliciesWebhook FailingPoliciesWebhookSettings `json:"failing_policies_webhook"`
|
||||
}
|
||||
|
||||
// DefaultTeamIntegrations contains only the integrations supported for team ID 0
|
||||
type DefaultTeamIntegrations struct {
|
||||
Jira []*TeamJiraIntegration `json:"jira"`
|
||||
Zendesk []*TeamZendeskIntegration `json:"zendesk"`
|
||||
}
|
||||
|
||||
type TeamSpecSoftwareAsset struct {
|
||||
Path string `json:"path"`
|
||||
}
|
||||
@@ -336,9 +346,22 @@ func (t *TeamConfig) Copy() *TeamConfig {
|
||||
clone.AgentOptions = &agentOptionsCopy
|
||||
}
|
||||
|
||||
// Deep copy WebhookSettings
|
||||
if t.WebhookSettings.HostStatusWebhook != nil {
|
||||
hostStatusCopy := *t.WebhookSettings.HostStatusWebhook
|
||||
clone.WebhookSettings.HostStatusWebhook = &hostStatusCopy
|
||||
}
|
||||
if len(t.WebhookSettings.FailingPoliciesWebhook.PolicyIDs) > 0 {
|
||||
clone.WebhookSettings.FailingPoliciesWebhook.PolicyIDs = make([]uint, len(t.WebhookSettings.FailingPoliciesWebhook.PolicyIDs))
|
||||
copy(clone.WebhookSettings.FailingPoliciesWebhook.PolicyIDs, t.WebhookSettings.FailingPoliciesWebhook.PolicyIDs)
|
||||
}
|
||||
|
||||
// Deep copy integrations
|
||||
clone.Integrations = t.Integrations.Copy()
|
||||
|
||||
// Deep copy Features
|
||||
clone.Features = *t.Features.Copy()
|
||||
|
||||
// Deep copy all MDM fields (includes macOS/windows custom settings and setup software)
|
||||
clone.MDM = *t.MDM.Copy()
|
||||
|
||||
|
||||
@@ -303,3 +303,85 @@ func TestTeamMDMCopy(t *testing.T) {
|
||||
require.NotSame(t, tm.MacOSSettings.DeprecatedEnableDiskEncryption, clone.MacOSSettings.DeprecatedEnableDiskEncryption)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTeamConfigCopy(t *testing.T) {
|
||||
t.Run("nil receiver", func(t *testing.T) {
|
||||
var tc *TeamConfig
|
||||
require.Nil(t, tc.Copy())
|
||||
})
|
||||
|
||||
t.Run("deep copy webhook settings", func(t *testing.T) {
|
||||
tc := &TeamConfig{
|
||||
WebhookSettings: TeamWebhookSettings{
|
||||
HostStatusWebhook: &HostStatusWebhookSettings{
|
||||
Enable: true,
|
||||
DestinationURL: "https://example.com",
|
||||
HostPercentage: 0.5,
|
||||
DaysCount: 7,
|
||||
},
|
||||
FailingPoliciesWebhook: FailingPoliciesWebhookSettings{
|
||||
Enable: true,
|
||||
DestinationURL: "https://policies.example.com",
|
||||
PolicyIDs: []uint{1, 2, 3},
|
||||
HostBatchSize: 100,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
clone := tc.Copy()
|
||||
require.NotNil(t, clone)
|
||||
require.NotSame(t, tc, clone)
|
||||
|
||||
// Verify deep copy of HostStatusWebhook pointer
|
||||
require.NotSame(t, tc.WebhookSettings.HostStatusWebhook, clone.WebhookSettings.HostStatusWebhook)
|
||||
require.Equal(t, tc.WebhookSettings.HostStatusWebhook, clone.WebhookSettings.HostStatusWebhook)
|
||||
|
||||
// Verify deep copy of PolicyIDs slice
|
||||
require.NotEqual(t,
|
||||
reflect.ValueOf(tc.WebhookSettings.FailingPoliciesWebhook.PolicyIDs).Pointer(),
|
||||
reflect.ValueOf(clone.WebhookSettings.FailingPoliciesWebhook.PolicyIDs).Pointer(),
|
||||
)
|
||||
require.Equal(t, tc.WebhookSettings.FailingPoliciesWebhook.PolicyIDs, clone.WebhookSettings.FailingPoliciesWebhook.PolicyIDs)
|
||||
|
||||
// Modify original and verify clone is unaffected
|
||||
tc.WebhookSettings.HostStatusWebhook.Enable = false
|
||||
tc.WebhookSettings.FailingPoliciesWebhook.PolicyIDs[0] = 999
|
||||
require.True(t, clone.WebhookSettings.HostStatusWebhook.Enable)
|
||||
require.Equal(t, uint(1), clone.WebhookSettings.FailingPoliciesWebhook.PolicyIDs[0])
|
||||
})
|
||||
|
||||
t.Run("deep copy features", func(t *testing.T) {
|
||||
tc := &TeamConfig{
|
||||
Features: Features{
|
||||
EnableHostUsers: true,
|
||||
EnableSoftwareInventory: true,
|
||||
AdditionalQueries: ptr.RawMessage([]byte(`{"query": "test"}`)),
|
||||
DetailQueryOverrides: map[string]*string{
|
||||
"key1": ptr.String("value1"),
|
||||
"key2": ptr.String("value2"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
clone := tc.Copy()
|
||||
require.NotNil(t, clone)
|
||||
require.NotSame(t, tc, clone)
|
||||
|
||||
// Verify deep copy of AdditionalQueries
|
||||
require.NotSame(t, tc.Features.AdditionalQueries, clone.Features.AdditionalQueries)
|
||||
require.Equal(t, tc.Features.AdditionalQueries, clone.Features.AdditionalQueries)
|
||||
|
||||
// Verify deep copy of DetailQueryOverrides map
|
||||
require.NotEqual(t,
|
||||
reflect.ValueOf(tc.Features.DetailQueryOverrides).Pointer(),
|
||||
reflect.ValueOf(clone.Features.DetailQueryOverrides).Pointer(),
|
||||
)
|
||||
require.Equal(t, tc.Features.DetailQueryOverrides, clone.Features.DetailQueryOverrides)
|
||||
|
||||
// Modify original and verify clone is unaffected
|
||||
tc.Features.EnableHostUsers = false
|
||||
*tc.Features.DetailQueryOverrides["key1"] = "modified"
|
||||
require.True(t, clone.Features.EnableHostUsers)
|
||||
require.Equal(t, "value1", *clone.Features.DetailQueryOverrides["key1"])
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2352,20 +2352,23 @@ func (s *integrationEnterpriseTestSuite) TestNoTeamWebhookConfig() {
|
||||
t := s.T()
|
||||
|
||||
// Test that we can configure webhooks for "No Team" (team ID 0)
|
||||
var tmResp teamResponse
|
||||
// Use a generic response that will work with DefaultTeam
|
||||
var defaultTeamResp struct {
|
||||
Team *fleet.DefaultTeam `json:"team"`
|
||||
}
|
||||
|
||||
// First clear any existing webhook configuration for "No Team"
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/teams/0", fleet.TeamPayload{WebhookSettings: &fleet.TeamWebhookSettings{
|
||||
FailingPoliciesWebhook: fleet.FailingPoliciesWebhookSettings{
|
||||
Enable: false,
|
||||
},
|
||||
}}, http.StatusOK, &tmResp)
|
||||
}}, http.StatusOK, &defaultTeamResp)
|
||||
|
||||
// Get the default team config (team ID 0) - should be disabled now
|
||||
s.DoJSON("GET", "/api/latest/fleet/teams/0", nil, http.StatusOK, &tmResp)
|
||||
require.Equal(t, uint(0), tmResp.Team.ID)
|
||||
require.Equal(t, fleet.ReservedNameNoTeam, tmResp.Team.Name)
|
||||
require.False(t, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
s.DoJSON("GET", "/api/latest/fleet/teams/0", nil, http.StatusOK, &defaultTeamResp)
|
||||
require.Equal(t, uint(0), defaultTeamResp.Team.ID)
|
||||
require.Equal(t, fleet.ReservedNameNoTeam, defaultTeamResp.Team.Name)
|
||||
require.False(t, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
|
||||
// Configure webhook settings for "No Team"
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/teams/0", fleet.TeamPayload{WebhookSettings: &fleet.TeamWebhookSettings{
|
||||
@@ -2375,23 +2378,25 @@ func (s *integrationEnterpriseTestSuite) TestNoTeamWebhookConfig() {
|
||||
PolicyIDs: []uint{1, 2, 3},
|
||||
HostBatchSize: 100,
|
||||
},
|
||||
}}, http.StatusOK, &tmResp)
|
||||
require.Equal(t, uint(0), tmResp.Team.ID)
|
||||
require.Equal(t, fleet.ReservedNameNoTeam, tmResp.Team.Name)
|
||||
require.True(t, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
require.Equal(t, "https://example.com/no-team-webhook", tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.DestinationURL)
|
||||
require.Equal(t, []uint{1, 2, 3}, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.PolicyIDs)
|
||||
require.Equal(t, 100, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.HostBatchSize)
|
||||
}}, http.StatusOK, &defaultTeamResp)
|
||||
require.Equal(t, uint(0), defaultTeamResp.Team.ID)
|
||||
require.Equal(t, fleet.ReservedNameNoTeam, defaultTeamResp.Team.Name)
|
||||
require.True(t, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
require.Equal(t, "https://example.com/no-team-webhook", defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.DestinationURL)
|
||||
require.Equal(t, []uint{1, 2, 3}, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.PolicyIDs)
|
||||
require.Equal(t, 100, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.HostBatchSize)
|
||||
|
||||
// Get the config again to verify it persisted
|
||||
tmResp = teamResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/teams/0", nil, http.StatusOK, &tmResp)
|
||||
require.Equal(t, uint(0), tmResp.Team.ID)
|
||||
require.Equal(t, fleet.ReservedNameNoTeam, tmResp.Team.Name)
|
||||
require.True(t, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
require.Equal(t, "https://example.com/no-team-webhook", tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.DestinationURL)
|
||||
require.Equal(t, []uint{1, 2, 3}, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.PolicyIDs)
|
||||
require.Equal(t, 100, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.HostBatchSize)
|
||||
defaultTeamResp = struct {
|
||||
Team *fleet.DefaultTeam `json:"team"`
|
||||
}{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/teams/0", nil, http.StatusOK, &defaultTeamResp)
|
||||
require.Equal(t, uint(0), defaultTeamResp.Team.ID)
|
||||
require.Equal(t, fleet.ReservedNameNoTeam, defaultTeamResp.Team.Name)
|
||||
require.True(t, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
require.Equal(t, "https://example.com/no-team-webhook", defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.DestinationURL)
|
||||
require.Equal(t, []uint{1, 2, 3}, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.PolicyIDs)
|
||||
require.Equal(t, 100, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.HostBatchSize)
|
||||
|
||||
// Update the webhook settings
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/teams/0", fleet.TeamPayload{WebhookSettings: &fleet.TeamWebhookSettings{
|
||||
@@ -2401,19 +2406,19 @@ func (s *integrationEnterpriseTestSuite) TestNoTeamWebhookConfig() {
|
||||
PolicyIDs: []uint{4, 5},
|
||||
HostBatchSize: 200,
|
||||
},
|
||||
}}, http.StatusOK, &tmResp)
|
||||
require.False(t, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
require.Equal(t, "https://example.com/updated", tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.DestinationURL)
|
||||
require.Equal(t, []uint{4, 5}, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.PolicyIDs)
|
||||
require.Equal(t, 200, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.HostBatchSize)
|
||||
}}, http.StatusOK, &defaultTeamResp)
|
||||
require.False(t, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
require.Equal(t, "https://example.com/updated", defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.DestinationURL)
|
||||
require.Equal(t, []uint{4, 5}, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.PolicyIDs)
|
||||
require.Equal(t, 200, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.HostBatchSize)
|
||||
|
||||
// Clear the webhook settings
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/teams/0", fleet.TeamPayload{WebhookSettings: &fleet.TeamWebhookSettings{
|
||||
FailingPoliciesWebhook: fleet.FailingPoliciesWebhookSettings{
|
||||
Enable: false,
|
||||
},
|
||||
}}, http.StatusOK, &tmResp)
|
||||
require.False(t, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
}}, http.StatusOK, &defaultTeamResp)
|
||||
require.False(t, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
}
|
||||
|
||||
func (s *integrationEnterpriseTestSuite) TestNoTeamFailingPolicyWebhookTrigger() {
|
||||
@@ -2471,7 +2476,9 @@ func (s *integrationEnterpriseTestSuite) TestNoTeamFailingPolicyWebhookTrigger()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Configure webhook for "No Team" - only include pol1 and pol2
|
||||
var tmResp teamResponse
|
||||
var defaultTeamResp struct {
|
||||
Team *fleet.DefaultTeam `json:"team"`
|
||||
}
|
||||
s.DoJSON("PATCH", "/api/latest/fleet/teams/0", fleet.TeamPayload{WebhookSettings: &fleet.TeamWebhookSettings{
|
||||
FailingPoliciesWebhook: fleet.FailingPoliciesWebhookSettings{
|
||||
Enable: true,
|
||||
@@ -2479,8 +2486,8 @@ func (s *integrationEnterpriseTestSuite) TestNoTeamFailingPolicyWebhookTrigger()
|
||||
PolicyIDs: []uint{noTeamPol1.ID, noTeamPol2.ID}, // pol3 is NOT included
|
||||
HostBatchSize: 100,
|
||||
},
|
||||
}}, http.StatusOK, &tmResp)
|
||||
require.True(t, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
}}, http.StatusOK, &defaultTeamResp)
|
||||
require.True(t, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
|
||||
// Record policy results - all fail
|
||||
err = s.ds.RecordPolicyQueryExecutions(ctx, host, map[uint]*bool{
|
||||
@@ -2507,13 +2514,15 @@ func (s *integrationEnterpriseTestSuite) TestNoTeamFailingPolicyWebhookTrigger()
|
||||
require.Empty(t, pfs, "empty reset should not mark any policies")
|
||||
|
||||
// Test that we can configure and retrieve the "No Team" webhook settings
|
||||
tmResp = teamResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/teams/0", nil, http.StatusOK, &tmResp)
|
||||
require.Equal(t, uint(0), tmResp.Team.ID)
|
||||
require.Equal(t, fleet.ReservedNameNoTeam, tmResp.Team.Name)
|
||||
require.True(t, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
require.Equal(t, "https://example.com/webhook", tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.DestinationURL)
|
||||
require.Equal(t, []uint{noTeamPol1.ID, noTeamPol2.ID}, tmResp.Team.Config.WebhookSettings.FailingPoliciesWebhook.PolicyIDs)
|
||||
defaultTeamResp = struct {
|
||||
Team *fleet.DefaultTeam `json:"team"`
|
||||
}{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/teams/0", nil, http.StatusOK, &defaultTeamResp)
|
||||
require.Equal(t, uint(0), defaultTeamResp.Team.ID)
|
||||
require.Equal(t, fleet.ReservedNameNoTeam, defaultTeamResp.Team.Name)
|
||||
require.True(t, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.Enable)
|
||||
require.Equal(t, "https://example.com/webhook", defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.DestinationURL)
|
||||
require.Equal(t, []uint{noTeamPol1.ID, noTeamPol2.ID}, defaultTeamResp.Team.WebhookSettings.FailingPoliciesWebhook.PolicyIDs)
|
||||
|
||||
// Now reset by team ID 0 to mark policies for automation
|
||||
s.DoJSON("POST", "/api/latest/fleet/automations/reset", resetAutomationRequest{
|
||||
|
||||
+30
-28
@@ -67,39 +67,39 @@ type getTeamResponse struct {
|
||||
|
||||
func (r getTeamResponse) Error() error { return r.Err }
|
||||
|
||||
type getDefaultTeamResponse struct {
|
||||
type defaultTeamResponse struct {
|
||||
Team *fleet.DefaultTeam `json:"team"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r getDefaultTeamResponse) Error() error { return r.Err }
|
||||
func (r defaultTeamResponse) Error() error { return r.Err }
|
||||
|
||||
func getTeamEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) {
|
||||
req := request.(*getTeamRequest)
|
||||
|
||||
// Special handling for team ID 0 - return limited fields
|
||||
if req.ID == 0 {
|
||||
team, err := svc.GetTeam(ctx, req.ID)
|
||||
if err != nil {
|
||||
return getDefaultTeamResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
// Convert to DefaultTeam with limited fields
|
||||
defaultTeam := &fleet.DefaultTeam{
|
||||
ID: team.ID,
|
||||
Name: team.Name,
|
||||
WebhookSettings: fleet.DefaultTeamWebhookSettings{
|
||||
FailingPoliciesWebhook: team.Config.WebhookSettings.FailingPoliciesWebhook,
|
||||
},
|
||||
}
|
||||
return getDefaultTeamResponse{Team: defaultTeam}, nil
|
||||
}
|
||||
|
||||
// Regular team handling
|
||||
team, err := svc.GetTeam(ctx, req.ID)
|
||||
if err != nil {
|
||||
return getTeamResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
// Special handling for team ID 0 - return DefaultTeam structure
|
||||
if team.ID == 0 {
|
||||
defaultTeam := &fleet.DefaultTeam{
|
||||
ID: team.ID,
|
||||
Name: team.Name,
|
||||
DefaultTeamConfig: fleet.DefaultTeamConfig{
|
||||
WebhookSettings: fleet.DefaultTeamWebhookSettings{
|
||||
FailingPoliciesWebhook: team.Config.WebhookSettings.FailingPoliciesWebhook,
|
||||
},
|
||||
Integrations: fleet.DefaultTeamIntegrations{
|
||||
Jira: team.Config.Integrations.Jira,
|
||||
Zendesk: team.Config.Integrations.Zendesk,
|
||||
},
|
||||
},
|
||||
}
|
||||
return defaultTeamResponse{Team: defaultTeam}, nil
|
||||
}
|
||||
|
||||
return getTeamResponse{Team: team}, nil
|
||||
}
|
||||
|
||||
@@ -157,10 +157,6 @@ func modifyTeamEndpoint(ctx context.Context, request interface{}, svc fleet.Serv
|
||||
req := request.(*modifyTeamRequest)
|
||||
team, err := svc.ModifyTeam(ctx, req.ID, req.TeamPayload)
|
||||
if err != nil {
|
||||
// For team ID 0, return appropriate error response
|
||||
if req.ID == 0 {
|
||||
return getDefaultTeamResponse{Err: err}, nil
|
||||
}
|
||||
return teamResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
@@ -170,11 +166,17 @@ func modifyTeamEndpoint(ctx context.Context, request interface{}, svc fleet.Serv
|
||||
defaultTeam := &fleet.DefaultTeam{
|
||||
ID: team.ID,
|
||||
Name: team.Name,
|
||||
WebhookSettings: fleet.DefaultTeamWebhookSettings{
|
||||
FailingPoliciesWebhook: team.Config.WebhookSettings.FailingPoliciesWebhook,
|
||||
DefaultTeamConfig: fleet.DefaultTeamConfig{
|
||||
WebhookSettings: fleet.DefaultTeamWebhookSettings{
|
||||
FailingPoliciesWebhook: team.Config.WebhookSettings.FailingPoliciesWebhook,
|
||||
},
|
||||
Integrations: fleet.DefaultTeamIntegrations{
|
||||
Jira: team.Config.Integrations.Jira,
|
||||
Zendesk: team.Config.Integrations.Zendesk,
|
||||
},
|
||||
},
|
||||
}
|
||||
return getDefaultTeamResponse{Team: defaultTeam}, nil
|
||||
return defaultTeamResponse{Team: defaultTeam}, nil
|
||||
}
|
||||
|
||||
return teamResponse{Team: team}, err
|
||||
|
||||
@@ -161,7 +161,7 @@ func (j *Jira) getClient(ctx context.Context, args jiraArgs) (JiraClient, error)
|
||||
// configuration has changed since it was created.
|
||||
var opts *externalsvc.JiraOptions
|
||||
if useTeamCfg {
|
||||
tm, err := j.Datastore.Team(ctx, teamID)
|
||||
tm, err := j.Datastore.TeamWithoutExtras(ctx, teamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ func TestJiraRun(t *testing.T) {
|
||||
},
|
||||
}}, nil
|
||||
}
|
||||
ds.TeamFunc = func(ctx context.Context, tid uint) (*fleet.Team, error) {
|
||||
ds.TeamWithoutExtrasFunc = func(ctx context.Context, tid uint) (*fleet.Team, error) {
|
||||
if tid != 123 {
|
||||
return nil, errors.New("unexpected team id")
|
||||
}
|
||||
@@ -378,7 +378,7 @@ func TestJiraRunClientUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
var teamCount int
|
||||
ds.TeamFunc = func(ctx context.Context, tid uint) (*fleet.Team, error) {
|
||||
ds.TeamWithoutExtrasFunc = func(ctx context.Context, tid uint) (*fleet.Team, error) {
|
||||
teamCount++
|
||||
|
||||
if tid != 123 {
|
||||
|
||||
@@ -157,7 +157,7 @@ func (z *Zendesk) getClient(ctx context.Context, args zendeskArgs) (ZendeskClien
|
||||
// configuration has changed since it was created.
|
||||
var opts *externalsvc.ZendeskOptions
|
||||
if useTeamCfg {
|
||||
tm, err := z.Datastore.Team(ctx, teamID)
|
||||
tm, err := z.Datastore.TeamWithoutExtras(ctx, teamID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ func TestZendeskRun(t *testing.T) {
|
||||
},
|
||||
}}, nil
|
||||
}
|
||||
ds.TeamFunc = func(ctx context.Context, tid uint) (*fleet.Team, error) {
|
||||
ds.TeamWithoutExtrasFunc = func(ctx context.Context, tid uint) (*fleet.Team, error) {
|
||||
if tid != 123 {
|
||||
return nil, errors.New("unexpected team id")
|
||||
}
|
||||
@@ -357,7 +357,7 @@ func TestZendeskRunClientUpdate(t *testing.T) {
|
||||
}
|
||||
|
||||
var teamCount int
|
||||
ds.TeamFunc = func(ctx context.Context, tid uint) (*fleet.Team, error) {
|
||||
ds.TeamWithoutExtrasFunc = func(ctx context.Context, tid uint) (*fleet.Team, error) {
|
||||
teamCount++
|
||||
|
||||
if tid != 123 {
|
||||
|
||||
Reference in New Issue
Block a user