Skip to content

Commit 501e4be

Browse files
authored
Prepare for release 1.1.0 (#925)
* Update dependencies to clear all vulnerabilities * Bump version (minor) for upcoming release * UI stack can now use OAC via new L2 construct S3bucketOrigin - win! * Update README with comprehensive stack testing instructions
1 parent d84a307 commit 501e4be

15 files changed

Lines changed: 2922 additions & 2512 deletions

backend/package-lock.json

Lines changed: 838 additions & 583 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

backend/package.json

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "prompt-injection-api",
3-
"version": "1.0.3",
3+
"version": "1.1.0",
44
"type": "module",
55
"scripts": {
66
"build": "tsc --noEmit",
@@ -15,8 +15,8 @@
1515
"cors": "^2.8.5",
1616
"d3-dsv": "^2.0.0",
1717
"dotenv": "^16.4.5",
18-
"express": "^4.19.2",
19-
"express-session": "^1.18.0",
18+
"express": "^4.21.1",
19+
"express-session": "^1.18.1",
2020
"langchain": "^0.1.33",
2121
"memorystore": "^1.6.7",
2222
"openai": "^4.33.0",
@@ -29,22 +29,22 @@
2929
"@types/cors": "^2.8.17",
3030
"@types/express": "^4.17.21",
3131
"@types/express-session": "^1.18.0",
32-
"@types/node": "^20.14.10",
32+
"@types/node": "^20.16.15",
3333
"@types/supertest": "^6.0.2",
34-
"@typescript-eslint/eslint-plugin": "^7.16.0",
35-
"@typescript-eslint/parser": "^7.16.0",
36-
"concurrently": "^8.2.2",
34+
"@typescript-eslint/eslint-plugin": "^7.18.0",
35+
"@typescript-eslint/parser": "^7.18.0",
36+
"concurrently": "^9.0.1",
3737
"cross-env": "^7.0.3",
38-
"eslint": "^8.57.0",
38+
"eslint": "^8.57.1",
3939
"eslint-config-prettier": "^9.1.0",
4040
"eslint-import-resolver-alias": "^1.1.2",
41-
"eslint-plugin-import": "^2.29.1",
42-
"eslint-plugin-jest": "^28.6.0",
41+
"eslint-plugin-import": "^2.31.0",
42+
"eslint-plugin-jest": "^28.8.3",
4343
"jest-junit": "^16.0.0",
4444
"prettier": "^3.3.3",
4545
"supertest": "^7.0.0",
46-
"ts-jest": "^29.2.2",
47-
"tsx": "^4.16.2",
48-
"typescript": "^5.5.3"
46+
"ts-jest": "^29.2.5",
47+
"tsx": "^4.19.1",
48+
"typescript": "^5.6.3"
4949
}
5050
}

cloud/README.md

Lines changed: 50 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
This project uses AWS CDK (with TypeScript) to build CloudFormation templates for deployment of all resources for the
44
SpyLogic application. The main stack defines a CodePipeline, configured with a single Stage to deploy the application
5-
stacks on merging into the repo main branch.
5+
stacks on merging into the repo `main` branch.
66

77
The API layer is a _fairly_ typical containerized Node Express server, managed by AWS Fargate with a load-balancer in
88
front. The UI is S3-hosted and served through CloudFront, and Cognito handles AuthN / AuthZ.
@@ -12,7 +12,8 @@ authorize users (via Cognito) when accessing the API. This seemingly simple task
1212
Application Load Balancer (ALB), which only allows _initiating_ authentication rather than verifying an existing access
1313
token. The solution is to re-use our CloudFront distribution for the UI to proxy API requests as well, with an Edge
1414
function to verify the token and, if verified, insert a custom header into the request before passing to the load
15-
balancer. We then filter requests at the load balancer, and reject any requests without the expected header / value.
15+
balancer. We then filter requests at the load balancer, and reject any requests without the expected header and value,
16+
to prevent attempts to bypass auth.
1617

1718
This should be much easier, as it is natively supported by API Gateway, but it seems ALB is yet to catch up.
1819

@@ -44,22 +45,58 @@ need to be deleted manually in the AWS Console.
4445
As the pipeline deploys the application stacks, it is wise to test any changes to those stacks before committing them.
4546
You can do this by synthesizing just the application stacks locally, and deploying to AWS as `dev` stage.
4647

