Skip to content

Commit 0aecfeb

Browse files
Update: [AEA-5874] - adds direct slackbot lambda invocation role (#145)
## Summary **Remove items from this list if they are not relevant. Remove this line once this has been done** - Routine Change - ❗ Breaking Change - 🤖 Operational or Infrastructure Change - ✨ New Feature - ⚠️ Potential issues that might be caused by this change ### Details Add any summary information of what is in the change. **Remove this line if you have nothing to add.** ## Pull Request Naming Pull requests should be named using the following format: ```text Tag: [AEA-NNNN] - Short description ``` Tag can be one of: - `Fix` - for a bug fix. (Patch release) - `Update` - either for a backwards-compatible enhancement or for a rule change that adds reported problems. (Patch release) - `New` - implemented a new feature. (Minor release) - `Breaking` - for a backwards-incompatible enhancement or feature. (Major release) - `Docs` - changes to documentation only. (Patch release) - `Build` - changes to build process only. (No release) - `Upgrade` - for a dependency upgrade. (Patch release) - `Chore` - for refactoring, adding tests, etc. (anything that isn't user-facing). (Patch release) If the current release is x.y.z then - a patch release increases z by 1 - a minor release increases y by 1 - a major release increases x by 1 Correct tagging is necessary for our automated versioning and release process. The description of your pull request will be used as the commit message for the merge, and also be included in the changelog. Please ensure that your title is sufficiently descriptive. ### Rerunning Checks If you need to rename your pull request, you can restart the checks by either: - Closing and reopening the pull request - pushing an empty commit ```bash git commit --allow-empty -m 'trigger build' git push ``` - Amend your last commit and force push to the branch ```bash git commit --amend --no-edit git push --force ``` Rerunning the checks from within the pull request will not use the updated title.
1 parent af8447e commit 0aecfeb

File tree

4 files changed

+73
-10
lines changed

4 files changed

+73
-10
lines changed

.github/workflows/run_regression_tests.yml

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,9 @@ jobs:
5454
with:
5555
path: |
5656
~/.asdf
57-
key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }}
57+
key: ${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }}-${{ steps.asdf-version.outputs.version }}
5858
restore-keys: |
59-
${{ runner.os }}-asdf-
59+
${{ runner.os }}-asdf-${{ hashFiles('**/.tool-versions') }}-${{ steps.asdf-version.outputs.version }}
6060
6161
- name: Install asdf dependencies in .tool-versions
6262
uses: asdf-vm/actions/install@b7bcd026f18772e44fe1026d729e1611cc435d47
@@ -73,14 +73,28 @@ jobs:
7373
GITHUB-TOKEN: ${{ steps.generate-token.outputs.token }}
7474
run: |
7575
if [[ "$TARGET_ENVIRONMENT" != "prod" && "$TARGET_ENVIRONMENT" != "ref" ]]; then
76-
# this should be the tag of the tests you want to run
77-
REGRESSION_TEST_REPO_TAG=v3.4.26
76+
REGRESSION_TEST_REPO_TAG="v3.5.0" # This is the tag or branch of the regression test code to run, usually a version tag like v3.1.0 or a branch name
77+
REGRESSION_TEST_WORKFLOW_TAG="v3.5.0" # This is the tag of the github workflow to run, usually the same as REGRESSION_TEST_REPO_TAG
7878
79-
# this should be the tag of the regression test workflow you want to run
80-
# This will normally be the same as REGRESSION_TEST_REPO_TAG
81-
REGRESSION_TEST_WORKFLOW_TAG=v3.4.26
79+
if [[ -z "$REGRESSION_TEST_REPO_TAG" || -z "$REGRESSION_TEST_WORKFLOW_TAG" ]]; then
80+
echo "Error: One or both tag variables are not set" >&2
81+
exit 1
82+
fi
83+
84+
# HELPER IF STATEMENT - It will automatically determine the correct Git URL to use based on the REGRESSION_TEST_WORKFLOW_TAG value
85+
if [[ "$REGRESSION_TEST_WORKFLOW_TAG" =~ ^v([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
86+
echo "REGRESSION_TEST_WORKFLOW_TAG is a version tag, using tag link"
87+
curl "https://raw.githubusercontent.com/NHSDigital/electronic-prescription-service-api-regression-tests/refs/tags/${REGRESSION_TEST_WORKFLOW_TAG}/scripts/run_regression_tests.py" -o run_regression_tests.py
88+
else
89+
echo "REGRESSION_TEST_WORKFLOW_TAG doesn't look like a version tag, using branch link"
90+
curl "https://raw.githubusercontent.com/NHSDigital/electronic-prescription-service-api-regression-tests/refs/heads/${REGRESSION_TEST_REPO_TAG}/scripts/run_regression_tests.py" -o run_regression_tests.py
91+
fi
92+
93+
if [[ ! -f run_regression_tests.py ]]; then
94+
echo "Error: run_regression_tests.py not found" >&2
95+
exit 1
96+
fi
8297
83-
curl https://raw.githubusercontent.com/NHSDigital/electronic-prescription-service-api-regression-tests/refs/tags/${REGRESSION_TEST_WORKFLOW_TAG}/scripts/run_regression_tests.py -o run_regression_tests.py
8498
poetry install
8599
echo Running regression tests in the "$TARGET_ENVIRONMENT" environment
86100
poetry run python -u run_regression_tests.py \

packages/cdk/nagSuppressions.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,17 @@ export const nagSuppressions = (stack: Stack) => {
280280
]
281281
)
282282

283+
safeAddNagSuppression(
284+
stack,
285+
"/EpsAssistMeStack/RegressionTestPolicy/Resource",
286+
[
287+
{
288+
id: "AwsSolutions-IAM5",
289+
reason: "Auto-generated CDK Provider role requires wildcard permissions for cloudformation stack listing."
290+
}
291+
]
292+
)
293+
283294
}
284295

285296
const safeAddNagSuppression = (stack: Stack, path: string, suppressions: Array<NagPackSuppression>) => {

packages/cdk/resources/Functions.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ export class Functions extends Construct {
7575
props.slackBotTokenSecret.grantRead(slackBotLambda.function)
7676
props.slackBotSigningSecret.grantRead(slackBotLambda.function)
7777

78+
// pr environments need main bot to invoke pr-specific lambda
7879
if (props.isPullRequest) {
7980
const mainSlackBotLambdaExecutionRole = Role.fromRoleArn(
8081
this,
@@ -84,7 +85,7 @@ export class Functions extends Construct {
8485
})
8586

8687
const executeSlackBotPolicy = new ManagedPolicy(this, "ExecuteSlackBotPolicy", {
87-
description: "foo",
88+
description: "cross-lambda invocation for pr: command routing",
8889
statements: [
8990
new PolicyStatement({
9091
actions: [

packages/cdk/stacks/EpsAssistMeStack.ts

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {DatabaseTables} from "../resources/DatabaseTables"
1818
import {BedrockPromptResources} from "../resources/BedrockPromptResources"
1919
import {S3LambdaNotification} from "../constructs/S3LambdaNotification"
2020
import {VectorIndex} from "../resources/VectorIndex"
21-
import {Role} from "aws-cdk-lib/aws-iam"
21+
import {ManagedPolicy, PolicyStatement, Role} from "aws-cdk-lib/aws-iam"
2222

2323
export interface EpsAssistMeStackProps extends StackProps {
2424
readonly stackName: string
@@ -32,6 +32,8 @@ export class EpsAssistMeStack extends Stack {
3232

3333
// imports
3434
const mainSlackBotLambdaExecutionRoleArn = Fn.importValue("epsam:lambda:SlackBot:ExecutionRole:Arn")
35+
// regression testing needs direct lambda invoke — bypasses slack webhooks entirely
36+
const regressionTestRoleArn = Fn.importValue("ci-resources:AssistMeRegressionTestRole")
3537

3638
// Get variables from context
3739
const region = Stack.of(this).region
@@ -165,6 +167,36 @@ export class EpsAssistMeStack extends Stack {
165167
}
166168
})
167169

170+
// enable direct lambda testing — regression tests bypass slack infrastructure
171+
const regressionTestRole = Role.fromRoleArn(
172+
this,
173+
"regressionTestRole",
174+
regressionTestRoleArn, {
175+
mutable: true
176+
})
177+
178+
const regressionTestPolicy = new ManagedPolicy(this, "RegressionTestPolicy", {
179+
description: "regression test cross-account invoke permission for direct ai validation",
180+
statements: [
181+
new PolicyStatement({
182+
actions: [
183+
"lambda:InvokeFunction"
184+
],
185+
resources: [
186+
functions.slackBotLambda.function.functionArn
187+
]
188+
}),
189+
new PolicyStatement({
190+
actions: [
191+
"cloudformation:ListStacks",
192+
"cloudformation:DescribeStacks"
193+
],
194+
resources: ["*"]
195+
})
196+
]
197+
})
198+
regressionTestRole.addManagedPolicy(regressionTestPolicy)
199+
168200
// Output: SlackBot Endpoint
169201
new CfnOutput(this, "SlackBotEventsEndpoint", {
170202
value: `https://${apis.apis["api"].api.domainName?.domainName}/slack/events`,
@@ -196,6 +228,11 @@ export class EpsAssistMeStack extends Stack {
196228
exportName: `${props.stackName}:lambda:SlackBot:Arn`
197229
})
198230

231+
new CfnOutput(this, "SlackBotLambdaName", {
232+
value: functions.slackBotLambda.function.functionName,
233+
exportName: `${props.stackName}:lambda:SlackBot:FunctionName`
234+
})
235+
199236
if (isPullRequest) {
200237
new CfnOutput(this, "VERSION_NUMBER", {
201238
value: props.version,

0 commit comments

Comments
 (0)