Repository: cloud-custodian/cloud-custodian

Issue:
Add support for Sagemaker Model Bias Job resource
### Describe the feature
Would be useful to support SageMaker Model Bias Jobs as a aws.sagemaker-model-bias-job resource type

Extra information or context


### Extra information or context

https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/sagemaker/client/create_model_bias_job_definition.html
https://docs.aws.amazon.com/sagemaker/latest/APIReference/API_CreateModelBiasJobDefinition.html


Discussion:

Resolving patch:
diff --git a/c7n/resources/resource_map.py b/c7n/resources/resource_map.py
--- a/c7n/resources/resource_map.py
+++ b/c7n/resources/resource_map.py
@@ -239,6 +239,8 @@
   "aws.sagemaker-transform-job": "c7n.resources.sagemaker.SagemakerTransformJob",
   "aws.sagemaker-hyperparameter-tuning-job":
     "c7n.resources.sagemaker.SagemakerHyperParameterTuningJob",
+  "aws.sagemaker-model-bias-job-definition":
+    "c7n.resources.sagemaker.SagemakerModelBiasJobDefinition",
   "aws.scaling-policy": "c7n.resources.asg.ScalingPolicy",
   "aws.secrets-manager": "c7n.resources.secretsmanager.SecretsManager",
   "aws.security-group": "c7n.resources.vpc.SecurityGroup",
diff --git a/c7n/resources/sagemaker.py b/c7n/resources/sagemaker.py
--- a/c7n/resources/sagemaker.py
+++ b/c7n/resources/sagemaker.py
@@ -296,6 +296,30 @@ def resources(self, query=None):
         return super(SagemakerProcessingJob, self).resources(query=query)
 
 
+class SagemakerModelBiasJobDefinitionDescribe(DescribeSource):
+
+    def augment(self, resources):
+        return universal_augment(self.manager, super().augment(resources))
+
+
+@resources.register('sagemaker-model-bias-job-definition')
+class SagemakerModelBiasJobDefinition(QueryResourceManager):
+
+    class resource_type(TypeInfo):
+        service = 'sagemaker'
+        enum_spec = ('list_model_bias_job_definitions', 'JobDefinitionSummaries', None)
+        detail_spec = (
+            'describe_model_bias_job_definition', 'JobDefinitionName',
+            'MonitoringJobDefinitionName', None)
+        arn = id = 'JobDefinitionArn'
+        name = 'JobDefinitionName'
+        date = 'CreationTime'
+        permissions_prefix = 'sagemaker'
+        universal_taggable = object()
+
+    source_mapping = {'describe': SagemakerModelBiasJobDefinitionDescribe}
+
+
 class QueryFilter:
 
     JOB_FILTERS = ('StatusEquals', 'NameContains',)
@@ -955,6 +979,23 @@ def process(self, endpoints):
                 pass
 
 
