diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..e9ff2bac --- /dev/null +++ b/.dockerignore @@ -0,0 +1,27 @@ +# Files to exclude from COPY and ADD commands when +# building a docker image from this directory + +# Exclude Docker build related files +Dockerfile +.dockerignore + +# Exclude the git directory and gitignore file +.git +.gitignore + +# Skip any existing logs +log/* + +# Skip LICENSE, README, etc. +LICENSE +*.md + +# Skip pipenv/virtualenv related things +.envrc +.venv + +# Skip ansible-container stuff +ansible* +container.yml +meta.yml +requirements.yml diff --git a/.travis.yml b/.travis.yml index a1a290a0..9b5500d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,29 @@ +sudo: required language: python -python: - - "3.6" +python: "3.6" +services: docker +env: + global: + - TESTER_IMAGE_NAME=atst-tester + - PROD_IMAGE_NAME=atst-prod + before_install: - - pip install pipenv - - pipenv install --dev --skip-lock - - gem install sass - - npm install + - docker login -u $ATAT_DOCKER_REGISTRY_USERNAME -p $ATAT_DOCKER_REGISTRY_PASSWORD $ATAT_DOCKER_REGISTRY_URL + - docker build --tag "${TESTER_IMAGE_NAME}" . -f docker/tester/Dockerfile + script: - - python -m pytest + - docker run "${TESTER_IMAGE_NAME}" + +before_deploy: + - docker build --tag "${PROD_IMAGE_NAME}" . -f docker/prod/Dockerfile + - git_sha="$(git rev-parse --short HEAD)" + - remote_image_name="${ATAT_DOCKER_REGISTRY_URL}/${PROD_IMAGE_NAME}:${git_sha}" + - docker tag "${PROD_IMAGE_NAME}" "${remote_image_name}" + - docker images + - docker push "${remote_image_name}" + +deploy: + provider: script + script: echo "** Image push only for now... stay tuned! **" + on: + branch: master diff --git a/Pipfile b/Pipfile index acc32a92..91730759 100644 --- a/Pipfile +++ b/Pipfile @@ -12,6 +12,7 @@ pendulum = "*" redis = "*" [dev-packages] +bandit = "*" pytest = "==3.6.0" pytest-tornado = "==0.5.0" ipython = "*" diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile new file mode 100644 index 00000000..ea4bdbcc --- /dev/null +++ b/docker/prod/Dockerfile @@ -0,0 +1,46 @@ +FROM python:3.6.5-alpine + +### Very low chance of changing +############################### +# Overridable default config +ARG APP_USER=atst +ARG APP_GROUP=atat +ARG APP_DIR=/opt/atat/atst +ARG APP_PORT=8000 +ARG SITE_PACKAGES_DIR=/usr/local/lib/python3.6/site-packages + +ENV APP_USER "${APP_USER}" +ENV APP_GROUP "${APP_GROUP}" +ENV APP_DIR "${APP_DIR}" +ENV SKIP_PIPENV true + +# Set port to open +EXPOSE "${APP_PORT}" + +# Use dumb-init for proper signal handling +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Default command is to launch the server +CMD ["bash", "-c", "${APP_DIR}/script/server"] + +### Items that will change almost every build +############################################# +# Copy installed python packages from the tester image +COPY --from=atst-tester:latest "${SITE_PACKAGES_DIR}" "${SITE_PACKAGES_DIR}" + +# Copy the app directory contents from the tester image (includes node modules) +COPY --from=atst-tester:latest "${APP_DIR}" "${APP_DIR}" + +# Set working dir +WORKDIR ${APP_DIR} + +# Add required system packages and app user +RUN set -x ; \ + script/alpine_setup "${APP_USER}" "${APP_GROUP}" + +# Update file ownership +RUN set -x ; \ + for subdir in $(find . -type d -maxdepth 1 | grep -Ee '.[^/]' | grep -Fve 'node_modules'); do chown atst:atat -R ${subdir}; done + +# Run as the unprivileged APP user +USER "${APP_USER}" diff --git a/docker/tester/Dockerfile b/docker/tester/Dockerfile new file mode 100644 index 00000000..30c6cc11 --- /dev/null +++ b/docker/tester/Dockerfile @@ -0,0 +1,40 @@ +FROM registry.atat.codes:443/atat-app-builder:latest + +### Very low chance of changing +############################### +ARG APP_USER=atst +ARG APP_GROUP=atat +ARG APP_DIR=/opt/atat/atst +ARG CIBUILD=true + +ENV APP_DIR "${APP_DIR}" +ENV SKIP_PIPENV true + +# Use dumb-init for proper signal handling +ENTRYPOINT ["/usr/bin/dumb-init", "--"] + +# Default command is to run all the tests +CMD ["bash", "-c", "${APP_DIR}/script/cibuild"] + +# Create application directory +RUN set -x ; \ + mkdir -p ${APP_DIR} + +# Set working dir +WORKDIR ${APP_DIR} + +# Copy over alpine setup script +COPY script/alpine_setup ./script/ + +# Add required system packages and app user +RUN set -x ; \ + script/alpine_setup "${APP_USER}" "${APP_GROUP}" + +### Items that will change almost every build +############################################# +# Copy over the rest of the app source +COPY . . + +# Install app dependencies +RUN set -x ; \ + script/setup diff --git a/script/alpine_setup b/script/alpine_setup new file mode 100755 index 00000000..c029d19b --- /dev/null +++ b/script/alpine_setup @@ -0,0 +1,22 @@ +#!/bin/sh + +# script/alpine_setup: Adds all the system packages, directors, users, etc. +# required to run the application on Alpine + +# If a command fails, exit the script +set -e + +# Ensure we are in the app root directory (not the /script directory) +cd "$(dirname "${0}")/.." + +APP_USER=${1} +APP_GROUP=${2} + +apk update +apk upgrade + +apk add bash +apk add dumb-init + +addgroup -g 8000 -S "${APP_GROUP}" +adduser -u 8010 -D -S -G "${APP_GROUP}" "${APP_USER}" diff --git a/script/bootstrap b/script/bootstrap index 922e23e3..034b2974 100755 --- a/script/bootstrap +++ b/script/bootstrap @@ -28,5 +28,9 @@ pipenv install ${PIPENV_INSTALL_FLAGS} # Install uswds node module and dependencies npm install +# Relink uswds fonts into the /static directory +rm -f ./static/fonts +ln -s ../node_modules/uswds/src/fonts ./static/fonts + # Precompile assets for deployment ${WEBASSETS_CMD} -m atst.assets build diff --git a/script/cibuild b/script/cibuild new file mode 100755 index 00000000..c9fd2975 --- /dev/null +++ b/script/cibuild @@ -0,0 +1,16 @@ +#!/bin/bash + +# script/cibuild: Run CI related checks and tests + +# If a command fails, exit the script +set -e + +# Ensure we are in the app root directory (not the /script directory) +cd "$(dirname "${0}")/.." + +# Run lint/style checks and unit tests +script/test + +# Run static code analysis security checks +# (excluding the tests and node_modules subdirs) +bandit -r . -x node_modules,tests diff --git a/script/setup b/script/setup index cb3389c3..e96c12df 100755 --- a/script/setup +++ b/script/setup @@ -23,7 +23,3 @@ fi # Install application dependencies script/bootstrap - -# Symlink uswds fonts into the /static directory -rm -f ./static/fonts -ln -s ../node_modules/uswds/src/fonts ./static/fonts