Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions tests/ci/cdk/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@ __pycache__
# CDK asset staging directory
.cdk.staging
cdk.out

cr/
125 changes: 125 additions & 0 deletions tests/ci/cdk/cdk/aws_lc_ai_code_review_stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR ISC
import typing

from aws_cdk import (
Duration,
Tags,
aws_codebuild as codebuild,
aws_iam as iam,
aws_s3 as s3,
RemovalPolicy,
Environment,
)
from constructs import Construct

from util.metadata import (
GITHUB_REPO_OWNER,
GITHUB_REPO_NAME
)

from cdk.aws_lc_base_ci_stack import AwsLcBaseCiStack
from cdk.components import PruneStaleGitHubBuilds
from util.iam_policies import (
bedrock_policy_in_json
)
from util.build_spec_loader import BuildSpecLoader

class AwsLcAiCodeReviewStack(AwsLcBaseCiStack):
"""Define a stack used to batch execute AWS-LC tests in GitHub."""

def __init__(
self,
scope: Construct,
id: str,
spec_file_path: str,
env: typing.Union[Environment, typing.Dict[str, typing.Any]],
**kwargs
) -> None:
super().__init__(scope, id, env=env, timeout=180, **kwargs)

# Create S3 bucket for AI code review files with versioning
bucket = s3.Bucket(
self,
"aws-lc-ai-code-review-files",
versioned=True,
removal_policy=RemovalPolicy.RETAIN,
block_public_access=s3.BlockPublicAccess.BLOCK_ALL,
)

# Tag the bucket for easy discovery
Tags.of(bucket).add("aws-lc", "aws-lc-ai-code-review-files")

self.git_hub_source = codebuild.Source.git_hub(
owner=self.github_repo_owner,
repo=self.github_repo_name,
webhook=True,
Comment thread
nhatnghiho marked this conversation as resolved.
webhook_filters=[
codebuild.FilterGroup.in_event_of(
codebuild.EventAction.PULL_REQUEST_CREATED,
codebuild.EventAction.PULL_REQUEST_UPDATED,
codebuild.EventAction.PULL_REQUEST_REOPENED,
)
],
webhook_triggers_batch_build=False,
)

# Define a IAM role for this stack.
bedrock_policy = iam.PolicyDocument.from_json(
bedrock_policy_in_json()
)

inline_policies = {
"bedrock_policy": bedrock_policy,
}
role = iam.Role(
scope=self,
id="{}-role".format(id),
assumed_by=iam.ServicePrincipal("codebuild.amazonaws.com"),
inline_policies=inline_policies,
)

# Grant CodeBuild read access to the S3 bucket
bucket.grant_read(role)

# Define CodeBuild.
project = codebuild.Project(
scope=self,
id=id,
project_name=id,
source=self.git_hub_source,
role=role,
timeout=Duration.minutes(self.timeout),
environment=codebuild.BuildEnvironment(
compute_type=codebuild.ComputeType.SMALL,
privileged=False,
build_image=codebuild.LinuxBuildImage.STANDARD_7_0,
environment_variables={
"GITHUB_REPO_OWNER": codebuild.BuildEnvironmentVariable(
type=codebuild.BuildEnvironmentVariableType.PLAINTEXT,
value=GITHUB_REPO_OWNER
),
"GITHUB_REPO_NAME": codebuild.BuildEnvironmentVariable(
type=codebuild.BuildEnvironmentVariableType.PLAINTEXT,
value=GITHUB_REPO_NAME
),
"AI_CODE_REVIEW_BUCKET": codebuild.BuildEnvironmentVariable(
type=codebuild.BuildEnvironmentVariableType.PLAINTEXT,
value=bucket.bucket_name
)
}
),
build_spec=BuildSpecLoader.load(spec_file_path, env=env),
)

cfn_project = project.node.default_child
cfn_project.add_property_override("Triggers.PullRequestBuildPolicy", self.pull_request_policy)

PruneStaleGitHubBuilds(
scope=self,
id="PruneStaleGitHubBuilds",
project=project,
ec2_permissions=False,
env=env,
)

17 changes: 17 additions & 0 deletions tests/ci/cdk/cdk/codebuild/ai_code_review_omnibus.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: Apache-2.0 OR ISC

version: 0.2

phases:
install:
runtime-versions:
nodejs: 18
pre_build:
commands:
# Download all files from S3
- aws s3 sync "s3://${AI_CODE_REVIEW_BUCKET}/" ./tests/ci/cdk/cr/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the script function download_ai_code_review_files be reused here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can but it'll be more steps and potentially more confusing. I think run-cdk.sh should be used for local development only

