diff --git a/docker/Dockerfile.lambda b/docker/Dockerfile.lambda index 46e777ad..38dc9d25 100644 --- a/docker/Dockerfile.lambda +++ b/docker/Dockerfile.lambda @@ -1,4 +1,4 @@ -FROM public.ecr.aws/lambda/python:3.12 +FROM public.ecr.aws/lambda/python:3.12 AS base RUN dnf update -y && \ dnf install -y gcc python3-devel git && \ @@ -9,4 +9,10 @@ RUN pip install --no-cache-dir . && rm pyproject.toml RUN pip install --no-cache-dir mangum==0.17.0 COPY pr_agent/ ${LAMBDA_TASK_ROOT}/pr_agent/ -CMD ["pr_agent.servers.serverless.serverless"] +FROM base AS github_lambda +CMD ["pr_agent.servers.serverless.serverless_github"] + +FROM base AS gitlab_lambda +CMD ["pr_agent.servers.serverless.serverless_gitlab"] + +FROM github_lambda diff --git a/docs/docs/installation/github.md b/docs/docs/installation/github.md index 69b34b8a..ca4bcfa1 100644 --- a/docs/docs/installation/github.md +++ b/docs/docs/installation/github.md @@ -187,7 +187,8 @@ For example: `GITHUB.WEBHOOK_SECRET` --> `GITHUB__WEBHOOK_SECRET` 2. Build a docker image that can be used as a lambda function ```shell - docker buildx build --platform=linux/amd64 . -t codiumai/pr-agent:serverless -f docker/Dockerfile.lambda + # Note: --target github_lambda is optional as it's the default target + docker buildx build --platform=linux/amd64 . -t codiumai/pr-agent:serverless --target github_lambda -f docker/Dockerfile.lambda ``` 3. Push image to ECR diff --git a/docs/docs/installation/gitlab.md b/docs/docs/installation/gitlab.md index bbcf4027..c40517a9 100644 --- a/docs/docs/installation/gitlab.md +++ b/docs/docs/installation/gitlab.md @@ -88,3 +88,50 @@ OPENAI__KEY= 8. Create a webhook in your GitLab project. Set the URL to `http[s]:///webhook`, the secret token to the generated secret from step 3, and enable the triggers `push`, `comments` and `merge request events`. 9. Test your installation by opening a merge request or commenting on a merge request using one of PR Agent's commands. + +## Deploy as a Lambda Function + +Note that since AWS Lambda env vars cannot have "." in the name, you can replace each "." in an env variable with "__".
+For example: `GITLAB.PERSONAL_ACCESS_TOKEN` --> `GITLAB__PERSONAL_ACCESS_TOKEN` + +1. Follow steps 1-5 from [Run a GitLab webhook server](#run-a-gitlab-webhook-server). +2. Build a docker image that can be used as a lambda function + + ```shell + docker buildx build --platform=linux/amd64 . -t codiumai/pr-agent:serverless --target gitlab_lambda -f docker/Dockerfile.lambda + ``` + +3. Push image to ECR + + ```shell + docker tag codiumai/pr-agent:serverless .dkr.ecr..amazonaws.com/codiumai/pr-agent:serverless + docker push .dkr.ecr..amazonaws.com/codiumai/pr-agent:serverless + ``` + +4. Create a lambda function that uses the uploaded image. Set the lambda timeout to be at least 3m. +5. Configure the lambda function to have a Function URL. +6. In the environment variables of the Lambda function, specify `AZURE_DEVOPS_CACHE_DIR` to a writable location such as /tmp. (see [link](https://github.com/Codium-ai/pr-agent/pull/450#issuecomment-1840242269)) +7. Go back to steps 8-9 of [Run a GitLab webhook server](#run-a-gitlab-webhook-server) with the function url as your Webhook URL. + The Webhook URL would look like `https:///webhook` + +### Using AWS Secrets Manager + +For production Lambda deployments, use AWS Secrets Manager instead of environment variables: + +1. Create a secret in AWS Secrets Manager with JSON format like this: + +```json +{ + "openai.key": "sk-proj-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + "gitlab.shared_secret": "your-shared-secret-from-step-3", + "gitlab.personal_access_token": "glpat-xxxxxxxxxxxxxxxxxxxxxxxx" +} +``` + +2. Add IAM permission `secretsmanager:GetSecretValue` to your Lambda execution role +3. Set these environment variables in your Lambda: + +```bash +AWS_SECRETS_MANAGER__SECRET_ARN=arn:aws:secretsmanager:us-east-1:123456789012:secret:pr-agent-secrets-AbCdEf +CONFIG__SECRET_PROVIDER=aws_secrets_manager +``` diff --git a/pr_agent/servers/serverless.py b/pr_agent/servers/serverless.py index 938be31b..7deb9882 100644 --- a/pr_agent/servers/serverless.py +++ b/pr_agent/servers/serverless.py @@ -3,8 +3,6 @@ from mangum import Mangum from starlette.middleware import Middleware from starlette_context.middleware import RawContextMiddleware -from pr_agent.servers.github_app import router - try: from pr_agent.config_loader import apply_secrets_manager_config apply_secrets_manager_config() @@ -16,12 +14,18 @@ except Exception as e: # Fail completely silently if log module is not available pass -middleware = [Middleware(RawContextMiddleware)] -app = FastAPI(middleware=middleware) -app.include_router(router) +def _create_handler(router): + middleware = [Middleware(RawContextMiddleware)] + app = FastAPI(middleware=middleware) + app.include_router(router) + return Mangum(app, lifespan="off") -handler = Mangum(app, lifespan="off") - - -def serverless(event, context): +def serverless_github(event, context): + from pr_agent.servers.github_app import router + handler = _create_handler(router) + return handler(event, context) + +def serverless_gitlab(event, context): + from pr_agent.servers.gitlab_webhook import router + handler = _create_handler(router) return handler(event, context)