diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml new file mode 100644 index 000000000..f35c5792c --- /dev/null +++ b/.github/workflows/tests.yaml @@ -0,0 +1,120 @@ +name: Tests +on: + push: + branches: + - main + pull_request: + branches: + - main + +# Restrict tests to the most recent commit. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + name: Build Docker Images + runs-on: ubuntu-22.04 + outputs: + testcases: ${{ steps.enum-tests.outputs.testcases }} + steps: + - name: Clone repository + uses: actions/checkout@v4 + + - name: Build images + shell: bash + run: make generate build + + - name: Save images + shell: bash + run: | + mkdir -p docker-cache + docker save -o docker-cache/autograph-images.tar autograph-app autograph-app-hsm + + - name: Enumerate tests + id: enum-tests + shell: bash + run: | + echo -n "testcases=" >> $GITHUB_OUTPUT + yq -o=json '.services | keys' tools/autograph-client/integration-tests.yml | jq -c >> $GITHUB_OUTPUT + + - uses: actions/upload-artifact@v4 + with: + name: autograph-images-${{ github.sha }} + path: docker-cache/ + + unit-tests: + name: Run Unit Tests + runs-on: ubuntu-22.04 + needs: + - build + env: + DBNAME: autograph + PGPASSWORD: myautographdbpassword + + services: + database: + image: postgres:11 + env: + POSTGRES_DB: ${{ env.DBNAME }} + POSTGRES_PASSWORD: ${{ env.PGPASSWORD }} + POSTGRES_HOST_AUTH_METHOD: trust + ports: + - 5432:5432 + + steps: + - name: Clone repository + uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: autograph-images-${{ github.sha }} + path: docker-cache/ + + - name: Initialize database + shell: bash + run: psql -h localhost -p 5432 -U postgres --no-password -f database/schema.sql ${{ env.DBNAME }} + + - name: Load images + shell: bash + run: docker load -i docker-cache/autograph-images.tar + + - name: Run Tests + shell: bash + env: + AUTOGRAPH_DB_DSN: postgres://myautographdbuser:${{ env.PGPASSWORD }}@localhost/${{ env.DBNAME }}?sslmode=disable + run: | + docker run \ + --env AUTOGRAPH_DB_DSN \ + --env RACE_TEST=0 \ + --workdir /app/src/autograph \ + --net=host \ + --user 0 \ + autograph-app ./bin/run_unit_tests.sh + + integration-tests: + name: Run Integration Tests + runs-on: ubuntu-22.04 + needs: + - build + strategy: + fail-fast: false # Don't cancel other jobs if a test fails + matrix: + testcase: ${{ fromJSON(needs.build.outputs.testcases) }} + steps: + - name: Clone repository + uses: actions/checkout@v4 + + - uses: actions/download-artifact@v4 + with: + name: autograph-images-${{ github.sha }} + path: docker-cache/ + + - name: Load images + shell: bash + run: docker load -i docker-cache/autograph-images.tar + + - name: Running ${{ matrix.testcase }} + shell: bash + run: docker compose -f tools/autograph-client/integration-tests.yml run ${{ matrix.testcase }} diff --git a/bin/run_integration_tests.sh b/bin/run_integration_tests.sh index b25763b95..1df2aced3 100755 --- a/bin/run_integration_tests.sh +++ b/bin/run_integration_tests.sh @@ -29,26 +29,19 @@ docker cp autograph-app-hsm:/tmp/normandy_dev_root_hash.txt . APP_HSM_NORMANDY_ROOT_HASH=$(grep '[0-9A-F]' normandy_dev_root_hash.txt | tr -d '\r\n') # start the monitor lambda emulators -docker compose up -d monitor-lambda-emulator -AUTOGRAPH_ROOT_HASH=$APP_HSM_NORMANDY_ROOT_HASH docker compose up -d monitor-hsm-lambda-emulator - -echo "waiting for monitor-lambda-emulator to start" -while test "true" != "$(docker inspect -f {{.State.Running}} autograph-monitor-lambda-emulator)"; do - echo -n "." - sleep 1 # wait before checking again -done -echo "waiting for monitor-hsm-lambda-emulator to start" -while test "true" != "$(docker inspect -f {{.State.Running}} autograph-monitor-hsm-lambda-emulator)"; do - echo -n "." - sleep 1 # wait before checking again -done +echo "checking autograph monitors" +docker compose run \ + --rm \ + -e AUTOGRAPH_URL=http://app:8000/ \ + --entrypoint /usr/local/bin/lambda-selftest-entrypoint.sh \ + monitor-lambda-emulator /go/bin/autograph-monitor -echo "checking monitoring using hsm root hash:" "$APP_HSM_NORMANDY_ROOT_HASH" -# exec in containers to workaround https://circleci.com/docs/2.0/building-docker-images/#accessing-services -docker compose exec monitor-lambda-emulator "/usr/local/bin/test_monitor.sh" -docker compose logs monitor-lambda-emulator -docker compose exec monitor-hsm-lambda-emulator "/usr/local/bin/test_monitor.sh" -docker compose logs monitor-hsm-lambda-emulator +docker compose run \ + --rm \ + -e AUTOGRAPH_URL=http://autograph-app-hsm:8001/ \ + -e AUTOGRAPH_ROOT_HASH=$APP_HSM_NORMANDY_ROOT_HASH \ + --entrypoint /usr/local/bin/lambda-selftest-entrypoint.sh \ + monitor-hsm-lambda-emulator /go/bin/autograph-monitor echo "checking read-only API" # user bob doesn't exist in the softhsm config @@ -100,7 +93,7 @@ docker compose run \ --rm \ --user 0 \ -e TARGET=http://app:8000 \ - -e VERIFY=1 \ + -e VERIFY=1 \ --workdir /app/src/autograph/tools/autograph-client \ --entrypoint ./build_test_apks.sh \ app diff --git a/docker-compose.yml b/docker-compose.yml index 4d91884f1..237b99332 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -66,10 +66,7 @@ services: monitor: container_name: autograph-monitor image: autograph-app - command: - [ - "/go/bin/autograph-monitor", - ] + command: ["/go/bin/autograph-monitor"] monitor-lambda-emulator: container_name: autograph-monitor-lambda-emulator @@ -83,6 +80,7 @@ services: # set a non-empty value to use the lambda handler - LAMBDA_TASK_ROOT=/usr/local/bin/ - AUTOGRAPH_ROOT_HASH + command: ["/go/bin/autograph-monitor"] ports: - "9000:8080" links: @@ -104,6 +102,7 @@ services: # set a non-empty value to use the lambda handler - LAMBDA_TASK_ROOT=/usr/local/bin/ - AUTOGRAPH_ROOT_HASH + command: ["/go/bin/autograph-monitor"] ports: - "9001:8080" links: diff --git a/tools/autograph-client/integration-tests.yml b/tools/autograph-client/integration-tests.yml new file mode 100644 index 000000000..ffb218343 --- /dev/null +++ b/tools/autograph-client/integration-tests.yml @@ -0,0 +1,70 @@ +include: + - ../../docker-compose.yml +services: + test-api-app: + container_name: test-api-app + image: autograph-app + user: "0" + links: + - app + depends_on: + - app + entrypoint: ./test-entrypoint.sh + environment: + - CHECK_BOB=1 + - AUTOGRAPH_URL=http://app:8000 + working_dir: "/app/src/autograph/tools/autograph-client" + command: [ "./integration_test_api.sh" ] + + test-api-hsm: + container_name: test-api-hsm + image: autograph-app + user: "0" + links: + - app-hsm + depends_on: + - app-hsm + entrypoint: ./test-entrypoint.sh + environment: + - AUTOGRAPH_URL=http://app-hsm:8001 + working_dir: "/app/src/autograph/tools/autograph-client" + command: [ "./integration_test_api.sh" ] + + test-gpg-signing: + container_name: test-gpg-signing + extends: + service: test-api-app + command: [ "./integration_test_gpg2_signer.sh" ] + + test-xpi-signing: + container_name: test-xpi-signing + extends: + service: test-api-app + command: [ "./integration_test_xpis.sh" ] + + test-xpi-signing-hsm: + container_name: test-xpi-signing-hsm + extends: + service: test-api-hsm + environment: + - SIGNER_ID_PREFIX=hsm- + command: [ "./integration_test_xpis.sh" ] + + test-apk-signing: + container_name: test-apk-signing + extends: + service: test-api-app + environment: + - TARGET=http://app:8000 + - VERIFY=1 + command: [ "./build_test_apks.sh" ] + + test-monitor-app: + container_name: test-monitor-app + extends: + file: ../../docker-compose.yml + service: monitor-lambda-emulator + entrypoint: [ "/usr/local/bin/lambda-selftest-entrypoint.sh" ] + + # TODO: Add a monitor test for the HSM lambda - tricky because we need + # a way to dynamically grab the root hash from the HSM. diff --git a/tools/autograph-client/test-entrypoint.sh b/tools/autograph-client/test-entrypoint.sh new file mode 100755 index 000000000..43243fe5e --- /dev/null +++ b/tools/autograph-client/test-entrypoint.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env sh + +# Wait for the heartbeat +RESULT=$(curl --silent \ + --connect-timeout 5 \ + --max-time 10 \ + --retry-connrefused \ + --retry 5 \ + --retry-delay 5 \ + --retry-max-time 60 \ + "${AUTOGRAPH_URL}/__heartbeat__") +RETCODE=$? +if [ $RETCODE -ne 0 ]; then + echo "Failed to reach autograph heartbeat" >&2 + exit $RETCODE +else + echo "Autograph is running: ${RESULT}" + echo "Starting test" +fi + +# Run the test +set -e +exec "$@" diff --git a/tools/autograph-monitor/Dockerfile.lambda-emulator b/tools/autograph-monitor/Dockerfile.lambda-emulator index 29a96f399..2bc095d3d 100644 --- a/tools/autograph-monitor/Dockerfile.lambda-emulator +++ b/tools/autograph-monitor/Dockerfile.lambda-emulator @@ -2,11 +2,13 @@ FROM autograph-app USER root -RUN cp /app/src/autograph/bin/test_monitor.sh /usr/local/bin/test_monitor.sh RUN curl -Lo /usr/local/bin/aws-lambda-rie \ https://github.com/aws/aws-lambda-runtime-interface-emulator/releases/latest/download/aws-lambda-rie \ && \ - chmod +x /usr/local/bin/aws-lambda-rie /usr/local/bin/test_monitor.sh + chmod +x /usr/local/bin/aws-lambda-rie + +COPY lambda-selftest-entrypoint.sh /usr/local/bin/lambda-selftest-entrypoint.sh USER app -CMD ["/usr/local/bin/aws-lambda-rie", "/go/bin/autograph-monitor"] +ENTRYPOINT ["/usr/local/bin/aws-lambda-rie"] +CMD ["/go/bin/autograph-monitor"] diff --git a/bin/test_monitor.sh b/tools/autograph-monitor/lambda-selftest-entrypoint.sh old mode 100644 new mode 100755 similarity index 59% rename from bin/test_monitor.sh rename to tools/autograph-monitor/lambda-selftest-entrypoint.sh index ddb248105..4b250c11e --- a/bin/test_monitor.sh +++ b/tools/autograph-monitor/lambda-selftest-entrypoint.sh @@ -3,8 +3,17 @@ set -e set -o pipefail +# Fork to start the AWS runtime emulator +/usr/local/bin/aws-lambda-rie "$@" & +AWS_RUNTIME_PID=$! +cleanup() { + kill -TERM $AWS_RUNTIME_PID + wait $AWS_RUNTIME_PID +} +trap cleanup EXIT SIGINT SIGTERM + # invoke a test monitor run in a lambda monitor -MONITOR_ERROR=$(curl -w '\n' -X POST 'http://localhost:8080/2015-03-31/functions/function/invocations' -d '{}') +MONITOR_ERROR=$(curl -s -w '\n' -X POST 'http://localhost:8080/2015-03-31/functions/function/invocations' -d '{}') # If the result was null - then we succeeded! if [ "${MONITOR_ERROR}" == "null" ]; then @@ -19,4 +28,3 @@ else echo "${MONITOR_ERROR}" | jq >&2 fi exit 1 -