Skip to content

Commit

Permalink
Prepare for release 1.1.0 (#925)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
chriswilty authored Oct 23, 2024
1 parent d84a307 commit 501e4be
Show file tree
Hide file tree
Showing 15 changed files with 2,922 additions and 2,512 deletions.
1,421 changes: 838 additions & 583 deletions backend/package-lock.json

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions backend/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "prompt-injection-api",
"version": "1.0.3",
"version": "1.1.0",
"type": "module",
"scripts": {
"build": "tsc --noEmit",
Expand All @@ -15,8 +15,8 @@
"cors": "^2.8.5",
"d3-dsv": "^2.0.0",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"express-session": "^1.18.0",
"express": "^4.21.1",
"express-session": "^1.18.1",
"langchain": "^0.1.33",
"memorystore": "^1.6.7",
"openai": "^4.33.0",
Expand All @@ -29,22 +29,22 @@
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/express-session": "^1.18.0",
"@types/node": "^20.14.10",
"@types/node": "^20.16.15",
"@types/supertest": "^6.0.2",
"@typescript-eslint/eslint-plugin": "^7.16.0",
"@typescript-eslint/parser": "^7.16.0",
"concurrently": "^8.2.2",
"@typescript-eslint/eslint-plugin": "^7.18.0",
"@typescript-eslint/parser": "^7.18.0",
"concurrently": "^9.0.1",
"cross-env": "^7.0.3",
"eslint": "^8.57.0",
"eslint": "^8.57.1",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-alias": "^1.1.2",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jest": "^28.6.0",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jest": "^28.8.3",
"jest-junit": "^16.0.0",
"prettier": "^3.3.3",
"supertest": "^7.0.0",
"ts-jest": "^29.2.2",
"tsx": "^4.16.2",
"typescript": "^5.5.3"
"ts-jest": "^29.2.5",
"tsx": "^4.19.1",
"typescript": "^5.6.3"
}
}
63 changes: 50 additions & 13 deletions cloud/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

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

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

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

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

`npm run cdk:test:synth` - synthesizes just the application stacks (i.e. not the pipeline)
```shell
# synthesize the application stacks (no pipeline)
npm run cdk:test:synth

# deploy resources to AWS as "dev" stage
npm run cdk:test:deploy
```

Once this is complete, you will need to set some environment vars for the UI build. Copy the following stack outputs
from the above deployment command into file `frontend/.env`, using [.env.example](../frontend/.env.example) as a
template:

`npm run cdk:test:deploy` - deploys these stacks to AWS as "dev" stage
- from dev-spylogic-auth-stack,
copy UserPoolId, UserPoolClient and UserPoolDomain into corresponding properties
- from dev-spylogic-hostedzone-stack,
copy `HostUrl` into VITE_COGNITO_REDIRECT_URL, and `BackendUrl` into VITE_BACKEND_URL

Also uncomment VITE_AUTH_PROVIDER. Once that is done, run the following commands:

```shell
# Build the UI
cd ../frontend
npm run build

All being successful, you should see the application login screen at `https://dev.spylogic.ai`. Log into the AWS Console
to add a user to the dev Cognito userpool, then log into the UI to test app deployment was successful.
# Deploy to S3
aws s3 sync dist s3://dev-spylogic-host-bucket
```

All being successful, you should see the login screen when you navigate to the `HostUrl` (see above).
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
the application UI and check everything works as expected - including authenticated calls to the API, and session
persistence via the SpyLogic.sid secure cookie.

Finally, remember to destroy the stacks after testing, else you will rack up costs:

```shell
# Tear down all deployed resources
npm run cdk:test:destroy
```

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

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

## A note on costs

Expand Down
2 changes: 1 addition & 1 deletion cloud/lib/auth-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export class AuthStack extends Stack {
this.userPoolId = new CfnOutput(this, 'UserPool.Id', {
value: userPool.userPoolId,
});
this.userPoolClient = new CfnOutput(this, 'UserPoolClient.Id', {
this.userPoolClient = new CfnOutput(this, 'UserPool.Client', {
value: userPoolClient.userPoolClientId,
});
this.userPoolDomain = new CfnOutput(this, 'UserPool.Domain', {
Expand Down
21 changes: 4 additions & 17 deletions cloud/lib/ui-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@ import {
Distribution,
experimental,
LambdaEdgeEventType,
OriginAccessIdentity,
OriginRequestPolicy,
PriceClass,
ResponseHeadersPolicy,
ViewerProtocolPolicy,
} from 'aws-cdk-lib/aws-cloudfront';
import { HttpOrigin, S3Origin } from 'aws-cdk-lib/aws-cloudfront-origins';
import { CanonicalUserPrincipal, Effect, PolicyStatement } from 'aws-cdk-lib/aws-iam';
import { HttpOrigin, S3BucketOrigin } from 'aws-cdk-lib/aws-cloudfront-origins';
import { Effect, PolicyStatement } from 'aws-cdk-lib/aws-iam';
import { Runtime } from 'aws-cdk-lib/aws-lambda';
import { AaaaRecord, ARecord, IHostedZone, RecordTarget } from 'aws-cdk-lib/aws-route53';
import { CloudFrontTarget } from 'aws-cdk-lib/aws-route53-targets';
Expand Down Expand Up @@ -63,8 +62,6 @@ export class UiStack extends Stack {
throw new Error('Region not defined in stack env, cannot continue!');
}

const cloudfrontOAI = new OriginAccessIdentity(this, generateResourceId('cloudfront-OAI'));

/*
UI Host Bucket
*/
Expand All @@ -76,15 +73,6 @@ export class UiStack extends Stack {
removalPolicy: RemovalPolicy.DESTROY,
autoDeleteObjects: true,
});
hostBucket.addToResourcePolicy(
new PolicyStatement({
actions: ['s3:GetObject'],
resources: [hostBucket.arnForObjects('*')],
principals: [
new CanonicalUserPrincipal(cloudfrontOAI.cloudFrontOriginAccessIdentityS3CanonicalUserId),
],
})
);

/*
Edge lambda as JWT token verifier, to check request has access token
Expand Down Expand Up @@ -151,10 +139,9 @@ export class UiStack extends Stack {
},
],
defaultBehavior: {
origin: new S3Origin(hostBucket, {
originAccessIdentity: cloudfrontOAI,
}),
origin: S3BucketOrigin.withOriginAccessControl(hostBucket),
cachePolicy: new CachePolicy(this, generateResourceId('site-cache-policy'), {
// TODO Try removing this: cookie should only be needed on backend calls
cookieBehavior: CacheCookieBehavior.allowList(`${appName}.sid`),
}),
compress: true,
Expand Down
Loading

0 comments on commit 501e4be

Please sign in to comment.