Repository: getmoto/moto

Issue:
_validate_required_params_service_role expects wrong string format
I installed moto with `pip install moto` and I'm using version 4.1.10.

The unit test below is currently commented out in [my project](https://github.com/uktrade/copilot-tools/blob/main/tests/test_codebuild_cli.py#L193), but, when I uncomment and run, it errors with `InvalidInputException("An error occurred (InvalidInputException) when calling the CreateProject operation: Invalid service role: Service role account ID does not match caller's account"`. (I don't get any more traceback than that). I would expect a successful 200 response and for the project to be created with this role.

```
@patch("commands.codebuild_cli.check_github_conn")
@mock_sts
@mock_iam
@mock_codebuild
def test_codedeploy(check_github_conn, aws_credentials):
    session = boto3.session.Session()
    session.client("iam").create_account_alias(AccountAlias="foo")
    runner = CliRunner()
    runner.invoke(create_codedeploy_role, ["--project-profile", "foo"])
    result = runner.invoke(codedeploy, ["--name", "unit-test-project", "--git", "https://github.com/uktrade/not-a-real-repo", "--branch", "main", "--buildspec", "./buildspec.yml", "--project-profile", "foo" ])

    assert "Codebuild project unit-test-project created" in result.output
```

There are [instructions](https://github.com/uktrade/copilot-tools/blob/main/README.md) for setting up the project and running the test in full, but the crux of the issue is that I'm calling the boto `client("codebuild").create_project() ` method with `serviceRole="arn:aws:iam::123456789012:role/ci-CodeBuild-role"` . The error is raised by [this method](https://github.com/getmoto/moto/blob/master/moto/codebuild/responses.py#L32) in moto/codebuild/responses:

```
def _validate_required_params_service_role(account_id: str, service_role: str) -> None:
    if f"arn:aws:iam::{account_id}:role/service-role/" not in service_role:
        raise InvalidInputException(
            "Invalid service role: Service role account ID does not match caller's account"
        )
```
I believe that it's a bug to require the service role arn to end with "service-role". When I create a service role through the AWS console, it doesn't end with "service-role". Moreover, it is not possible to create a linked service role, as [codebuild does not support these](https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_aws-services-that-work-with-iam.html). Even if it were, the arn would end with `aws-service-role`, not `service-role`.


Discussion:
Thanks for letting us know @gabelton - looks like we should indeed loosen that validation. Will raise a PR shortly to fix this.

Resolving patch:
diff --git a/moto/codebuild/responses.py b/moto/codebuild/responses.py
--- a/moto/codebuild/responses.py
+++ b/moto/codebuild/responses.py
@@ -30,14 +30,13 @@ def _validate_required_params_source(source: Dict[str, Any]) -> None:
 
 
 def _validate_required_params_service_role(account_id: str, service_role: str) -> None:
-    if f"arn:aws:iam::{account_id}:role/service-role/" not in service_role:
+    if not service_role.startswith(f"arn:aws:iam::{account_id}:role/"):
         raise InvalidInputException(
             "Invalid service role: Service role account ID does not match caller's account"
         )
 
 
 def _validate_required_params_artifacts(artifacts: Dict[str, Any]) -> None:
-
     if artifacts["type"] not in ["CODEPIPELINE", "S3", "NO_ARTIFACTS"]:
         raise InvalidInputException("Invalid type provided: Artifact type")
 
@@ -51,7 +50,6 @@ def _validate_required_params_artifacts(artifacts: Dict[str, Any]) -> None:
 
 
 def _validate_required_params_environment(environment: Dict[str, Any]) -> None:
-
     if environment["type"] not in [
         "WINDOWS_CONTAINER",
         "LINUX_CONTAINER",
@@ -116,9 +114,8 @@ def list_builds_for_project(self) -> str:
 
     def create_project(self) -> str:
         _validate_required_params_source(self._get_param("source"))
-        _validate_required_params_service_role(
-            self.current_account, self._get_param("serviceRole")
-        )
+        service_role = self._get_param("serviceRole")
+        _validate_required_params_service_role(self.current_account, service_role)
         _validate_required_params_artifacts(self._get_param("artifacts"))
         _validate_required_params_environment(self._get_param("environment"))
         _validate_required_params_project_name(self._get_param("name"))
@@ -134,7 +131,7 @@ def create_project(self) -> str:
             self._get_param("source"),
             self._get_param("artifacts"),
             self._get_param("environment"),
-            self._get_param("serviceRole"),
+            service_role=service_role,
         )
 
         return json.dumps({"project": project_metadata})


Test patch:
diff --git a/tests/test_codebuild/test_codebuild.py b/tests/test_codebuild/test_codebuild.py
--- a/tests/test_codebuild/test_codebuild.py
+++ b/tests/test_codebuild/test_codebuild.py
@@ -107,64 +107,34 @@ def test_codebuild_create_project_no_artifacts():
 
 
 @mock_codebuild
-def test_codebuild_create_project_with_invalid_name():
+def test_codebuild_create_project_with_invalid_inputs():
     client = boto3.client("codebuild", region_name="eu-central-1")
 
-    name = "!some_project"
-    source = dict()
-    source["type"] = "S3"
-    # repository location for S3
-    source["location"] = "bucketname/path/file.zip"
-    # output artifacts
-    artifacts = {"type": "NO_ARTIFACTS"}
-
-    environment = dict()
-    environment["type"] = "LINUX_CONTAINER"
-    environment["image"] = "contents_not_validated"
-    environment["computeType"] = "BUILD_GENERAL1_SMALL"
-    service_role = (
-        f"arn:aws:iam::{ACCOUNT_ID}:role/service-role/my-codebuild-service-role"
-    )
+    _input = {
+        "source": {"type": "S3", "location": "bucketname/path/file.zip"},
+        "artifacts": {"type": "NO_ARTIFACTS"},
+        "environment": {
+            "type": "LINUX_CONTAINER",
+            "image": "contents_not_validated",
+            "computeType": "BUILD_GENERAL1_SMALL",
+        },
+        "serviceRole": f"arn:aws:iam::{ACCOUNT_ID}:role/service-role/my-role",
+    }
 
+    # Name too long
     with pytest.raises(client.exceptions.from_code("InvalidInputException")) as err:
-        client.create_project(
-            name=name,
-            source=source,
-            artifacts=artifacts,
-            environment=environment,
-            serviceRole=service_role,
-        )
+        client.create_project(name=("some_project_" * 12), **_input)
     err.value.response["Error"]["Code"].should.equal("InvalidInputException")
 
+    # Name invalid
+    with pytest.raises(client.exceptions.from_code("InvalidInputException")) as err:
+        client.create_project(name="!some_project_", **_input)
+    err.value.response["Error"]["Code"].should.equal("InvalidInputException")
 
-@mock_codebuild
-def test_codebuild_create_project_with_invalid_name_length():
-    client = boto3.client("codebuild", region_name="eu-central-1")
-
-    name = "some_project_" * 12
-    source = dict()
-    source["type"] = "S3"
-    # repository location for S3
-    source["location"] = "bucketname/path/file.zip"
-    # output artifacts
-    artifacts = {"type": "NO_ARTIFACTS"}
-
-    environment = dict()
-    environment["type"] = "LINUX_CONTAINER"
-    environment["image"] = "contents_not_validated"
-    environment["computeType"] = "BUILD_GENERAL1_SMALL"
-    service_role = (
-        f"arn:aws:iam::{ACCOUNT_ID}:role/service-role/my-codebuild-service-role"
-    )
-
+    # ServiceRole invalid
+    _input["serviceRole"] = "arn:aws:iam::0000:role/service-role/my-role"
     with pytest.raises(client.exceptions.from_code("InvalidInputException")) as err:
-        client.create_project(
-            name=name,
-            source=source,
-            artifacts=artifacts,
-            environment=environment,
-            serviceRole=service_role,
-        )
+        client.create_project(name="valid_name", **_input)
     err.value.response["Error"]["Code"].should.equal("InvalidInputException")
 
 
@@ -349,7 +319,6 @@ def test_codebuild_get_batch_builds_for_project_no_history():
 
 @mock_codebuild
 def test_codebuild_start_build_no_project():
-
     client = boto3.client("codebuild", region_name="eu-central-1")
 
     name = "some_project"
@@ -361,7 +330,6 @@ def test_codebuild_start_build_no_project():
 
 @mock_codebuild
 def test_codebuild_start_build_no_overrides():
-
     client = boto3.client("codebuild", region_name="eu-central-1")
 
     name = "some_project"
@@ -428,7 +396,6 @@ def test_codebuild_start_build_multiple_times():
 
 @mock_codebuild
 def test_codebuild_start_build_with_overrides():
-
     client = boto3.client("codebuild", region_name="eu-central-1")
 
     name = "some_project"