From 20e2c76327bc5ad7a4b0e14584e33f7a993b4e95 Mon Sep 17 00:00:00 2001 From: Steven Moy Date: Thu, 24 Aug 2023 19:13:42 -0700 Subject: [PATCH 1/6] Make import work for BitBucket, CodeCommit and GitLab --- .vscode/launch.json | 11 ++ .../simulate_generic_git.py | 58 ++++++ .../v0_1_0/generic_git_provider/__init__.py | 0 .../aws_lambda_handler.py | 182 ++++++++++++++++++ .../generic_git_client.py | 40 ++++ 5 files changed, 291 insertions(+) create mode 100644 dev_tools/simulate_generic_git_in_aws_lambda/simulate_generic_git.py create mode 100644 iambic/plugins/v0_1_0/generic_git_provider/__init__.py create mode 100644 iambic/plugins/v0_1_0/generic_git_provider/aws_lambda_handler.py create mode 100644 iambic/plugins/v0_1_0/generic_git_provider/generic_git_client.py diff --git a/.vscode/launch.json b/.vscode/launch.json index 0ba859c2b..557b893de 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -199,6 +199,17 @@ ], "justMyCode": true }, + { + "name": "Iambic: Simulate Generic Git Provider", + "type": "python", + "request": "launch", + "program": "${workspaceFolder}/dev_tools/simulate_generic_git_in_aws_lambda/simulate_generic_git.py", + "args": [ + ], + "console": "integratedTerminal", + "justMyCode": true, + "envFile": "${workspaceFolder}/.env", + }, { "name": "Iambic: Simulate Lambda GitHub Webhook", "type": "python", diff --git a/dev_tools/simulate_generic_git_in_aws_lambda/simulate_generic_git.py b/dev_tools/simulate_generic_git_in_aws_lambda/simulate_generic_git.py new file mode 100644 index 000000000..6763eb7fb --- /dev/null +++ b/dev_tools/simulate_generic_git_in_aws_lambda/simulate_generic_git.py @@ -0,0 +1,58 @@ +from __future__ import annotations + +import os +from functools import cache +from unittest.mock import patch + +import boto3 +import yaml + +from iambic.plugins.v0_1_0.generic_git_provider.aws_lambda_handler import run_handler + +DEV_REGION = os.environ.get("DEV_REGION", "us-west-2") +DEV_EMAIL_DOMAIN_SUFFIX = os.environ.get("DEV_EMAIL_DOMAIN_SUFFIX", "@example.com") +DEV_ACCOUNT_ID = os.environ.get("DEV_ACCOUNT_ID", "") +GIT_PROVIDER_UNDER_TEST = os.environ.get("GIT_PROVIDER_UNDER_TEST", "") + +# GIT_PROVIDER_UNDER_TEST valid ones are +# bitbucket +# codecommit +# gitlab + +# You cannot proceed without these values. Check your environment setup. +assert DEV_ACCOUNT_ID +assert GIT_PROVIDER_UNDER_TEST + + +@cache +def _get_app_secrets_as_lambda_context_current() -> dict: + # Create a Secrets Manager client + session = boto3.session.Session() + client = session.client(service_name="secretsmanager", region_name=DEV_REGION) + + try: + get_secret_value_response = client.get_secret_value( + SecretId="iambic-dev/generic-git-providers-secrets" + ) + except Exception as e: + # For a list of exceptions thrown, see + # https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html + raise e + + # Decrypts secret using the associated KMS key. + return yaml.safe_load(get_secret_value_response["SecretString"])["git_providers"][ + GIT_PROVIDER_UNDER_TEST + ] + + +if __name__ == "__main__": + # to simulate lambda, we are pretending to be a lambda function + os.environ["AWS_LAMBDA_FUNCTION_NAME"] = "simulate_generic_git.py" + + req = {"source": "EventBridgeCron", "command": "import"} + + with patch( + "iambic.plugins.v0_1_0.generic_git_provider.aws_lambda_handler._get_app_secrets_as_lambda_context_current", + new=_get_app_secrets_as_lambda_context_current, + ): + run_handler(req, None) diff --git a/iambic/plugins/v0_1_0/generic_git_provider/__init__.py b/iambic/plugins/v0_1_0/generic_git_provider/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/iambic/plugins/v0_1_0/generic_git_provider/aws_lambda_handler.py b/iambic/plugins/v0_1_0/generic_git_provider/aws_lambda_handler.py new file mode 100644 index 000000000..35b96f78c --- /dev/null +++ b/iambic/plugins/v0_1_0/generic_git_provider/aws_lambda_handler.py @@ -0,0 +1,182 @@ +from __future__ import annotations + +import os +import shutil +import tempfile +import traceback +from functools import cache +from typing import Callable + +import boto3 +import yaml +from botocore.exceptions import ClientError + +import iambic.core.utils +import iambic.plugins.v0_1_0.github.github +from iambic.core.logger import log +from iambic.plugins.v0_1_0.generic_git_provider.generic_git_client import ( + create_git_client, +) +from iambic.plugins.v0_1_0.github.github import ( + _handle_import, + get_session_name, + iambic_app, +) + + +def run_handler(event=None, context=None): + """ + Default handler for AWS Lambda. It is split out from the actual + handler so we can also run via IDE run configurations + """ + + # debug + print("Event: ", event) + + # Check if the event source is CloudWatch Events + if isinstance(event, dict) and event.get("source") == "EventBridgeCron": + return handle_events_cron(event, context) + + +@cache +def _get_app_secrets_as_lambda_context_current() -> dict: + # Create a Secrets Manager client + session = boto3.session.Session() + client = session.client(service_name="secretsmanager") + + try: + get_secret_value_response = client.get_secret_value( + SecretId="iambic/github-app-secrets" + ) + except ClientError as e: + # For a list of exceptions thrown, see + # https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html + raise e + + # Decrypts secret using the associated KMS key. + return yaml.safe_load(get_secret_value_response["SecretString"]) + + +def handle_events_cron(event=None, context=None) -> None: + secrets = _get_app_secrets_as_lambda_context_current() + git_client = create_git_client(secrets) + + command = event["command"] + + if not (callable := AWS_EVENTS_WORKFLOW_DISPATCH_MAP.get(command)): + log_params = {"command": command} + log.error("handle_events_cron: Unable to find command", **log_params) + return + + repo_url = git_client.repo_url + + # TODO, don't have a generic GitProviderRepo interface yet + # templates_repo = git_client.get_repo(REPOSITORY_FULL_NAME) + # TODO, don't have a generic GitProviderRepoFullName interface yet + default_branch = git_client.default_branch_name + repo_full_name = git_client.repo_full_name + temp_templates_directory = tempfile.mkdtemp(prefix="lambda") + os.chdir(temp_templates_directory) + getattr(iambic_app, "lambda").app.init_plan_output_path() + getattr(iambic_app, "lambda").app.init_repo_base_path() + iambic.plugins.v0_1_0.github.github.init_shared_data_directory() + iambic.core.utils.init_writable_directory() + + return callable( + git_client, + None, # TODO, don't have a generic GitProviderRepo interface yet + repo_full_name, + repo_url, + default_branch, + proposed_changes_path=getattr(iambic_app, "lambda").app.PLAN_OUTPUT_PATH, + ) + + +def workflow_wrapper(workflow_func: Callable, ux_op_name: str) -> Callable: + def wrapped_workflow_func( + github_client, + templates_repo, + repo_name: str, + repo_url: str, + default_branch: str, + proposed_changes_path: str = None, + ): + pull_number = ( + 0 # 0 is not a valid pull number in github. workflow implementation + ) + # does not have an associated PR. This is the path of least resistance adaption + # for stable session name + session_name = get_session_name(repo_name, pull_number) + os.environ["IAMBIC_SESSION_NAME"] = session_name + + try: + if proposed_changes_path: + # code smell to have to change a module variable + # to control the destination of proposed_changes.yaml + # It's questionable if we still need to depend on the lambda interface + # because lambda interface was created to dynamic populate template config + # but templates config is now already stored in the templates repo itself. + getattr( + iambic_app, "lambda" + ).app.PLAN_OUTPUT_PATH = proposed_changes_path + + template_changes = workflow_func( + repo_url, + default_branch, + github_client=github_client, + templates_repo=templates_repo, + ) + + if template_changes: + # TODO This is here just so pre-commit won't yell at me + assert True + + # TODO disable _post_artifact_to_companion_repository because i don't have an interface defined yet + # _process_template_changes( + # github_client, + # templates_repo, + # None, + # pull_number, + # proposed_changes_path, + # template_changes, + # f"{ux_op_name}", # TODO this can probably be improved for user-experience + # ) + except Exception as e: + captured_traceback = traceback.format_exc() + log.error("fault", exception=captured_traceback) + try: + temp_dir = tempfile.mkdtemp(suffix=None, prefix=None, dir=None) + with open(f"{temp_dir}/crash.txt", "w") as f: + f.write(captured_traceback) + # TODO disable _post_artifact_to_companion_repository because i don't have an interface defined yet + # _post_artifact_to_companion_repository( + # github_client, + # templates_repo, + # pull_number, + # f"{ux_op_name}", + # f"{temp_dir}/crash.txt", + # captured_traceback, + # default_base_name="crash.txt", + # ) + except Exception: + captured_traceback = traceback.format_exc() + log.error( + "fail to post exception to companion repo", + exception=captured_traceback, + ) + finally: + if temp_dir: + shutil.rmtree(temp_dir) + raise e + + return wrapped_workflow_func + + +AWS_EVENTS_WORKFLOW_DISPATCH_MAP: dict[str, Callable] = { + # "enforce": workflow_wrapper(_handle_enforce, "enforce"), + # "expire": workflow_wrapper(_handle_expire, "expire"), + "import": workflow_wrapper(_handle_import, "import"), + # "detect": workflow_wrapper( + # _handle_detect_changes_from_eventbridge, "detect" + # ), +} diff --git a/iambic/plugins/v0_1_0/generic_git_provider/generic_git_client.py b/iambic/plugins/v0_1_0/generic_git_provider/generic_git_client.py new file mode 100644 index 000000000..565109b55 --- /dev/null +++ b/iambic/plugins/v0_1_0/generic_git_provider/generic_git_client.py @@ -0,0 +1,40 @@ +from __future__ import annotations + +import urllib + + +class GenericGitClient(object): + def __init__(self, secrets): + """ + secrets has to be a dictionary format as the following + + username: non-empty string (before url_quote_plus) + token: non-empty string (before url_quote_plus) + clone_url: typically https://git-provider.com/group/repo_name (must be https:// protocol) + default_branch_name: typically main or master + repo_full_name: must be in group/repo format (like example_corp/iambic-templates) + """ + self.username = secrets["username"] + self.token = secrets["token"] + self.clone_url = secrets["clone_url"] + self.default_branch_name = secrets["default_branch_name"] + self.repo_full_name = secrets["repo_full_name"] + + # we should always take the precaution someone did not give us a non-https url + assert self.clone_url.startswith("https://") + # we should always take the precaution someone did not sneak an @ in the url + # that may accidentally be a password. A simple assert may print the potential + # url with password + if "@" in self.clone_url: + raise ValueError("@ is detected in url") + self.clone_url_without_protocol = self.clone_url.replace("https://", "") + + @property + def repo_url(self): + encoded_username = urllib.parse.quote_plus(self.username) + encoded_token = urllib.parse.quote_plus(self.token) + return f"https://{encoded_username}:{encoded_token}@{self.clone_url_without_protocol}" + + +def create_git_client(secrets): + return GenericGitClient(secrets) From 7c34837b7db986d5d9d55e834481f702e27a0338 Mon Sep 17 00:00:00 2001 From: Steven Moy Date: Fri, 25 Aug 2023 17:03:32 -0700 Subject: [PATCH 2/6] Add iambic setup option to setup generic git provider support --- docs/cep/000-cep-template.md | 3 + docs/cep/004-generic-git-provider-support.md | 53 ++++ iambic/config/wizard.py | 250 +++++++++++++++++- .../templates/iambic_code_build_roles.yaml | 51 ++++ .../iambic_generic_git_provider_lambda.yaml | 156 +++++++++++ ...bic_generic_git_provider_lambda_roles.yaml | 48 ++++ .../v0_1_0/aws/cloud_formation/utils.py | 153 ++++++++++- iambic/plugins/v0_1_0/aws/models.py | 1 + .../aws_lambda_handler.py | 4 +- 9 files changed, 711 insertions(+), 8 deletions(-) create mode 100644 docs/cep/004-generic-git-provider-support.md create mode 100644 iambic/plugins/v0_1_0/aws/cloud_formation/templates/iambic_code_build_roles.yaml create mode 100644 iambic/plugins/v0_1_0/aws/cloud_formation/templates/iambic_generic_git_provider_lambda.yaml create mode 100644 iambic/plugins/v0_1_0/aws/cloud_formation/templates/iambic_generic_git_provider_lambda_roles.yaml diff --git a/docs/cep/000-cep-template.md b/docs/cep/000-cep-template.md index c668740cc..c25159a75 100644 --- a/docs/cep/000-cep-template.md +++ b/docs/cep/000-cep-template.md @@ -1,5 +1,8 @@ # CEP xxx - Code Enhancement Proposal Title +## Champion +Who will help organize the effort of getting this implement? + ## Summary Short summary about a code enhancement proposal diff --git a/docs/cep/004-generic-git-provider-support.md b/docs/cep/004-generic-git-provider-support.md new file mode 100644 index 000000000..e10cbba54 --- /dev/null +++ b/docs/cep/004-generic-git-provider-support.md @@ -0,0 +1,53 @@ +# CEP 004 - Generic Git Provider Support + +## Champion +smoy + +## Summary +Quickly add support to other Git Provider that is not GitHub + +## Rationale +The GitHub integration took sometime because it uses GitHub App interaction model. Such app +support is not universal in other Git providers. We want to maximize other Git provider support +with minimum complexity. + +The most supported mechanism is git checkout repository using https. For the sake of concrete +examples, we will attempt to make this generic git provider at least support BitBucket, +AWS CodeCommit and GitLab. It's not limited to just these 3 providers. A Git provider +that supports git clone via https should be sufficient. + +https git clone for private repository typically involves http basic auth. We +recommend users use an repository scoped token for authentication. We strongly +advise against using actual username, password combination. Access token is +less prone to re-use across other services. + +Road Map +1. Launch import support with generic git provider. +2. Recruit additional help to implement Git Provider specific interactions. + +Git Provider specific interactions + +1. Each provider has different webhook event implementation details. +1. Each provider has different REST API +1. Each provider has different authentication + authorization model + +## Customer Experience +1. User will still use `iambic setup` to install a lambda function +1. The lambda function will be driven by AWS EventBridge to periodic +import. +1. During install, user will need to provide the following + +* username +* token +* clone url (must be https:// based) +* repo full name (typically company_name/repo_name ) +* default branch name (typically main or master) + +## Alternative +Is there alternative considered? + +## Implementation +What's needed on the implementation? + +## Compatibility concern +Is there any compatibility concern? \ No newline at end of file diff --git a/iambic/config/wizard.py b/iambic/config/wizard.py index a3a28db84..a2eab9898 100644 --- a/iambic/config/wizard.py +++ b/iambic/config/wizard.py @@ -45,6 +45,9 @@ from iambic.core.template_generation import get_existing_template_map from iambic.core.utils import gather_templates, yaml from iambic.plugins.v0_1_0.aws.cloud_formation.utils import ( + create_code_build_roles_stack, + create_generic_git_provider_lambda_roles_stack, + create_generic_git_provider_lambda_stack, create_github_app_code_build_stack, create_github_app_ecr_pull_through_cache_stack, create_github_app_ecr_repo_stack, @@ -65,6 +68,7 @@ from iambic.plugins.v0_1_0.aws.models import ( ARN_RE, IAMBIC_CHANGE_DETECTION_SUFFIX, + IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX, IAMBIC_HUB_ROLE_NAME, IAMBIC_SPOKE_ROLE_NAME, AWSAccount, @@ -1883,6 +1887,229 @@ def set_aws_cf_customization(self): tags = aws_cf_parse_key_value_string(unparse_tags) return hub_role_name, spoke_role_name, tags + def configuration_generic_git_provider_aws_lambda_setup(self): # noqa: C901 + input_username = questionary.text( + "username (consult your git provider docs when using access token): ", + ).ask() + input_token = questionary.password( + "access token (consult your git provider docs): ", + ).ask() + input_clone_url = questionary.text( + "clone url (must start with https://): ", + ).ask() + input_default_branch_name = questionary.text( + "default branch: ", default="main" + ).ask() + input_repo_full_name = questionary.text( + "repo full name (typically company_name/iambic-templates): ", + ).ask() + generic_git_provider_secrets = { + "username": input_username, + "token": input_token, + "clone_url": input_clone_url, + "default_branch_name": input_default_branch_name, + "repo_full_name": input_repo_full_name, + } + # TODO do a verification to prevent bad input get into secret manager + + click.echo( + "\nSetting up a GitHub App for IAMbic involves creating CloudFormation stacks. \n" + "If you wish to inspect the templates used or handle their deployment manually, use the `iambic_generic_git_provider` templates at the following location:\n" + "https://github.com/noqdev/iambic/tree/main/iambic/plugins/v0_1_0/aws/cloud_formation/templates\n" + "Note that IAMbic will verify the successful deployment of your stacks, and it will not attempt to overwrite or recreate them if they already exist.\n" + ) + + unparse_tags = questionary.text( + "Add Tags (leave blank or `team=ops_team, cost_center=engineering`): ", + default="", + validate=validate_aws_cf_input_tags, + ).ask() + tags = aws_cf_parse_key_value_string(unparse_tags) + if not questionary.confirm("Proceed?").unsafe_ask(): + return + + account_name_to_account_id = { + account.account_name: account.account_id + for account in self.config.aws.accounts + } + available_account_names = sorted(list(account_name_to_account_id.keys())) + questionary_params = {} + question_text = "We recommend you deploy Lambda integration on a non-management account.\nTarget AWS Account name: " + if len(available_account_names) == 1: + target_account_name = available_account_names[0] + elif len(available_account_names) < 10: + target_account_name = questionary.select( + question_text, choices=available_account_names, **questionary_params + ).unsafe_ask() + else: + target_account_name = questionary.autocomplete( + question_text, + choices=available_account_names, + style=CUSTOM_AUTO_COMPLETE_STYLE, + **questionary_params, + ).unsafe_ask() + + target_account_id = account_name_to_account_id[target_account_name] + log.info(f"Target AWS Account ID is {target_account_id}") + + session, _ = self.get_boto3_session_for_account(target_account_id) + + secretsmanager_client = session.client( + service_name="secretsmanager", region_name=self.aws_default_region + ) + secrets_kwargs = {} + generic_git_provider_secret_arn = None + if tags: + secrets_kwargs["Tags"] = tags + try: + response = secretsmanager_client.create_secret( + Name="iambic/generic-git-provider-secrets", + Description="iambic github app private key", + SecretString=yaml.dump(generic_git_provider_secrets), + **secrets_kwargs, + ) + generic_git_provider_secret_arn = response["ARN"] + except secretsmanager_client.exceptions.ResourceExistsException: + log.info( + f"iambic/generic-git-provider-secrets already exists in account: {target_account_id} in region: {self.aws_default_region}" + ) + + # verify the existing secrets actually match our known values + response = secretsmanager_client.describe_secret( + SecretId="iambic/generic-git-provider-secrets", + ) + generic_git_provider_secret_arn = response["ARN"] + response = secretsmanager_client.get_secret_value( + SecretId="iambic/generic-git-provider-secrets", + ) + + if not questionary.confirm( + "Continue with value in existing Secret?" + ).unsafe_ask(): + log.error( + "Please remove the iambic/generic-git-provider-secrets secret or update the secret before re-running this wizard" + ) + return + + cf_client = session.client( + "cloudformation", region_name=self.aws_default_region + ) + + # Note: We are not going to prompt user to give us an optional CloudFormation Role ARN + # to use because it seems like additional friction. If we get feedback to restore it, + # we will simply called cf_role_arn = self.cf_role_arn + cf_role_arn = None + + successfully_created = asyncio.run( + create_generic_git_provider_lambda_roles_stack( + cf_client, + self.hub_account_id, + IAMBIC_HUB_ROLE_NAME, + cf_role_arn, + tags=tags, + ) + ) + assert successfully_created + + # modify the trust policy of IambicHubRole to allow iambic lambda execution role + lambda_role_arn = f"arn:aws:iam::{target_account_id}:role/iambic_generic_git_provider_lambda_execution{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}" + + self.github_app_amend_trust_policy_for_iambic_integration( + lambda_role_arn, target_sid="AllowIAMbicGenericGitProviderLambdaIntegration" + ) + + successfully_created = asyncio.run( + create_code_build_roles_stack( + cf_client, + cf_role_arn, + tags=tags, + ) + ) + assert successfully_created + + try: + successfully_created = asyncio.run( + create_github_app_ecr_pull_through_cache_stack( + cf_client, + cf_role_arn, + stack_name=f"IAMbicECRPullThroughCache{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}", + tags=tags, + ) + ) + assert successfully_created + + successfully_created = asyncio.run( + create_github_app_ecr_repo_stack( + cf_client, + cf_role_arn, + stack_name=f"IAMbicECRRepo{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}", + tags=tags, + ) + ) + assert successfully_created + + code_build_role_arn = f"arn:aws:iam::{target_account_id}:role/iambic_code_build{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}" + code_build_name = f"iambic_code_build{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}" + + successfully_created = asyncio.run( + create_github_app_code_build_stack( + cf_client, + target_account_id, + cf_role_arn, + code_build_role_arn=code_build_role_arn, + code_build_name=code_build_name, + stack_name=f"IAMbicGenericGitProviderCodeBuild{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}", + tags=tags, + ) + ) + assert successfully_created + + except Exception as e: + log.error(str(e)) + # keep going: doing this because during development, we use the ecr cache rule and repo for many other things + + self.github_app_pull_latest_iambic_image(session) + + self.github_app_wait_until_image_is_ready(session) + + successfully_created = asyncio.run( + create_generic_git_provider_lambda_stack( + cf_client, + target_account_id, + generic_git_provider_secret_arn, + cf_role_arn, + tags=tags, + ) + ) + assert successfully_created + + # TODO Disable for now since we don't have webhook integrated yet. + # webhook_url = None + + # lambda_stack_name = f"IAMbicGenericGitProviderLambda{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}" + # response = cf_client.describe_stacks(StackName=lambda_stack_name) + # outputs = response["Stacks"][0]["Outputs"] + # for output in outputs: + # keyName = output["OutputKey"] + # if keyName == "FunctionUrl": + # webhook_url = output["OutputValue"] + + # assert webhook_url + + # github_app_jwt = generate_jwt(generic_git_provider_secrets) + # try: + # update_webhook_url(webhook_url, github_app_jwt) + # except Exception: + # log.exception( + # "Failed to update webhook URL with GitHub App. Please manually update the webhook URL in the GitHub App settings page", + # webhook_url=webhook_url, + # ) + # if not questionary.confirm("Proceed?").unsafe_ask(): + # return + + # # Remove the local secrets because it's already saved in secret manager + # remove_github_app_secrets() + def configuration_github_app_aws_lambda_setup(self): # noqa: C901 from iambic.plugins.v0_1_0.aws.cloud_formation.utils import ( IAMBIC_GITHUB_APP_SUFFIX, @@ -2163,7 +2390,11 @@ def configuration_github_app_aws_lambda_setup(self): # noqa: C901 # Remove the local secrets because it's already saved in secret manager remove_github_app_secrets() - def github_app_amend_trust_policy_for_iambic_integration(self, lambda_role_arn): + def github_app_amend_trust_policy_for_iambic_integration( + self, lambda_role_arn, target_sid=None + ): + if target_sid is None: + target_sid = "AllowIAMbicLambdaIntegration" hub_session, _ = self.get_boto3_session_for_account(self.hub_account_id) hub_iam_client = hub_session.client("iam", region_name=self.aws_default_region) hub_role_arn = self.config.aws.hub_role_arn @@ -2174,13 +2405,13 @@ def github_app_amend_trust_policy_for_iambic_integration(self, lambda_role_arn): needs_to_add_statement = True statements: list = existing_trust_policy.get("Statement", []) new_statement = { - "Sid": "AllowIAMbicLambdaIntegration", + "Sid": target_sid, "Effect": "Allow", "Principal": {"AWS": lambda_role_arn}, "Action": ["sts:AssumeRole", "sts:TagSession"], } for statement in statements: # FIXME: watch out other cases - if statement.get("Sid", "") == "AllowIAMbicLambdaIntegration": + if statement.get("Sid", "") == target_sid: needs_to_add_statement = False if statement["Principal"]["AWS"] != lambda_role_arn: # Update the statement @@ -2332,6 +2563,9 @@ def run(self): # noqa: C901 if self.has_aws_account_or_organizations: choices.append("Setup GitHub App Integration using AWS Lambda") + choices.append( + "Setup Generic Git Provider Integration using AWS Lambda" + ) if ( self.config.aws.organizations and not self.config.aws.sqs_cloudtrail_changes_queues @@ -2379,6 +2613,16 @@ def run(self): # noqa: C901 log.info( "Unable to edit this attribute without CloudFormation permissions." ) + elif ( + action == "Setup Generic Git Provider Integration using AWS Lambda" + ): + self.setup_aws_configuration() + if self.has_confirm_cf_permissions: + self.configuration_generic_git_provider_aws_lambda_setup() + else: + log.info( + "Unable to edit this attribute without CloudFormation permissions." + ) elif action == "Setup AWS change detection": self.setup_aws_configuration() if self.has_cf_stacksets_permissions: diff --git a/iambic/plugins/v0_1_0/aws/cloud_formation/templates/iambic_code_build_roles.yaml b/iambic/plugins/v0_1_0/aws/cloud_formation/templates/iambic_code_build_roles.yaml new file mode 100644 index 000000000..b17cd1c24 --- /dev/null +++ b/iambic/plugins/v0_1_0/aws/cloud_formation/templates/iambic_code_build_roles.yaml @@ -0,0 +1,51 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: This creates AWS Roles required by the IAMbic git integration to run Lambda using a container image +Parameters: + IambicCodeBuildRoleName: + Type: String + Default: "iambic_lambda_code_build" + IambicECRRepoName: + Type: String + Default: "iambic-ecr-public/iambic/iambic" +Resources: + IambicCodeBuildRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: + - codebuild.amazonaws.com + Action: + - "sts:AssumeRole" + Description: Execution role for IAMbic code build + MaxSessionDuration: 3600 + Policies: + - PolicyName: code-build + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: "Logging" + Effect: Allow + Action: + - "logs:CreateLogGroup" + - "logs:CreateLogStream" + - "logs:PutLogEvents" + Resource: "*" + - Sid: "ECRGetAuthToken" + Effect: Allow + Action: + - "ecr:GetAuthorizationToken" + Resource: "*" + - Sid: "ECRPull" + Effect: Allow + Action: + - "ecr:BatchCheckLayerAvailability" + - "ecr:BatchImportUpstreamImage" + - "ecr:BatchGetImage" + - "ecr:GetDownloadUrlForLayer" + Resource: + - !Sub "arn:*:ecr:*:*:repository/${IambicECRRepoName}" + RoleName: !Ref IambicCodeBuildRoleName \ No newline at end of file diff --git a/iambic/plugins/v0_1_0/aws/cloud_formation/templates/iambic_generic_git_provider_lambda.yaml b/iambic/plugins/v0_1_0/aws/cloud_formation/templates/iambic_generic_git_provider_lambda.yaml new file mode 100644 index 000000000..48c6216e1 --- /dev/null +++ b/iambic/plugins/v0_1_0/aws/cloud_formation/templates/iambic_generic_git_provider_lambda.yaml @@ -0,0 +1,156 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: This creates a lambda function and function url to enable IAMbic generic git provider Integration +Parameters: + LambdaFunctionName: + Type: String + Default: "iambic_generic_git_provider_webhook" + ImageUri: + Type: String + LambdaExecutionRoleArn: + Type: String + GenericGitProviderSecretArn: + Type: String + LambdaMemorySize: + Type: Number + Default: 2048 + LambdaTimeout: + Type: Number + Default: 900 + ImportSchedule: + Type: String + Default: "cron(0 */2 * * ? *)" # Every 2 hours by default + ExpireSchedule: + Type: String + Default: "cron(5 * * * ? *)" # Every hour at minute 5 + EnforceSchedule: + Type: String + Default: "cron(0 * * * ? *)" # Every hour + DetectSchedule: + Type: String + Default: "cron(*/5 * * * ? *)" # Every 5 minutes +Resources: + IambicWebHookLambda: + Type: 'AWS::Lambda::Function' + Properties: + FunctionName: + Ref: LambdaFunctionName + PackageType: Image + ImageConfig: + Command: + - "iambic.plugins.v0_1_0.generic_git_provider.aws_lambda_handler.run_handler" + EntryPoint: + - "python" + - "-m" + - "awslambdaric" + Role: + Ref: LambdaExecutionRoleArn + Code: + ImageUri: + Ref: ImageUri + Description: IAMbic Webhook Lambda + TracingConfig: + Mode: Active + MemorySize: + Ref: LambdaMemorySize + Timeout: + Ref: LambdaTimeout + Environment: + Variables: + GENERIC_GIT_PROVIDER_SECRET_ARN: !Ref GenericGitProviderSecretArn + IambicWebHookLambdaLogGroup: + Type: AWS::Logs::LogGroup + Properties: + LogGroupName: !Sub "/aws/lambda/${IambicWebHookLambda}" + RetentionInDays: 3 + IambicWebHookLambdaPermission: + Type: AWS::Lambda::Permission + Properties: + FunctionName: !Ref IambicWebHookLambda + # IambicWebHook is secured using shared webhook secret between GitHub App and Lambda + FunctionUrlAuthType: 'NONE' + Action: lambda:InvokeFunctionUrl + Principal: '*' + IambicWebHookUrl: + Type: 'AWS::Lambda::Url' + Properties: + AuthType: "NONE" + TargetFunctionArn: !GetAtt IambicWebHookLambda.Arn + DependsOn: + - IambicWebHookLambda + + ImportCronRule: + Type: 'AWS::Events::Rule' + Properties: + ScheduleExpression: + Ref: ImportSchedule + Targets: + - Arn: !GetAtt IambicWebHookLambda.Arn + Id: "ImportCronTarget" + Input: '{"command": "import", "source": "EventBridgeCron"}' + + ExpireCronRule: + Type: 'AWS::Events::Rule' + Properties: + ScheduleExpression: + Ref: ExpireSchedule + Targets: + - Arn: !GetAtt IambicWebHookLambda.Arn + Id: "ExpireCronTarget" + Input: '{"command": "expire", "source": "EventBridgeCron"}' + + EnforceCronRule: + Type: 'AWS::Events::Rule' + Properties: + ScheduleExpression: + Ref: EnforceSchedule + Targets: + - Arn: !GetAtt IambicWebHookLambda.Arn + Id: "EnforceCronTarget" + Input: '{"command": "enforce", "source": "EventBridgeCron"}' + + DetectCronRule: + Type: 'AWS::Events::Rule' + Properties: + ScheduleExpression: + Ref: DetectSchedule + Targets: + - Arn: !GetAtt IambicWebHookLambda.Arn + Id: "DetectCronTarget" + Input: '{"command": "detect", "source": "EventBridgeCron"}' + + ImportCronLambdaPermission: + Type: "AWS::Lambda::Permission" + Properties: + FunctionName: !Ref IambicWebHookLambda + Action: "lambda:InvokeFunction" + Principal: "events.amazonaws.com" + SourceArn: !GetAtt ImportCronRule.Arn + + ExpireCronLambdaPermission: + Type: "AWS::Lambda::Permission" + Properties: + FunctionName: !Ref IambicWebHookLambda + Action: "lambda:InvokeFunction" + Principal: "events.amazonaws.com" + SourceArn: !GetAtt ExpireCronRule.Arn + + EnforceCronLambdaPermission: + Type: "AWS::Lambda::Permission" + Properties: + FunctionName: !Ref IambicWebHookLambda + Action: "lambda:InvokeFunction" + Principal: "events.amazonaws.com" + SourceArn: !GetAtt EnforceCronRule.Arn + + DetectCronLambdaPermission: + Type: "AWS::Lambda::Permission" + Properties: + FunctionName: !Ref IambicWebHookLambda + Action: "lambda:InvokeFunction" + Principal: "events.amazonaws.com" + SourceArn: !GetAtt DetectCronRule.Arn + +Outputs: + FunctionUrl: + Description: URL of the Lambda Function + Value: !GetAtt IambicWebHookUrl.FunctionUrl \ No newline at end of file diff --git a/iambic/plugins/v0_1_0/aws/cloud_formation/templates/iambic_generic_git_provider_lambda_roles.yaml b/iambic/plugins/v0_1_0/aws/cloud_formation/templates/iambic_generic_git_provider_lambda_roles.yaml new file mode 100644 index 000000000..55950ebda --- /dev/null +++ b/iambic/plugins/v0_1_0/aws/cloud_formation/templates/iambic_generic_git_provider_lambda_roles.yaml @@ -0,0 +1,48 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: This creates AWS Roles required by the IAMbic generic git provider integration +Parameters: + IambicHubRoleArn: + Type: String + IambicWebhookLambdaExecutionRoleName: + Type: String + Default: "iambic_generic_git_provider_lambda_execution" +Resources: + IambicWebhookLambdaExecutionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: "2012-10-17" + Statement: + - Effect: Allow + Principal: + Service: + - lambda.amazonaws.com + Action: + - "sts:AssumeRole" + Description: Execution role for IAMbic Lambda Webhook + MaxSessionDuration: 3600 + Policies: + - PolicyName: Lambda + PolicyDocument: + Version: "2012-10-17" + Statement: + - Sid: "Logging" + Effect: Allow + Action: + - "logs:CreateLogGroup" + - "logs:CreateLogStream" + - "logs:PutLogEvents" + Resource: "*" + - Sid: "SecretReading" + Effect: Allow + Action: + - "secretsmanager:GetSecretValue" + Resource: + - "arn:aws:secretsmanager:*:*:secret:iambic/generic-git-provider-secrets-*" + - Sid: "AssumeRole" + Effect: Allow + Action: + - "sts:AssumeRole" + Resource: + - !Ref IambicHubRoleArn + RoleName: !Ref IambicWebhookLambdaExecutionRoleName diff --git a/iambic/plugins/v0_1_0/aws/cloud_formation/utils.py b/iambic/plugins/v0_1_0/aws/cloud_formation/utils.py index 9a9042b36..7abafecd7 100644 --- a/iambic/plugins/v0_1_0/aws/cloud_formation/utils.py +++ b/iambic/plugins/v0_1_0/aws/cloud_formation/utils.py @@ -10,6 +10,7 @@ from iambic.core.logger import log from iambic.plugins.v0_1_0.aws.models import ( IAMBIC_CHANGE_DETECTION_SUFFIX, + IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX, IAMBIC_GITHUB_APP_SUFFIX, IAMBIC_HUB_ROLE_NAME, IAMBIC_SPOKE_ROLE_NAME, @@ -32,6 +33,24 @@ def get_central_rule_template_body() -> str: return f.read() +def get_generic_git_provider_lambda_roles_template_body() -> str: + template = f"{TEMPLATE_DIR}/iambic_generic_git_provider_lambda_roles.yaml" + with open(template, "r") as f: + return f.read() + + +def get_code_build_roles_template_body() -> str: + template = f"{TEMPLATE_DIR}/iambic_code_build_roles.yaml" + with open(template, "r") as f: + return f.read() + + +def get_generic_git_provider_lambda_template_body() -> str: + template = f"{TEMPLATE_DIR}/iambic_generic_git_provider_lambda.yaml" + with open(template, "r") as f: + return f.read() + + def get_github_app_roles_template_body() -> str: template = f"{TEMPLATE_DIR}/iambic_github_app_roles.yaml" with open(template, "r") as f: @@ -282,6 +301,68 @@ async def create_stack_set( return not bool(failed_instances) +async def create_generic_git_provider_lambda_roles_stack( + cf_client, + hub_account_id: str, + hub_role_name: str, + role_arn: str = None, + tags: Optional[dict] = None, +) -> bool: + additional_kwargs: dict[str, Any] = {"RoleARN": role_arn} if role_arn else {} + + if tags: + additional_kwargs["Tags"] = tags + + stack_created = await create_stack( + cf_client, + stack_name=f"IAMbicGenericGitLambdaRole{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}", + template_body=get_generic_git_provider_lambda_roles_template_body(), + parameters=[ + { + "ParameterKey": "IambicHubRoleArn", + "ParameterValue": get_hub_role_arn( + hub_account_id, role_name=hub_role_name + ), + }, + { + "ParameterKey": "IambicWebhookLambdaExecutionRoleName", + "ParameterValue": f"iambic_generic_git_provider_lambda_execution{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}", + }, + ], + Capabilities=["CAPABILITY_NAMED_IAM"], + **additional_kwargs, + ) + + return stack_created + + +async def create_code_build_roles_stack( + cf_client, + role_arn: str = None, + tags: Optional[dict] = None, +) -> bool: + additional_kwargs: dict[str, Any] = {"RoleARN": role_arn} if role_arn else {} + + if tags: + additional_kwargs["Tags"] = tags + + stack_created = await create_stack( + cf_client, + stack_name=f"IAMbicCodeBuildRoles{IAMBIC_GITHUB_APP_SUFFIX}", + template_body=get_code_build_roles_template_body(), + parameters=[ + { + "ParameterKey": "IambicCodeBuildRoleName", + "ParameterValue": f"iambic_code_build{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}", + }, + ], + Capabilities=["CAPABILITY_NAMED_IAM"], + **additional_kwargs, + ) + + return stack_created + + async def create_github_app_roles_stack( cf_client, hub_account_id: str, @@ -324,6 +405,7 @@ async def create_github_app_roles_stack( async def create_github_app_ecr_pull_through_cache_stack( cf_client, role_arn: str = None, + stack_name: str = None, tags: Optional[dict] = None, ) -> bool: additional_kwargs: dict[str, Any] = {"RoleARN": role_arn} if role_arn else {} @@ -331,9 +413,12 @@ async def create_github_app_ecr_pull_through_cache_stack( if tags: additional_kwargs["Tags"] = tags + if stack_name is None: + stack_name = f"IAMbicGitHubAppECRPullThroughCache{IAMBIC_GITHUB_APP_SUFFIX}" + stack_created = await create_stack( cf_client, - stack_name=f"IAMbicGitHubAppECRPullThroughCache{IAMBIC_GITHUB_APP_SUFFIX}", + stack_name=stack_name, template_body=get_github_app_ecr_pull_through_template_body(), parameters=[], **additional_kwargs, @@ -345,6 +430,7 @@ async def create_github_app_ecr_pull_through_cache_stack( async def create_github_app_ecr_repo_stack( cf_client, role_arn: str = None, + stack_name: str = None, tags: Optional[dict] = None, ) -> bool: additional_kwargs: dict[str, Any] = {"RoleARN": role_arn} if role_arn else {} @@ -352,9 +438,12 @@ async def create_github_app_ecr_repo_stack( if tags: additional_kwargs["Tags"] = tags + if stack_name is None: + stack_name = f"IAMbicGitHubAppECRRepo{IAMBIC_GITHUB_APP_SUFFIX}" + stack_created = await create_stack( cf_client, - stack_name=f"IAMbicGitHubAppECRRepo{IAMBIC_GITHUB_APP_SUFFIX}", + stack_name=stack_name, template_body=get_github_app_ecr_repo_template_body(), parameters=[], **additional_kwargs, @@ -367,6 +456,9 @@ async def create_github_app_code_build_stack( cf_client, target_account_id: str, role_arn: str = None, + code_build_name: str = None, + code_build_role_arn: str = None, + stack_name: str = None, tags: Optional[dict] = None, ) -> bool: additional_kwargs: dict[str, Any] = {"RoleARN": role_arn} if role_arn else {} @@ -374,14 +466,67 @@ async def create_github_app_code_build_stack( if tags: additional_kwargs["Tags"] = tags + if code_build_role_arn is None: + code_build_role_arn = f"arn:aws:iam::{target_account_id}:role/iambic_code_build{IAMBIC_GITHUB_APP_SUFFIX}" + + if stack_name is None: + stack_name = f"IAMbicGitHubAppCodeBuild{IAMBIC_GITHUB_APP_SUFFIX}" + + if code_build_name is None: + code_build_name = ("iambic_code_build",) + stack_created = await create_stack( cf_client, - stack_name=f"IAMbicGitHubAppCodeBuild{IAMBIC_GITHUB_APP_SUFFIX}", + stack_name=stack_name, template_body=get_github_app_code_build_template_body(), parameters=[ { "ParameterKey": "CodeBuildServiceRoleArn", - "ParameterValue": f"arn:aws:iam::{target_account_id}:role/iambic_code_build{IAMBIC_GITHUB_APP_SUFFIX}", + "ParameterValue": code_build_role_arn, + }, + { + "ParameterKey": "IambicCodeBuildName", + "ParameterValue": code_build_name, + }, + ], + **additional_kwargs, + ) + + return stack_created + + +async def create_generic_git_provider_lambda_stack( + cf_client, + target_account_id: str, + generic_git_provider_secret_arn: str, + role_arn: str = None, + tags: Optional[dict] = None, +) -> bool: + region = cf_client.meta.region_name + additional_kwargs: dict[str, Any] = {"RoleARN": role_arn} if role_arn else {} + assert target_account_id + if tags: + additional_kwargs["Tags"] = tags + stack_created = await create_stack( + cf_client, + stack_name=f"IAMbicGenericGitProviderLambda{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}", + template_body=get_generic_git_provider_lambda_template_body(), + parameters=[ + { + "ParameterKey": "ImageUri", + "ParameterValue": f"{target_account_id}.dkr.ecr.{region}.amazonaws.com/iambic-ecr-public/iambic/iambic:latest", + }, + { + "ParameterKey": "LambdaExecutionRoleArn", + "ParameterValue": f"arn:aws:iam::{target_account_id}:role/iambic_generic_git_provider_lambda_execution{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}", + }, + { + "ParameterKey": "LambdaFunctionName", + "ParameterValue": f"iambic_generic_git_provider_webhook{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}", + }, + { + "ParameterKey": "GenericGitProviderSecretArn", + "ParameterValue": generic_git_provider_secret_arn, }, ], **additional_kwargs, diff --git a/iambic/plugins/v0_1_0/aws/models.py b/iambic/plugins/v0_1_0/aws/models.py index 5a30e2637..1d8ee859e 100644 --- a/iambic/plugins/v0_1_0/aws/models.py +++ b/iambic/plugins/v0_1_0/aws/models.py @@ -57,6 +57,7 @@ IAMBIC_SPOKE_ROLE_NAME = os.getenv("IAMBIC_SPOKE_ROLE_NAME", "IambicSpokeRole") IAMBIC_CHANGE_DETECTION_SUFFIX = os.getenv("IAMBIC_CHANGE_DETECTION_SUFFIX", "") IAMBIC_GITHUB_APP_SUFFIX = os.getenv("IAMBIC_GITHUB_APP_SUFFIX", "") +IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX = os.getenv("IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX", "") def get_hub_role_arn(account_id: str, role_name=None) -> str: diff --git a/iambic/plugins/v0_1_0/generic_git_provider/aws_lambda_handler.py b/iambic/plugins/v0_1_0/generic_git_provider/aws_lambda_handler.py index 35b96f78c..b0fc6f174 100644 --- a/iambic/plugins/v0_1_0/generic_git_provider/aws_lambda_handler.py +++ b/iambic/plugins/v0_1_0/generic_git_provider/aws_lambda_handler.py @@ -23,6 +23,8 @@ iambic_app, ) +GENERIC_GIT_PROVIDER_SECRET_ARN = os.environ.get("GENERIC_GIT_PROVIDER_SECRET_ARN") + def run_handler(event=None, context=None): """ @@ -46,7 +48,7 @@ def _get_app_secrets_as_lambda_context_current() -> dict: try: get_secret_value_response = client.get_secret_value( - SecretId="iambic/github-app-secrets" + SecretId=GENERIC_GIT_PROVIDER_SECRET_ARN, ) except ClientError as e: # For a list of exceptions thrown, see From 5802e4901881f1c3ddeb63f55ebfc24da1d57c56 Mon Sep 17 00:00:00 2001 From: Steven Moy Date: Fri, 25 Aug 2023 17:20:56 -0700 Subject: [PATCH 3/6] updater script for user to update the version used by cloudformation template for generic git provider --- ...mbic-github-app-updater-role-template.yaml | 53 ++++++ .../upgrade_lambda.py | 151 ++++++++++++++++++ 2 files changed, 204 insertions(+) create mode 100644 deployment/upgrade_iambic_version_for_generic_git_provider_lambda/iambic-github-app-updater-role-template.yaml create mode 100644 deployment/upgrade_iambic_version_for_generic_git_provider_lambda/upgrade_lambda.py diff --git a/deployment/upgrade_iambic_version_for_generic_git_provider_lambda/iambic-github-app-updater-role-template.yaml b/deployment/upgrade_iambic_version_for_generic_git_provider_lambda/iambic-github-app-updater-role-template.yaml new file mode 100644 index 000000000..dba734214 --- /dev/null +++ b/deployment/upgrade_iambic_version_for_generic_git_provider_lambda/iambic-github-app-updater-role-template.yaml @@ -0,0 +1,53 @@ +template_type: NOQ::AWS::IAM::Role +template_schema_url: https://docs.iambic.org/reference/schemas/aws_iam_role_template +included_accounts: + - "REPLACE_THIS_WITH_YOUR_AWS_ACCOUNT_NAME_THAT_CONTAINS_IAMBIC_GENERIC_GIT_PROVIDER_LAMBDA_CODE" +identifier: iambic_generic_git_provider_updater +properties: + description: "Use to update IAMbic Generic Git Provider integration on AWS Lambda" + assume_role_policy_document: + statement: + - action: + - sts:AssumeRole + - sts:TagSession + effect: Allow + principal: + aws: "REPLACE_THIS_WITH_CI_CD_ROLE_THAT_WOULD_RUN_THE_UPDATER" + version: '2012-10-17' + inline_policies: + - policy_name: CloudFormation + statement: + - action: cloudformation:ListStacks + effect: Allow + resource: '*' + sid: ListPermissions + - action: + - cloudformation:DescribeStacks + - cloudformation:UpdateStack + effect: Allow + resource: arn:aws:cloudformation:*:{{var.account_id}}:stack/IAMbicGenericGitProviderLambda/* + version: '2012-10-17' + - policy_name: CodeBuild + statement: + - action: + - codebuild:BatchGetBuilds + - codebuild:StartBuild + effect: Allow + resource: arn:aws:codebuild:*:{{var.account_id}}:project/iambic_code_build + version: '2012-10-17' + - policy_name: ECR + statement: + - action: ecr:DescribeImages + effect: Allow + resource: arn:aws:ecr:*:{{var.account_id}}:repository/iambic-ecr-public/iambic/iambic + version: '2012-10-17' + - policy_name: Lambda + statement: + - action: + - lambda:GetFunctionUrlConfig + - lambda:ListTags + - lambda:UpdateFunctionCode + effect: Allow + resource: arn:aws:lambda:*:{{var.account_id}}:function:iambic_generic_git_provider_webhook + version: '2012-10-17' + role_name: iambic_generic_git_provider_updater \ No newline at end of file diff --git a/deployment/upgrade_iambic_version_for_generic_git_provider_lambda/upgrade_lambda.py b/deployment/upgrade_iambic_version_for_generic_git_provider_lambda/upgrade_lambda.py new file mode 100644 index 000000000..30df5e9b6 --- /dev/null +++ b/deployment/upgrade_iambic_version_for_generic_git_provider_lambda/upgrade_lambda.py @@ -0,0 +1,151 @@ +from __future__ import annotations + +import os +import time + +import boto3 + +REGION_NAME = os.environ.get("AWS_REGION", "us-east-1") +IAMBIC_CODE_BUILD_PROJECT_NAME = os.environ.get( + "IAMBIC_CODE_BUILD_PROJECT_NAME", "iambic_code_build" +) +IAMBIC_FUNCTION_NAME = os.environ.get( + "IAMBIC_FUNCTION_NAME", "iambic_generic_git_provider_webhook" +) +IAMBIC_REPOSITORY_NAME = os.environ.get( + "IAMBIC_REPOSITORY_NAME", "iambic-ecr-public/iambic/iambic" +) +IAMBIC_CF_LAMBDA_STACK_NAME = os.environ.get( + "IAMBIC_CF_LAMBDA_STACK_NAME", "IAMbicGenericGitProviderLambda" +) +IAMBIC_TARGET_VERSION = os.environ.get("IAMBIC_TARGET_VERSION", "latest") + + +def start_code_build_with_pin_version(ver): + code_build_client = boto3.client("codebuild", region_name=REGION_NAME) + + response = code_build_client.start_build( + projectName=IAMBIC_CODE_BUILD_PROJECT_NAME, + environmentVariablesOverride=[ + { + "name": "IMAGE_TAG", + "value": ver, + "type": "PLAINTEXT", + }, + ], + ) + + build_id = response["build"]["id"] + # FIXME explain why this is stalling for builds + # log.info("Preparing container image. This process should take around 2 minutes") + for _ in range(6): + resp = code_build_client.batch_get_builds(ids=[build_id]) + build_status = resp["builds"][0]["buildStatus"] + if build_status == "IN_PROGRESS": + time.sleep(30) + continue + elif build_status == "SUCCEEDED": + break + else: + raise ValueError(f"build status is {build_status}") + + +def is_image_label_ready(ecr_client, ver): + if ver == "latest": + raise ValueError( + "We do not support `latest` as image label because ECR cache maybe out of date. Please point to a specific version" + ) + repository_name = IAMBIC_REPOSITORY_NAME + try: + resp = ecr_client.describe_images( + repositoryName=repository_name, imageIds=[{"imageTag": ver}] + ) + if len(resp["imageDetails"]) == 0: + return False + else: + return True + except ecr_client.exceptions.ImageNotFoundException: + return False + + +def wait_until_image_is_ready(ecr_client, ver): + print("Waiting for image label to be ready") + for _ in range(6): + if is_image_label_ready(ecr_client, ver): + break + else: + time.sleep(30) + continue + + +def update_lambda_code(ver): + client = boto3.client("lambda", region_name=REGION_NAME) + response = client.get_function( + FunctionName=IAMBIC_FUNCTION_NAME, + ) + image_uri = response["Code"]["ImageUri"] + base_uri, current_ver = image_uri.split(":") + assert base_uri + assert current_ver + new_image_uri = f"{base_uri}:{ver}" + print(f"new image uri: {new_image_uri}") + response = client.update_function_code( + FunctionName=IAMBIC_FUNCTION_NAME, + ImageUri=new_image_uri, + Publish=True, + ) + + +def update_cf_lambda_ver(ver): + client = boto3.client("cloudformation", region_name=REGION_NAME) + response = client.describe_stacks( + StackName=IAMBIC_CF_LAMBDA_STACK_NAME, + ) + existing_parameters = response["Stacks"][0]["Parameters"] + new_parameters = [] + image_uri = None + for param in existing_parameters: + if param["ParameterKey"] != "ImageUri": + new_parameters.append( + {"ParameterKey": param["ParameterKey"], "UsePreviousValue": True} + ) + else: + image_uri = param["ParameterValue"] + assert image_uri + base_uri, current_ver = image_uri.split(":") + assert base_uri + assert current_ver + new_image_uri = f"{base_uri}:{ver}" + print(f"new image uri: {new_image_uri}") + new_parameters.append({"ParameterKey": "ImageUri", "ParameterValue": new_image_uri}) + response = client.update_stack( + StackName=IAMBIC_CF_LAMBDA_STACK_NAME, + UsePreviousTemplate=True, + Parameters=new_parameters, + ) + for _ in range(6): + response = client.describe_stacks( + StackName=IAMBIC_CF_LAMBDA_STACK_NAME, + ) + stack_status = response["Stacks"][0]["StackStatus"] + if stack_status != "UPDATE_IN_PROGRESS": + print(f"stack status: {stack_status}") + break + else: + print("waiting for stack to finish updating") + time.sleep(60) + + +def upgrade_lambda(ver): + ecr_client = boto3.client("ecr", region_name=REGION_NAME) + if not is_image_label_ready(ecr_client, ver): + # only trigger the pull if the version is not already in ECR + # this helps speed up rollback + start_code_build_with_pin_version(ver) + # the wait is required due to eventual consistency + wait_until_image_is_ready(ecr_client, ver) + update_cf_lambda_ver(ver) + + +if __name__ == "__main__": + upgrade_lambda(IAMBIC_TARGET_VERSION) From 37ae9cdee577d373db06c1260846d47a6f909faf Mon Sep 17 00:00:00 2001 From: Steven Moy Date: Mon, 28 Aug 2023 14:53:24 -0700 Subject: [PATCH 4/6] Add docs --- .../3-reference/14-generic-git-provider.mdx | 85 +++++++++++++++++++ ...urity-credentials-generate-credentials.png | 3 + ...decommit-iam-user-security-credentials.png | 3 + .../aws-codecommit-iam-user.png | 3 + .../generic-git-provider/bitbucket-clone.png | 3 + ...ucket-create-repository-access-token-2.png | 3 + ...ucket-create-repository-access-token-3.png | 3 + ...tbucket-create-repository-access-token.png | 3 + .../bitbucket-repository-settings.png | 3 + .../bitbucket-security-access-tokens.png | 3 + .../gitlab-add-new-token-details.png | 3 + .../gitlab-add-new-token.png | 3 + .../generic-git-provider/gitlab-settings.png | 3 + 13 files changed, 121 insertions(+) create mode 100644 docs/web/docs/3-reference/14-generic-git-provider.mdx create mode 100644 docs/web/static/img/git/generic-git-provider/aws-codecommit-iam-user-security-credentials-generate-credentials.png create mode 100644 docs/web/static/img/git/generic-git-provider/aws-codecommit-iam-user-security-credentials.png create mode 100644 docs/web/static/img/git/generic-git-provider/aws-codecommit-iam-user.png create mode 100644 docs/web/static/img/git/generic-git-provider/bitbucket-clone.png create mode 100644 docs/web/static/img/git/generic-git-provider/bitbucket-create-repository-access-token-2.png create mode 100644 docs/web/static/img/git/generic-git-provider/bitbucket-create-repository-access-token-3.png create mode 100644 docs/web/static/img/git/generic-git-provider/bitbucket-create-repository-access-token.png create mode 100644 docs/web/static/img/git/generic-git-provider/bitbucket-repository-settings.png create mode 100644 docs/web/static/img/git/generic-git-provider/bitbucket-security-access-tokens.png create mode 100644 docs/web/static/img/git/generic-git-provider/gitlab-add-new-token-details.png create mode 100644 docs/web/static/img/git/generic-git-provider/gitlab-add-new-token.png create mode 100644 docs/web/static/img/git/generic-git-provider/gitlab-settings.png diff --git a/docs/web/docs/3-reference/14-generic-git-provider.mdx b/docs/web/docs/3-reference/14-generic-git-provider.mdx new file mode 100644 index 000000000..724542e89 --- /dev/null +++ b/docs/web/docs/3-reference/14-generic-git-provider.mdx @@ -0,0 +1,85 @@ +--- +title: Setup IAMbic with Generic Git Provider +--- + +# Overview +Current implementation IAMbic work best with GitHub. As the project evolves, more Git provider +will be supported. Until then, if you like to use IAMbic with non-explicitly supported provider. +You can use this guide to setup IAMbic. + +The generic git provider support uses https protocol with http basic auth to authenticate with +git provider to clone the repository. Almost all git providers has a way to create a repository-scoped +access token. Consult your Git provider documentation to generate a repository-scope access token. +We recommend against using your regular username/password to authenticate for IAMbic usage. It's +safer to generate a app specific access token to audit access to your private repository. + +As a reminder, if your git provider has explicit support, you should use the provider specific +implementation as that has more native integrated features. + +# Pre-requisite + +1. In your git provider, create a repository called `iambic-templates`. The contents of the repository will be like +[this](https://github.com/noqdev/github-iambic-templates). We recommend you to keep this repository private +because there is no need for this to be publicly accessible. +1. Run `iambic setup` to generate the necessary IAMbic config file. Check the config file into your private repository. +1. Generate a repository-scoped access token for your private repository. Next section includes include some well known +providers. + + +# Generate repository-scoped access token + +## BitBucket +1. Navigate to your BitBucket `iambic-templates` repository. +1. Click "Repository Settings" +1. Click "Access tokens" under Security + +1. Click "Create Repository Access Token" + +1. For name, input `iambic-integrations`. For scopes, click "Write" under repository. In order for iambic to integrate + +automatic import. The token needs to have write permission to write the new change into the repository. Click Create. + +1. Save the token in a a safe place. You will not be able to return to this screen later. + +1. Note the value is later on referenced as the "access token". +1. For BitBucket, the corresponding username is `x-token-auth` + +## AWS CodeCommit +1. Navigate to AWS IAM user. If you don't already have an IAM user to represent automation usage. Please create one. +The IAM user does not need AWS API keys or AWS console login. You don't have to create them for the only https codecommit usage. + +1. Click on "Security Credentials" + +1. Click on "Generate credentials" +1. Save the username and password in a safe place. You will not be able to go back to this screen later. + + +## GitLab +1. Navigate to your `iambic-templates` repository in GitLab +1. Click "Settings", then click "Access Token" + +1. Click "Add new token" + +1. Token name, input "iambic-integrations" +1. Expiration date, pick a date you are comfortable with. When your token is expired, you have to generate a new one. +1. Select a role, choose "Maintainer". (iambic automatic import will push to iambic-template default branch) +1. Select scopes, choose "write repository" (iambic automatic import will push to iambic-template default branch). + +1. Save the token in a a safe place. You will not be able to return to this screen later. +1. For GitLab, the corresponding username is name of your token. In this instruction, we name it `iambic-integrations` + +# Install AWS Lambda to run automatic import to your iambic-templates repository with a generic git provider +1. Navigate to your locally clone checkout of your private `iambic-templates` repository +1. Run `iambic setup` +1. Select "Setup Generic Git Provider Integration using AWS Lambda" +1. When prompt for "username": use the username for your prepared access token. +1. When prompt for "access token": use your prepared access token for "iambic-templates" repository. +1. When prompt for "clone url", this is the https clone url for private repository. +(for example: "https://bitbucket.org/iambic-test-org/iambic-templates.git") yours will be different. +1. When prompt for "default branch", input your configured default branch. This is typically default or main. +1. When prompt for "repo full name", input your "YOUR_ORG_IDENTIFIER/iambic-templates". +(for example: "iambic-test-org/iambic-templates"). Yours should be different. +1. Follow the onscreen instruction, until you are return to the menu. +1. Select Done. +1. At this point, a AWS Lambda function is installed in your account to periodically run "iambic import". +The up-to-date templates will be pushed into your configured repository. \ No newline at end of file diff --git a/docs/web/static/img/git/generic-git-provider/aws-codecommit-iam-user-security-credentials-generate-credentials.png b/docs/web/static/img/git/generic-git-provider/aws-codecommit-iam-user-security-credentials-generate-credentials.png new file mode 100644 index 000000000..42809ecfa --- /dev/null +++ b/docs/web/static/img/git/generic-git-provider/aws-codecommit-iam-user-security-credentials-generate-credentials.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8a62c2ddd3943d6f2b816850a7375a4a0d8facf0de606ed0f558fda8230aacec +size 56092 diff --git a/docs/web/static/img/git/generic-git-provider/aws-codecommit-iam-user-security-credentials.png b/docs/web/static/img/git/generic-git-provider/aws-codecommit-iam-user-security-credentials.png new file mode 100644 index 000000000..7af40804a --- /dev/null +++ b/docs/web/static/img/git/generic-git-provider/aws-codecommit-iam-user-security-credentials.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:97ca939ee76231f5adaa1306d40695b90110d69e5480fcf1f3e0d803d99739a0 +size 95004 diff --git a/docs/web/static/img/git/generic-git-provider/aws-codecommit-iam-user.png b/docs/web/static/img/git/generic-git-provider/aws-codecommit-iam-user.png new file mode 100644 index 000000000..fa6644d91 --- /dev/null +++ b/docs/web/static/img/git/generic-git-provider/aws-codecommit-iam-user.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bdb1bf479d7c8642ea65e063b4e421f37cdd3c800d1b5a5ddc78a4e7e051c618 +size 91017 diff --git a/docs/web/static/img/git/generic-git-provider/bitbucket-clone.png b/docs/web/static/img/git/generic-git-provider/bitbucket-clone.png new file mode 100644 index 000000000..e7909aa61 --- /dev/null +++ b/docs/web/static/img/git/generic-git-provider/bitbucket-clone.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4800baf3c24526eba7dbb572194b49c1ca20f8802bad66abfe211f89867ee242 +size 33357 diff --git a/docs/web/static/img/git/generic-git-provider/bitbucket-create-repository-access-token-2.png b/docs/web/static/img/git/generic-git-provider/bitbucket-create-repository-access-token-2.png new file mode 100644 index 000000000..6b291bc1c --- /dev/null +++ b/docs/web/static/img/git/generic-git-provider/bitbucket-create-repository-access-token-2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64906beaf3d411af5fc5b30c53cac4141779e510e2f649e6224ef8d42ce61b56 +size 124779 diff --git a/docs/web/static/img/git/generic-git-provider/bitbucket-create-repository-access-token-3.png b/docs/web/static/img/git/generic-git-provider/bitbucket-create-repository-access-token-3.png new file mode 100644 index 000000000..b20c90790 --- /dev/null +++ b/docs/web/static/img/git/generic-git-provider/bitbucket-create-repository-access-token-3.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f3b0f1cadd4b3299ea3799461914be5c8493ae71e18c7a96ec22b3aee3a550e6 +size 60572 diff --git a/docs/web/static/img/git/generic-git-provider/bitbucket-create-repository-access-token.png b/docs/web/static/img/git/generic-git-provider/bitbucket-create-repository-access-token.png new file mode 100644 index 000000000..06254980c --- /dev/null +++ b/docs/web/static/img/git/generic-git-provider/bitbucket-create-repository-access-token.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e0d213d8b92473b39354402978802ddebdf38f9f8025f812897672f991d93308 +size 112749 diff --git a/docs/web/static/img/git/generic-git-provider/bitbucket-repository-settings.png b/docs/web/static/img/git/generic-git-provider/bitbucket-repository-settings.png new file mode 100644 index 000000000..6c478c9ba --- /dev/null +++ b/docs/web/static/img/git/generic-git-provider/bitbucket-repository-settings.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a1a39cdf1434d43e80ad193f37baefc35d36ed578b6231579efef2f4787753a9 +size 106597 diff --git a/docs/web/static/img/git/generic-git-provider/bitbucket-security-access-tokens.png b/docs/web/static/img/git/generic-git-provider/bitbucket-security-access-tokens.png new file mode 100644 index 000000000..4a30291d3 --- /dev/null +++ b/docs/web/static/img/git/generic-git-provider/bitbucket-security-access-tokens.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d42ab5610cfb4a1b7530eb4b62b5441796b45ee074edf050f43156ba3318f8b2 +size 105651 diff --git a/docs/web/static/img/git/generic-git-provider/gitlab-add-new-token-details.png b/docs/web/static/img/git/generic-git-provider/gitlab-add-new-token-details.png new file mode 100644 index 000000000..b39948e4d --- /dev/null +++ b/docs/web/static/img/git/generic-git-provider/gitlab-add-new-token-details.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:50ed01dc0896768f300b9081608938f0db70170e80bb46f5d29b542a710bbdfc +size 179523 diff --git a/docs/web/static/img/git/generic-git-provider/gitlab-add-new-token.png b/docs/web/static/img/git/generic-git-provider/gitlab-add-new-token.png new file mode 100644 index 000000000..0fd30c3f2 --- /dev/null +++ b/docs/web/static/img/git/generic-git-provider/gitlab-add-new-token.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b48c557077bb66ca7008787b42cc9f9b59e6a4f11a3b8af751466d82acb02e8 +size 114376 diff --git a/docs/web/static/img/git/generic-git-provider/gitlab-settings.png b/docs/web/static/img/git/generic-git-provider/gitlab-settings.png new file mode 100644 index 000000000..b2a1d929c --- /dev/null +++ b/docs/web/static/img/git/generic-git-provider/gitlab-settings.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dc26e985ceda309ffaf3a44d37fe96cf89e51082c5e726919fdecbadffe4787b +size 161598 From de15eb97b13e8e628f122782eb146942d1a95339 Mon Sep 17 00:00:00 2001 From: Curtis Castrapel Date: Mon, 28 Aug 2023 16:17:18 -0700 Subject: [PATCH 5/6] minor doc fixes --- .../3-reference/14-generic-git-provider.mdx | 109 +++++++----------- 1 file changed, 39 insertions(+), 70 deletions(-) diff --git a/docs/web/docs/3-reference/14-generic-git-provider.mdx b/docs/web/docs/3-reference/14-generic-git-provider.mdx index 724542e89..73badecc1 100644 --- a/docs/web/docs/3-reference/14-generic-git-provider.mdx +++ b/docs/web/docs/3-reference/14-generic-git-provider.mdx @@ -3,83 +3,52 @@ title: Setup IAMbic with Generic Git Provider --- # Overview -Current implementation IAMbic work best with GitHub. As the project evolves, more Git provider -will be supported. Until then, if you like to use IAMbic with non-explicitly supported provider. -You can use this guide to setup IAMbic. +IAMbic primarily supports GitHub, but you can set it up with other Git providers using this guide. +The method involves using HTTPS protocol and HTTP basic auth. Create a repository-specific access +token for safer authentication. -The generic git provider support uses https protocol with http basic auth to authenticate with -git provider to clone the repository. Almost all git providers has a way to create a repository-scoped -access token. Consult your Git provider documentation to generate a repository-scope access token. -We recommend against using your regular username/password to authenticate for IAMbic usage. It's -safer to generate a app specific access token to audit access to your private repository. +If your Git provider is explicitly supported, it's better to use the specific +implementation for additional features. -As a reminder, if your git provider has explicit support, you should use the provider specific -implementation as that has more native integrated features. +# Pre-requisites +1. Create a private repository called `iambic-templates` on your Git provider. Keep this repository private. +The contents of the repository will be like [this](https://github.com/noqdev/github-iambic-templates) +1. Run `iambic setup` and commit the generated config file to your private repository. +1. Generate a repository-scoped access token. Guidance for popular providers is provided below. -# Pre-requisite - -1. In your git provider, create a repository called `iambic-templates`. The contents of the repository will be like -[this](https://github.com/noqdev/github-iambic-templates). We recommend you to keep this repository private -because there is no need for this to be publicly accessible. -1. Run `iambic setup` to generate the necessary IAMbic config file. Check the config file into your private repository. -1. Generate a repository-scoped access token for your private repository. Next section includes include some well known -providers. - - -# Generate repository-scoped access token +# Generate Repository-Scoped Access Token ## BitBucket -1. Navigate to your BitBucket `iambic-templates` repository. -1. Click "Repository Settings" -1. Click "Access tokens" under Security - -1. Click "Create Repository Access Token" - -1. For name, input `iambic-integrations`. For scopes, click "Write" under repository. In order for iambic to integrate - -automatic import. The token needs to have write permission to write the new change into the repository. Click Create. - -1. Save the token in a a safe place. You will not be able to return to this screen later. +Follow the steps below to create a repository access token in BitBucket: +1. Navigate to `iambic-templates` → "Repository Settings" → "Access tokens" under Security. + +1. Click "Create Repository Access Token". + +1. Name it `iambic-integrations`, select "Write" under repository, and click Create. + + +1. Save the token. You'll use it as the "access token" and `x-token-auth` as the username. -1. Note the value is later on referenced as the "access token". -1. For BitBucket, the corresponding username is `x-token-auth` ## AWS CodeCommit -1. Navigate to AWS IAM user. If you don't already have an IAM user to represent automation usage. Please create one. -The IAM user does not need AWS API keys or AWS console login. You don't have to create them for the only https codecommit usage. - -1. Click on "Security Credentials" - -1. Click on "Generate credentials" -1. Save the username and password in a safe place. You will not be able to go back to this screen later. - +Follow these steps for AWS CodeCommit: +1. Navigate to IAM → User → "Security Credentials". + +1. Click "Generate credentials" and save them. + ## GitLab -1. Navigate to your `iambic-templates` repository in GitLab -1. Click "Settings", then click "Access Token" - -1. Click "Add new token" - -1. Token name, input "iambic-integrations" -1. Expiration date, pick a date you are comfortable with. When your token is expired, you have to generate a new one. -1. Select a role, choose "Maintainer". (iambic automatic import will push to iambic-template default branch) -1. Select scopes, choose "write repository" (iambic automatic import will push to iambic-template default branch). - -1. Save the token in a a safe place. You will not be able to return to this screen later. -1. For GitLab, the corresponding username is name of your token. In this instruction, we name it `iambic-integrations` - -# Install AWS Lambda to run automatic import to your iambic-templates repository with a generic git provider -1. Navigate to your locally clone checkout of your private `iambic-templates` repository -1. Run `iambic setup` -1. Select "Setup Generic Git Provider Integration using AWS Lambda" -1. When prompt for "username": use the username for your prepared access token. -1. When prompt for "access token": use your prepared access token for "iambic-templates" repository. -1. When prompt for "clone url", this is the https clone url for private repository. -(for example: "https://bitbucket.org/iambic-test-org/iambic-templates.git") yours will be different. -1. When prompt for "default branch", input your configured default branch. This is typically default or main. -1. When prompt for "repo full name", input your "YOUR_ORG_IDENTIFIER/iambic-templates". -(for example: "iambic-test-org/iambic-templates"). Yours should be different. -1. Follow the onscreen instruction, until you are return to the menu. -1. Select Done. -1. At this point, a AWS Lambda function is installed in your account to periodically run "iambic import". -The up-to-date templates will be pushed into your configured repository. \ No newline at end of file +Here's how to generate a token in GitLab: +1. Go to `iambic-templates` → "Settings" → "Access Token". + +1. Click "Add new token", name it `iambic-integrations`, and select "Maintainer" role with "write repository" scope. + +1. Save the token. You'll use it as the "access token" and `iambic-integrations` as the username. + +# AWS Lambda Setup for Automatic Import +1. Navigate to your local copy of `iambic-templates` and run `iambic setup`. +1. Choose "Setup Generic Git Provider Integration using AWS Lambda". +1. Provide username, access token, clone URL, default branch, and repo full name when prompted. + 1. Example clone URL: "https://bitbucket.org/iambic-test-org/iambic-templates.git" + 1. Example repo full name: "YOUR_ORG_IDENTIFIER/iambic-templates" +1. Follow on-screen instructions to complete the setup. AWS Lambda will be configured to periodically run "iambic import". From 18c400e3c2f16a67e03595f6f586c318dc650d58 Mon Sep 17 00:00:00 2001 From: Steven Moy Date: Tue, 29 Aug 2023 10:09:25 -0700 Subject: [PATCH 6/6] Address review feedbacks --- .../upgrade_lambda.py | 4 +-- docs/cep/000-cep-template.md | 2 +- iambic/config/wizard.py | 27 ------------------- .../generic_git_client.py | 2 +- 4 files changed, 4 insertions(+), 31 deletions(-) diff --git a/deployment/upgrade_iambic_version_for_generic_git_provider_lambda/upgrade_lambda.py b/deployment/upgrade_iambic_version_for_generic_git_provider_lambda/upgrade_lambda.py index 30df5e9b6..38d7602fc 100644 --- a/deployment/upgrade_iambic_version_for_generic_git_provider_lambda/upgrade_lambda.py +++ b/deployment/upgrade_iambic_version_for_generic_git_provider_lambda/upgrade_lambda.py @@ -1,5 +1,6 @@ from __future__ import annotations +import logging import os import time @@ -36,8 +37,7 @@ def start_code_build_with_pin_version(ver): ) build_id = response["build"]["id"] - # FIXME explain why this is stalling for builds - # log.info("Preparing container image. This process should take around 2 minutes") + logging.info("Preparing container image. This process should take around 2 minutes") for _ in range(6): resp = code_build_client.batch_get_builds(ids=[build_id]) build_status = resp["builds"][0]["buildStatus"] diff --git a/docs/cep/000-cep-template.md b/docs/cep/000-cep-template.md index c25159a75..27d13a860 100644 --- a/docs/cep/000-cep-template.md +++ b/docs/cep/000-cep-template.md @@ -1,7 +1,7 @@ # CEP xxx - Code Enhancement Proposal Title ## Champion -Who will help organize the effort of getting this implement? +Who will help organize the effort of getting this implemented? ## Summary Short summary about a code enhancement proposal diff --git a/iambic/config/wizard.py b/iambic/config/wizard.py index a2eab9898..d881f2661 100644 --- a/iambic/config/wizard.py +++ b/iambic/config/wizard.py @@ -2083,33 +2083,6 @@ def configuration_generic_git_provider_aws_lambda_setup(self): # noqa: C901 ) assert successfully_created - # TODO Disable for now since we don't have webhook integrated yet. - # webhook_url = None - - # lambda_stack_name = f"IAMbicGenericGitProviderLambda{IAMBIC_GENERIC_GIT_PROVIDER_SUFFIX}" - # response = cf_client.describe_stacks(StackName=lambda_stack_name) - # outputs = response["Stacks"][0]["Outputs"] - # for output in outputs: - # keyName = output["OutputKey"] - # if keyName == "FunctionUrl": - # webhook_url = output["OutputValue"] - - # assert webhook_url - - # github_app_jwt = generate_jwt(generic_git_provider_secrets) - # try: - # update_webhook_url(webhook_url, github_app_jwt) - # except Exception: - # log.exception( - # "Failed to update webhook URL with GitHub App. Please manually update the webhook URL in the GitHub App settings page", - # webhook_url=webhook_url, - # ) - # if not questionary.confirm("Proceed?").unsafe_ask(): - # return - - # # Remove the local secrets because it's already saved in secret manager - # remove_github_app_secrets() - def configuration_github_app_aws_lambda_setup(self): # noqa: C901 from iambic.plugins.v0_1_0.aws.cloud_formation.utils import ( IAMBIC_GITHUB_APP_SUFFIX, diff --git a/iambic/plugins/v0_1_0/generic_git_provider/generic_git_client.py b/iambic/plugins/v0_1_0/generic_git_provider/generic_git_client.py index 565109b55..0913d98a0 100644 --- a/iambic/plugins/v0_1_0/generic_git_provider/generic_git_client.py +++ b/iambic/plugins/v0_1_0/generic_git_provider/generic_git_client.py @@ -20,7 +20,7 @@ def __init__(self, secrets): self.default_branch_name = secrets["default_branch_name"] self.repo_full_name = secrets["repo_full_name"] - # we should always take the precaution someone did not give us a non-https url + # we should always take the precaution someone give us a non-https url assert self.clone_url.startswith("https://") # we should always take the precaution someone did not sneak an @ in the url # that may accidentally be a password. A simple assert may print the potential