- chmod +x ./tests/ci/cdk/cr/*.sh
build:
commands:
- ./tests/ci/cdk/cr/run_ai_code_review.sh
12 changes: 11 additions & 1 deletion tests/ci/cdk/pipeline/ci_util.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from aws_cdk import Environment
from constructs import Construct

from cdk.aws_lc_ai_code_review_stack import AwsLcAiCodeReviewStack
from cdk.aws_lc_analytics_stack import AwsLcGitHubAnalyticsStack
from cdk.aws_lc_android_ci_stack import AwsLcAndroidCIStack
from cdk.aws_lc_ec2_test_framework_ci_stack import AwsLcEC2TestingCIStack
Expand Down Expand Up @@ -105,4 +106,13 @@ def add_ci_stacks(
ignore_failure=True,
stack_name="aws-lc-ci-x509",
)


ai_pr_review_spec_file = "cdk/codebuild/ai_code_review_omnibus.yaml"
AwsLcAiCodeReviewStack(
scope,
"aws-lc-ai-code-review",
ai_pr_review_spec_file,
env=env,
ignore_failure=False,
stack_name="aws-lc-ai-code-review"
)
80 changes: 80 additions & 0 deletions tests/ci/cdk/run-cdk.sh
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are upload_ai_code_review_files and download_ai_code_review_files provided to make editing the s3 bucket contents easier?

Nit: We're missing documentation for upload_ai_code_review_files btw.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are upload_ai_code_review_files and download_ai_code_review_files provided to make editing the s3 bucket contents easier?

Yup! I think this will be useful to those that want to edit the files but don't want to install/deal with the cdk cli or the AWS console.

Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,74 @@ function deploy_dev_pipeline() {
cdk deploy AwsLcCiPipeline --require-approval never
}

function deploy_ai_code_review() {
local cr_dir="$(dirname "$0")/cr"

echo "Deploying AI code review stack first..."
cdk deploy AwsLcCiPipeline/Dev-CiTests/aws-lc-ai-code-review --require-approval never

if [[ ! -d "${cr_dir}" ]]; then
echo "Error: cr/ directory not found at ${cr_dir}"
return
fi

# Find bucket after deployment
bucket_name=$(aws s3api list-buckets --query "Buckets[].Name" --output text | tr '\t' '\n' | while read -r bucket; do
tags=$(aws s3api get-bucket-tagging --bucket "${bucket}" 2>/dev/null || echo "")
if echo "${tags}" | grep -q ${S3_BUCKET_TAG_FOR_AI_CODE_REVIEW}; then
echo "${bucket}"
break
fi
done)

echo "Uploading files to s3://${bucket_name}/"
aws s3 sync "${cr_dir}/" "s3://${bucket_name}/" --delete
}

function upload_ai_code_review_files() {
local cr_dir="$(dirname "$0")/cr"

if [[ ! -d "${cr_dir}" ]]; then
echo "Error: cr/ directory not found at ${cr_dir}"
return
fi

# Find bucket after deployment
bucket_name=$(aws s3api list-buckets --query "Buckets[].Name" --output text | tr '\t' '\n' | while read -r bucket; do
tags=$(aws s3api get-bucket-tagging --bucket "${bucket}" 2>/dev/null || echo "")
if echo "${tags}" | grep -q ${S3_BUCKET_TAG_FOR_AI_CODE_REVIEW}; then
echo "${bucket}"
break
fi
done)

echo "Uploading files to s3://${bucket_name}/"
aws s3 sync "${cr_dir}/" "s3://${bucket_name}/" --delete
}

function download_ai_code_review_files() {
local cr_dir="$(dirname "$0")/cr"

# Find bucket by tag
local bucket_name=$(aws s3api list-buckets --query "Buckets[].Name" --output text | tr '\t' '\n' | while read -r bucket; do
tags=$(aws s3api get-bucket-tagging --bucket "${bucket}" 2>/dev/null || echo "")
if echo "${tags}" | grep -q ${S3_BUCKET_TAG_FOR_AI_CODE_REVIEW}; then
echo "${bucket}"
break
fi
done)

if [[ -z "${bucket_name}" ]]; then
echo "Error: No bucket found with tag ${S3_BUCKET_TAG_FOR_AI_CODE_REVIEW}"
exit 1
fi

mkdir -p "${cr_dir}"

echo "Downloading files from s3://${bucket_name}/ to cr/"
aws s3 sync "s3://${bucket_name}/" "${cr_dir}/"
}

###########################
# Main and related helper #
###########################
Expand All @@ -266,6 +334,8 @@ Options:
After image build, AWS resources are cleaned up.
'build-win-img': builds Windows Docker image used by aws-lc ci.
After image build, AWS resources are cleaned up.
'deploy-ai-code-review': syncs cr/ files to S3 and deploys AI code review stack.
'download-ai-code-review-files': downloads files from S3 to local cr/ directory.
'diff': compares the specified stack with the deployed stack.
'synth': synthesizes and prints the CloudFormation template for the stacks.
'bootstrap': Bootstraps the CDK stack. This is needed before deployment or updating the CI.
Expand Down Expand Up @@ -302,6 +372,7 @@ function export_global_variables() {
export S3_FOR_WIN_DOCKER_IMG_BUILD='aws-lc-windows-docker-image-build-s3'
export MAX_TEST_RETRY=2
export IMG_BUILD_STATUS='unknown'
export S3_BUCKET_TAG_FOR_AI_CODE_REVIEW='aws-lc-ai-code-review-files'
# 620771051181 and 351119683581 is AWS-LC team AWS account.
if [[ "${DEPLOY_ACCOUNT}" != "620771051181" && "${DEPLOY_ACCOUNT}" != '351119683581' ]] && [[ "${GITHUB_REPO_OWNER}" == 'aws' ]]; then
echo "Only team account is allowed to create CI stacks on aws repo."
Expand Down Expand Up @@ -378,6 +449,15 @@ function main() {
export IS_DEV="True"
deploy_dev_pipeline
;;
deploy-ai-code-review)
deploy_ai_code_review
;;
upload-ai-code-review-files)
upload_ai_code_review_files
;;
download-ai-code-review-files)
download_ai_code_review_files
;;
deploy-ci)
setup_ci
;;
Expand Down
23 changes: 23 additions & 0 deletions tests/ci/cdk/util/iam_policies.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,26 @@ def device_farm_access_policy_in_json(env):
}
],
}

def bedrock_policy_in_json():
"""
Define an IAM policy statement for accessing Bedrock.
:return: an IAM policy statement in json.
"""
return {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": [
"arn:aws:bedrock:*:*:foundation-model/*",
"arn:aws:bedrock:*:*:inference-profile/*",
"arn:aws:bedrock:*:*:application-inference-profile/*"
]
}
],
}
Loading