+@SagemakerModelBiasJobDefinition.action_registry.register('delete')
+class SagemakerModelBiasJobDefinitionDelete(BaseAction):
+    """ Deletes sagemaker-model-bias-job-definition """
+    schema = type_schema('delete')
+    permissions = ('sagemaker:DeleteModelBiasJobDefinition',)
+
+    def process(self, definitions):
+        client = local_session(self.manager.session_factory).client('sagemaker')
+
+        for d in definitions:
+            try:
+                client.delete_model_bias_job_definition(
+                    JobDefinitionName=d['JobDefinitionName'])
+            except client.exceptions.ResourceNotFound:
+                pass
+
+
 @SagemakerEndpointConfig.action_registry.register('delete')
 class SagemakerEndpointConfigDelete(BaseAction):
     """Delete a SageMaker endpoint


Test patch:
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/api.sagemaker.DeleteModelBiasJobDefinition_1.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/api.sagemaker.DeleteModelBiasJobDefinition_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/api.sagemaker.DeleteModelBiasJobDefinition_1.json
@@ -0,0 +1,6 @@
+{
+    "status_code": 200,
+    "data": {
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/api.sagemaker.DescribeModelBiasJobDefinition_1.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/api.sagemaker.DescribeModelBiasJobDefinition_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/api.sagemaker.DescribeModelBiasJobDefinition_1.json
@@ -0,0 +1,59 @@
+{
+    "status_code": 200,
+    "data": {
+        "JobDefinitionArn": "arn:aws:sagemaker:us-east-1:644160558196:model-bias-job-definition/test-c7n-mdl-bias-job-def",
+        "JobDefinitionName": "test-c7n-mdl-bias-job-def",
+        "CreationTime": {
+            "__class__": "datetime",
+            "year": 2024,
+            "month": 4,
+            "day": 25,
+            "hour": 14,
+            "minute": 42,
+            "second": 41,
+            "microsecond": 396000
+        },
+        "ModelBiasAppSpecification": {
+            "ImageUri": "string",
+            "ConfigUri": "s3://test-sagemaker-model-bias-job/model-bias-app-spec-config.json"
+        },
+        "ModelBiasJobInput": {
+            "EndpointInput": {
+                "EndpointName": "c7n-test-endpoint",
+                "LocalPath": "/opt/ml/processing/endpointdata",
+                "S3InputMode": "File",
+                "S3DataDistributionType": "FullyReplicated"
+            },
+            "GroundTruthS3Input": {
+                "S3Uri": "s3://test-sagemaker-model-bias-job/template-1713927382441.yaml"
+            }
+        },
+        "ModelBiasJobOutputConfig": {
+            "MonitoringOutputs": [
+                {
+                    "S3Output": {
+                        "S3Uri": "s3://test-sagemaker-model-bias-job",
+                        "LocalPath": "/opt/ml/processing/localpath",
+                        "S3UploadMode": "EndOfJob"
+                    }
+                }
+            ]
+        },
+        "JobResources": {
+            "ClusterConfig": {
+                "InstanceCount": 1,
+                "InstanceType": "ml.t3.medium",
+                "VolumeSizeInGB": 1
+            }
+        },
+        "NetworkConfig": {
+            "EnableInterContainerTrafficEncryption": true,
+            "EnableNetworkIsolation": true
+        },
+        "RoleArn": "arn:aws:iam::644160558196:role/sagemaker-bias-job-role",
+        "StoppingCondition": {
+            "MaxRuntimeInSeconds": 120
+        },
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/api.sagemaker.ListModelBiasJobDefinitions_1.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/api.sagemaker.ListModelBiasJobDefinitions_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/api.sagemaker.ListModelBiasJobDefinitions_1.json
@@ -0,0 +1,23 @@
+{
+    "status_code": 200,
+    "data": {
+        "JobDefinitionSummaries": [
+            {
+                "MonitoringJobDefinitionName": "test-c7n-mdl-bias-job-def",
+                "MonitoringJobDefinitionArn": "arn:aws:sagemaker:us-east-1:644160558196:model-bias-job-definition/test-c7n-mdl-bias-job-def",
+                "CreationTime": {
+                    "__class__": "datetime",
+                    "year": 2024,
+                    "month": 4,
+                    "day": 25,
+                    "hour": 14,
+                    "minute": 42,
+                    "second": 41,
+                    "microsecond": 396000
+                },
+                "EndpointName": "c7n-test-endpoint"
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/api.sagemaker.ListModelBiasJobDefinitions_2.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/api.sagemaker.ListModelBiasJobDefinitions_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/api.sagemaker.ListModelBiasJobDefinitions_2.json
@@ -0,0 +1,7 @@
+{
+    "status_code": 200,
+    "data": {
+        "JobDefinitionSummaries": [],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/tagging.GetResources_1.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/tagging.GetResources_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_delete/tagging.GetResources_1.json
@@ -0,0 +1,18 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [
+            {
+                "ResourceARN": "arn:aws:sagemaker:us-east-1:644160558196:model-bias-job-definition/test-c7n-mdl-bias-job-def",
+                "Tags": [
+                    {
+                        "Key": "c7n-test",
+                        "Value": "c7n-test"
+                    }
+                ]
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_query/api.sagemaker.DescribeModelBiasJobDefinition_1.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_query/api.sagemaker.DescribeModelBiasJobDefinition_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_query/api.sagemaker.DescribeModelBiasJobDefinition_1.json
@@ -0,0 +1,59 @@
+{
+    "status_code": 200,
+    "data": {
+        "JobDefinitionArn": "arn:aws:sagemaker:us-east-1:644160558196:model-bias-job-definition/test-c7n-mdl-bias-job-def",
+        "JobDefinitionName": "test-c7n-mdl-bias-job-def",
+        "CreationTime": {
+            "__class__": "datetime",
+            "year": 2024,
+            "month": 4,
+            "day": 25,
+            "hour": 14,
+            "minute": 42,
+            "second": 41,
+            "microsecond": 396000
+        },
+        "ModelBiasAppSpecification": {
+            "ImageUri": "string",
+            "ConfigUri": "s3://test-sagemaker-model-bias-job/model-bias-app-spec-config.json"
+        },
+        "ModelBiasJobInput": {
+            "EndpointInput": {
+                "EndpointName": "c7n-test-endpoint",
+                "LocalPath": "/opt/ml/processing/endpointdata",
+                "S3InputMode": "File",
+                "S3DataDistributionType": "FullyReplicated"
+            },
+            "GroundTruthS3Input": {
+                "S3Uri": "s3://test-sagemaker-model-bias-job/template-1713927382441.yaml"
+            }
+        },
+        "ModelBiasJobOutputConfig": {
+            "MonitoringOutputs": [
+                {
+                    "S3Output": {
+                        "S3Uri": "s3://test-sagemaker-model-bias-job",
+                        "LocalPath": "/opt/ml/processing/localpath",
+                        "S3UploadMode": "EndOfJob"
+                    }
+                }
+            ]
+        },
+        "JobResources": {
+            "ClusterConfig": {
+                "InstanceCount": 1,
+                "InstanceType": "ml.t3.medium",
+                "VolumeSizeInGB": 1
+            }
+        },
+        "NetworkConfig": {
+            "EnableInterContainerTrafficEncryption": true,
+            "EnableNetworkIsolation": true
+        },
+        "RoleArn": "arn:aws:iam::644160558196:role/sagemaker-bias-job-role",
+        "StoppingCondition": {
+            "MaxRuntimeInSeconds": 120
+        },
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_query/api.sagemaker.ListModelBiasJobDefinitions_1.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_query/api.sagemaker.ListModelBiasJobDefinitions_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_query/api.sagemaker.ListModelBiasJobDefinitions_1.json
@@ -0,0 +1,23 @@
+{
+    "status_code": 200,
+    "data": {
+        "JobDefinitionSummaries": [
+            {
+                "MonitoringJobDefinitionName": "test-c7n-mdl-bias-job-def",
+                "MonitoringJobDefinitionArn": "arn:aws:sagemaker:us-east-1:644160558196:model-bias-job-definition/test-c7n-mdl-bias-job-def",
+                "CreationTime": {
+                    "__class__": "datetime",
+                    "year": 2024,
+                    "month": 4,
+                    "day": 25,
+                    "hour": 14,
+                    "minute": 42,
+                    "second": 41,
+                    "microsecond": 396000
+                },
+                "EndpointName": "c7n-test-endpoint"
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_query/tagging.GetResources_1.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_query/tagging.GetResources_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_query/tagging.GetResources_1.json
@@ -0,0 +1,18 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [
+            {
+                "ResourceARN": "arn:aws:sagemaker:us-east-1:644160558196:model-bias-job-definition/test-c7n-mdl-bias-job-def",
+                "Tags": [
+                    {
+                        "Key": "c7n-test",
+                        "Value": "c7n-test"
+                    }
+                ]
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.DescribeModelBiasJobDefinition_1.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.DescribeModelBiasJobDefinition_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.DescribeModelBiasJobDefinition_1.json
@@ -0,0 +1,59 @@
+{
+    "status_code": 200,
+    "data": {
+        "JobDefinitionArn": "arn:aws:sagemaker:us-east-1:644160558196:model-bias-job-definition/test-c7n-mdl-bias-job-def",
+        "JobDefinitionName": "test-c7n-mdl-bias-job-def",
+        "CreationTime": {
+            "__class__": "datetime",
+            "year": 2024,
+            "month": 4,
+            "day": 25,
+            "hour": 14,
+            "minute": 42,
+            "second": 41,
+            "microsecond": 396000
+        },
+        "ModelBiasAppSpecification": {
+            "ImageUri": "string",
+            "ConfigUri": "s3://test-sagemaker-model-bias-job/model-bias-app-spec-config.json"
+        },
+        "ModelBiasJobInput": {
+            "EndpointInput": {
+                "EndpointName": "c7n-test-endpoint",
+                "LocalPath": "/opt/ml/processing/endpointdata",
+                "S3InputMode": "File",
+                "S3DataDistributionType": "FullyReplicated"
+            },
+            "GroundTruthS3Input": {
+                "S3Uri": "s3://test-sagemaker-model-bias-job/template-1713927382441.yaml"
+            }
+        },
+        "ModelBiasJobOutputConfig": {
+            "MonitoringOutputs": [
+                {
+                    "S3Output": {
+                        "S3Uri": "s3://test-sagemaker-model-bias-job",
+                        "LocalPath": "/opt/ml/processing/localpath",
+                        "S3UploadMode": "EndOfJob"
+                    }
+                }
+            ]
+        },
+        "JobResources": {
+            "ClusterConfig": {
+                "InstanceCount": 1,
+                "InstanceType": "ml.t3.medium",
+                "VolumeSizeInGB": 1
+            }
+        },
+        "NetworkConfig": {
+            "EnableInterContainerTrafficEncryption": true,
+            "EnableNetworkIsolation": true
+        },
+        "RoleArn": "arn:aws:iam::644160558196:role/sagemaker-bias-job-role",
+        "StoppingCondition": {
+            "MaxRuntimeInSeconds": 120
+        },
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.DescribeModelBiasJobDefinition_2.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.DescribeModelBiasJobDefinition_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.DescribeModelBiasJobDefinition_2.json
@@ -0,0 +1,59 @@
+{
+    "status_code": 200,
+    "data": {
+        "JobDefinitionArn": "arn:aws:sagemaker:us-east-1:644160558196:model-bias-job-definition/test-c7n-mdl-bias-job-def",
+        "JobDefinitionName": "test-c7n-mdl-bias-job-def",
+        "CreationTime": {
+            "__class__": "datetime",
+            "year": 2024,
+            "month": 4,
+            "day": 25,
+            "hour": 14,
+            "minute": 42,
+            "second": 41,
+            "microsecond": 396000
+        },
+        "ModelBiasAppSpecification": {
+            "ImageUri": "string",
+            "ConfigUri": "s3://test-sagemaker-model-bias-job/model-bias-app-spec-config.json"
+        },
+        "ModelBiasJobInput": {
+            "EndpointInput": {
+                "EndpointName": "c7n-test-endpoint",
+                "LocalPath": "/opt/ml/processing/endpointdata",
+                "S3InputMode": "File",
+                "S3DataDistributionType": "FullyReplicated"
+            },
+            "GroundTruthS3Input": {
+                "S3Uri": "s3://test-sagemaker-model-bias-job/template-1713927382441.yaml"
+            }
+        },
+        "ModelBiasJobOutputConfig": {
+            "MonitoringOutputs": [
+                {
+                    "S3Output": {
+                        "S3Uri": "s3://test-sagemaker-model-bias-job",
+                        "LocalPath": "/opt/ml/processing/localpath",
+                        "S3UploadMode": "EndOfJob"
+                    }
+                }
+            ]
+        },
+        "JobResources": {
+            "ClusterConfig": {
+                "InstanceCount": 1,
+                "InstanceType": "ml.t3.medium",
+                "VolumeSizeInGB": 1
+            }
+        },
+        "NetworkConfig": {
+            "EnableInterContainerTrafficEncryption": true,
+            "EnableNetworkIsolation": true
+        },
+        "RoleArn": "arn:aws:iam::644160558196:role/sagemaker-bias-job-role",
+        "StoppingCondition": {
+            "MaxRuntimeInSeconds": 120
+        },
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.ListModelBiasJobDefinitions_1.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.ListModelBiasJobDefinitions_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.ListModelBiasJobDefinitions_1.json
@@ -0,0 +1,23 @@
+{
+    "status_code": 200,
+    "data": {
+        "JobDefinitionSummaries": [
+            {
+                "MonitoringJobDefinitionName": "test-c7n-mdl-bias-job-def",
+                "MonitoringJobDefinitionArn": "arn:aws:sagemaker:us-east-1:644160558196:model-bias-job-definition/test-c7n-mdl-bias-job-def",
+                "CreationTime": {
+                    "__class__": "datetime",
+                    "year": 2024,
+                    "month": 4,
+                    "day": 25,
+                    "hour": 14,
+                    "minute": 42,
+                    "second": 41,
+                    "microsecond": 396000
+                },
+                "EndpointName": "c7n-test-endpoint"
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.ListModelBiasJobDefinitions_2.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.ListModelBiasJobDefinitions_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.ListModelBiasJobDefinitions_2.json
@@ -0,0 +1,23 @@
+{
+    "status_code": 200,
+    "data": {
+        "JobDefinitionSummaries": [
+            {
+                "MonitoringJobDefinitionName": "test-c7n-mdl-bias-job-def",
+                "MonitoringJobDefinitionArn": "arn:aws:sagemaker:us-east-1:644160558196:model-bias-job-definition/test-c7n-mdl-bias-job-def",
+                "CreationTime": {
+                    "__class__": "datetime",
+                    "year": 2024,
+                    "month": 4,
+                    "day": 25,
+                    "hour": 14,
+                    "minute": 42,
+                    "second": 41,
+                    "microsecond": 396000
+                },
+                "EndpointName": "c7n-test-endpoint"
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.ListTags_1.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.ListTags_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.ListTags_1.json
@@ -0,0 +1,16 @@
+{
+    "status_code": 200,
+    "data": {
+        "Tags": [
+            {
+                "Key": "c7n-test",
+                "Value": "c7n-test"
+            },
+            {
+                "Key": "Owner",
+                "Value": "c7n"
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.ListTags_2.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.ListTags_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/api.sagemaker.ListTags_2.json
@@ -0,0 +1,12 @@
+{
+    "status_code": 200,
+    "data": {
+        "Tags": [
+            {
+                "Key": "c7n-test",
+                "Value": "c7n-test"
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/tagging.GetResources_1.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/tagging.GetResources_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/tagging.GetResources_1.json
@@ -0,0 +1,18 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [
+            {
+                "ResourceARN": "arn:aws:sagemaker:us-east-1:644160558196:model-bias-job-definition/test-c7n-mdl-bias-job-def",
+                "Tags": [
+                    {
+                        "Key": "c7n-test",
+                        "Value": "c7n-test"
+                    }
+                ]
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/tagging.GetResources_2.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/tagging.GetResources_2.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/tagging.GetResources_2.json
@@ -0,0 +1,22 @@
+{
+    "status_code": 200,
+    "data": {
+        "PaginationToken": "",
+        "ResourceTagMappingList": [
+            {
+                "ResourceARN": "arn:aws:sagemaker:us-east-1:644160558196:model-bias-job-definition/test-c7n-mdl-bias-job-def",
+                "Tags": [
+                    {
+                        "Key": "Owner",
+                        "Value": "c7n"
+                    },
+                    {
+                        "Key": "c7n-test",
+                        "Value": "c7n-test"
+                    }
+                ]
+            }
+        ],
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/tagging.TagResources_1.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/tagging.TagResources_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/tagging.TagResources_1.json
@@ -0,0 +1,7 @@
+{
+    "status_code": 200,
+    "data": {
+        "FailedResourcesMap": {},
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/tagging.UntagResources_1.json b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/tagging.UntagResources_1.json
new file mode 100644
--- /dev/null
+++ b/tests/data/placebo/test_sagemaker_model_bias_job_definition_tag/tagging.UntagResources_1.json
@@ -0,0 +1,7 @@
+{
+    "status_code": 200,
+    "data": {
+        "FailedResourcesMap": {},
+        "ResponseMetadata": {}
+    }
+}
\ No newline at end of file
diff --git a/tests/test_sagemaker.py b/tests/test_sagemaker.py
--- a/tests/test_sagemaker.py
+++ b/tests/test_sagemaker.py
@@ -744,6 +744,77 @@ def test_stop_sagemaker_compilation_job(self):
         self.assertEqual(job["CompilationJobStatus"], "STOPPING")
 
 
+class TestSageMakerModelBiasJobDefinition(BaseTest):
+
+    def test_sagemaker_model_bias_job_query(self):
+        session_factory = self.replay_flight_data("test_sagemaker_model_bias_job_definition_query")
+        p = self.load_policy(
+            {
+                "name": "query-model-bias-job-definition",
+                "resource": "sagemaker-model-bias-job-definition",
+            },
+            session_factory=session_factory,
+        )
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+
+    def test_delete_sagemaker_model_bias_job_definition(self):
+        session_factory = self.replay_flight_data("test_sagemaker_model_bias_job_definition_delete")
+        client = session_factory(region="us-east-1").client("sagemaker")
+        p = self.load_policy(
+            {
+                "name": "delete-model-bias-job-definition",
+                "resource": "sagemaker-model-bias-job-definition",
+                "filters": [
+                    {
+                        "type": "value",
+                        "key": "MonitoringJobDefinitionName",
+                        "value": "test",
+                        "op": "contains",
+                    }
+                ],
+                "actions": [{"type": "delete"}],
+            },
+            session_factory=session_factory,
+        )
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+        jobs = client.list_model_bias_job_definitions().get("JobDefinitionSummaries")
+        self.assertEqual(len(jobs), 0)
+
+    def test_tag_data_sagemaker_model_bias_job_definition(self):
+        session_factory = self.replay_flight_data("test_sagemaker_model_bias_job_definition_tag")
+        p = self.load_policy(
+            {
+                "name": "tag-model-bias-job-definition",
+                "resource": "sagemaker-model-bias-job-definition",
+                "filters": [{"tag:Owner": "absent"}],
+                "actions": [{"type": "tag", "key": "Owner", "value": "c7n"}],
+            },
+            session_factory=session_factory,
+        )
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+        client = session_factory(region="us-east-1").client("sagemaker")
+        tags = client.list_tags(ResourceArn=resources[0]["JobDefinitionArn"])["Tags"]
+        self.assertEqual(tags[1]['Key'], 'Owner')
+        self.assertEqual(tags[1]['Value'], 'c7n')
+
+        p = self.load_policy(
+            {
+                "name": "remove-model-bias-job-definition-tag",
+                "resource": "sagemaker-model-bias-job-definition",
+                "filters": [{"tag:Owner": "c7n"}],
+                "actions": [{"type": "remove-tag", "tags": ["Owner"]}],
+            },
+            session_factory=session_factory,
+        )
+        resources = p.run()
+        self.assertEqual(len(resources), 1)
+        tags = client.list_tags(ResourceArn=resources[0]["JobDefinitionArn"])["Tags"]
+        self.assertEqual(len(tags), 1)
+
+
 class TestSagemakerProcessingJob(BaseTest):
 
     def test_sagemaker_processing_job_query(self):