diff --git a/.github/workflows/outpost-api-image.yml b/.github/workflows/publish-outpost-api-image.yml similarity index 72% rename from .github/workflows/outpost-api-image.yml rename to .github/workflows/publish-outpost-api-image.yml index c71c2f2..600253b 100644 --- a/.github/workflows/outpost-api-image.yml +++ b/.github/workflows/publish-outpost-api-image.yml @@ -1,13 +1,13 @@ # This action pre-builds the dev-base image and pushes it to the GitHub Container Registry (GHCR) -name: Deploy outpost api image to github container registry +name: Publish outpost-api-service to github container registry on: push: branches: [develop, staging, production] jobs: - push-outpost-api-image: + publish-outpost-api-image: runs-on: ubuntu-latest strategy: matrix: @@ -28,18 +28,26 @@ jobs: run: | BRANCH_NAME=${GITHUB_REF#refs/heads/} if [[ "$BRANCH_NAME" == "develop" ]]; then - echo "::set-output name=tag::development" + echo "tag=development" >> $GITHUB_ENV elif [[ "$BRANCH_NAME" == "staging" ]]; then - echo "::set-output name=tag::staging" + echo "tag=staging" >> $GITHUB_ENV elif [[ "$BRANCH_NAME" == "production" ]]; then - echo "::set-output name=tag::latest" + echo "tag=latest" >> $GITHUB_ENV + else + echo "tag=default" >> $GITHUB_ENV fi + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - name: Build and push outpost api docker image uses: docker/build-push-action@v5 with: context: . - tags: ghcr.io/wearefuturegov/outpost-api-service:${{ steps.vars.outputs.tag }} + tags: ghcr.io/wearefuturegov/outpost-api-service:${{ env.tag }} file: Dockerfile.production platforms: ${{ matrix.platforms }} push: true diff --git a/.github/workflows/test-docker-build.yml b/.github/workflows/test-docker-build.yml new file mode 100644 index 0000000..0ea6509 --- /dev/null +++ b/.github/workflows/test-docker-build.yml @@ -0,0 +1,44 @@ +# This action tests to make sure that the docker image can be built successfully on the specified platforms + +name: Test outpost-api-image docker build + +on: push + +jobs: + test-docker-build: + runs-on: ubuntu-latest + strategy: + matrix: + platforms: ["linux/amd64", "linux/arm64", "linux/arm64/v8"] + steps: + - name: "Checkout GitHub Action" + uses: actions/checkout@main + + - name: Set Docker Image Tag + id: vars + run: | + BRANCH_NAME=${GITHUB_HEAD_REF#refs/heads/} + if [[ "$BRANCH_NAME" == "develop" ]]; then + echo "tag=development" >> $GITHUB_ENV + elif [[ "$BRANCH_NAME" == "staging" ]]; then + echo "tag=staging" >> $GITHUB_ENV + elif [[ "$BRANCH_NAME" == "production" ]]; then + echo "tag=latest" >> $GITHUB_ENV + else + echo "tag=default" >> $GITHUB_ENV + fi + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker image + uses: docker/build-push-action@v5 + with: + context: . + tags: outpost-api-service:${{ env.tag }} + file: Dockerfile.production + platforms: ${{ matrix.platforms }} + push: false diff --git a/.github/workflows/test-in-docker.yml b/.github/workflows/test-in-docker.yml new file mode 100644 index 0000000..1a7882b --- /dev/null +++ b/.github/workflows/test-in-docker.yml @@ -0,0 +1,75 @@ +# This action tests to make sure that the docker image can be built successfully on the specified platforms + +name: Run tests in docker container + +on: push + +jobs: + test-in-docker: + runs-on: ubuntu-latest + + steps: + - name: "Checkout GitHub Action" + uses: actions/checkout@main + + - name: "Create custom network" + run: docker network create outpost-api-test-network + + - name: "Setup mongo" + run: | + docker run --rm -d -p 27017:27017 \ + --name mongo \ + -e MONGO_INITDB_ROOT_USERNAME=admin \ + -e MONGO_INITDB_ROOT_PASSWORD=password \ + -e MONGO_INITDB_USERNAME=outpost \ + -e MONGO_INITDB_PASSWORD=password \ + -e MONGO_INITDB_DATABASE=outpost_api_development \ + -v $PWD/.docker/services/mongo/setup-mongodb.js:/docker-entrypoint-initdb.d/mongo-init.js:ro \ + --network=outpost-api-test-network \ + mongo:latest + + - name: Set Docker Image Tag + id: vars + run: | + BRANCH_NAME=${GITHUB_HEAD_REF#refs/heads/} + if [[ "$BRANCH_NAME" == "develop" ]]; then + echo "tag=development" >> $GITHUB_ENV + elif [[ "$BRANCH_NAME" == "staging" ]]; then + echo "tag=staging" >> $GITHUB_ENV + elif [[ "$BRANCH_NAME" == "production" ]]; then + echo "tag=latest" >> $GITHUB_ENV + else + echo "tag=default" >> $GITHUB_ENV + fi + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build Docker image + uses: docker/build-push-action@v5 + with: + context: . + tags: outpost-api-service:${{ env.tag }} + file: Dockerfile.production + push: false + load: true + build-args: | + NODE_ENV=development + FORCE_SSL=false + + - name: Run the image + env: + DB_URI: mongodb://outpost:password@mongo:27017/outpost_api_development + run: | + docker run --rm -d \ + -e DEBUG_LEVEL=debug \ + -e DB_URI=$DB_URI \ + --name temp_container \ + --network=outpost-api-test-network \ + outpost-api-service:${{ env.tag }} + docker exec temp_container npm run dummy-data + docker exec temp_container npm run test + docker stop temp_container diff --git a/Dockerfile.production b/Dockerfile.production index 963b36b..3c7914b 100644 --- a/Dockerfile.production +++ b/Dockerfile.production @@ -21,6 +21,7 @@ RUN if [ "${NODE_ENV}" = "development" ] || [ -z "${NODE_ENV}" ]; then \ RUN if [ "${NODE_ENV}" = "production" ]; then \ npm ci --omit=dev && npm cache clean --force; fi +USER outpost-user WORKDIR /app # ---------------------------------------------------------------- @@ -31,7 +32,7 @@ ENV NODE_ENV $NODE_ENV ENV FORCE_SSL $FORCE_SSL COPY --from=build_frontend --chown=outpost-user:outpost-user /tmp/node_modules /app/node_modules -COPY . /app +COPY --chown=outpost-user:outpost-user . /app USER outpost-user EXPOSE 3000 diff --git a/src/db.js b/src/db.js index 1655882..5f30a5e 100644 --- a/src/db.js +++ b/src/db.js @@ -10,6 +10,11 @@ let db module.exports = { connect: async cb => { + if (!uri) { + logger.error(`DB_URI not set`) + return false + } + MongoClient.connect(uri) .then(async client => { // const ping = await client.db().command({ ping: 1 })