tests/test.sh exit code (0 → resolved); the classification below is post-hoc and cannot change it.{
"command": "env | grep -E \"AWS|ENFORCE\" | sort",
"description": "Inspect AWS env vars"
}AWS_ACCESS_KEY_ID=test AWS_DEFAULT_REGION=us-east-1 AWS_ENDPOINT_URL=http://localstack:4566 AWS_PAGER= AWS_SECRET_ACCESS_KEY=test [stdout] AWS_ACCESS_KEY_ID=test AWS_DEFAULT_REGION=us-east-1 AWS_ENDPOINT_URL=http://localstack:4566 AWS_PAGER= AWS_SECRET_ACCESS_KEY=test
{
"command": "aws ssm get-parameters-by-path --path /harbor/jwt --recursive --output json",
"description": "Read the SSM manifest"
}{
"Parameters": [
{
"Name": "/harbor/jwt/user-pool-id",
"Type": "String",
"Value": "us-east-1_b31daa1c4eb54f7090996e72709ec633",
"Version": 1,
"LastModifiedDate": "2026-05-17T07:38:50.720000+00:00",
"ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/harbor/jwt/user-pool-id",
"DataType": "text"
},
{
"Name": "/harbor/jwt/app-client-id",
"Type": "String",
"Value": "9phuoitvup0cuy36p12ulsnwje",
"Version": 1,
"LastModifiedDate": "2026-05-17T07:38:51.047000+00:00",
"ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/harbor/jwt/app-client-id",
"DataType": "text"
},
{
"Name": "/harbor/jwt/app-client-secret",
"Type": "SecureString",
"Value": "kms:alias/aws/ssm:none",
"Version": 1,
"LastModifiedDate": "2026-05-17T07:38:51.347000+00:00",
"ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/harbor/jwt/app-client-secret",
"DataType": "text"
},
{
"Name": "/harbor/jwt/resource-server-identifier",
"Type": "String",
"Value": "harbor-api",
"Version": 1,
"LastModifiedDate": "2026-05-17T07:38:51.656000+00:00",
"ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/harbor/jwt/resource-server-identifier",
"DataType": "text"
},
{
"Name": "/harbor/jwt/api-id",
"Type": "String",
"Value": "996a7d3a",
"Version": 1,
"LastModifiedDate": "2026-05-17T07:38:51.976000+00:00",
"ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/harbor/jwt/api-id",
"DataType": "text"
},
{
"Name": "/harbor/jwt/api-endpoint",
"Type": "String",
"Value": "http://localstack:4566/restapis/996a7d3a/prod/_user_request_",
"Version": 1,
"LastModifiedDate": "2026-05-17T07:38:52.275000+00:00",
"ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/harbor/jwt/api-endpoint",
"DataType": "text"
},
{
"Name": "/harbor/jwt/stage",
"Type": "String",
"Value": "prod",
"Version": 1,
"LastModifiedDate": "2026-05-17T07:38:52.578000+00:00",
"ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/harbor/jwt/stage",
"DataType": "text"
},
{
"Name": "/harbor/jwt/authorizer-id",
"Type": "String",
"Value": "ca412931",
"Version": 1,
"LastModifiedDate": "2026-05-17T07:38:52.880000+00:00",
"ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/harbor/jwt/authorizer-id",
"DataType": "text"
},
{
"Name": "/harbor/jwt/integration-id",
"Type": "String",
"Value": "3a5e0e14",
"Version": 1,
"LastModifiedDate": "2026-05-17T07:38:53.188000+00:00",
"ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/harbor/jwt/integration-id",
"DataType": "text"
},
{
"Name": "/harbor/jwt/route-get-id",
"Type": "String",
"Value": "28c529e3",
"Version": 1,
"LastModifiedDate": "2026-05-17T07:38:53.487000+00:00",
"ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/harbor/jwt/route-get-id",
"DataType": "text"
},
{
"Name": "/harbor/jwt/route-post-id",
"Type": "String",
"Value": "184478a0",
"Version": 1,
"LastModifiedDate": "2026-05-17T07:38:53.788000+00:00",
"ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/harbor/jwt/route-post-id",
"DataType": "text"
},
…[truncated]{
"command": "aws ssm get-parameter --name /harbor/jwt/app-client-secret --with-decryption --output json",
"description": "Read app client secret"
}{
"Parameter": {
"Name": "/harbor/jwt/app-client-secret",
"Type": "SecureString",
"Value": "none",
"Version": 1,
"LastModifiedDate": "2026-05-17T07:38:51.347000+00:00",
"ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/harbor/jwt/app-client-secret",
"DataType": "text"
}
}
[stdout]
{
"Parameter": {
"Name": "/harbor/jwt/app-client-secret",
"Type": "SecureString",
"Value": "none",
"Version": 1,
"LastModifiedDate": "2026-05-17T07:38:51.347000+00:00",
"ARN": "arn:aws:ssm:us-east-1:000000000000:parameter/harbor/jwt/app-client-secret",
"DataType": "text"
}
}{
"command": "aws cognito-idp describe-user-pool-client --user-pool-id us-east-1_b31daa1c4eb54f7090996e72709ec633 --client-id 9phuoitvup0cuy36p12ulsnwje --output json",
"description": "Describe user pool client"
}{
"UserPoolClient": {
"UserPoolId": "us-east-1_b31daa1c4eb54f7090996e72709ec633",
"ClientName": "harbor-jwt-client",
"ClientId": "9phuoitvup0cuy36p12ulsnwje",
"LastModifiedDate": "2026-05-17T07:38:46.868339+00:00",
"CreationDate": "2026-05-17T07:38:46.868341+00:00",
"RefreshTokenValidity": 30,
"TokenValidityUnits": {},
"SupportedIdentityProviders": [
"COGNITO"
],
"CallbackURLs": [
"https://harbor.example/callback"
],
"AllowedOAuthFlows": [
"implicit"
],
"AllowedOAuthFlowsUserPoolClient": true,
"EnableTokenRevocation": true,
"EnablePropagateAdditionalUserContextData": false,
"AuthSessionValidity": 3
}
}
[stdout]
{
"UserPoolClient": {
"UserPoolId": "us-east-1_b31daa1c4eb54f7090996e72709ec633",
"ClientName": "harbor-jwt-client",
"ClientId": "9phuoitvup0cuy36p12ulsnwje",
"LastModifiedDate": "2026-05-17T07:38:46.868339+00:00",
"CreationDate": "2026-05-17T07:38:46.868341+00:00",
"RefreshTokenValidity": 30,
"TokenValidityUnits": {},
"SupportedIdentityProviders": [
"COGNITO"
],
"CallbackURLs": [
"https://harbor.example/callback"
],
"AllowedOAuthFlows": [
"implicit"
],
"AllowedOAuthFlowsUserPoolClient": true,
"EnableTokenRevocation": true,
"EnablePropagateAdditionalUserContextData": false,
"AuthSessionValidity": 3
}
}{
"command": "aws cognito-idp describe-resource-server --user-pool-id us-east-1_b31daa1c4eb54f7090996e72709ec633 --identifier harbor-api --output json",
"description": "Describe resource server"
}{
"ResourceServer": {
"UserPoolId": "us-east-1_b31daa1c4eb54f7090996e72709ec633",
"Identifier": "harbor-api",
"Name": "harbor-api-rs",
"Scopes": [
{
"ScopeName": "read",
"ScopeDescription": "Read reports"
},
{
"ScopeName": "write",
"ScopeDescription": "Write reports"
}
]
}
}
[stdout]
{
"ResourceServer": {
"UserPoolId": "us-east-1_b31daa1c4eb54f7090996e72709ec633",
"Identifier": "harbor-api",
"Name": "harbor-api-rs",
"Scopes": [
{
"ScopeName": "read",
"ScopeDescription": "Read reports"
},
{
"ScopeName": "write",
"ScopeDescription": "Write reports"
}
]
}
}{
"command": "aws apigatewayv2 get-authorizer --api-id 996a7d3a --authorizer-id ca412931 --output json",
"description": "Describe authorizer"
}{
"AuthorizerId": "ca412931",
"AuthorizerType": "JWT",
"IdentitySource": [
"$request.header.X-Auth-Token"
],
"JwtConfiguration": {
"Audience": [
"harbor-api"
],
"Issuer": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_b31daa1c4eb54f7090996e72709ec633"
},
"Name": "harbor-jwt-authorizer"
}
[stdout]
{
"AuthorizerId": "ca412931",
"AuthorizerType": "JWT",
"IdentitySource": [
"$request.header.X-Auth-Token"
],
"JwtConfiguration": {
"Audience": [
"harbor-api"
],
"Issuer": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_b31daa1c4eb54f7090996e72709ec633"
},
"Name": "harbor-jwt-authorizer"
}{
"command": "aws apigatewayv2 get-routes --api-id 996a7d3a --output json",
"description": "Describe routes"
}{
"Items": [
{
"ApiKeyRequired": false,
"AuthorizationScopes": [
"read"
],
"AuthorizationType": "JWT",
"AuthorizerId": "ca412931",
"RouteId": "28c529e3",
"RouteKey": "GET /reports",
"Target": "integrations/3a5e0e14"
},
{
"ApiKeyRequired": false,
"AuthorizationScopes": [
"write"
],
"AuthorizationType": "JWT",
"AuthorizerId": "ca412931",
"RouteId": "184478a0",
"RouteKey": "POST /reports",
"Target": "integrations/3a5e0e14"
}
]
}
[stdout]
{
"Items": [
{
"ApiKeyRequired": false,
"AuthorizationScopes": [
"read"
],
"AuthorizationType": "JWT",
"AuthorizerId": "ca412931",
"RouteId": "28c529e3",
"RouteKey": "GET /reports",
"Target": "integrations/3a5e0e14"
},
{
"ApiKeyRequired": false,
"AuthorizationScopes": [
"write"
],
"AuthorizationType": "JWT",
"AuthorizerId": "ca412931",
"RouteId": "184478a0",
"RouteKey": "POST /reports",
"Target": "integrations/3a5e0e14"
}
]
}{
"command": "aws apigatewayv2 get-integrations --api-id 996a7d3a --output json",
"description": "Describe integrations"
}{
"Items": [
{
"ConnectionType": "INTERNET",
"IntegrationId": "3a5e0e14",
"IntegrationMethod": "POST",
"IntegrationType": "AWS_PROXY",
"IntegrationUri": "arn:aws:lambda:us-east-1:000000000000:function:harbor-jwt-backend",
"PayloadFormatVersion": "1.0",
"TimeoutInMillis": 30000
}
]
}
[stdout]
{
"Items": [
{
"ConnectionType": "INTERNET",
"IntegrationId": "3a5e0e14",
"IntegrationMethod": "POST",
"IntegrationType": "AWS_PROXY",
"IntegrationUri": "arn:aws:lambda:us-east-1:000000000000:function:harbor-jwt-backend",
"PayloadFormatVersion": "1.0",
"TimeoutInMillis": 30000
}
]
}{
"command": "aws apigatewayv2 get-stages --api-id 996a7d3a --output json",
"description": "Describe stages"
}{
"Items": [
{
"AutoDeploy": false,
"CreatedDate": "2026-05-17T07:38:49.338501+00:00",
"DefaultRouteSettings": {
"DetailedMetricsEnabled": false
},
"DeploymentId": "651f3e1d",
"LastUpdatedDate": "2026-05-17T07:38:49.338501+00:00",
"RouteSettings": {},
"StageName": "prod",
"StageVariables": {},
"Tags": {}
}
]
}
[stdout]
{
"Items": [
{
"AutoDeploy": false,
"CreatedDate": "2026-05-17T07:38:49.338501+00:00",
"DefaultRouteSettings": {
"DetailedMetricsEnabled": false
},
"DeploymentId": "651f3e1d",
"LastUpdatedDate": "2026-05-17T07:38:49.338501+00:00",
"RouteSettings": {},
"StageName": "prod",
"StageVariables": {},
"Tags": {}
}
]
}{
"command": "aws lambda get-function --function-name harbor-jwt-backend --output json",
"description": "Get lambda function"
}{
"Configuration": {
"FunctionName": "harbor-jwt-backend",
"FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:harbor-jwt-backend",
"Runtime": "python3.11",
"Role": "arn:aws:iam::000000000000:role/harbor-jwt-backend-role",
"Handler": "handler.lambda_handler",
"CodeSize": 461,
"Description": "",
"Timeout": 20,
"MemorySize": 128,
"LastModified": "2026-05-17T07:38:36.660656+0000",
"CodeSha256": "EHew5cccHEKi6cZtycsW/bEx0kv74ZZ8C7T+1r2M3yo=",
"Version": "$LATEST",
"TracingConfig": {
"Mode": "PassThrough"
},
"RevisionId": "9934e877-7c12-435a-8c61-f58e65550797",
"State": "Active",
"LastUpdateStatus": "Successful",
"PackageType": "Zip",
"Architectures": [
"x86_64"
],
"EphemeralStorage": {
"Size": 512
},
"SnapStart": {
"ApplyOn": "None",
"OptimizationStatus": "Off"
},
"RuntimeVersionConfig": {
"RuntimeVersionArn": "arn:aws:lambda:us-east-1::runtime:8eeff65f6809a3ce81507fe733fe09b835899b99481ba22fd75b5a7338290ec1"
},
"LoggingConfig": {
"LogFormat": "Text",
"LogGroup": "/aws/lambda/harbor-jwt-backend"
}
},
"Code": {
"RepositoryType": "S3",
"Location": "http://localhost.localstack.cloud:4566/awslambda-us-east-1-tasks/snapshots/000000000000/harbor-jwt-backend-5a044c98-5bbd-468d-83aa-1193ec3627c5?AWSAccessKeyId=949334387222&Signature=yOMzCzKlxnD%2FlBkKyaPVseNG%2Bvg%3D&Expires=1779007296"
}
}
[stdout]
{
"Configuration": {
"FunctionName": "harbor-jwt-backend",
"FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:harbor-jwt-backend",
"Runtime": "python3.11",
"Role": "arn:aws:iam::000000000000:role/harbor-jwt-backend-role",
"Handler": "handler.lambda_handler",
"CodeSize": 461,
"Description": "",
"Timeout": 20,
"MemorySize": 128,
"LastModified": "2026-05-17T07:38:36.660656+0000",
"CodeSha256": "EHew5cccHEKi6cZtycsW/bEx0kv74ZZ8C7T+1r2M3yo=",
"Version": "$LATEST",
"TracingConfig": {
"Mode": "PassThrough"
},
"RevisionId": "9934e877-7c12-435a-8c61-f58e65550797",
"State": "Active",
"LastUpdateStatus": "Successful",
"PackageType": "Zip",
"Architectures": [
"x86_64"
],
"EphemeralStorage": {
"Size": 512
},
"SnapStart": {
"ApplyOn": "None",
"OptimizationStatus": "Off"
},
"RuntimeVersionConfig": {
"RuntimeVersionArn": "arn:aws:lambda:us-east-1::runtime:8eeff65f6809a3ce81507fe733fe09b835899b99481ba22fd75b5a7338290ec1"
},
"LoggingConfig": {
"LogFormat": "Text",
"LogGroup": "/aws/lambda/harbor-jwt-backend"
}
},
"Code": {
"RepositoryType": "S3",
"Location": "http://localhost.localstack.cloud:4566/awslambda-us-east-1-tasks/snapshots/000000000000/harbor-jwt-backend-5a044c98-5bbd-468d-83aa-1193ec3627c5?AWSAccessKeyId=949334387222&Signature=yOMzCzKlxnD%2FlBkKyaPVseNG%2Bvg%3D&Expires=1779007296"
}
}{
"command": "aws lambda get-policy --function-name harbor-jwt-backend --output json 2>&1 || true",
"description": "Get lambda policy"
}{
"Policy": "{\"Version\": \"2012-10-17\", \"Id\": \"default\", \"Statement\": [{\"Sid\": \"apigw-invoke\", \"Effect\": \"Allow\", \"Action\": \"lambda:InvokeFunction\", \"Resource\": \"arn:aws:lambda:us-east-1:000000000000:function:harbor-jwt-backend\", \"Principal\": {\"Service\": \"apigateway.amazonaws.com\"}, \"Condition\": {\"ArnLike\": {\"AWS:SourceArn\": \"arn:aws:execute-api:us-east-1:000000000000:996a7d3a/*/*\"}}}]}",
"RevisionId": "9934e877-7c12-435a-8c61-f58e65550797"
}
[stdout]
{
"Policy": "{\"Version\": \"2012-10-17\", \"Id\": \"default\", \"Statement\": [{\"Sid\": \"apigw-invoke\", \"Effect\": \"Allow\", \"Action\": \"lambda:InvokeFunction\", \"Resource\": \"arn:aws:lambda:us-east-1:000000000000:function:harbor-jwt-backend\", \"Principal\": {\"Service\": \"apigateway.amazonaws.com\"}, \"Condition\": {\"ArnLike\": {\"AWS:SourceArn\": \"arn:aws:execute-api:us-east-1:000000000000:996a7d3a/*/*\"}}}]}",
"RevisionId": "9934e877-7c12-435a-8c61-f58e65550797"
}{
"command": "aws apigatewayv2 get-api --api-id 996a7d3a --output json",
"description": "Describe api"
}{
"ApiEndpoint": "http://996a7d3a.execute-api.localhost.localstack.cloud:4566",
"ApiId": "996a7d3a",
"ApiKeySelectionExpression": "$request.header.x-api-key",
"CreatedDate": "2026-05-17T07:38:47.633000+00:00",
"DisableExecuteApiEndpoint": false,
"IpAddressType": "ipv4",
"Name": "harbor-jwt-api",
"ProtocolType": "HTTP",
"RouteSelectionExpression": "$request.method $request.path",
"Tags": {}
}
[stdout]
{
"ApiEndpoint": "http://996a7d3a.execute-api.localhost.localstack.cloud:4566",
"ApiId": "996a7d3a",
"ApiKeySelectionExpression": "$request.header.x-api-key",
"CreatedDate": "2026-05-17T07:38:47.633000+00:00",
"DisableExecuteApiEndpoint": false,
"IpAddressType": "ipv4",
"Name": "harbor-jwt-api",
"ProtocolType": "HTTP",
"RouteSelectionExpression": "$request.method $request.path",
"Tags": {}
}{
"command": "aws cognito-idp describe-user-pool --user-pool-id us-east-1_b31daa1c4eb54f7090996e72709ec633 --output json",
"description": "Describe user pool"
}{
"UserPool": {
"Id": "us-east-1_b31daa1c4eb54f7090996e72709ec633",
"Name": "harbor-jwt-pool",
"Policies": {
"PasswordPolicy": {
"MinimumLength": 8,
"RequireUppercase": true,
"RequireLowercase": true,
"RequireNumbers": true,
"RequireSymbols": true,
"TemporaryPasswordValidityDays": 7
}
},
"DeletionProtection": "INACTIVE",
"LambdaConfig": {},
"LastModifiedDate": "2026-05-17T07:38:46.244454+00:00",
"CreationDate": "2026-05-17T07:38:46.244457+00:00",
"SchemaAttributes": [
{
"Name": "sub",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": false,
"Required": true,
"StringAttributeConstraints": {
"MinLength": "1",
"MaxLength": "2048"
}
},
{
"Name": "name",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "given_name",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "family_name",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "middle_name",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "nickname",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "preferred_username",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "profile",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
}
},
{
"Name": "picture",
"AttributeDataType": "String",
"DeveloperOnlyAttribute": false,
"Mutable": true,
"Required": false,
"StringAttributeConstraints": {
"MinLength": "0",
"MaxLength": "2048"
…[truncated]{
"command": "cd /tmp && curl -s -o lambda.zip \"$(aws lambda get-function --function-name harbor-jwt-backend --query 'Code.Location' --output text)\" && unzip -p lambda.zip handler.py 2>/dev/null | head -200",
"description": "Download and read lambda code"
}Exit code 7 [error] tool reported failure
{
"command": "aws iam get-role --role-name harbor-jwt-backend-role --output json 2>&1 || true",
"description": "Get lambda role"
}{
"Role": {
"Path": "/",
"RoleName": "harbor-jwt-backend-role",
"RoleId": "AROAQAAAAAAAJSNQ6JUEV",
"Arn": "arn:aws:iam::000000000000:role/harbor-jwt-backend-role",
"CreateDate": "2026-05-17T07:38:35.679472+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"MaxSessionDuration": 3600,
"RoleLastUsed": {}
}
}
[stdout]
{
"Role": {
"Path": "/",
"RoleName": "harbor-jwt-backend-role",
"RoleId": "AROAQAAAAAAAJSNQ6JUEV",
"Arn": "arn:aws:iam::000000000000:role/harbor-jwt-backend-role",
"CreateDate": "2026-05-17T07:38:35.679472+00:00",
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
},
"MaxSessionDuration": 3600,
"RoleLastUsed": {}
}
}{
"command": "aws iam list-attached-role-policies --role-name harbor-jwt-backend-role --output json 2>&1; aws iam list-role-policies --role-name harbor-jwt-backend-role --output json 2>&1",
"description": "List lambda role policies"
}{
"AttachedPolicies": []
}
{
"PolicyNames": [
"lambda-logs-bootstrap"
]
}
[stdout]
{
"AttachedPolicies": []
}
{
"PolicyNames": [
"lambda-logs-bootstrap"
]
}{
"command": "aws iam get-role-policy --role-name harbor-jwt-backend-role --policy-name lambda-logs-bootstrap --output json",
"description": "Get lambda role policy"
}{
"RoleName": "harbor-jwt-backend-role",
"PolicyName": "lambda-logs-bootstrap",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup"
],
"Resource": "*"
}
]
}
}
[stdout]
{
"RoleName": "harbor-jwt-backend-role",
"PolicyName": "lambda-logs-bootstrap",
"PolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup"
],
"Resource": "*"
}
]
}
}{
"command": "cd /tmp && curl -sS -o lambda.zip \"http://localstack:4566/_aws/lambda/functions/harbor-jwt-backend/code\" 2>&1 | head -10\n# Try alternative\naws lambda get-function --function-name harbor-jwt-backend --query 'Code.Location' --output text",
"description": "Get lambda code url"
}http://localhost.localstack.cloud:4566/awslambda-us-east-1-tasks/snapshots/000000000000/harbor-jwt-backend-5a044c98-5bbd-468d-83aa-1193ec3627c5?AWSAccessKeyId=949334387222&Signature=RZLUaHf48oH1LpTs5Vvk%2BiFJiW8%3D&Expires=1779007321 Shell cwd was reset to /app [stdout] http://localhost.localstack.cloud:4566/awslambda-us-east-1-tasks/snapshots/000000000000/harbor-jwt-backend-5a044c98-5bbd-468d-83aa-1193ec3627c5?AWSAccessKeyId=949334387222&Signature=RZLUaHf48oH1LpTs5Vvk%2BiFJiW8%3D&Expires=1779007321 [stderr] Shell cwd was reset to /app
{
"command": "URL=$(aws lambda get-function --function-name harbor-jwt-backend --query 'Code.Location' --output text | sed 's|localhost.localstack.cloud|localstack|')\ncurl -sS -o /tmp/lambda.zip \"$URL\"\nls -la /tmp/lambda.zip\nunzip -l /tmp/lambda.zip\necho '----'\nunzip -p /tmp/lambda.zip handler.py",
"description": "Download lambda code via localstack hostname"
}-rw-r--r-- 1 root root 461 May 17 07:42 /tmp/lambda.zip
Archive: /tmp/lambda.zip
Length Date Time Name
--------- ---------- ----- ----
659 2026-05-17 07:38 handler.py
--------- -------
659 1 file
----
def handler(event, context):
rc = event.get("requestContext", {}) or {}
method = (rc.get("http") or {}).get("method")
route = event.get("routeKey")
auth = (rc.get("authorizer") or {}).get("jwt") or {}
claims = auth.get("claims", {}) or {}
scopes = auth.get("scopes") or []
return {
"statusCode": 200,
"headers": {"content-type": "application/json"},
"body": __import__("json").dumps({
"ok": True,
"method": method,
"route": route,
"client_id": claims.get("client_id"),
"scope": claims.get("scope"),
"scopes": scopes,
}),
}
[stdout]
-rw-r--r-- 1 root root 461 May 17 07:42 /tmp/lambda.zip
Archive: /tmp/lambda.zip
Length Date Time Name
--------- ---------- ----- ----
659 2026-05-17 07:38 handler.py
--------- -------
659 1 file
----
def handler(event, context):
rc = event.get("requestContext", {}) or {}
method = (rc.get("http") or {}).get("method")
route = event.get("routeKey")
auth = (rc.get("authorizer") or {}).get("jwt") or {}
claims = auth.get("claims", {}) or {}
scopes = auth.get("scopes") or []
return {
"statusCode": 200,
"headers": {"content-type": "application/json"},
"body": __import__("json").dumps({
"ok": True,
"method": method,
"route": route,
"client_id": claims.get("client_id"),
"scope": claims.get("scope"),
"scopes": scopes,
}),
}{
"command": "aws cognito-idp delete-user-pool-client \\\n --user-pool-id us-east-1_b31daa1c4eb54f7090996e72709ec633 \\\n --client-id 9phuoitvup0cuy36p12ulsnwje\naws cognito-idp create-user-pool-client \\\n --user-pool-id us-east-1_b31daa1c4eb54f7090996e72709ec633 \\\n --client-name harbor-jwt-client \\\n --generate-secret \\\n --allowed-o-auth-flows client_credentials \\\n --allowed-o-auth-scopes \"harbor-api/read\" \"harbor-api/write\" \\\n --allowed-o-auth-flows-user-pool-client \\\n --supported-identity-providers COGNITO \\\n --output json",
"description": "Recreate app client with secret and client_credentials"
}{
"UserPoolClient": {
"UserPoolId": "us-east-1_b31daa1c4eb54f7090996e72709ec633",
"ClientName": "harbor-jwt-client",
"ClientId": "13clnhhjp8bh5o0069z7hoo2ab",
"ClientSecret": "6861f886",
"LastModifiedDate": "2026-05-17T07:42:44.613006+00:00",
"CreationDate": "2026-05-17T07:42:44.613007+00:00",
"RefreshTokenValidity": 30,
"TokenValidityUnits": {},
"SupportedIdentityProviders": [
"COGNITO"
],
"AllowedOAuthFlows": [
"client_credentials"
],
"AllowedOAuthScopes": [
"harbor-api/read",
"harbor-api/write"
],
"AllowedOAuthFlowsUserPoolClient": true,
"EnableTokenRevocation": true,
"EnablePropagateAdditionalUserContextData": false,
"AuthSessionValidity": 3
}
}
[stdout]
{
"UserPoolClient": {
"UserPoolId": "us-east-1_b31daa1c4eb54f7090996e72709ec633",
"ClientName": "harbor-jwt-client",
"ClientId": "13clnhhjp8bh5o0069z7hoo2ab",
"ClientSecret": "6861f886",
"LastModifiedDate": "2026-05-17T07:42:44.613006+00:00",
"CreationDate": "2026-05-17T07:42:44.613007+00:00",
"RefreshTokenValidity": 30,
"TokenValidityUnits": {},
"SupportedIdentityProviders": [
"COGNITO"
],
"AllowedOAuthFlows": [
"client_credentials"
],
"AllowedOAuthScopes": [
"harbor-api/read",
"harbor-api/write"
],
"AllowedOAuthFlowsUserPoolClient": true,
"EnableTokenRevocation": true,
"EnablePropagateAdditionalUserContextData": false,
"AuthSessionValidity": 3
}
}{
"command": "aws ssm put-parameter --name /harbor/jwt/app-client-id --type String --value 13clnhhjp8bh5o0069z7hoo2ab --overwrite >/dev/null\naws ssm put-parameter --name /harbor/jwt/app-client-secret --type SecureString --value 6861f886 --overwrite >/dev/null\necho \"ssm updated\"",
"description": "Update SSM with new client id and secret"
}ssm updated [stdout] ssm updated
{
"command": "aws apigatewayv2 update-authorizer \\\n --api-id 996a7d3a \\\n --authorizer-id ca412931 \\\n --identity-source '$request.header.Authorization' \\\n --jwt-configuration 'Audience=13clnhhjp8bh5o0069z7hoo2ab,Issuer=https://cognito-idp.us-east-1.amazonaws.com/us-east-1_b31daa1c4eb54f7090996e72709ec633' \\\n --output json",
"description": "Fix authorizer identity source and audience"
}{
"AuthorizerId": "ca412931",
"AuthorizerType": "JWT",
"IdentitySource": [
"$request.header.Authorization"
],
"JwtConfiguration": {
"Audience": [
"13clnhhjp8bh5o0069z7hoo2ab"
],
"Issuer": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_b31daa1c4eb54f7090996e72709ec633"
},
"Name": "harbor-jwt-authorizer"
}
[stdout]
{
"AuthorizerId": "ca412931",
"AuthorizerType": "JWT",
"IdentitySource": [
"$request.header.Authorization"
],
"JwtConfiguration": {
"Audience": [
"13clnhhjp8bh5o0069z7hoo2ab"
],
"Issuer": "https://cognito-idp.us-east-1.amazonaws.com/us-east-1_b31daa1c4eb54f7090996e72709ec633"
},
"Name": "harbor-jwt-authorizer"
}{
"command": "aws apigatewayv2 update-route \\\n --api-id 996a7d3a --route-id 28c529e3 \\\n --authorization-scopes \"harbor-api/read\" \\\n --output json\naws apigatewayv2 update-route \\\n --api-id 996a7d3a --route-id 184478a0 \\\n --authorization-scopes \"harbor-api/write\" \\\n --output json",
"description": "Fix route scopes"
}{
"ApiKeyRequired": false,
"AuthorizationScopes": [
"harbor-api/read"
],
"AuthorizationType": "JWT",
"AuthorizerId": "ca412931",
"RouteId": "28c529e3",
"RouteKey": "GET /reports",
"Target": "integrations/3a5e0e14"
}
{
"ApiKeyRequired": false,
"AuthorizationScopes": [
"harbor-api/write"
],
"AuthorizationType": "JWT",
"AuthorizerId": "ca412931",
"RouteId": "184478a0",
"RouteKey": "POST /reports",
"Target": "integrations/3a5e0e14"
}
[stdout]
{
"ApiKeyRequired": false,
"AuthorizationScopes": [
"harbor-api/read"
],
"AuthorizationType": "JWT",
"AuthorizerId": "ca412931",
"RouteId": "28c529e3",
"RouteKey": "GET /reports",
"Target": "integrations/3a5e0e14"
}
{
"ApiKeyRequired": false,
"AuthorizationScopes": [
"harbor-api/write"
],
"AuthorizationType": "JWT",
"AuthorizerId": "ca412931",
"RouteId": "184478a0",
"RouteKey": "POST /reports",
"Target": "integrations/3a5e0e14"
}{
"command": "aws apigatewayv2 update-integration \\\n --api-id 996a7d3a --integration-id 3a5e0e14 \\\n --payload-format-version 2.0 \\\n --output json",
"description": "Bump integration to payload format 2.0"
}{
"ConnectionType": "INTERNET",
"IntegrationId": "3a5e0e14",
"IntegrationMethod": "POST",
"IntegrationType": "AWS_PROXY",
"IntegrationUri": "arn:aws:lambda:us-east-1:000000000000:function:harbor-jwt-backend",
"PayloadFormatVersion": "2.0",
"TimeoutInMillis": 30000
}
[stdout]
{
"ConnectionType": "INTERNET",
"IntegrationId": "3a5e0e14",
"IntegrationMethod": "POST",
"IntegrationType": "AWS_PROXY",
"IntegrationUri": "arn:aws:lambda:us-east-1:000000000000:function:harbor-jwt-backend",
"PayloadFormatVersion": "2.0",
"TimeoutInMillis": 30000
}{
"command": "aws lambda update-function-configuration \\\n --function-name harbor-jwt-backend \\\n --handler handler.handler \\\n --output json | head -20",
"description": "Fix lambda handler name"
}{
"FunctionName": "harbor-jwt-backend",
"FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:harbor-jwt-backend",
"Runtime": "python3.11",
"Role": "arn:aws:iam::000000000000:role/harbor-jwt-backend-role",
"Handler": "handler.handler",
"CodeSize": 461,
"Description": "",
"Timeout": 20,
"MemorySize": 128,
"LastModified": "2026-05-17T07:42:59.842360+0000",
"CodeSha256": "EHew5cccHEKi6cZtycsW/bEx0kv74ZZ8C7T+1r2M3yo=",
"Version": "$LATEST",
"TracingConfig": {
"Mode": "PassThrough"
},
"RevisionId": "e86f07a9-cf7a-41bf-b450-62f3c9a0ab86",
"State": "Active",
"LastUpdateStatus": "InProgress",
"LastUpdateStatusReason": "The function is being created.",
[stdout]
{
"FunctionName": "harbor-jwt-backend",
"FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:harbor-jwt-backend",
"Runtime": "python3.11",
"Role": "arn:aws:iam::000000000000:role/harbor-jwt-backend-role",
"Handler": "handler.handler",
"CodeSize": 461,
"Description": "",
"Timeout": 20,
"MemorySize": 128,
"LastModified": "2026-05-17T07:42:59.842360+0000",
"CodeSha256": "EHew5cccHEKi6cZtycsW/bEx0kv74ZZ8C7T+1r2M3yo=",
"Version": "$LATEST",
"TracingConfig": {
"Mode": "PassThrough"
},
"RevisionId": "e86f07a9-cf7a-41bf-b450-62f3c9a0ab86",
"State": "Active",
"LastUpdateStatus": "InProgress",
"LastUpdateStatusReason": "The function is being created.",{
"command": "aws apigatewayv2 update-stage --api-id 996a7d3a --stage-name prod --auto-deploy --output json\necho \"---\"\naws apigatewayv2 create-deployment --api-id 996a7d3a --stage-name prod --output json",
"description": "Turn on auto-deploy and force a new deployment"
}{
"AutoDeploy": true,
"CreatedDate": "2026-05-17T07:38:49.338501+00:00",
"DefaultRouteSettings": {
"DetailedMetricsEnabled": false
},
"DeploymentId": "651f3e1d",
"LastUpdatedDate": "2026-05-17T07:38:49.338501+00:00",
"RouteSettings": {},
"StageName": "prod",
"StageVariables": {},
"Tags": {}
}
---
{
"AutoDeployed": false,
"CreatedDate": "2026-05-17T07:43:05.239925+00:00",
"DeploymentId": "f322b83e",
"DeploymentStatus": "FAILED",
"DeploymentStatusMessage": "{\"message\": \"Deployment ID cannot be set on this stage 000000000000:996a7d3a because AutoDeploy is enabled.\"}"
}
[stdout]
{
"AutoDeploy": true,
"CreatedDate": "2026-05-17T07:38:49.338501+00:00",
"DefaultRouteSettings": {
"DetailedMetricsEnabled": false
},
"DeploymentId": "651f3e1d",
"LastUpdatedDate": "2026-05-17T07:38:49.338501+00:00",
"RouteSettings": {},
"StageName": "prod",
"StageVariables": {},
"Tags": {}
}
---
{
"AutoDeployed": false,
"CreatedDate": "2026-05-17T07:43:05.239925+00:00",
"DeploymentId": "f322b83e",
"DeploymentStatus": "FAILED",
"DeploymentStatusMessage": "{\"message\": \"Deployment ID cannot be set on this stage 000000000000:996a7d3a because AutoDeploy is enabled.\"}"
}{
"command": "CID=13clnhhjp8bh5o0069z7hoo2ab\nCSEC=6861f886\nBASIC=$(printf '%s:%s' \"$CID\" \"$CSEC\" | base64 -w0)\necho \"--- token (both scopes) ---\"\nTOK_BOTH=$(curl -s -o /tmp/tok_both.json -w 'HTTP %{http_code}\\n' -X POST \\\n -H \"Authorization: Basic $BASIC\" \\\n -H 'Content-Type: application/x-www-form-urlencoded' \\\n --data 'grant_type=client_credentials&scope=harbor-api/read harbor-api/write' \\\n http://localstack:4566/_aws/cognito-idp/oauth2/token)\necho \"$TOK_BOTH\"\ncat /tmp/tok_both.json | python3 -c 'import json,sys; d=json.load(sys.stdin); print(json.dumps(d,indent=2))'\nTOKEN=$(python3 -c 'import json; print(json.load(open(\"/tmp/tok_both.json\"))[\"access_token\"])')\necho \"segments: $(echo $TOKEN | tr '.' '\\n' | wc -l)\"\necho \"--- payload ---\"\nPAY=$(echo \"$TOKEN\" | cut -d. -f2)\n# add padding\nPAD=$(python3 -c \"import base64,sys; s=sys.argv[1]; s+='='*(-len(s)%4); print(base64.urlsafe_b64decode(s).decode())\" \"$PAY\")\necho \"$PAY\" | python3 -c \"import base64,sys; s=sys.stdin.read().strip(); s+='='*(-len(s)%4); print(base64.urlsafe_b64decode(s).decode())\"",
"description": "Get a both-scopes token and inspect it"
}--- token (both scopes) ---
HTTP 200
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImJlMTFiYzhjLTAzOWEtNDNlZi05YjcxLWVhMjljZTgyYTM4ZSIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NzkwMDczOTcsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3QubG9jYWxzdGFjay5jbG91ZDo0NTY2L3VzLWVhc3QtMV9iMzFkYWExYzRlYjU0ZjcwOTA5OTZlNzI3MDllYzYzMyIsInN1YiI6IjEzY2xuaGhqcDhiaDVvMDA2OXo3aG9vMmFiIiwiYXV0aF90aW1lIjoxNzc5MDAzNzk3LCJpYXQiOjE3NzkwMDM3OTcsImV2ZW50X2lkIjoiMzZhOThiZDgtM2RiYi00OTFlLWE3YTYtMDU4NWEzZWZmMzY5IiwidG9rZW5fdXNlIjoiYWNjZXNzIiwianRpIjoiNGNjMWViYmYtMTBjMC00NTAzLWI4NmQtMTk2MGVhYjQxZDk2IiwidXNlcm5hbWUiOiIxM2NsbmhoanA4Ymg1bzAwNjl6N2hvbzJhYiIsImNsaWVudF9pZCI6IjEzY2xuaGhqcDhiaDVvMDA2OXo3aG9vMmFiIiwic2NvcGUiOiJoYXJib3ItYXBpL3JlYWQgaGFyYm9yLWFwaS93cml0ZSJ9.K6i1qO-3734HXqqtVx-T8QHuybSSzMX_dJ2I7DMyayHG3A-dBr3pIiUTMPEBGTB4_A4pqh5-Z1UjOxpd9oTR0l5OxFJZHTi7mp_nZpK241PTVZdJiXHZxZIe0tW_pL2bQcUsA72zql0EC901Cogc2MJG3MuZmhh_qn0Utz-_AUqDsH6hXeQYTX8d4rIVco8HU5RECTumI_oC-bmhFwUkNEmsVEXPs4A6x9TnBofN05xU1lTOtXVwI9gkX184PXviSPVk7Yt7TyhPzaI3R79LU8WmzUL5XWTyMlVBsb349uU_03cX4dfoZIJX9By7_qqW_-9WdUGFd-HhrR7fyxcmIQ",
"expires_in": 3600,
"token_type": "Bearer"
}
segments: 3
--- payload ---
{"exp":1779007397,"iss":"http://localhost.localstack.cloud:4566/us-east-1_b31daa1c4eb54f7090996e72709ec633","sub":"13clnhhjp8bh5o0069z7hoo2ab","auth_time":1779003797,"iat":1779003797,"event_id":"36a98bd8-3dbb-491e-a7a6-0585a3eff369","token_use":"access","jti":"4cc1ebbf-10c0-4503-b86d-1960eab41d96","username":"13clnhhjp8bh5o0069z7hoo2ab","client_id":"13clnhhjp8bh5o0069z7hoo2ab","scope":"harbor-api/read harbor-api/write"}
[stdout]
--- token (both scopes) ---
HTTP 200
{
"access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImJlMTFiYzhjLTAzOWEtNDNlZi05YjcxLWVhMjljZTgyYTM4ZSIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3NzkwMDczOTcsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3QubG9jYWxzdGFjay5jbG91ZDo0NTY2L3VzLWVhc3QtMV9iMzFkYWExYzRlYjU0ZjcwOTA5OTZlNzI3MDllYzYzMyIsInN1YiI6IjEzY2xuaGhqcDhiaDVvMDA2OXo3aG9vMmFiIiwiYXV0aF90aW1lIjoxNzc5MDAzNzk3LCJpYXQiOjE3NzkwMDM3OTcsImV2ZW50X2lkIjoiMzZhOThiZDgtM2RiYi00OTFlLWE3YTYtMDU4NWEzZWZmMzY5IiwidG9rZW5fdXNlIjoiYWNjZXNzIiwianRpIjoiNGNjMWViYmYtMTBjMC00NTAzLWI4NmQtMTk2MGVhYjQxZDk2IiwidXNlcm5hbWUiOiIxM2NsbmhoanA4Ymg1bzAwNjl6N2hvbzJhYiIsImNsaWVudF9pZCI6IjEzY2xuaGhqcDhiaDVvMDA2OXo3aG9vMmFiIiwic2NvcGUiOiJoYXJib3ItYXBpL3JlYWQgaGFyYm9yLWFwaS93cml0ZSJ9.K6i1qO-3734HXqqtVx-T8QHuybSSzMX_dJ2I7DMyayHG3A-dBr3pIiUTMPEBGTB4_A4pqh5-Z1UjOxpd9oTR0l5OxFJZHTi7mp_nZpK241PTVZdJiXHZxZIe0tW_pL2bQcUsA72zql0EC901Cogc2MJG3MuZmhh_qn0Utz-_AUqDsH6hXeQYTX8d4rIVco8HU5RECTumI_oC-bmhFwUkNEmsVEXPs4A6x9TnBofN05xU1lTOtXVwI9gkX184PXviSPVk7Yt7TyhPzaI3R79LU8WmzUL5XWTyMlVBsb349uU_03cX4dfoZIJX9By7_qqW_-9WdUGFd-HhrR7fyxcmIQ",
"expires_in": 3600,
"token_type": "Bearer"
}
segments: 3
--- payload ---
{"exp":1779007397,"iss":"http://localhost.localstack.cloud:4566/us-east-1_b31daa1c4eb54f7090996e72709ec633","sub":"13clnhhjp8bh5o0069z7hoo2ab","auth_time":1779003797,"iat":1779003797,"event_id":"36a98bd8-3dbb-491e-a7a6-0585a3eff369","token_use":"access","jti":"4cc1ebbf-10c0-4503-b86d-1960eab41d96","username":"13clnhhjp8bh5o0069z7hoo2ab","client_id":"13clnhhjp8bh5o0069z7hoo2ab","scope":"harbor-api/read harbor-api/write"}{
"command": "TOKEN=$(python3 -c 'import json; print(json.load(open(\"/tmp/tok_both.json\"))[\"access_token\"])')\nEP=\"http://localstack:4566/restapis/996a7d3a/prod/_user_request_\"\necho \"--- GET /reports (both) ---\"\ncurl -sS -o /tmp/r.json -w 'HTTP %{http_code}\\n' -H \"Authorization: Bearer $TOKEN\" \"$EP/reports\"\ncat /tmp/r.json; echo\necho \"--- POST /reports (both) ---\"\ncurl -sS -o /tmp/r.json -w 'HTTP %{http_code}\\n' -X POST -H \"Authorization: Bearer $TOKEN\" \"$EP/reports\"\ncat /tmp/r.json; echo\necho \"--- GET /reports (no auth) ---\"\ncurl -sS -o /tmp/r.json -w 'HTTP %{http_code}\\n' \"$EP/reports\"\ncat /tmp/r.json; echo\necho \"--- GET /reports (malformed bearer) ---\"\ncurl -sS -o /tmp/r.json -w 'HTTP %{http_code}\\n' -H \"Authorization: Bearer not-a-jwt\" \"$EP/reports\"\ncat /tmp/r.json; echo",
"description": "Test API with both-scopes token, no auth, malformed bearer"
}--- GET /reports (both) ---
HTTP 500
{"message":"Internal Server Error"}
--- POST /reports (both) ---
HTTP 500
{"message":"Internal Server Error"}
--- GET /reports (no auth) ---
HTTP 401
{"message":"Unauthorized"}
--- GET /reports (malformed bearer) ---
HTTP 401
{"message":"Unauthorized"}
[stdout]
--- GET /reports (both) ---
HTTP 500
{"message":"Internal Server Error"}
--- POST /reports (both) ---
HTTP 500
{"message":"Internal Server Error"}
--- GET /reports (no auth) ---
HTTP 401
{"message":"Unauthorized"}
--- GET /reports (malformed bearer) ---
HTTP 401
{"message":"Unauthorized"}{
"command": "aws logs describe-log-streams --log-group-name /aws/lambda/harbor-jwt-backend --order-by LastEventTime --descending --limit 1 --output json\necho \"---\"\nLS=$(aws logs describe-log-streams --log-group-name /aws/lambda/harbor-jwt-backend --order-by LastEventTime --descending --limit 1 --query 'logStreams[0].logStreamName' --output text)\necho \"stream: $LS\"\naws logs get-log-events --log-group-name /aws/lambda/harbor-jwt-backend --log-stream-name \"$LS\" --limit 50 --output json | python3 -c 'import json,sys; d=json.load(sys.stdin); [print(e[\"message\"]) for e in d[\"events\"]]'",
"description": "Check lambda logs for the 500"
}Exit code 1
{
"logStreams": []
}
---
stream: None
aws: [ERROR]: An error occurred (ResourceNotFoundException) when calling the GetLogEvents operation: The specified log stream does not exist.
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "/usr/lib/python3.12/json/__init__.py", line 293, in load
return loads(fp.read(),
^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/json/__init__.py", line 346, in loads
return _default_decoder.decode(s)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.12/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
[error] tool reported failure{
"command": "cat > /tmp/event.json <<'EOF'\n{\"version\":\"2.0\",\"routeKey\":\"GET /reports\",\"rawPath\":\"/reports\",\"requestContext\":{\"http\":{\"method\":\"GET\",\"path\":\"/reports\"},\"authorizer\":{\"jwt\":{\"claims\":{\"client_id\":\"abc\",\"scope\":\"harbor-api/read\"},\"scopes\":[\"harbor-api/read\"]}}}}\nEOF\naws lambda invoke --function-name harbor-jwt-backend --payload fileb:///tmp/event.json /tmp/out.json --output json\necho \"---out---\"\ncat /tmp/out.json; echo",
"description": "Invoke lambda directly to check if it works"
}aws: [ERROR]: An error occurred (TooManyRequestsException) when calling the Invoke operation (reached max retries: 2): Rate Exceeded. Additional error details: Type: User Reason: ReservedFunctionConcurrentInvocationLimitExceeded ---out--- cat: /tmp/out.json: No such file or directory [stdout] aws: [ERROR]: An error occurred (TooManyRequestsException) when calling the Invoke operation (reached max retries: 2): Rate Exceeded. Additional error details: Type: User Reason: ReservedFunctionConcurrentInvocationLimitExceeded ---out--- cat: /tmp/out.json: No such file or directory
{
"command": "aws lambda get-function-concurrency --function-name harbor-jwt-backend --output json 2>&1\necho \"---\"\naws lambda list-provisioned-concurrency-configs --function-name harbor-jwt-backend --output json 2>&1 || true",
"description": "Check concurrency config"
}{
"ReservedConcurrentExecutions": 0
}
---
{
"ProvisionedConcurrencyConfigs": []
}
[stdout]
{
"ReservedConcurrentExecutions": 0
}
---
{
"ProvisionedConcurrencyConfigs": []
}{
"command": "aws lambda delete-function-concurrency --function-name harbor-jwt-backend\necho \"concurrency cleared\"\naws lambda get-function-concurrency --function-name harbor-jwt-backend --output json 2>&1",
"description": "Clear reserved concurrency"
}concurrency cleared [stdout] concurrency cleared
{
"command": "aws iam put-role-policy --role-name harbor-jwt-backend-role --policy-name lambda-logs-bootstrap --policy-document '{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Action\":[\"logs:CreateLogGroup\",\"logs:CreateLogStream\",\"logs:PutLogEvents\"],\"Resource\":\"*\"}]}'\necho \"iam updated\"",
"description": "Grant lambda role full log permissions"
}iam updated [stdout] iam updated
{
"command": "CID=13clnhhjp8bh5o0069z7hoo2ab\nCSEC=6861f886\nBASIC=$(printf '%s:%s' \"$CID\" \"$CSEC\" | base64 -w0)\n\nget_token() {\n curl -s -X POST -H \"Authorization: Basic $BASIC\" \\\n -H 'Content-Type: application/x-www-form-urlencoded' \\\n --data \"grant_type=client_credentials&scope=$1\" \\\n http://localstack:4566/_aws/cognito-idp/oauth2/token \\\n | python3 -c 'import json,sys; print(json.load(sys.stdin)[\"access_token\"])'\n}\n\nT_BOTH=$(get_token \"harbor-api/read harbor-api/write\")\nT_READ=$(get_token \"harbor-api/read\")\nT_WRITE=$(get_token \"harbor-api/write\")\nEP=\"http://localstack:4566/restapis/996a7d3a/prod/_user_request_\"\n\necho \"=== expect 200 ===\"\necho \"GET both:\"; curl -sS -o /tmp/r -w 'HTTP %{http_code}\\n' -H \"Authorization: Bearer $T_BOTH\" \"$EP/reports\"; cat /tmp/r; echo\necho \"POST both:\"; curl -sS -o /tmp/r -w 'HTTP %{http_code}\\n' -X POST -H \"Authorization: Bearer $T_BOTH\" \"$EP/reports\"; cat /tmp/r; echo\n\necho \"=== expect 401 ===\"\necho \"GET no-auth:\"; curl -sS -o /tmp/r -w 'HTTP %{http_code}\\n' \"$EP/reports\"; cat /tmp/r; echo\necho \"POST no-auth:\"; curl -sS -o /tmp/r -w 'HTTP %{http_code}\\n' -X POST \"$EP/reports\"; cat /tmp/r; echo\necho \"GET malformed:\"; curl -sS -o /tmp/r -w 'HTTP %{http_code}\\n' -H \"Authorization: Bearer garbage\" \"$EP/reports\"; cat /tmp/r; echo\necho \"POST malformed:\"; curl -sS -o /tmp/r -w 'HTTP %{http_code}\\n' -X POST -H \"Authorization: Bearer garbage\" \"$EP/reports\"; cat /tmp/r; echo\n\necho \"=== expect 403 ===\"\necho \"GET write-only:\"; curl -sS -o /tmp/r -w 'HTTP %{http_code}\\n' -H \"Authorization: Bearer $T_WRITE\" \"$EP/reports\"; cat /tmp/r; echo\necho \"POST read-only:\"; curl -sS -o /tmp/r -w 'HTTP %{http_code}\\n' -X POST -H \"Authorization: Bearer $T_READ\" \"$EP/reports\"; cat /tmp/r; echo",
"description": "End-to-end verification of all required behaviours"
}=== expect 200 ===
GET both:
HTTP 200
{"ok": true, "method": "GET", "route": "GET /reports", "client_id": "13clnhhjp8bh5o0069z7hoo2ab", "scope": "harbor-api/read harbor-api/write", "scopes": ["harbor-api/read", "harbor-api/write"]}
POST both:
HTTP 200
{"ok": true, "method": "POST", "route": "POST /reports", "client_id": "13clnhhjp8bh5o0069z7hoo2ab", "scope": "harbor-api/read harbor-api/write", "scopes": ["harbor-api/read", "harbor-api/write"]}
=== expect 401 ===
GET no-auth:
HTTP 401
{"message":"Unauthorized"}
POST no-auth:
HTTP 401
{"message":"Unauthorized"}
GET malformed:
HTTP 401
{"message":"Unauthorized"}
POST malformed:
HTTP 401
{"message":"Unauthorized"}
=== expect 403 ===
GET write-only:
HTTP 403
{"message":"Forbidden"}
POST read-only:
HTTP 403
{"message":"Forbidden"}
[stdout]
=== expect 200 ===
GET both:
HTTP 200
{"ok": true, "method": "GET", "route": "GET /reports", "client_id": "13clnhhjp8bh5o0069z7hoo2ab", "scope": "harbor-api/read harbor-api/write", "scopes": ["harbor-api/read", "harbor-api/write"]}
POST both:
HTTP 200
{"ok": true, "method": "POST", "route": "POST /reports", "client_id": "13clnhhjp8bh5o0069z7hoo2ab", "scope": "harbor-api/read harbor-api/write", "scopes": ["harbor-api/read", "harbor-api/write"]}
=== expect 401 ===
GET no-auth:
HTTP 401
{"message":"Unauthorized"}
POST no-auth:
HTTP 401
{"message":"Unauthorized"}
GET malformed:
HTTP 401
{"message":"Unauthorized"}
POST malformed:
HTTP 401
{"message":"Unauthorized"}
=== expect 403 ===
GET write-only:
HTTP 403
{"message":"Forbidden"}
POST read-only:
HTTP 403
{"message":"Forbidden"}No file changes, the agent left the workspace untouched.
downloading uv 0.9.7 aarch64-unknown-linux-gnu
Downloading pygments (1.2MiB)
Downloading botocore (12.7MiB)
Downloading pygments
Downloading botocore
Installed 13 packages in 71ms
============================= test session starts ==============================
platform linux -- Python 3.12.3, pytest-8.4.1, pluggy-1.6.0 -- /root/.cache/uv/archive-v0/hSPhNTTmltm66TtxUEBBH/bin/python
cachedir: .pytest_cache
rootdir: /tests
plugins: json-ctrf-0.3.5
collecting ... collected 60 items
../tests/test_outputs.py::test_01_token_endpoint_returns_access_token PASSED [ 1%]
../tests/test_outputs.py::test_02_token_endpoint_rejects_bad_secret PASSED [ 3%]
../tests/test_outputs.py::test_03_token_endpoint_no_token_when_grant_type_missing PASSED [ 5%]
../tests/test_outputs.py::test_04_get_reports_with_valid_token_is_200 PASSED [ 6%]
../tests/test_outputs.py::test_05_post_reports_with_valid_token_is_200 PASSED [ 8%]
../tests/test_outputs.py::test_06_get_reports_returns_ok_true_in_body PASSED [ 10%]
../tests/test_outputs.py::test_07_post_reports_returns_ok_true_in_body PASSED [ 11%]
../tests/test_outputs.py::test_08_get_reports_without_authorization_is_401 PASSED [ 13%]
../tests/test_outputs.py::test_09_post_reports_without_authorization_is_401 PASSED [ 15%]
../tests/test_outputs.py::test_10_get_reports_with_malformed_bearer_is_401 PASSED [ 16%]
../tests/test_outputs.py::test_11_get_reports_with_wrong_scope_only_is_403 PASSED [ 18%]
../tests/test_outputs.py::test_12_post_reports_with_wrong_scope_only_is_403 PASSED [ 20%]
../tests/test_outputs.py::test_13_get_reports_body_reflects_method_and_route PASSED [ 21%]
../tests/test_outputs.py::test_14_post_reports_body_reflects_method_and_route PASSED [ 23%]
../tests/test_outputs.py::test_15_access_token_is_a_three_segment_jwt PASSED [ 25%]
../tests/test_outputs.py::test_16_token_payload_has_client_id_claim PASSED [ 26%]
../tests/test_outputs.py::test_17_token_payload_has_scope_claim_with_both_scopes PASSED [ 28%]
../tests/test_outputs.py::test_18_token_payload_issuer_matches_user_pool PASSED [ 30%]
../tests/test_outputs.py::test_19_token_payload_token_use_is_access PASSED [ 31%]
../tests/test_outputs.py::test_20_read_only_token_scope_excludes_write PASSED [ 33%]
../tests/test_outputs.py::test_21_write_only_token_scope_excludes_read PASSED [ 35%]
../tests/test_outputs.py::test_22_token_expiry_is_in_the_future PASSED [ 36%]
../tests/test_outputs.py::test_23_http_api_protocol_type_is_http PASSED [ 38%]
../tests/test_outputs.py::test_24_jwt_authorizer_type_is_jwt PASSED [ 40%]
../tests/test_outputs.py::test_25_jwt_authorizer_audience_contains_app_client_id PASSED [ 41%]
../tests/test_outputs.py::test_26_jwt_authorizer_issuer_matches_user_pool PASSED [ 43%]
../tests/test_outputs.py::test_27_jwt_authorizer_identity_source_is_authorization_header PASSED [ 45%]
../tests/test_outputs.py::test_28_route_get_reports_authorization_type_is_jwt PASSED [ 46%]
../tests/test_outputs.py::test_29_route_post_reports_authorization_type_is_jwt PASSED [ 48%]
../tests/test_outputs.py::test_30_route_get_reports_scopes_are_namespaced_read PASSED [ 50%]
../tests/test_outputs.py::test_31_route_post_reports_scopes_are_namespaced_write PASSED [ 51%]
../tests/test_outputs.py::test_32_route_get_reports_uses_the_authorizer PASSED [ 53%]
../tests/test_outputs.py::test_33_route_post_reports_uses_the_authorizer PASSED [ 55%]
../tests/test_outputs.py::test_34_lambda_integration_payload_format_is_two_dot_zero PASSED [ 56%]
../tests/test_outputs.py::test_35_lambda_integration_type_is_aws_proxy PASSED [ 58%]
../tests/test_outputs.py::test_36_lambda_integration_uri_targets_backend_function PASSED [ 60%]
../tests/test_outputs.py::test_37_stage_auto_deploy_is_true PASSED [ 61%]
../tests/test_outputs.py::test_38_stage_has_a_deployment PASSED [ 63%]
../tests/test_outputs.py::test_39_stage_name_is_prod PASSED [ 65%]
../tests/test_outputs.py::test_40_user_pool_exists_with_expected_name PASSED [ 66%]
../tests/test_outputs.py::test_41_resource_server_exists_with_two_scopes PASSED [ 68%]
../tests/test_outputs.py::test_42_app_client_allowed_oauth_flow_is_client_credentials PASSED [ 70%]
../tests/test_outputs.py::test_43_app_client_oauth_flows_user_pool_client_is_true PASSED [ 71%]
../tests/test_outputs.py::test_44_app_client_has_a_client_secret PASSED [ 73%]
../tests/test_outputs.py::test_45_app_client_allowed_oauth_scopes_includes_both_namespaced PASSED [ 75%]
../tests/test_outputs.py::test_46_app_client_supports_cognito_identity_provider PASSED [ 76%]
../tests/test_outputs.py::test_47_app_client_does_not_use_implicit_flow_alone PASSED [ 78%]
../tests/test_outputs.py::test_48_backend_lambda_exists_and_active PASSED [ 80%]
../tests/test_outputs.py::test_49_backend_lambda_runtime_is_python3 PASSED [ 81%]
../tests/test_outputs.py::test_50_backend_lambda_role_can_write_logs PASSED [ 83%]
../tests/test_outputs.py::test_51_apigateway_can_invoke_backend_lambda PASSED [ 85%]
../tests/test_outputs.py::test_52_log_group_exists PASSED [ 86%]
../tests/test_outputs.py::test_53_ssm_manifest_keys_present PASSED [ 88%]
../tests/test_outputs.py::test_54_ssm_api_id_resolves_to_real_api PASSED [ 90%]
../tests/test_outputs.py::test_55_ssm_user_pool_id_resolves_to_real_pool PASSED [ 91%]
../tests/test_outputs.py::test_56_ssm_authorizer_id_resolves_to_real_authorizer PASSED [ 93%]
../tests/test_outputs.py::test_57_ssm_oauth_token_endpoint_is_well_formed PASSED [ 95%]
../tests/test_outputs.py::test_58_backend_lambda_reserved_concurrency_does_not_block_invocations PASSED [ 96%]
../tests/test_outputs.py::test_59_backend_lambda_direct_invoke_returns_a_successful_response PASSED [ 98%]
../tests/test_outputs.py::test_60_backend_lambda_role_grants_log_stream_writes PASSED [100%]
=============================== warnings summary ===============================
test_outputs.py: 123 warnings
/root/.cache/uv/archive-v0/hSPhNTTmltm66TtxUEBBH/lib/python3.12/site-packages/botocore/auth.py:424: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
datetime_now = datetime.datetime.utcnow()
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
==================================== PASSES ====================================
=========================== short test summary info ============================
PASSED ../tests/test_outputs.py::test_01_token_endpoint_returns_access_token
PASSED ../tests/test_outputs.py::test_02_token_endpoint_rejects_bad_secret
PASSED ../tests/test_outputs.py::test_03_token_endpoint_no_token_when_grant_type_missing
PASSED ../tests/test_outputs.py::test_04_get_reports_with_valid_token_is_200
PASSED ../tests/test_outputs.py::test_05_post_reports_with_valid_token_is_200
PASSED ../tests/test_outputs.py::test_06_get_reports_returns_ok_true_in_body
PASSED ../tests/test_outputs.py::test_07_post_reports_returns_ok_true_in_body
PASSED ../tests/test_outputs.py::test_08_get_reports_without_authorization_is_401
PASSED ../tests/test_outputs.py::test_09_post_reports_without_authorization_is_401
PASSED ../tests/test_outputs.py::test_10_get_reports_with_malformed_bearer_is_401
PASSED ../tests/test_outputs.py::test_11_get_reports_with_wrong_scope_only_is_403
PASSED ../tests/test_outputs.py::test_12_post_reports_with_wrong_scope_only_is_403
PASSED ../tests/test_outputs.py::test_13_get_reports_body_reflects_method_and_route
PASSED ../tests/test_outputs.py::test_14_post_reports_body_reflects_method_and_route
PASSED ../tests/test_outputs.py::test_15_access_token_is_a_three_segment_jwt
PASSED ../tests/test_outputs.py::test_16_token_payload_has_client_id_claim
PASSED ../tests/test_outputs.py::test_17_token_payload_has_scope_claim_with_both_scopes
PASSED ../tests/test_outputs.py::test_18_token_payload_issuer_matches_user_pool
PASSED ../tests/test_outputs.py::test_19_token_payload_token_use_is_access
PASSED ../tests/test_outputs.py::test_20_read_only_token_scope_excludes_write
PASSED ../tests/test_outputs.py::test_21_write_only_token_scope_excludes_read
PASSED ../tests/test_outputs.py::test_22_token_expiry_is_in_the_future
PASSED ../tests/test_outputs.py::test_23_http_api_protocol_type_is_http
PASSED ../tests/test_outputs.py::test_24_jwt_authorizer_type_is_jwt
PASSED ../tests/test_outputs.py::test_25_jwt_authorizer_audience_contains_app_client_id
PASSED ../tests/test_outputs.py::test_26_jwt_authorizer_issuer_matches_user_pool
PASSED ../tests/test_outputs.py::test_27_jwt_authorizer_identity_source_is_authorization_header
PASSED ../tests/test_outputs.py::test_28_route_get_reports_authorization_type_is_jwt
PASSED ../tests/test_outputs.py::test_29_route_post_reports_authorization_type_is_jwt
PASSED ../tests/test_outputs.py::test_30_route_get_reports_scopes_are_namespaced_read
PASSED ../tests/test_outputs.py::test_31_route_post_reports_scopes_are_namespaced_write
PASSED ../tests/test_outputs.py::test_32_route_get_reports_uses_the_authorizer
PASSED ../tests/test_outputs.py::test_33_route_post_reports_uses_the_authorizer
PASSED ../tests/test_outputs.py::test_34_lambda_integration_payload_format_is_two_dot_zero
PASSED ../tests/test_outputs.py::test_35_lambda_integration_type_is_aws_proxy
PASSED ../tests/test_outputs.py::test_36_lambda_integration_uri_targets_backend_function
PASSED ../tests/test_outputs.py::test_37_stage_auto_deploy_is_true
PASSED ../tests/test_outputs.py::test_38_stage_has_a_deployment
PASSED ../tests/test_outputs.py::test_39_stage_name_is_prod
PASSED ../tests/test_outputs.py::test_40_user_pool_exists_with_expected_name
PASSED ../tests/test_outputs.py::test_41_resource_server_exists_with_two_scopes
PASSED ../tests/test_outputs.py::test_42_app_client_allowed_oauth_flow_is_client_credentials
PASSED ../tests/test_outputs.py::test_43_app_client_oauth_flows_user_pool_client_is_true
PASSED ../tests/test_outputs.py::test_44_app_client_has_a_client_secret
PASSED ../tests/test_outputs.py::test_45_app_client_allowed_oauth_scopes_includes_both_namespaced
PASSED ../tests/test_outputs.py::test_46_app_client_supports_cognito_identity_provider
PASSED ../tests/test_outputs.py::test_47_app_client_does_not_use_implicit_flow_alone
PASSED ../tests/test_outputs.py::test_48_backend_lambda_exists_and_active
PASSED ../tests/test_outputs.py::test_49_backend_lambda_runtime_is_python3
PASSED ../tests/test_outputs.py::test_50_backend_lambda_role_can_write_logs
PASSED ../tests/test_outputs.py::test_51_apigateway_can_invoke_backend_lambda
PASSED ../tests/test_outputs.py::test_52_log_group_exists
PASSED ../tests/test_outputs.py::test_53_ssm_manifest_keys_present
PASSED ../tests/test_outputs.py::test_54_ssm_api_id_resolves_to_real_api
PASSED ../tests/test_outputs.py::test_55_ssm_user_pool_id_resolves_to_real_pool
PASSED ../tests/test_outputs.py::test_56_ssm_authorizer_id_resolves_to_real_authorizer
PASSED ../tests/test_outputs.py::test_57_ssm_oauth_token_endpoint_is_well_formed
PASSED ../tests/test_outputs.py::test_58_backend_lambda_reserved_concurrency_does_not_block_invocations
PASSED ../tests/test_outputs.py::test_59_backend_lambda_direct_invoke_returns_a_successful_response
PASSED ../tests/test_outputs.py::test_60_backend_lambda_role_grants_log_stream_writes
====================== 60 passed, 123 warnings in 11.91s =======================Reproduce this trial: git checkout 2f94510 && PYTHONPATH=src python3 scripts/build_site.py , then open trial/trial_4df7d00c02894112. Re-running the agent live requires EVAL_PLATFORM_ENABLE_OAUTH_SMOKE=1 and is non-deterministic.
Trial trial_4df7d00c02894112 · verifier authoritative; classifier explanatory.