@@ -21,16 +21,14 @@ permissions:
2121concurrency : deploy
2222
2323jobs :
24- deploy :
25- strategy :
26- matrix :
27- # Define which environments you want to deploy
28- # Environments are setup in GutHub
29- environment : [ stage-us-east, prod-us-east ]
30- runs-on : ${{ format('codebuild-java-cdk-serverless-clamscan-{0}-runner-{1}-{2}', matrix.environment, github.run_id, github.run_attempt) }}
31- environment : ${{ matrix.environment }}
32-
33-
24+ deploy-stage :
25+ name : deploy (stage-us-east)
26+ runs-on : ${{ format('codebuild-java-cdk-serverless-clamscan-stage-us-east-runner-{0}-{1}', github.run_id, github.run_attempt) }}
27+ environment : stage-us-east
28+ outputs :
29+ image_manifest_b64 : ${{ steps.capture-image.outputs.image_manifest_b64 }}
30+ image_manifest_media_type : ${{ steps.capture-image.outputs.image_manifest_media_type }}
31+
3432 steps :
3533 - name : Checkout Code
3634 uses : actions/checkout@v6
@@ -114,6 +112,53 @@ jobs:
114112 sleep 30
115113 echo "Running Virus Scan Validation Tests..."
116114 mvn --batch-mode --no-transfer-progress exec:java
115+
116+ - name : Capture Tested Image Manifest For Promotion
117+ id : capture-image
118+ working-directory : ./cdk
119+ run : |
120+ FUNCTION_NAME=$(aws cloudformation describe-stacks \
121+ --stack-name ClamavLambdaStack \
122+ --query "Stacks[0].Outputs[?OutputKey=='ClamavLambdaStackLambdaName'].OutputValue" \
123+ --output text)
124+
125+ RESOLVED_IMAGE_URI=$(aws lambda get-function \
126+ --function-name "$FUNCTION_NAME" \
127+ --query 'Code.ResolvedImageUri' \
128+ --output text)
129+
130+ REPOSITORY_NAME="${RESOLVED_IMAGE_URI%@*}"
131+ REPOSITORY_NAME="${REPOSITORY_NAME#*.amazonaws.com/}"
132+ IMAGE_DIGEST="${RESOLVED_IMAGE_URI#*@}"
133+
134+ IMAGE_MANIFEST=$(aws ecr batch-get-image \
135+ --repository-name "$REPOSITORY_NAME" \
136+ --image-ids imageDigest="$IMAGE_DIGEST" \
137+ --accepted-media-types \
138+ application/vnd.docker.distribution.manifest.v2+json \
139+ application/vnd.oci.image.manifest.v1+json \
140+ --query 'images[0].imageManifest' \
141+ --output text)
142+
143+ IMAGE_MANIFEST_MEDIA_TYPE=$(aws ecr batch-get-image \
144+ --repository-name "$REPOSITORY_NAME" \
145+ --image-ids imageDigest="$IMAGE_DIGEST" \
146+ --accepted-media-types \
147+ application/vnd.docker.distribution.manifest.v2+json \
148+ application/vnd.oci.image.manifest.v1+json \
149+ --query 'images[0].imageManifestMediaType' \
150+ --output text)
151+
152+ if [ -z "$IMAGE_MANIFEST_MEDIA_TYPE" ] || [ "$IMAGE_MANIFEST_MEDIA_TYPE" = "None" ]; then
153+ IMAGE_MANIFEST_MEDIA_TYPE="application/vnd.docker.distribution.manifest.v2+json"
154+ fi
155+
156+ IMAGE_MANIFEST_B64=$(printf '%s' "$IMAGE_MANIFEST" | base64 -w 0)
157+
158+ {
159+ echo "image_manifest_b64=$IMAGE_MANIFEST_B64"
160+ echo "image_manifest_media_type=$IMAGE_MANIFEST_MEDIA_TYPE"
161+ } >> "$GITHUB_OUTPUT"
117162
118163 - name : Rollback Lambda Alias if Tests Fail
119164 if : failure() && steps.scan-tests.outcome == 'failure'
@@ -135,3 +180,88 @@ jobs:
135180 --function-name "$FUNCTION_NAME" \
136181 --name "$ALIAS_NAME" \
137182 --function-version "$PREV_VERSION"
183+
184+ deploy-prod :
185+ name : deploy (prod-us-east)
186+ needs : deploy-stage
187+ runs-on : ubuntu-latest
188+ environment : prod-us-east
189+
190+ steps :
191+ - name : Checkout Code
192+ uses : actions/checkout@v6
193+
194+ - name : Set up JDK 21
195+ uses : actions/setup-java@v5
196+ with :
197+ java-version : ' 21'
198+ distribution : ' corretto'
199+ cache : maven
200+
201+ - name : Install the latest AWS CDK
202+ run : |
203+ npm install -g aws-cdk
204+ echo "Node Version: $(node -v)"
205+ echo "CDK Version: $(cdk version)"
206+
207+ - name : Setup AWS Credentials
208+ id : aws-creds
209+ uses : aws-actions/configure-aws-credentials@v6
210+ with :
211+ aws-region : ${{ vars.AWS_REGION || 'us-east-1' }}
212+ role-to-assume : ${{ secrets.AWS_ROLE_TO_ASSUME }}
213+ aws-access-key-id : ${{ secrets.AWS_ACCESS_KEY_ID }}
214+ aws-secret-access-key : ${{ secrets.AWS_SECRET_ACCESS_KEY }}
215+ mask-aws-account-id : true
216+
217+ - name : Add AWS_ACCOUNT_ID to Environment
218+ run : echo "AWS_ACCOUNT_ID=${{ steps.aws-creds.outputs.aws-account-id }}" >> $GITHUB_ENV
219+
220+ - name : Build CDK project without rebuilding the Lambda image
221+ run : >
222+ mvn -pl shared-model,cdk -am install -DskipTests
223+ --no-transfer-progress --quiet
224+
225+ - name : Construct bucketNames Context
226+ run : |
227+ echo "BUCKET_NAMES=${{ vars.S3_BUCKET_NAMES }}" >> $GITHUB_ENV
228+ echo "Final list of bucket names to deploy against: ${{ vars.S3_BUCKET_NAMES }}"
229+
230+ - name : Ensure CDK is bootstraped and up to date
231+ working-directory : ./cdk
232+ run : cdk bootstrap --ci=true aws://${AWS_ACCOUNT_ID}/${{ vars.AWS_REGION || 'us-east-1' }}
233+
234+ - name : Promote Tested Image Into Production ECR
235+ run : |
236+ TARGET_REPOSITORY_NAME="cdk-hnb659fds-container-assets-${AWS_ACCOUNT_ID}-${{ vars.AWS_REGION || 'us-east-1' }}"
237+ PROMOTED_IMAGE_TAG="promoted-${GITHUB_SHA}"
238+
239+ printf '%s' '${{ needs.deploy-stage.outputs.image_manifest_b64 }}' | base64 -d > /tmp/promoted-image-manifest.json
240+ IMAGE_MANIFEST="$(tr -d '\n' < /tmp/promoted-image-manifest.json)"
241+
242+ aws ecr put-image \
243+ --repository-name "$TARGET_REPOSITORY_NAME" \
244+ --image-manifest "$IMAGE_MANIFEST" \
245+ --image-manifest-media-type "${{ needs.deploy-stage.outputs.image_manifest_media_type }}" \
246+ --image-tag "$PROMOTED_IMAGE_TAG"
247+
248+ PROMOTED_IMAGE_DIGEST=$(aws ecr describe-images \
249+ --repository-name "$TARGET_REPOSITORY_NAME" \
250+ --image-ids imageTag="$PROMOTED_IMAGE_TAG" \
251+ --query 'imageDetails[0].imageDigest' \
252+ --output text)
253+
254+ echo "PROMOTED_IMAGE_REPOSITORY_NAME=$TARGET_REPOSITORY_NAME" >> $GITHUB_ENV
255+ echo "PROMOTED_IMAGE_DIGEST=$PROMOTED_IMAGE_DIGEST" >> $GITHUB_ENV
256+
257+ - name : Deploy CDK Stack Using Promoted Image
258+ working-directory : ./cdk
259+ env :
260+ ONLY_TAG_INFECTED : ${{ vars.ONLY_TAG_INFECTED }}
261+ VALIDATION_BUCKET : ${{ vars.VALIDATION_BUCKET }}
262+ run : >
263+ cdk deploy --require-approval=never --ci=true
264+ --context bucketNames="${{ env.BUCKET_NAMES }}"
265+ --context addBucketPolicy="${{ vars.ADD_BUCKET_POLICY || 'false' }}"
266+ --context imageRepositoryName="${{ env.PROMOTED_IMAGE_REPOSITORY_NAME }}"
267+ --context imageTagOrDigest="${{ env.PROMOTED_IMAGE_DIGEST }}"
0 commit comments