diff --git a/cfn-resources/organization/cmd/resource/model.go b/cfn-resources/organization/cmd/resource/model.go index c5cfe5992..eb3b79439 100644 --- a/cfn-resources/organization/cmd/resource/model.go +++ b/cfn-resources/organization/cmd/resource/model.go @@ -17,6 +17,7 @@ type Model struct { ApiAccessListRequired *bool `json:",omitempty"` MultiFactorAuthRequired *bool `json:",omitempty"` RestrictEmployeeAccess *bool `json:",omitempty"` + SecurityContact *string `json:",omitempty"` } // APIKey is autogenerated from the json schema diff --git a/cfn-resources/organization/cmd/resource/resource.go b/cfn-resources/organization/cmd/resource/resource.go index a017f8e52..1a0753a95 100644 --- a/cfn-resources/organization/cmd/resource/resource.go +++ b/cfn-resources/organization/cmd/resource/resource.go @@ -217,7 +217,7 @@ func Delete(req handler.Request, prevModel *Model, currentModel *Model) (handler // If exists _, response, err = currentModel.getOrgDetails(ctx, conn, currentModel) - if err != nil && response.StatusCode == http.StatusUnauthorized { + if err != nil && util.StatusUnauthorized(response) { return handleError(response, constants.DELETE, err) } @@ -283,7 +283,7 @@ func deleteCallback(ctx context.Context, conn *admin.APIClient, currentModel *Mo // Read before delete org, response, err := currentModel.getOrgDetails(ctx, conn, currentModel) if err != nil { - if response.StatusCode == http.StatusUnauthorized { + if util.StatusUnauthorized(response) { return handler.ProgressEvent{ OperationStatus: handler.Success, Message: DeleteCompleted, @@ -333,6 +333,7 @@ func (model *Model) getOrgDetails(ctx context.Context, conn *admin.APIClient, cu model.MultiFactorAuthRequired = settings.MultiFactorAuthRequired model.RestrictEmployeeAccess = settings.RestrictEmployeeAccess model.GenAIFeaturesEnabled = settings.GenAIFeaturesEnabled + model.SecurityContact = settings.SecurityContact return model, response, nil } @@ -340,21 +341,21 @@ func (model *Model) getOrgDetails(ctx context.Context, conn *admin.APIClient, cu func handleError(response *http.Response, method constants.CfnFunctions, err error) (handler.ProgressEvent, error) { errMsg := fmt.Sprintf("%s error:%s", method, err.Error()) _, _ = logger.Warn(errMsg) - if response.StatusCode == http.StatusConflict { + if util.StatusConflict(response) { return handler.ProgressEvent{ OperationStatus: handler.Failed, Message: errMsg, HandlerErrorCode: string(types.HandlerErrorCodeAlreadyExists)}, nil } - if response.StatusCode == http.StatusUnauthorized { + if util.StatusUnauthorized(response) { return handler.ProgressEvent{ OperationStatus: handler.Failed, Message: "Not found", HandlerErrorCode: string(types.HandlerErrorCodeNotFound)}, nil } - if response.StatusCode == http.StatusBadRequest { + if util.StatusBadRequest(response) { return handler.ProgressEvent{ OperationStatus: handler.Failed, Message: errMsg, @@ -377,6 +378,7 @@ func newOrganizationSettings(model *Model) *admin.OrganizationSettings { MultiFactorAuthRequired: model.MultiFactorAuthRequired, RestrictEmployeeAccess: model.RestrictEmployeeAccess, GenAIFeaturesEnabled: model.GenAIFeaturesEnabled, + SecurityContact: model.SecurityContact, } } diff --git a/cfn-resources/organization/docs/README.md b/cfn-resources/organization/docs/README.md index 3f4d9e1a6..50d5c585c 100644 --- a/cfn-resources/organization/docs/README.md +++ b/cfn-resources/organization/docs/README.md @@ -23,7 +23,8 @@ To declare this entity in your AWS CloudFormation template, use the following sy "IsDeleted" : Boolean, "ApiAccessListRequired" : Boolean, "MultiFactorAuthRequired" : Boolean, - "RestrictEmployeeAccess" : Boolean + "RestrictEmployeeAccess" : Boolean, + "SecurityContact" : String } } @@ -45,6 +46,7 @@ Properties: ApiAccessListRequired: Boolean MultiFactorAuthRequired: Boolean RestrictEmployeeAccess: Boolean + SecurityContact: String ## Properties @@ -173,6 +175,16 @@ _Type_: Boolean _Update requires_: [No interruption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt) +#### SecurityContact + +Email address of the security contact for the organization. + +_Required_: No + +_Type_: String + +_Update requires_: [No interruption](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html#update-no-interrupt) + ## Return Values ### Fn::GetAtt diff --git a/cfn-resources/organization/mongodb-atlas-organization.json b/cfn-resources/organization/mongodb-atlas-organization.json index 0cc169cb2..06cd1d342 100644 --- a/cfn-resources/organization/mongodb-atlas-organization.json +++ b/cfn-resources/organization/mongodb-atlas-organization.json @@ -83,6 +83,10 @@ "RestrictEmployeeAccess": { "type": "boolean", "description": "Flag that indicates whether to block MongoDB Support from accessing Atlas infrastructure for any deployment in the specified organization without explicit permission. Once this setting is turned on, you can grant MongoDB Support a 24-hour bypass access to the Atlas deployment to resolve support issues. To learn more, see: https://www.mongodb.com/docs/atlas/security-restrict-support-access/." + }, + "SecurityContact": { + "type": "string", + "description": "Email address of the security contact for the organization." } }, "additionalProperties": false, diff --git a/cfn-resources/organization/test/inputs_1_create.json b/cfn-resources/organization/test/inputs_1_create.json index 3aedc06f6..b18c50abb 100644 --- a/cfn-resources/organization/test/inputs_1_create.json +++ b/cfn-resources/organization/test/inputs_1_create.json @@ -14,5 +14,6 @@ "RestrictEmployeeAccess": "false", "ApiAccessListRequired": "false", "SkipDefaultAlertsSettings": "true", - "GenAIFeaturesEnabled": "true" + "GenAIFeaturesEnabled": "true", + "SecurityContact": "security-test@example.com" } diff --git a/cfn-resources/organization/test/inputs_1_update.json b/cfn-resources/organization/test/inputs_1_update.json index 555aec23f..868d065c4 100644 --- a/cfn-resources/organization/test/inputs_1_update.json +++ b/cfn-resources/organization/test/inputs_1_update.json @@ -14,5 +14,6 @@ "RestrictEmployeeAccess": "true", "ApiAccessListRequired": "false", "SkipDefaultAlertsSettings": "false", - "GenAIFeaturesEnabled": "false" + "GenAIFeaturesEnabled": "false", + "SecurityContact": "security-updated@example.com" } diff --git a/cfn-resources/util/http_status.go b/cfn-resources/util/http_status.go index 588d8eb1a..6ef4911ce 100644 --- a/cfn-resources/util/http_status.go +++ b/cfn-resources/util/http_status.go @@ -31,3 +31,7 @@ func StatusBadRequest(resp *http.Response) bool { func StatusServiceUnavailable(resp *http.Response) bool { return resp != nil && resp.StatusCode == http.StatusServiceUnavailable } + +func StatusUnauthorized(resp *http.Response) bool { + return resp != nil && resp.StatusCode == http.StatusUnauthorized +} diff --git a/examples/organization/organization.json b/examples/organization/organization.json index 3670da7da..fd55a3db9 100644 --- a/examples/organization/organization.json +++ b/examples/organization/organization.json @@ -81,6 +81,11 @@ ], "Default": "true", "Description": "Flag that indicates whether this organization has access to generative AI features. This setting only applies to Atlas Commercial and defaults to `true`. With this setting on, Project Owners may be able to enable or disable individual AI features at the project level. To learn more, see https://www.mongodb.com/docs/generative-ai-faq/" + }, + "SecurityContact": { + "Type": "String", + "Description": "Email address of the security contact for the organization.", + "Default": "" } }, "Mappings": {}, @@ -139,6 +144,9 @@ }, "GenAIFeaturesEnabled": { "Ref": "GenAIFeaturesEnabled" + }, + "SecurityContact": { + "Ref": "SecurityContact" } } }