47-
There is one small task to complete before you begin. In AWS Secrets Manager, you will find a secret storing API key and
48-
secret values for the `prod` stage, which the server needs for successful startup. You must create a new secret for the
49-
dev stage, with the same OPENAI_API_KEY value and any random string for SESSION_SECRET. Once that is in place, you can
50-
synthesize and deploy the stacks for testing. Once you have finished, please delete the secret to avoid unnecessary
51-
costs.
48+
Before you begin, ensure you have added [your API key](#server-secrets) into AWS Secrets Manager, for the dev stage.
49+
Once you have finished testing, we recommend deleting the secret to avoid unnecessary costs.
5250

53-
`npm run cdk:test:synth` - synthesizes just the application stacks (i.e. not the pipeline)
51+
```shell
52+
# synthesize the application stacks (no pipeline)
53+
npm run cdk:test:synth
54+
55+
# deploy resources to AWS as "dev" stage
56+
npm run cdk:test:deploy
57+
```
58+
59+
Once this is complete, you will need to set some environment vars for the UI build. Copy the following stack outputs
60+
from the above deployment command into file `frontend/.env`, using [.env.example](../frontend/.env.example) as a
61+
template:
5462

55-
`npm run cdk:test:deploy` - deploys these stacks to AWS as "dev" stage
63+
- from dev-spylogic-auth-stack,
64+
copy UserPoolId, UserPoolClient and UserPoolDomain into corresponding properties
65+
- from dev-spylogic-hostedzone-stack,
66+
copy `HostUrl` into VITE_COGNITO_REDIRECT_URL, and `BackendUrl` into VITE_BACKEND_URL
67+
68+
Also uncomment VITE_AUTH_PROVIDER. Once that is done, run the following commands:
69+
70+
```shell
71+
# Build the UI
72+
cd ../frontend
73+
npm run build
5674

57-
All being successful, you should see the application login screen at `https://dev.spylogic.ai`. Log into the AWS Console
58-
to add a user to the dev Cognito userpool, then log into the UI to test app deployment was successful.
75+
# Deploy to S3
76+
aws s3 sync dist s3://dev-spylogic-host-bucket
77+
```
78+
79+
All being successful, you should see the login screen when you navigate to the `HostUrl` (see above).
80+
Before you can sign in, you'll need to add a user to the dev userpool in Cognito, in AWS Console. After that, log into
81+
the application UI and check everything works as expected - including authenticated calls to the API, and session
82+
persistence via the SpyLogic.sid secure cookie.
83+
84+
Finally, remember to destroy the stacks after testing, else you will rack up costs:
85+
86+
```shell
87+
# Tear down all deployed resources
88+
npm run cdk:test:destroy
89+
```
5990

60-
`npm run cdk:test:destroy` - Remember to destroy the stacks after testing, else you will rack up costs!
91+
## Troubleshooting
6192

62-
---
93+
- `SSOTokenProviderFailure: SSO Token refresh failed. Please log in using "aws sso login"` - Go on, try it!
94+
- Deployment of the spylogic-api-stack fails with "docker authorization token expired" error. Try this:
95+
[docker login for AWS](https://stackoverflow.com/a/66919813)
96+
- AccessDenied page when accessing UI. If deploying manually for testing the stacks, did you forget to deploy the UI to
97+
the host bucket? If deployed via the pipeline, check CodePipeline in AWS Console to see if the task failed.
98+
- UI seems stuck on old version even after merging to main. Is the pipeline awaiting manual approval? This can happen
99+
if changes made to a stack broaden any required permissions.
63100

64101
## A note on costs
65102

cloud/lib/auth-stack.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ export class AuthStack extends Stack {
142142
this.userPoolId = new CfnOutput(this, 'UserPool.Id', {
143143
value: userPool.userPoolId,
144144
});
145-
this.userPoolClient = new CfnOutput(this, 'UserPoolClient.Id', {
145+
this.userPoolClient = new CfnOutput(this, 'UserPool.Client', {
146146
value: userPoolClient.userPoolClientId,
147147
});
148148
this.userPoolDomain = new CfnOutput(this, 'UserPool.Domain', {

cloud/lib/ui-stack.ts

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,13 @@ import {
77
Distribution,
88
experimental,
99
LambdaEdgeEventType,
10-
OriginAccessIdentity,
1110
OriginRequestPolicy,
1211
PriceClass,
1312
ResponseHeadersPolicy,
1413
ViewerProtocolPolicy,
1514
} from 'aws-cdk-lib/aws-cloudfront';
16-
import { HttpOrigin, S3Origin } from 'aws-cdk-lib/aws-cloudfront-origins';
17-
import { CanonicalUserPrincipal, Effect, PolicyStatement } from 'aws-cdk-lib/aws-iam';
15+
import { HttpOrigin, S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
16+
import { Effect, PolicyStatement } from 'aws-cdk-lib/aws-iam';
1817
import { Runtime } from 'aws-cdk-lib/aws-lambda';
1918
import { AaaaRecord, ARecord, IHostedZone, RecordTarget } from 'aws-cdk-lib/aws-route53';
2019
import { CloudFrontTarget } from 'aws-cdk-lib/aws-route53-targets';
@@ -63,8 +62,6 @@ export class UiStack extends Stack {
6362
throw new Error('Region not defined in stack env, cannot continue!');
6463
}
6564

66-
const cloudfrontOAI = new OriginAccessIdentity(this, generateResourceId('cloudfront-OAI'));
67-
6865
/*
6966
UI Host Bucket
7067
*/
@@ -76,15 +73,6 @@ export class UiStack extends Stack {
7673
removalPolicy: RemovalPolicy.DESTROY,
7774
autoDeleteObjects: true,
7875
});
79-
hostBucket.addToResourcePolicy(
80-
new PolicyStatement({
81-
actions: ['s3:GetObject'],
82-
resources: [hostBucket.arnForObjects('*')],
83-
principals: [
84-
new CanonicalUserPrincipal(cloudfrontOAI.cloudFrontOriginAccessIdentityS3CanonicalUserId),
85-
],
86-
})
87-
);
8876

8977
/*
9078
Edge lambda as JWT token verifier, to check request has access token
@@ -151,10 +139,9 @@ export class UiStack extends Stack {
151139
},
152140
],
153141
defaultBehavior: {
154-
origin: new S3Origin(hostBucket, {
155-
originAccessIdentity: cloudfrontOAI,
156-
}),
142+
origin: S3BucketOrigin.withOriginAccessControl(hostBucket),
157143
cachePolicy: new CachePolicy(this, generateResourceId('site-cache-policy'), {
144+
// TODO Try removing this: cookie should only be needed on backend calls
158145
cookieBehavior: CacheCookieBehavior.allowList(`${appName}.sid`),
159146
}),
160147
compress: true,

0 commit comments

Comments
 (0)