Skip to content

Commit

Permalink
Add Pact provider tests
Browse files Browse the repository at this point in the history
Add a pipeline that runs on PRs, branches and on repository dispatch.

Requires a JWT to be generated beforehand and included in headers for authentication.

Fixes VEGA-2196 #minor
  • Loading branch information
gregtyler committed Dec 4, 2023
1 parent cc50fcc commit e89efb7
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 16 deletions.
54 changes: 54 additions & 0 deletions .github/workflows/pact-provider-verification.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Pact Provider Verification

on:
repository_dispatch:
types: [provider-verification]
pull_request:
branches:
- main
push:
branches:
- main

jobs:
test:
name: Provider verification
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: make build up
- run: go build -o ./api-test/tester ./api-test && chmod +x ./api-test/tester
- run: cat ./docs/example-lpa.json | ./api-test/tester -jwtSecret=secret -expectedStatus=201 REQUEST PUT http://localhost:9000/lpas/M-3467-89QW-ERTY "`xargs -0`"
- run: export JWT=$(./api-test/tester -jwtSecret=secret JWT)
- name: Verify specified Pact
if: ${{ github.event_name == 'repository_dispatch' }}
run: |
docker-compose run --rm pact-verifier \
--header="X-Jwt-Authorization: Bearer $JWT" \
--provider-version=$(git rev-parse HEAD) \
--provider-branch=main \
--publish \
--user=admin \
--password=${{ secrets.PACT_BROKER_PASSWORD }} \
--url=${{ github.event.client_payload.pact_url }}
- name: Verify pacts, including pending
if: ${{ github.event_name == 'push' }}
run: |
docker-compose run --rm pact-verifier \
--header="X-Jwt-Authorization: Bearer $JWT" \
--provider-version=$(git rev-parse HEAD) \
--provider-branch=main \
--publish \
--user=admin \
--password=${{ secrets.PACT_BROKER_PASSWORD }} \
--consumer-version-selectors='{"mainBranch": true}' \
--enable-pending
- name: Verify pacts are still upheld
if: ${{ github.event_name == 'pull_request' }}
run: |
docker-compose run --rm pact-verifier \
--header="X-Jwt-Authorization=Bearer $JWT" \
--provider-version=$(git rev-parse HEAD) \
--provider-branch=${{ github.head_ref }} \
--consumer-version-selectors='{"branch": "VEGA2174_lpastore_service"}'
# --consumer-version-selectors='{"mainBranch": true}'
43 changes: 30 additions & 13 deletions api-test/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ import (
)

// ./api-test/tester UID -> generate a UID
// ./api-test/tester JWT -> generate a JWT
// ./api-test/tester -jwtSecret=secret -expectedStatus=200 REQUEST <METHOD> <URL> <REQUEST BODY>
// -> make a test request with a JWT generated using secret "secret" and expected status 200
//
// -> make a test request with a JWT generated using secret "secret" and expected status 200
//
// note that the jwtSecret sends a boilerplate JWT for now with valid iat, exp, iss and sub fields
func main() {
expectedStatusCode := flag.Int("expectedStatus", 200, "Expected response status code")
Expand All @@ -33,6 +36,11 @@ func main() {
os.Exit(0)
}

if args[0] == "JWT" {
fmt.Print(makeJwt([]byte(*jwtSecret)))
os.Exit(0)
}

if args[0] != "REQUEST" {
panic("Unrecognised command")
}
Expand All @@ -49,19 +57,9 @@ func main() {
req.Header.Add("Content-type", "application/json")

if *jwtSecret != "" {
secretKey := []byte(*jwtSecret)

claims := jwt.MapClaims{
"exp": time.Now().Add(time.Hour * 24).Unix(),
"iat": time.Now().Add(time.Hour * -24).Unix(),
"iss": "opg.poas.sirius",
"sub": "[email protected]",
}
tokenString := makeJwt([]byte(*jwtSecret))

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, _ := token.SignedString(secretKey)

req.Header.Add("X-Jwt-Authorization", fmt.Sprintf("Bearer: %s", tokenString))
req.Header.Add("X-Jwt-Authorization", fmt.Sprintf("Bearer %s", tokenString))
}

sess := session.Must(session.NewSession())
Expand All @@ -88,6 +86,25 @@ func main() {
log.Printf("invalid status code %d; expected: %d", resp.StatusCode, *expectedStatusCode)
log.Printf("error response: %s", buf.String())
} else {
log.Print(resp.Header)
log.Printf("Test passed - %s to %s - %d: %s", method, url, resp.StatusCode, buf.String())
}
}

func makeJwt(secretKey []byte) string {
claims := jwt.MapClaims{
"exp": time.Now().Add(time.Hour * 24).Unix(),
"iat": time.Now().Add(time.Hour * -24).Unix(),
"iss": "opg.poas.sirius",
"sub": "[email protected]",
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString(secretKey)

if err != nil {
panic(err)
}

return tokenString
}
16 changes: 13 additions & 3 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ services:
AWS_ACCESS_KEY_ID: X
AWS_SECRET_ACCESS_KEY: X
DDB_TABLE_NAME_DEEDS: deeds
JWT_SECRET_KEY: ${JWT_SECRET_KEY}
JWT_SECRET_KEY: ${JWT_SECRET_KEY:-secret}
volumes:
- "./lambda/.aws-lambda-rie:/aws-lambda"
entrypoint: /aws-lambda/aws-lambda-rie /var/task/main
Expand All @@ -35,7 +35,7 @@ services:
AWS_ACCESS_KEY_ID: X
AWS_SECRET_ACCESS_KEY: X
DDB_TABLE_NAME_DEEDS: deeds
JWT_SECRET_KEY: ${JWT_SECRET_KEY}
JWT_SECRET_KEY: ${JWT_SECRET_KEY:-secret}
volumes:
- "./lambda/.aws-lambda-rie:/aws-lambda"
entrypoint: /aws-lambda/aws-lambda-rie /var/task/main
Expand All @@ -53,7 +53,7 @@ services:
AWS_ACCESS_KEY_ID: X
AWS_SECRET_ACCESS_KEY: X
DDB_TABLE_NAME_DEEDS: deeds
JWT_SECRET_KEY: ${JWT_SECRET_KEY}
JWT_SECRET_KEY: ${JWT_SECRET_KEY:-secret}
volumes:
- "./lambda/.aws-lambda-rie:/aws-lambda"
entrypoint: /aws-lambda/aws-lambda-rie /var/task/main
Expand Down Expand Up @@ -88,3 +88,13 @@ services:
volumes:
- .:/app
command: -exclude-dir=.gocache -fmt sarif -out /app/results.sarif /app/...

pact-verifier:
image: pactfoundation/pact-ref-verifier
entrypoint:
- pact_verifier_cli
- --hostname=apigw
- --port=8080
- --base-path=/
- --broker-url=https://pact-broker.api.opg.service.justice.gov.uk/
- --provider-name=data-lpa-store
1 change: 1 addition & 0 deletions mock-apigw/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ func delegateHandler(w http.ResponseWriter, r *http.Request) {
var respBody events.APIGatewayProxyResponse
_ = json.Unmarshal(encodedRespBody, &respBody)

w.Header().Set("Content-Type", "application/json")
w.WriteHeader(respBody.StatusCode)
_, err = w.Write([]byte(respBody.Body))

Expand Down

0 comments on commit e89efb7

Please sign in to comment.