diff --git a/.checkov.yml b/.checkov.yml index 92b2252..6757075 100644 --- a/.checkov.yml +++ b/.checkov.yml @@ -20,3 +20,6 @@ skip-check: - CKV_AWS_382 # 0.0.0.0/0 egress accepted for AWS APIs - CKV_AWS_260 # HTTP:80 from internet required for demo - CKV_TF_1 # No external modules pinned by git hash + # OpenAPI — wake endpoint осознанно публичный + - CKV_OPENAPI_4 # No global security scheme for public wake demo API + - CKV_OPENAPI_5 # Operation is intentionally unauthenticated diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad304e3..44d61db 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,8 @@ env: permissions: id-token: write contents: read + pull-requests: write + issues: write concurrency: group: ci-${{ github.ref }} @@ -100,22 +102,34 @@ jobs: - name: Comment on PR with build result if: ${{ github.event_name == 'pull_request' && success() }} uses: actions/github-script@v7 + continue-on-error: true with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - const body = ` - ## Docker build result - - - Repository: \`${process.env.ECR_REPOSITORY}\` - - Region: \`${process.env.AWS_REGION}\` - - Image tag (PR SHA): \`${process.env.IMAGE_TAG}\` - - Workflow run: \`${process.env.GITHUB_RUN_NUMBER}\` - - Build for this pull request finished successfully (image built, not pushed). - `; - await github.rest.issues.createComment({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: context.issue.number, - body - }); + try { + const pr = context.payload.pull_request; + if (!pr) { + core.info('No pull_request context, skipping comment.'); + return; + } + + const body = ` + ## Docker build result + + - Repository: \`${process.env.ECR_REPOSITORY}\` + - Region: \`${process.env.AWS_REGION}\` + - Image tag (PR SHA): \`${process.env.IMAGE_TAG}\` + - Workflow run: \`${process.env.GITHUB_RUN_NUMBER}\` + + Build for this pull request finished successfully (image built, not pushed). + `; + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: pr.number, + body + }); + } catch (error) { + core.warning(`Failed to create Docker CI PR comment: ${error.message}`); + } diff --git a/.github/workflows/terraform-ci.yml b/.github/workflows/terraform-ci.yml index 30295b5..498ab64 100644 --- a/.github/workflows/terraform-ci.yml +++ b/.github/workflows/terraform-ci.yml @@ -71,24 +71,31 @@ jobs: - name: Comment on PR with Terraform CI result if: always() uses: actions/github-script@v7 + continue-on-error: true with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | - const conclusion = '${{ job.status }}'; - const symbols = { success: '✅', failure: '❌', cancelled: '⚪️' }; - const symbol = symbols[conclusion] || 'ℹ️'; - const body = - `${symbol} Terraform CI finished with status: **${conclusion}**\n\n` + - `Terraform versions tested: 1.6.6, 1.8.5, 1.9.5.\n` + - `See detailed results in the "Checks" tab.`; - const pr = context.payload.pull_request; - if (!pr) { - core.info('No pull_request context, skipping comment.'); - } else { + try { + const conclusion = '${{ job.status }}'; + const symbols = { success: '✅', failure: '❌', cancelled: '⚪️' }; + const symbol = symbols[conclusion] || 'ℹ️'; + const body = + `${symbol} Terraform CI finished with status: **${conclusion}**\n\n` + + `Terraform versions tested: 1.6.6, 1.8.5, 1.9.5.\n` + + `See detailed results in the "Checks" tab.`; + + const pr = context.payload.pull_request; + if (!pr) { + core.info('No pull_request context, skipping comment.'); + return; + } + await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: pr.number, body }); + } catch (error) { + core.warning(`Failed to create Terraform CI PR comment: ${error.message}`); } diff --git a/infra/api/openapi-wake.yaml b/infra/api/openapi-wake.yaml new file mode 100644 index 0000000..f0570d9 --- /dev/null +++ b/infra/api/openapi-wake.yaml @@ -0,0 +1,28 @@ +openapi: 3.0.1 + +info: + title: docker-ecs-deployment — Wake API + version: "1.0.0" + description: > + Public GET endpoint used only to trigger the wake Lambda for the demo ECS service. + No sensitive data is returned, security is enforced at the AWS/IAM boundary. +paths: + /: + get: + summary: Wake ECS service and redirect to app + operationId: getWake + responses: + "302": + description: Redirect to app or waiting page + "200": + description: HTML waiting/timeout page + x-amazon-apigateway-integration: + $ref: "#/components/x-amazon-apigateway-integrations/wake" + +components: + x-amazon-apigateway-integrations: + wake: + type: aws_proxy + uri: ${wake_lambda_invoke_arn} + httpMethod: POST + payloadFormatVersion: "2.0" diff --git a/infra/wake.tf b/infra/wake.tf index c499564..2515178 100644 --- a/infra/wake.tf +++ b/infra/wake.tf @@ -93,33 +93,17 @@ resource "aws_lambda_function" "wake" { } ############################################ -# API Gateway (HTTP API) — Wake endpoint API +# API Gateway (HTTP API) — Wake endpoint API (OpenAPI-driven) +# Purpose: Define routes and Lambda integration via OpenAPI spec ############################################ resource "aws_apigatewayv2_api" "wake" { count = var.enable_wake_api ? 1 : 0 name = "${var.project_name}-wake" protocol_type = "HTTP" -} - -############################################ -# API Integration — Lambda proxy (payload v2.0) -############################################ -resource "aws_apigatewayv2_integration" "wake" { - count = var.enable_wake_api ? 1 : 0 - api_id = aws_apigatewayv2_api.wake[0].id - integration_type = "AWS_PROXY" - integration_uri = aws_lambda_function.wake[0].invoke_arn - payload_format_version = "2.0" -} -############################################ -# API Route — GET / -############################################ -resource "aws_apigatewayv2_route" "wake" { - count = var.enable_wake_api ? 1 : 0 - api_id = aws_apigatewayv2_api.wake[0].id - route_key = "GET /" - target = "integrations/${aws_apigatewayv2_integration.wake[0].id}" + body = templatefile("${path.module}/api/openapi-wake.yaml", { + wake_lambda_invoke_arn = "arn:aws:apigateway:${data.aws_region.current.id}:lambda:path/2015-03-31/functions/${aws_lambda_function.wake[0].arn}/invocations" + }) } ############################################