diff --git a/.github/workflows/code-analysis.yml b/.github/workflows/code-analysis.yml deleted file mode 100644 index 42ac01b..0000000 --- a/.github/workflows/code-analysis.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Code Analysis - -permissions: - contents: read - -on: - pull_request: - -jobs: - CodeAnalysis: - runs-on: ubuntu-24.04 - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install uv - uses: astral-sh/setup-uv@v5 - - - name: Display Python version - run: | - uv run python --version - - - name: Install dependencies - run: | - uv sync --frozen - - - name: Check for outdated dependencies - run: | - uv tree --outdated - - - name: Run tests with coverage in latest stable 3.x - run: | - uv run pytest --cov=app --cov-report=term-missing - - - name: Run Bandit for security analysis - run: | - uv run bandit -r app - - - name: Run Ruff for linting - run: | - uv run ruff check . - - - name: Run Vulture for dead code analysis - run: | - uv run vulture . --min-confidence 70 --exclude .venv - diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md index c3eb62c..c159ae6 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,19 @@ The app resolves the database connection from environment variables in priority | `DATABASE_CREDENTIALS_SECRET_NAME` + AWS vars | Pull credentials from AWS Secrets Manager | | `DB_USERNAME` + `DB_PASSWORD` + `DB_HOST` + `DB_DATABASE` | Individual credential env vars | ---- +## CI (Continuous Integration) + +CI runs on AWS CodeBuild in the `cdl-d2d-dev` account. Every pull request triggers a build that runs tests, linting, and security checks, and reports a check status with a link to the build log back to GitHub. + +The job configuration lives in [`buildspec.yml`](buildspec.yml). + +### First-time setup + +The CodeBuild project is managed by Sceptre. Note that the GitHub connection is created and activated manually before deploying. + +### Test results + +Build status is automatically reported to GitHub on every PR. Test results are published to the CodeBuild **Test reports** panel (JUnit XML). ## Deploying to AWS @@ -136,3 +148,4 @@ The app resolves the database connection from environment variables in priority **CAUTION! CAUTION! This command will destroy all related AWS resources** `uv run sh deployment/scripts/destroy.sh `. + diff --git a/buildspec.yml b/buildspec.yml new file mode 100644 index 0000000..45e91dc --- /dev/null +++ b/buildspec.yml @@ -0,0 +1,25 @@ +version: 0.2 + +phases: + install: + commands: + - pip install uv + + pre_build: + commands: + - uv sync --frozen + + build: + commands: + - uv run python --version + - uv tree --outdated + - uv run pytest --cov=app --cov-report=term-missing --junitxml=pytest-report.xml + - uv run bandit -r app + - uv run ruff check . + - uv run vulture . --min-confidence 70 --exclude .venv + +reports: + pytest-reports: + files: + - pytest-report.xml + file-format: JUNITXML diff --git a/deployment/config/dev/codebuild.yaml b/deployment/config/dev/codebuild.yaml new file mode 100644 index 0000000..61c967e --- /dev/null +++ b/deployment/config/dev/codebuild.yaml @@ -0,0 +1,10 @@ +template: + path: codebuild.yaml.j2 + type: file + +# No dependencies on other stacks; CodeBuild is independent of ECS/network/etc. +# +# GitHubConnectionArn must be created and activated manually before deploying. +# See the "CI" section in README.md for instructions. +parameters: + GitHubConnectionArn: arn:aws:codeconnections:us-west-2:445017934155:connection/6af1f14e-4157-4e78-a1bd-73f160a9c4c5 diff --git a/deployment/templates/codebuild.yaml.j2 b/deployment/templates/codebuild.yaml.j2 new file mode 100644 index 0000000..1b977c7 --- /dev/null +++ b/deployment/templates/codebuild.yaml.j2 @@ -0,0 +1,85 @@ +AWSTemplateFormatVersion: 2010-09-09 +Description: CodeBuild CI project for Zephir API + +Parameters: + GitHubConnectionArn: + Type: String + Description: ARN of the manually-created and activated CodeStar connection to GitHub + +Resources: + CodeBuildServiceRole: + Type: AWS::IAM::Role + Properties: + RoleName: "{{ sceptre_user_data.resource_name_prefix }}-codebuild-service-role" + AssumeRolePolicyDocument: + Statement: + - Effect: Allow + Principal: + Service: codebuild.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: CloudWatch-Logs + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: + - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/{{ sceptre_user_data.resource_name_prefix }}-ci" + - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/{{ sceptre_user_data.resource_name_prefix }}-ci:*" + - PolicyName: CodeBuild-Reports + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - codebuild:CreateReportGroup + - codebuild:CreateReport + - codebuild:UpdateReport + - codebuild:BatchPutTestCases + Resource: !Sub "arn:aws:codebuild:${AWS::Region}:${AWS::AccountId}:report-group/{{ sceptre_user_data.resource_name_prefix }}-ci-*" + - PolicyName: GitHub-Connection + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - codeconnections:GetConnectionToken + - codeconnections:GetConnection + Resource: !Ref GitHubConnectionArn + + CodeBuildProject: + Type: AWS::CodeBuild::Project + Properties: + Name: "{{ sceptre_user_data.resource_name_prefix }}-ci" + Description: "CI for Zephir API" + ServiceRole: !GetAtt CodeBuildServiceRole.Arn + Source: + Type: GITHUB + Location: "{{ sceptre_user_data.repository }}" + BuildSpec: buildspec.yml + GitCloneDepth: 1 + ReportBuildStatus: true + Auth: + Type: OAUTH + Resource: !Ref GitHubConnectionArn + Environment: + Type: LINUX_CONTAINER + Image: aws/codebuild/standard:7.0 + ComputeType: BUILD_GENERAL1_SMALL + Triggers: + Webhook: true + FilterGroups: + - - Type: EVENT + Pattern: PULL_REQUEST_CREATED,PULL_REQUEST_UPDATED,PULL_REQUEST_REOPENED + Artifacts: + Type: NO_ARTIFACTS + +Outputs: + ProjectName: + Value: !Ref CodeBuildProject + ProjectArn: + Value: !GetAtt CodeBuildProject.Arn