github.com/gravitational/teleport/api@v0.0.0-20240507183017-3110591cbafc/types/plugin_test.go (about) 1 /* 2 Copyright 2023 Gravitational, Inc. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package types 18 19 import ( 20 "testing" 21 "time" 22 23 "github.com/gravitational/trace" 24 "github.com/stretchr/testify/require" 25 ) 26 27 func TestPluginWithoutSecrets(t *testing.T) { 28 spec := PluginSpecV1{ 29 Settings: &PluginSpecV1_SlackAccessPlugin{ 30 SlackAccessPlugin: &PluginSlackAccessSettings{ 31 FallbackChannel: "#access-requests", 32 }, 33 }, 34 } 35 36 creds := &PluginCredentialsV1{ 37 Credentials: &PluginCredentialsV1_Oauth2AccessToken{ 38 Oauth2AccessToken: &PluginOAuth2AccessTokenCredentials{ 39 AccessToken: "access_token", 40 RefreshToken: "refresh_token", 41 Expires: time.Now().UTC(), 42 }, 43 }, 44 } 45 46 plugin := NewPluginV1(Metadata{Name: "foobar"}, spec, creds) 47 plugin = plugin.WithoutSecrets().(*PluginV1) 48 require.Nil(t, plugin.Credentials) 49 } 50 51 func TestPluginOpenAIValidation(t *testing.T) { 52 spec := PluginSpecV1{ 53 Settings: &PluginSpecV1_Openai{}, 54 } 55 testCases := []struct { 56 name string 57 creds *PluginCredentialsV1 58 assertErr require.ErrorAssertionFunc 59 }{ 60 { 61 name: "no credentials", 62 creds: nil, 63 assertErr: func(t require.TestingT, err error, args ...any) { 64 require.Error(t, err) 65 require.True(t, trace.IsBadParameter(err)) 66 require.Contains(t, err.Error(), "credentials must be set") 67 }, 68 }, 69 { 70 name: "no credentials inner", 71 creds: &PluginCredentialsV1{}, 72 assertErr: func(t require.TestingT, err error, args ...any) { 73 require.Error(t, err) 74 require.True(t, trace.IsBadParameter(err)) 75 require.Contains(t, err.Error(), "must be used with the bearer token credential type") 76 }, 77 }, 78 { 79 name: "invalid credential type (oauth2)", 80 creds: &PluginCredentialsV1{ 81 Credentials: &PluginCredentialsV1_Oauth2AccessToken{}, 82 }, 83 assertErr: func(t require.TestingT, err error, args ...any) { 84 require.Error(t, err) 85 require.True(t, trace.IsBadParameter(err)) 86 require.Contains(t, err.Error(), "must be used with the bearer token credential type") 87 }, 88 }, 89 { 90 name: "valid credentials (token)", 91 creds: &PluginCredentialsV1{ 92 Credentials: &PluginCredentialsV1_BearerToken{ 93 BearerToken: &PluginBearerTokenCredentials{ 94 Token: "xxx-abc", 95 }, 96 }, 97 }, 98 assertErr: func(t require.TestingT, err error, args ...any) { 99 require.NoError(t, err) 100 }, 101 }, 102 } 103 104 for _, tc := range testCases { 105 t.Run(tc.name, func(t *testing.T) { 106 plugin := NewPluginV1(Metadata{Name: "foobar"}, spec, tc.creds) 107 tc.assertErr(t, plugin.CheckAndSetDefaults()) 108 }) 109 } 110 } 111 112 func TestPluginOpsgenieValidation(t *testing.T) { 113 testCases := []struct { 114 name string 115 settings *PluginSpecV1_Opsgenie 116 creds *PluginCredentialsV1 117 assertErr require.ErrorAssertionFunc 118 }{ 119 { 120 name: "no settings", 121 settings: &PluginSpecV1_Opsgenie{ 122 Opsgenie: nil, 123 }, 124 creds: nil, 125 assertErr: func(t require.TestingT, err error, args ...any) { 126 require.True(t, trace.IsBadParameter(err)) 127 require.Contains(t, err.Error(), "missing opsgenie settings") 128 }, 129 }, 130 { 131 name: "no api endpint", 132 settings: &PluginSpecV1_Opsgenie{ 133 Opsgenie: &PluginOpsgenieAccessSettings{}, 134 }, 135 creds: nil, 136 assertErr: func(t require.TestingT, err error, args ...any) { 137 require.True(t, trace.IsBadParameter(err)) 138 require.Contains(t, err.Error(), "api endpoint url must be set") 139 }, 140 }, 141 { 142 name: "no static credentials", 143 settings: &PluginSpecV1_Opsgenie{ 144 Opsgenie: &PluginOpsgenieAccessSettings{ 145 ApiEndpoint: "https://test.opsgenie.com", 146 }, 147 }, 148 assertErr: func(t require.TestingT, err error, args ...any) { 149 require.True(t, trace.IsBadParameter(err)) 150 require.Contains(t, err.Error(), "must be used with the static credentials ref type") 151 }, 152 }, 153 { 154 name: "static credentials labels not defined", 155 settings: &PluginSpecV1_Opsgenie{ 156 Opsgenie: &PluginOpsgenieAccessSettings{ 157 ApiEndpoint: "https://test.opsgenie.com", 158 }, 159 }, 160 creds: &PluginCredentialsV1{ 161 Credentials: &PluginCredentialsV1_StaticCredentialsRef{ 162 &PluginStaticCredentialsRef{ 163 Labels: map[string]string{}, 164 }, 165 }, 166 }, 167 assertErr: func(t require.TestingT, err error, args ...any) { 168 require.True(t, trace.IsBadParameter(err)) 169 require.Contains(t, err.Error(), "labels must be specified") 170 }, 171 }, 172 { 173 name: "valid credentials (static credentials)", 174 settings: &PluginSpecV1_Opsgenie{ 175 Opsgenie: &PluginOpsgenieAccessSettings{ 176 ApiEndpoint: "https://test.opsgenie.com", 177 }, 178 }, 179 creds: &PluginCredentialsV1{ 180 Credentials: &PluginCredentialsV1_StaticCredentialsRef{ 181 &PluginStaticCredentialsRef{ 182 Labels: map[string]string{ 183 "label1": "value1", 184 }, 185 }, 186 }, 187 }, 188 assertErr: func(t require.TestingT, err error, args ...any) { 189 require.NoError(t, err) 190 }, 191 }, 192 } 193 194 for _, tc := range testCases { 195 t.Run(tc.name, func(t *testing.T) { 196 plugin := NewPluginV1(Metadata{Name: "foobar"}, PluginSpecV1{ 197 Settings: tc.settings, 198 }, tc.creds) 199 tc.assertErr(t, plugin.CheckAndSetDefaults()) 200 }) 201 } 202 } 203 204 func requireBadParameterWith(msg string) require.ErrorAssertionFunc { 205 return func(t require.TestingT, err error, args ...interface{}) { 206 require.True(t, trace.IsBadParameter(err), "error: %v", err) 207 require.Contains(t, err.Error(), msg) 208 } 209 } 210 211 func TestPluginOktaValidation(t *testing.T) { 212 validSettings := &PluginSpecV1_Okta{ 213 Okta: &PluginOktaSettings{ 214 OrgUrl: "https://test.okta.com", 215 EnableUserSync: true, 216 SsoConnectorId: "some-sso-connector-id", 217 }, 218 } 219 220 validSettingsWithSyncSettings := &PluginSpecV1_Okta{ 221 Okta: &PluginOktaSettings{ 222 OrgUrl: "https://test.okta.com", 223 EnableUserSync: true, 224 SsoConnectorId: "some-sso-connector-id", 225 SyncSettings: &PluginOktaSyncSettings{ 226 SyncAccessLists: true, 227 DefaultOwners: []string{"owner1"}, 228 }, 229 }, 230 } 231 232 validCreds := &PluginCredentialsV1{ 233 Credentials: &PluginCredentialsV1_StaticCredentialsRef{ 234 &PluginStaticCredentialsRef{ 235 Labels: map[string]string{ 236 "label1": "value1", 237 }, 238 }, 239 }, 240 } 241 242 testCases := []struct { 243 name string 244 settings *PluginSpecV1_Okta 245 creds *PluginCredentialsV1 246 assertErr require.ErrorAssertionFunc 247 assertValue func(*testing.T, *PluginOktaSettings) 248 }{ 249 { 250 name: "valid values are preserved", 251 settings: validSettings, 252 creds: validCreds, 253 assertErr: require.NoError, 254 assertValue: func(t *testing.T, settings *PluginOktaSettings) { 255 require.Equal(t, "https://test.okta.com", settings.OrgUrl) 256 require.True(t, settings.EnableUserSync) 257 require.Equal(t, "some-sso-connector-id", settings.SsoConnectorId) 258 require.True(t, settings.SyncSettings.SyncUsers) 259 require.Equal(t, "some-sso-connector-id", settings.SyncSettings.SsoConnectorId) 260 require.False(t, settings.SyncSettings.SyncAccessLists) 261 }, 262 }, 263 { 264 name: "valid values are preserved, import populated", 265 settings: validSettingsWithSyncSettings, 266 creds: validCreds, 267 assertErr: require.NoError, 268 assertValue: func(t *testing.T, settings *PluginOktaSettings) { 269 require.Equal(t, "https://test.okta.com", settings.OrgUrl) 270 require.True(t, settings.EnableUserSync) 271 require.False(t, settings.SyncSettings.SyncUsers) // Mismatch because there are sync settings. 272 require.True(t, settings.SyncSettings.SyncAccessLists) 273 require.ElementsMatch(t, []string{"owner1"}, settings.SyncSettings.DefaultOwners) 274 }, 275 }, 276 { 277 name: "no settings", 278 settings: &PluginSpecV1_Okta{ 279 Okta: nil, 280 }, 281 creds: validCreds, 282 assertErr: requireBadParameterWith("missing Okta settings"), 283 }, 284 { 285 name: "no org URL", 286 settings: &PluginSpecV1_Okta{ 287 Okta: &PluginOktaSettings{}, 288 }, 289 creds: validCreds, 290 assertErr: requireBadParameterWith("org_url must be set"), 291 }, 292 { 293 name: "no credentials inner", 294 settings: &PluginSpecV1_Okta{ 295 Okta: &PluginOktaSettings{ 296 OrgUrl: "https://test.okta.com", 297 }, 298 }, 299 creds: &PluginCredentialsV1{}, 300 assertErr: requireBadParameterWith("must be used with the static credentials ref type"), 301 }, 302 { 303 name: "invalid credential type (oauth2)", 304 settings: &PluginSpecV1_Okta{ 305 Okta: &PluginOktaSettings{ 306 OrgUrl: "https://test.okta.com", 307 }, 308 }, 309 creds: &PluginCredentialsV1{ 310 Credentials: &PluginCredentialsV1_Oauth2AccessToken{}, 311 }, 312 assertErr: requireBadParameterWith("must be used with the static credentials ref type"), 313 }, 314 { 315 name: "invalid credentials (static credentials)", 316 settings: &PluginSpecV1_Okta{ 317 Okta: &PluginOktaSettings{ 318 OrgUrl: "https://test.okta.com", 319 }, 320 }, 321 creds: &PluginCredentialsV1{ 322 Credentials: &PluginCredentialsV1_StaticCredentialsRef{ 323 &PluginStaticCredentialsRef{ 324 Labels: map[string]string{}, 325 }, 326 }, 327 }, 328 assertErr: requireBadParameterWith("labels must be specified"), 329 }, { 330 name: "EnableUserSync defaults to false", 331 settings: &PluginSpecV1_Okta{ 332 Okta: &PluginOktaSettings{ 333 OrgUrl: "https://test.okta.com", 334 }, 335 }, 336 creds: validCreds, 337 assertErr: require.NoError, 338 assertValue: func(t *testing.T, settings *PluginOktaSettings) { 339 require.False(t, settings.EnableUserSync) 340 }, 341 }, { 342 name: "SSO connector ID required for user sync", 343 settings: &PluginSpecV1_Okta{ 344 Okta: &PluginOktaSettings{ 345 OrgUrl: "https://test.okta.com", 346 EnableUserSync: true, 347 }, 348 }, 349 creds: validCreds, 350 assertErr: require.Error, 351 }, { 352 name: "SSO connector ID not required without user sync", 353 settings: &PluginSpecV1_Okta{ 354 Okta: &PluginOktaSettings{ 355 OrgUrl: "https://test.okta.com", 356 EnableUserSync: false, 357 }, 358 }, 359 creds: validCreds, 360 assertErr: require.NoError, 361 assertValue: func(t *testing.T, settings *PluginOktaSettings) { 362 require.False(t, settings.EnableUserSync) 363 require.Empty(t, settings.SsoConnectorId) 364 require.False(t, settings.SyncSettings.SyncUsers) 365 require.Empty(t, settings.SyncSettings.SsoConnectorId) 366 }, 367 }, { 368 name: "import enabled without default owners", 369 settings: &PluginSpecV1_Okta{ 370 Okta: &PluginOktaSettings{ 371 OrgUrl: "https://test.okta.com", 372 EnableUserSync: true, 373 SsoConnectorId: "some-sso-connector-id", 374 SyncSettings: &PluginOktaSyncSettings{ 375 SyncAccessLists: true, 376 }, 377 }, 378 }, 379 creds: validCreds, 380 assertErr: requireBadParameterWith("default owners must be set when access list import is enabled"), 381 }, 382 } 383 384 for _, tc := range testCases { 385 t.Run(tc.name, func(t *testing.T) { 386 plugin := NewPluginV1(Metadata{Name: "foobar"}, PluginSpecV1{ 387 Settings: tc.settings, 388 }, tc.creds) 389 tc.assertErr(t, plugin.CheckAndSetDefaults()) 390 if tc.assertValue != nil { 391 tc.assertValue(t, plugin.Spec.GetOkta()) 392 } 393 }) 394 } 395 } 396 397 func TestPluginJamfValidation(t *testing.T) { 398 testCases := []struct { 399 name string 400 settings *PluginSpecV1_Jamf 401 creds *PluginCredentialsV1 402 assertErr require.ErrorAssertionFunc 403 }{ 404 { 405 name: "no settings", 406 settings: &PluginSpecV1_Jamf{ 407 Jamf: nil, 408 }, 409 creds: nil, 410 assertErr: func(t require.TestingT, err error, args ...any) { 411 require.True(t, trace.IsBadParameter(err)) 412 require.Contains(t, err.Error(), "missing Jamf settings") 413 }, 414 }, 415 { 416 name: "no api Endpoint", 417 settings: &PluginSpecV1_Jamf{ 418 Jamf: &PluginJamfSettings{ 419 JamfSpec: &JamfSpecV1{}, 420 }, 421 }, 422 creds: nil, 423 assertErr: func(t require.TestingT, err error, args ...any) { 424 require.True(t, trace.IsBadParameter(err)) 425 require.Contains(t, err.Error(), "api endpoint must be set") 426 }, 427 }, 428 { 429 name: "no credentials inner", 430 settings: &PluginSpecV1_Jamf{ 431 Jamf: &PluginJamfSettings{ 432 JamfSpec: &JamfSpecV1{ 433 ApiEndpoint: "https://api.testjamfserver.com", 434 }, 435 }, 436 }, 437 creds: &PluginCredentialsV1{}, 438 assertErr: func(t require.TestingT, err error, args ...any) { 439 require.True(t, trace.IsBadParameter(err)) 440 require.Contains(t, err.Error(), "must be used with the static credentials ref type") 441 }, 442 }, 443 { 444 name: "invalid credential type (oauth2)", 445 settings: &PluginSpecV1_Jamf{ 446 Jamf: &PluginJamfSettings{ 447 JamfSpec: &JamfSpecV1{ 448 ApiEndpoint: "https://api.testjamfserver.com", 449 }, 450 }, 451 }, 452 creds: &PluginCredentialsV1{ 453 Credentials: &PluginCredentialsV1_Oauth2AccessToken{}, 454 }, 455 assertErr: func(t require.TestingT, err error, args ...any) { 456 require.True(t, trace.IsBadParameter(err)) 457 require.Contains(t, err.Error(), "must be used with the static credentials ref type") 458 }, 459 }, 460 { 461 name: "invalid credentials (static credentials)", 462 settings: &PluginSpecV1_Jamf{ 463 Jamf: &PluginJamfSettings{ 464 JamfSpec: &JamfSpecV1{ 465 ApiEndpoint: "https://api.testjamfserver.com", 466 }, 467 }, 468 }, 469 creds: &PluginCredentialsV1{ 470 Credentials: &PluginCredentialsV1_StaticCredentialsRef{ 471 &PluginStaticCredentialsRef{ 472 Labels: map[string]string{}, 473 }, 474 }, 475 }, 476 assertErr: func(t require.TestingT, err error, args ...any) { 477 require.True(t, trace.IsBadParameter(err)) 478 require.Contains(t, err.Error(), "labels must be specified") 479 }, 480 }, 481 { 482 name: "valid credentials (static credentials)", 483 settings: &PluginSpecV1_Jamf{ 484 Jamf: &PluginJamfSettings{ 485 JamfSpec: &JamfSpecV1{ 486 ApiEndpoint: "https://api.testjamfserver.com", 487 }, 488 }, 489 }, 490 creds: &PluginCredentialsV1{ 491 Credentials: &PluginCredentialsV1_StaticCredentialsRef{ 492 &PluginStaticCredentialsRef{ 493 Labels: map[string]string{ 494 "label1": "value1", 495 }, 496 }, 497 }, 498 }, 499 assertErr: func(t require.TestingT, err error, args ...any) { 500 require.NoError(t, err) 501 }, 502 }, 503 } 504 505 for _, tc := range testCases { 506 t.Run(tc.name, func(t *testing.T) { 507 plugin := NewPluginV1(Metadata{Name: "foobar"}, PluginSpecV1{ 508 Settings: tc.settings, 509 }, tc.creds) 510 tc.assertErr(t, plugin.CheckAndSetDefaults()) 511 }) 512 } 513 } 514 515 func TestPluginMattermostValidation(t *testing.T) { 516 defaultSettings := &PluginSpecV1_Mattermost{ 517 Mattermost: &PluginMattermostSettings{ 518 ServerUrl: "https://test.mattermost.com", 519 Team: "team-llama", 520 Channel: "teleport", 521 }, 522 } 523 524 testCases := []struct { 525 name string 526 settings *PluginSpecV1_Mattermost 527 creds *PluginCredentialsV1 528 assertErr require.ErrorAssertionFunc 529 }{ 530 { 531 name: "no settings", 532 settings: &PluginSpecV1_Mattermost{ 533 Mattermost: nil, 534 }, 535 creds: nil, 536 assertErr: func(t require.TestingT, err error, args ...any) { 537 require.True(t, trace.IsBadParameter(err)) 538 require.Contains(t, err.Error(), "missing Mattermost settings") 539 }, 540 }, 541 { 542 name: "no server url", 543 settings: &PluginSpecV1_Mattermost{ 544 Mattermost: &PluginMattermostSettings{}, 545 }, 546 creds: nil, 547 assertErr: func(t require.TestingT, err error, args ...any) { 548 require.True(t, trace.IsBadParameter(err)) 549 require.Contains(t, err.Error(), "server url is required") 550 }, 551 }, 552 { 553 name: "no team", 554 settings: &PluginSpecV1_Mattermost{ 555 Mattermost: &PluginMattermostSettings{ 556 ServerUrl: "https://test.mattermost.com", 557 Channel: "some-channel", 558 }, 559 }, 560 creds: nil, 561 assertErr: func(t require.TestingT, err error, args ...any) { 562 require.True(t, trace.IsBadParameter(err)) 563 require.Contains(t, err.Error(), "team is required") 564 }, 565 }, 566 { 567 name: "no channel", 568 settings: &PluginSpecV1_Mattermost{ 569 Mattermost: &PluginMattermostSettings{ 570 ServerUrl: "https://test.mattermost.com", 571 Team: "team-llama", 572 }, 573 }, 574 creds: nil, 575 assertErr: func(t require.TestingT, err error, args ...any) { 576 require.True(t, trace.IsBadParameter(err)) 577 require.Contains(t, err.Error(), "channel is required") 578 }, 579 }, 580 { 581 name: "no credentials inner", 582 settings: defaultSettings, 583 creds: &PluginCredentialsV1{}, 584 assertErr: func(t require.TestingT, err error, args ...any) { 585 require.True(t, trace.IsBadParameter(err)) 586 require.Contains(t, err.Error(), "must be used with the static credentials ref type") 587 }, 588 }, 589 { 590 name: "invalid credential type (oauth2)", 591 settings: defaultSettings, 592 creds: &PluginCredentialsV1{ 593 Credentials: &PluginCredentialsV1_Oauth2AccessToken{}, 594 }, 595 assertErr: func(t require.TestingT, err error, args ...any) { 596 require.True(t, trace.IsBadParameter(err)) 597 require.Contains(t, err.Error(), "must be used with the static credentials ref type") 598 }, 599 }, 600 { 601 name: "no labels for credentials", 602 settings: defaultSettings, 603 creds: &PluginCredentialsV1{ 604 Credentials: &PluginCredentialsV1_StaticCredentialsRef{ 605 &PluginStaticCredentialsRef{ 606 Labels: map[string]string{}, 607 }, 608 }, 609 }, 610 assertErr: func(t require.TestingT, err error, args ...any) { 611 require.True(t, trace.IsBadParameter(err)) 612 require.Contains(t, err.Error(), "labels must be specified") 613 }, 614 }, 615 { 616 name: "valid settings with team/channel", 617 settings: defaultSettings, 618 creds: &PluginCredentialsV1{ 619 Credentials: &PluginCredentialsV1_StaticCredentialsRef{ 620 &PluginStaticCredentialsRef{ 621 Labels: map[string]string{ 622 "label1": "value1", 623 }, 624 }, 625 }, 626 }, 627 assertErr: func(t require.TestingT, err error, args ...any) { 628 require.NoError(t, err) 629 }, 630 }, 631 { 632 name: "valid settings with no team/channel", 633 settings: &PluginSpecV1_Mattermost{ 634 Mattermost: &PluginMattermostSettings{ 635 ServerUrl: "https://test.mattermost.com", 636 }, 637 }, 638 creds: &PluginCredentialsV1{ 639 Credentials: &PluginCredentialsV1_StaticCredentialsRef{ 640 &PluginStaticCredentialsRef{ 641 Labels: map[string]string{ 642 "label1": "value1", 643 }, 644 }, 645 }, 646 }, 647 assertErr: func(t require.TestingT, err error, args ...any) { 648 require.NoError(t, err) 649 }, 650 }, 651 } 652 653 for _, tc := range testCases { 654 t.Run(tc.name, func(t *testing.T) { 655 plugin := NewPluginV1(Metadata{Name: "foobar"}, PluginSpecV1{ 656 Settings: tc.settings, 657 }, tc.creds) 658 tc.assertErr(t, plugin.CheckAndSetDefaults()) 659 }) 660 } 661 } 662 663 func requireBadParameterError(t require.TestingT, err error, args ...any) { 664 if tt, ok := t.(*testing.T); ok { 665 tt.Helper() 666 } 667 require.Error(t, err) 668 require.True(t, trace.IsBadParameter(err), args...) 669 } 670 671 func requireNamedBadParameterError(name string) require.ErrorAssertionFunc { 672 return func(t require.TestingT, err error, args ...any) { 673 if tt, ok := t.(*testing.T); ok { 674 tt.Helper() 675 } 676 require.ErrorContains(t, err, name) 677 require.True(t, trace.IsBadParameter(err)) 678 } 679 } 680 681 func TestPluginJiraValidation(t *testing.T) { 682 validSettings := func() *PluginSpecV1_Jira { 683 return &PluginSpecV1_Jira{ 684 &PluginJiraSettings{ 685 ServerUrl: "https://example.com", 686 ProjectKey: "PRJ", 687 IssueType: "Task", 688 }, 689 } 690 } 691 validCreds := func() *PluginCredentialsV1 { 692 return &PluginCredentialsV1{ 693 Credentials: &PluginCredentialsV1_StaticCredentialsRef{ 694 &PluginStaticCredentialsRef{ 695 Labels: map[string]string{ 696 "jira/address": "https://jira.example.com", 697 "jira/project": "PRJ", 698 "jira/issueType": "Task", 699 }, 700 }, 701 }, 702 } 703 } 704 705 testCases := []struct { 706 name string 707 mutateSettings func(*PluginSpecV1_Jira) 708 mutateCreds func(*PluginCredentialsV1) 709 assertErr require.ErrorAssertionFunc 710 }{ 711 { 712 name: "Valid", 713 assertErr: require.NoError, 714 }, { 715 name: "Missing Settings", 716 mutateSettings: func(s *PluginSpecV1_Jira) { s.Jira = nil }, 717 assertErr: requireBadParameterError, 718 }, { 719 name: "Missing Server URL", 720 mutateSettings: func(s *PluginSpecV1_Jira) { s.Jira.ServerUrl = "" }, 721 assertErr: requireNamedBadParameterError("server URL"), 722 }, { 723 name: "Missing Project Key", 724 mutateSettings: func(s *PluginSpecV1_Jira) { s.Jira.ProjectKey = "" }, 725 assertErr: requireNamedBadParameterError("project key"), 726 }, { 727 name: "Missing Issue Type", 728 mutateSettings: func(s *PluginSpecV1_Jira) { s.Jira.IssueType = "" }, 729 assertErr: requireNamedBadParameterError("issue type"), 730 }, { 731 name: "Missing Credentials", 732 mutateCreds: func(c *PluginCredentialsV1) { c.Credentials = nil }, 733 assertErr: requireBadParameterError, 734 }, { 735 name: "Missing Credential Labels", 736 mutateCreds: func(c *PluginCredentialsV1) { 737 c.Credentials.(*PluginCredentialsV1_StaticCredentialsRef). 738 StaticCredentialsRef. 739 Labels = map[string]string{} 740 }, 741 assertErr: requireNamedBadParameterError("labels"), 742 }, { 743 name: "Invalid Credential Type", 744 mutateCreds: func(c *PluginCredentialsV1) { 745 c.Credentials = &PluginCredentialsV1_Oauth2AccessToken{} 746 }, 747 assertErr: requireNamedBadParameterError("static credentials"), 748 }, 749 } 750 751 for _, tc := range testCases { 752 t.Run(tc.name, func(t *testing.T) { 753 settings := validSettings() 754 if tc.mutateSettings != nil { 755 tc.mutateSettings(settings) 756 } 757 758 creds := validCreds() 759 if tc.mutateCreds != nil { 760 tc.mutateCreds(creds) 761 } 762 763 plugin := NewPluginV1(Metadata{Name: "uut"}, PluginSpecV1{ 764 Settings: settings, 765 }, creds) 766 tc.assertErr(t, plugin.CheckAndSetDefaults()) 767 }) 768 } 769 } 770 771 func TestPluginDiscordValidation(t *testing.T) { 772 validSettings := func() *PluginSpecV1_Discord { 773 return &PluginSpecV1_Discord{ 774 &PluginDiscordSettings{ 775 RoleToRecipients: map[string]*DiscordChannels{ 776 "*": {ChannelIds: []string{"1234567890"}}, 777 }, 778 }, 779 } 780 } 781 validCreds := func() *PluginCredentialsV1 { 782 return &PluginCredentialsV1{ 783 Credentials: &PluginCredentialsV1_StaticCredentialsRef{ 784 &PluginStaticCredentialsRef{ 785 Labels: map[string]string{}, 786 }, 787 }, 788 } 789 } 790 791 testCases := []struct { 792 name string 793 mutateSettings func(*PluginSpecV1_Discord) 794 mutateCreds func(*PluginCredentialsV1) 795 assertErr require.ErrorAssertionFunc 796 }{ 797 { 798 name: "Valid", 799 assertErr: require.NoError, 800 }, { 801 name: "Missing Settings", 802 mutateSettings: func(s *PluginSpecV1_Discord) { s.Discord = nil }, 803 assertErr: requireBadParameterError, 804 }, { 805 name: "Empty Role Mapping", 806 mutateSettings: func(s *PluginSpecV1_Discord) { 807 s.Discord.RoleToRecipients = map[string]*DiscordChannels{} 808 }, 809 assertErr: requireNamedBadParameterError("role_to_recipients"), 810 }, { 811 name: "Missing Default Mapping", 812 mutateSettings: func(s *PluginSpecV1_Discord) { 813 delete(s.Discord.RoleToRecipients, Wildcard) 814 s.Discord.RoleToRecipients["access"] = &DiscordChannels{ 815 ChannelIds: []string{"1234567890"}, 816 } 817 }, 818 assertErr: requireNamedBadParameterError("default entry"), 819 }, { 820 name: "Missing Credentials", 821 mutateCreds: func(c *PluginCredentialsV1) { c.Credentials = nil }, 822 assertErr: requireBadParameterError, 823 }, { 824 name: "Invalid Credential Type", 825 mutateCreds: func(c *PluginCredentialsV1) { 826 c.Credentials = &PluginCredentialsV1_Oauth2AccessToken{} 827 }, 828 assertErr: requireNamedBadParameterError("static credentials"), 829 }, 830 } 831 832 for _, tc := range testCases { 833 t.Run(tc.name, func(t *testing.T) { 834 settings := validSettings() 835 if tc.mutateSettings != nil { 836 tc.mutateSettings(settings) 837 } 838 839 creds := validCreds() 840 if tc.mutateCreds != nil { 841 tc.mutateCreds(creds) 842 } 843 844 plugin := NewPluginV1( 845 Metadata{Name: "uut"}, 846 PluginSpecV1{Settings: settings}, 847 creds) 848 tc.assertErr(t, plugin.CheckAndSetDefaults()) 849 }) 850 } 851 } 852 853 func TestPluginEntraIDValidation(t *testing.T) { 854 validSettings := func() *PluginSpecV1_EntraId { 855 return &PluginSpecV1_EntraId{ 856 EntraId: &PluginEntraIDSettings{ 857 SyncSettings: &PluginEntraIDSyncSettings{ 858 DefaultOwners: []string{"admin"}, 859 }, 860 }, 861 } 862 } 863 testCases := []struct { 864 name string 865 mutateSettings func(*PluginSpecV1_EntraId) 866 assertErr require.ErrorAssertionFunc 867 }{ 868 { 869 name: "valid", 870 mutateSettings: nil, 871 assertErr: require.NoError, 872 }, 873 { 874 name: "missing sync settings", 875 mutateSettings: func(s *PluginSpecV1_EntraId) { 876 s.EntraId.SyncSettings = nil 877 }, 878 assertErr: requireNamedBadParameterError("sync_settings"), 879 }, 880 { 881 name: "missing default owners", 882 mutateSettings: func(s *PluginSpecV1_EntraId) { 883 s.EntraId.SyncSettings.DefaultOwners = nil 884 }, 885 assertErr: requireNamedBadParameterError("sync_settings.default_owners"), 886 }, 887 { 888 name: "empty default owners", 889 mutateSettings: func(s *PluginSpecV1_EntraId) { 890 s.EntraId.SyncSettings.DefaultOwners = []string{} 891 }, 892 assertErr: requireNamedBadParameterError("sync_settings.default_owners"), 893 }, 894 } 895 896 for _, tc := range testCases { 897 t.Run(tc.name, func(t *testing.T) { 898 settings := validSettings() 899 if tc.mutateSettings != nil { 900 tc.mutateSettings(settings) 901 } 902 903 plugin := NewPluginV1( 904 Metadata{Name: "uut"}, 905 PluginSpecV1{Settings: settings}, 906 nil) 907 tc.assertErr(t, plugin.CheckAndSetDefaults()) 908 }) 909 } 910 }