diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..36375fb --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,97 @@ +--- +name: build + +on: [push] + +env: + IMAGE_NAME: cisagov/postfix + PIP_CACHE_DIR: ~/.cache/pip + PRE_COMMIT_CACHE_DIR: ~/.cache/pre-commit + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-python@v1 + with: + python-version: 3.7 + - name: Cache pip test requirements + uses: actions/cache@v1 + with: + path: ${{ env.PIP_CACHE_DIR }} + key: "${{ runner.os }}-pip-test-\ + ${{ hashFiles('**/requirements-test.txt') }}" + restore-keys: | + ${{ runner.os }}-pip-test- + ${{ runner.os }}-pip- + - name: Cache pre-commit hooks + uses: actions/cache@v1 + with: + path: ${{ env.PRE_COMMIT_CACHE_DIR }} + key: "${{ runner.os }}-pre-commit-\ + ${{ hashFiles('**/.pre-commit-config.yaml') }}" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install --upgrade -r requirements-test.txt + - name: Run linters on all files + run: pre-commit run --all-files + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Determine image version + id: get_ver + run: | + echo "##[set-output name=version;]$(./bump_version.sh show)" + - name: Build docker image + run: | + version=$(./bump_version.sh show) + docker build \ + --tag "$IMAGE_NAME" \ + --build-arg GIT_COMMIT=$(git log -1 --format=%H) \ + --build-arg GIT_REMOTE=$(git remote get-url origin) \ + --build-arg VERSION=${{ steps.get_ver.outputs.version }} \ + . + - name: Save docker image artifact + run: | + mkdir dist + version=$(./bump_version.sh show) + docker save $IMAGE_NAME:latest | gzip > dist/image.tar.gz + - name: Upload artifacts + uses: actions/upload-artifact@v1 + with: + name: dist + path: dist + test: + runs-on: ubuntu-latest + needs: [build] + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-python@v1 + with: + python-version: 3.7 + - name: Cache pip test requirements + uses: actions/cache@v1 + with: + path: ${{ env.PIP_CACHE_DIR }} + key: "${{ runner.os }}-pip-test-\ + ${{ hashFiles('**/requirements-test.txt') }}" + restore-keys: | + ${{ runner.os }}-pip-test- + ${{ runner.os }}-pip- + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install --upgrade -r requirements-test.txt + - name: Download docker image artifact + uses: actions/download-artifact@v1 + with: + name: dist + - name: Load docker image + run: docker load < dist/image.tar.gz + - name: Run tests + env: + RELEASE_TAG: ${{ github.event.release.tag_name }} + run: pytest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..67af144 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,53 @@ +--- +name: release + +on: + release: + types: [prereleased, released] + +env: + IMAGE_NAME: cisagov/postfix + DOCKER_PW: ${{ secrets.DOCKER_PW }} + DOCKER_USER: ${{ secrets.DOCKER_USER }} + +jobs: + release: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-python@v1 + with: + python-version: 3.7 + - name: Determine image version + id: get_ver + run: | + echo "##[set-output name=version;]$(./bump_version.sh show)" + - name: Build Docker image + run: | + docker build \ + --tag "$IMAGE_NAME" \ + --build-arg GIT_COMMIT=$(git log -1 --format=%H) \ + --build-arg GIT_REMOTE=$(git remote get-url origin) \ + --build-arg VERSION=${{ steps.get_ver.outputs.version }} \ + . + - name: Tag Docker image + run: | + IFS='.' read -r -a version_array \ + <<< "${{ steps.get_ver.outputs.version }}" + docker login --username "$DOCKER_USER" --password "$DOCKER_PW" + docker tag "$IMAGE_NAME" "${IMAGE_NAME}:latest" + docker tag "$IMAGE_NAME" \ + "${IMAGE_NAME}:${{ steps.get_ver.outputs.version }}" + docker tag "$IMAGE_NAME" \ + "${IMAGE_NAME}:${version_array[0]}.${version_array[1]}" + docker tag "$IMAGE_NAME" "${IMAGE_NAME}:${version_array[0]}" + - name: Publish image to Docker Hub + run: | + IFS='.' read -r -a version_array \ + <<< "${{ steps.get_ver.outputs.version }}" + docker push "${IMAGE_NAME}:latest" + docker push "${IMAGE_NAME}:${{ steps.get_ver.outputs.version }}" + docker push "${IMAGE_NAME}:${version_array[0]}.${version_array[1]}" + docker push "${IMAGE_NAME}:${version_array[0]}" + - name: Publish README.md to Docker Hub + run: ./push_readme.sh diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0d7aee6..7e2cef6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ --- repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v2.2.3 + rev: v2.4.0 hooks: - id: check-executables-have-shebangs - id: check-json @@ -24,13 +24,13 @@ repos: - id: requirements-txt-fixer - id: trailing-whitespace - repo: https://github.com/igorshubovych/markdownlint-cli - rev: v0.17.0 + rev: v0.19.0 hooks: - id: markdownlint args: - --config=.mdl_config.json - repo: https://github.com/adrienverge/yamllint - rev: v1.16.0 + rev: v1.18.0 hooks: - id: yamllint - repo: https://github.com/detailyang/pre-commit-shell @@ -38,18 +38,18 @@ repos: hooks: - id: shell-lint - repo: https://gitlab.com/pycqa/flake8 - rev: 3.7.7 + rev: 3.7.9 hooks: - id: flake8 additional_dependencies: - flake8-docstrings - repo: https://github.com/asottile/pyupgrade - rev: v1.19.0 + rev: v1.25.1 hooks: - id: pyupgrade # Run bandit on "tests" tree with a configuration - repo: https://github.com/PyCQA/bandit - rev: 1.6.1 + rev: 1.6.2 hooks: - id: bandit name: bandit (tests tree) @@ -64,11 +64,11 @@ repos: name: bandit (everything else) exclude: tests - repo: https://github.com/python/black - rev: 19.3b0 + rev: 19.10b0 hooks: - id: black - repo: https://github.com/ansible/ansible-lint.git - rev: v4.1.0a0 + rev: v4.1.1a3 hooks: - id: ansible-lint - repo: https://github.com/antonbabenko/pre-commit-terraform.git diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 864dc22..0000000 --- a/.travis.yml +++ /dev/null @@ -1,55 +0,0 @@ ---- -dist: xenial -language: python -python: 3.7 -services: docker -env: - global: - - IMAGE_NAME=dhsncats/postfix - - DOCKER_USER=felddy - - secure: >- # DOCKER_PW - R8uSOMb+2aZV/bTK8EU3L5sYqNUiVZpS3kBU0XvVW3rnZgdW1QIHwLU2VOAv9kgpw1e - zXaAi3OPPboi3eMWTXGQGYM3prZePlpDk+cVwCZB5sQn4xw692p/VmNgnxrY9NTts0Y - 0qPSW9YdCEza8RLYbxaar8PGaLDdh5GwYBeBK8wrvd51PQa8J1IKDKRKfsbrKLRjHv8 - d8qSNT2yKa8vX63l80ftwHs07IOO2YKaUjtS4DlON+XHbLqXkfgVqQ8VUntW0qjb1M1 - KBGLckD6/qeCqMAPHDvuJY+fT2n+6Q0tDZbyJhYzYDN9eTTBuetIDoEZSU8vpvDslrG - qH8Pu93x4g63DkMl+lfMm6gNjkB8DLxOlHJvdjBHjiiIsSPdUdSxI/Y7GtkchD/Mkdq - JI5PyQSPnMvLAiNrhysGuIkKnD4hfDyR2RyePFw8zLgKj/Hsm71O1oX7I3aJu08xYL5 - EaXRFkeOMzCPamXNcKjpHWxP7UZqGROBe6e7eOKaJSFzpNZPczgHyi3XxoS8NNPIh0q - 4LTxeqHSUuzyEtg8az3meRiR9z+5LGA7mt2YZ7yyTPwizi2X2LVbx9yCtfnfEG/jrqI - tx6GFgOb7a02jEbDNQ5q0qR56IwFRSlw55EdWMo2gnh2PtJ044QaMzr/du2VM6wydAR - n2KsiL8piwAEc= -cache: - pip: true - directories: - - "$HOME/.cache/pre-commit" -install: - - pip install --upgrade --requirement requirements-test.txt - - version=$(./bump_version.sh show) - - docker build - --tag "$IMAGE_NAME" - --build-arg GIT_COMMIT=$(git log -1 --format=%H) - --build-arg GIT_REMOTE=$(git remote get-url origin) - --build-arg VERSION=${version} - . -script: - - pre-commit run --all-files - - pytest --verbose -before_deploy: - - IFS='.' read -r -a version_array <<< "$version" - - docker login --username "$DOCKER_USER" --password "$DOCKER_PW" - - docker tag "$IMAGE_NAME" "${IMAGE_NAME}:latest" - - docker tag "$IMAGE_NAME" "${IMAGE_NAME}:${version}" - - docker tag "$IMAGE_NAME" - "${IMAGE_NAME}:${version_array[0]}.${version_array[1]}" - - docker tag "$IMAGE_NAME" "${IMAGE_NAME}:${version_array[0]}" -deploy: - - provider: script - script: docker push "${IMAGE_NAME}:latest" && - docker push "${IMAGE_NAME}:${version}" && - docker push "${IMAGE_NAME}:${version_array[0]}.${version_array[1]}" && - docker push "${IMAGE_NAME}:${version_array[0]}" && - ./push_readme.sh - on: - tags: true - python: '3.7' diff --git a/Dockerfile b/Dockerfile index 6a82707..b30fb1a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,18 @@ +ARG GIT_COMMIT=unspecified +ARG GIT_REMOTE=unspecified +ARG VERSION=unspecified + FROM debian:buster-slim -MAINTAINER Mark Feldhousen + +ARG GIT_COMMIT +ARG GIT_REMOTE +ARG VERSION + +LABEL git_commit=${GIT_COMMIT} +LABEL git_remote=${GIT_REMOTE} +LABEL maintainer="mark.feldhousen@trio.dhs.gov" +LABEL vendor="Cyber and Infrastructure Security Agency" +LABEL version=${VERSION} RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \ @@ -29,7 +42,7 @@ RUN mv /etc/default/opendkim /etc/default/opendkim.orig RUN mv /etc/default/opendmarc /etc/default/opendmarc.orig COPY ./src/templates ./templates/ -COPY ./src/docker-entrypoint.sh . +COPY ./src/docker-entrypoint.sh ./src/version.txt ./ VOLUME ["/var/log", "/var/spool/postfix"] EXPOSE 25/TCP 587/TCP 993/TCP diff --git a/README.md b/README.md index b4eba11..6b7da37 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,13 @@ # postfix-docker 📮🐳 # -[![Build Status](https://travis-ci.com/cisagov/postfix-docker.svg?branch=develop)](https://travis-ci.com/cisagov/postfix-docker) +[![GitHub Build Status](https://github.com/cisagov/postfix-docker/workflows/build/badge.svg)](https://github.com/cisagov/postfix-docker/actions) +[![Total alerts](https://img.shields.io/lgtm/alerts/g/cisagov/postfix-docker.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/cisagov/postfix-docker/alerts/) +[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/cisagov/postfix-docker.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/cisagov/postfix-docker/context:python) ## Docker Image ## -![MicroBadger Layers](https://img.shields.io/microbadger/layers/dhsncats/postfix.svg) -![MicroBadger Size](https://img.shields.io/microbadger/image-size/dhsncats/postfix.svg) +![MicroBadger Layers](https://img.shields.io/microbadger/layers/cisagov/postfix.svg) +![MicroBadger Size](https://img.shields.io/microbadger/image-size/cisagov/postfix.svg) Creates a Docker container with an installation of the [postfix](http://postfix.org) MTA. Additionally it has an IMAP @@ -16,11 +18,11 @@ of sent email. All email is BCC'd to the `mailarchive` account. ### Install ### -Pull `dhsncats/postfix` from the Docker repository: +Pull `cisagov/postfix` from the Docker repository: - docker pull dhsncats/postfix + docker pull cisagov/postfix -Or build `dhsncats/postfix` from source: +Or build `cisagov/postfix` from source: git clone https://github.com/cisagov/postfix-docker.git cd postfix-docker diff --git a/docker-compose.yml b/docker-compose.yml index 1f0d962..5a0cf56 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,9 +13,11 @@ secrets: services: postfix: build: + # VERSION must be specified on the command line: + # e.g., --build-arg VERSION=0.0.1 context: . dockerfile: Dockerfile - image: dhsncats/postfix + image: cisagov/postfix init: true restart: always environment: diff --git a/src/version.txt b/src/version.txt index 3b93d0b..27fdca4 100644 --- a/src/version.txt +++ b/src/version.txt @@ -1 +1 @@ -__version__ = "0.0.2" +__version__ = "0.0.3" diff --git a/tests/container_test.py b/tests/container_test.py index 732fc97..e7a0cec 100644 --- a/tests/container_test.py +++ b/tests/container_test.py @@ -3,21 +3,24 @@ from email.message import EmailMessage from imaplib import IMAP4_SSL +import os import smtplib import time import pytest +ARCHIVE_PW = "foobar" +ARCHIVE_USER = "mailarchive" +DOMAIN = "example.com" +IMAP_PORT = 1993 MESSAGE = """ This is a test message sent during the unit tests. """ -DOMAIN = "example.com" -ARCHIVE_USER = "mailarchive" -ARCHIVE_PW = "foobar" -TEST_SEND_USER = "testsender1" -TEST_SEND_PW = "lemmy is god" -IMAP_PORT = 1993 READY_MESSAGE = "daemon started" +RELEASE_TAG = os.getenv("RELEASE_TAG") +TEST_SEND_PW = "lemmy is god" +TEST_SEND_USER = "testsender1" +VERSION_FILE = "src/version.txt" def test_container_count(dockerc): @@ -149,3 +152,28 @@ def test_imap_messages_cleared(username, password): message_count = int(data[0]) print(f"inbox message count: {message_count}") assert message_count == 0, "Expected the inbox to be empty" + + +@pytest.mark.skipif( + RELEASE_TAG in [None, ""], reason="this is not a release (RELEASE_TAG not set)" +) +def test_release_version(): + """Verify that release tag version agrees with the module version.""" + pkg_vars = {} + with open(VERSION_FILE) as f: + exec(f.read(), pkg_vars) # nosec + project_version = pkg_vars["__version__"] + assert ( + RELEASE_TAG == f"v{project_version}" + ), "RELEASE_TAG does not match the project version" + + +def test_container_version_label_matches(main_container): + """Verify the container version label is the correct version.""" + pkg_vars = {} + with open(VERSION_FILE) as f: + exec(f.read(), pkg_vars) # nosec + project_version = pkg_vars["__version__"] + assert ( + main_container.labels["version"] == project_version + ), "Dockerfile version label does not match project version"