From 94c3f9197d209b6b94062a6c8a4fb9df72ab3f91 Mon Sep 17 00:00:00 2001 From: cytopia Date: Sun, 14 Mar 2021 13:18:49 +0100 Subject: [PATCH] Release v0.1 --- .github/workflows/build.yml | 166 ++++++++++++++++++++++++++++++ .github/workflows/lint.yml | 40 ++++++++ .github/workflows/nightly.yml | 185 ++++++++++++++++++++++++++++++++++ Dockerfile | 53 ++++++++++ LICENSE | 21 ++++ Makefile | 147 +++++++++++++++++++++++++++ 6 files changed, 612 insertions(+) create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/nightly.yml create mode 100644 Dockerfile create mode 100644 LICENSE create mode 100644 Makefile diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..47a6366 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,166 @@ +--- + +# ------------------------------------------------------------------------------------------------- +# Job Name +# ------------------------------------------------------------------------------------------------- +name: build + + +# ------------------------------------------------------------------------------------------------- +# When to run +# ------------------------------------------------------------------------------------------------- +on: + # Runs on Pull Requests + pull_request: + # Runs on Push + push: + + +# ------------------------------------------------------------------------------------------------- +# What to run +# ------------------------------------------------------------------------------------------------- +jobs: + build: + name: "[ ${{ matrix.version }} ]" + runs-on: ubuntu-latest + strategy: + fail-fast: False + matrix: + version: + - 'latest' + steps: + + # ------------------------------------------------------------ + # Checkout repository + # ------------------------------------------------------------ + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set variables + id: vars + run: | + # Retrieve git info (tags, etc) + git fetch --all + + # Branch, Tag or Commit + GIT_TYPE="$( \ + curl -sS https://raw.githubusercontent.com/cytopia/git-tools/master/git-info.sh \ + | sh \ + | grep '^GIT_TYPE' \ + | sed 's|.*=||g' \ + )" + # Branch name, Tag name or Commit Hash + GIT_SLUG="$( \ + curl -sS https://raw.githubusercontent.com/cytopia/git-tools/master/git-info.sh \ + | sh \ + | grep '^GIT_NAME' \ + | sed 's|.*=||g' \ + )" + # Docker Tag + if [ "${GIT_TYPE}" = "BRANCH" ] && [ "${GIT_SLUG}" = "master" ]; then + DOCKER_TAG="${VERSION}" + else + DOCKER_TAG="${VERSION}-${GIT_SLUG}" + fi + + # Output + echo "GIT_TYPE=${GIT_TYPE}" + echo "GIT_SLUG=${GIT_SLUG}" + echo "DOCKER_TAG=${DOCKER_TAG}" + + # Export variable + # https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#environment-files + echo "GIT_TYPE=${GIT_TYPE}" >> ${GITHUB_ENV} + echo "GIT_SLUG=${GIT_SLUG}" >> ${GITHUB_ENV} + echo "DOCKER_TAG=${DOCKER_TAG}" >> ${GITHUB_ENV} + env: + VERSION: ${{ matrix.version }} + + + # ------------------------------------------------------------ + # Build + # ------------------------------------------------------------ + - name: Build + run: | + retry() { + for n in $(seq ${RETRIES}); do + echo "[${n}/${RETRIES}] ${*}"; + if eval "${*}"; then + echo "[SUCC] ${n}/${RETRIES}"; + return 0; + fi; + sleep 2; + echo "[FAIL] ${n}/${RETRIES}"; + done; + return 1; + } + retry make build VERSION=${VERSION} + env: + VERSION: ${{ matrix.version }} + RETRIES: 20 + + - name: Test + run: | + retry() { + for n in $(seq ${RETRIES}); do + echo "[${n}/${RETRIES}] ${*}"; + if eval "${*}"; then + echo "[SUCC] ${n}/${RETRIES}"; + return 0; + fi; + sleep 2; + echo "[FAIL] ${n}/${RETRIES}"; + done; + return 1; + } + retry make test VERSION=${VERSION} + git diff --quiet || { echo "Build Changes"; git diff; git status; false; } + env: + VERSION: ${{ matrix.version }} + RETRIES: 20 + + + # ------------------------------------------------------------ + # Deploy + # ------------------------------------------------------------ + - name: Publish images (only repo owner) + run: | + retry() { + for n in $(seq ${RETRIES}); do + echo "[${n}/${RETRIES}] ${*}"; + if eval "${*}"; then + echo "[SUCC] ${n}/${RETRIES}"; + return 0; + fi; + sleep ${PAUSE}; + echo "[FAIL] ${n}/${RETRIES}"; + done; + return 1; + } + + # Output + echo "GIT_TYPE=${GIT_TYPE}" + echo "GIT_SLUG=${GIT_SLUG}" + echo "DOCKER_TAG=${DOCKER_TAG}" + + # Tag image + retry make tag TAG=${DOCKER_TAG} + docker images + + # Login and Push + retry make login USER=${{ secrets.DOCKERHUB_USERNAME }} PASS=${{ secrets.DOCKERHUB_PASSWORD }} + retry make push TAG=${DOCKER_TAG} + env: + RETRIES: 20 + PAUSE: 10 + # https://help.github.com/en/github/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions#functions + if: github.event.pull_request.base.repo.id == github.event.pull_request.head.repo.id + && ( + (github.event_name == 'schedule' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/'))) + || + (github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/'))) + || + (github.event_name == 'push' && startsWith(github.ref, 'refs/heads/release-')) + ) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..ae19b94 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,40 @@ +--- + +# ------------------------------------------------------------------------------------------------- +# Job Name +# ------------------------------------------------------------------------------------------------- +name: lint + + +# ------------------------------------------------------------------------------------------------- +# When to run +# ------------------------------------------------------------------------------------------------- +on: + # Runs on Pull Requests + pull_request: + + +# ------------------------------------------------------------------------------------------------- +# What to run +# ------------------------------------------------------------------------------------------------- +jobs: + lint: + name: "Lint" + runs-on: ubuntu-latest + steps: + # ------------------------------------------------------------ + # Setup repository + # ------------------------------------------------------------ + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + # ------------------------------------------------------------ + # Lint repository + # ------------------------------------------------------------ + - name: Lint + id: vars + run: | + make lint + diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 0000000..73c59c0 --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,185 @@ +--- + +# ------------------------------------------------------------------------------------------------- +# Job Name +# ------------------------------------------------------------------------------------------------- +name: nightly + + +# ------------------------------------------------------------------------------------------------- +# When to run +# ------------------------------------------------------------------------------------------------- +on: + # Runs daily + schedule: + - cron: '0 0 * * *' + + +# ------------------------------------------------------------------------------------------------- +# What to run +# ------------------------------------------------------------------------------------------------- +jobs: + nightly: + name: "[ ${{ matrix.version }} ] (ref: ${{ matrix.refs }})" + runs-on: ubuntu-latest + strategy: + fail-fast: False + matrix: + version: + - '0.1.0' + - '0.1.1' + - '0.2.0' + - '0.3.0' + - '0.4.0' + - '0.4.5' + - '0.5.0' + - '0.6.0' + - '0.7.0' + - '0.8.0' + - '0.8.1' + - '0.8.2' + - '0.9.0' + - '0.9.1' + - '0.10.0' + - '0.10.1' + - 'latest' + refs: + - 'master' + - '0.24' + steps: + + # ------------------------------------------------------------ + # Checkout repository + # ------------------------------------------------------------ + - name: Checkout repository + uses: actions/checkout@v2 + with: + fetch-depth: 0 + ref: ${{ matrix.refs }} + + - name: Set variables + id: vars + run: | + # Retrieve git info (tags, etc) + git fetch --all + + # Branch, Tag or Commit + GIT_TYPE="$( \ + curl -sS https://raw.githubusercontent.com/cytopia/git-tools/master/git-info.sh \ + | sh \ + | grep '^GIT_TYPE' \ + | sed 's|.*=||g' \ + )" + # Branch name, Tag name or Commit Hash + GIT_SLUG="$( \ + curl -sS https://raw.githubusercontent.com/cytopia/git-tools/master/git-info.sh \ + | sh \ + | grep '^GIT_NAME' \ + | sed 's|.*=||g' \ + )" + # Docker Tag + if [ "${GIT_TYPE}" = "BRANCH" ] && [ "${GIT_SLUG}" = "master" ]; then + DOCKER_TAG="${VERSION}" + else + DOCKER_TAG="${VERSION}-${GIT_SLUG}" + fi + + # Output + echo "GIT_TYPE=${GIT_TYPE}" + echo "GIT_SLUG=${GIT_SLUG}" + echo "DOCKER_TAG=${DOCKER_TAG}" + + # Export variable + # https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#environment-files + echo "GIT_TYPE=${GIT_TYPE}" >> ${GITHUB_ENV} + echo "GIT_SLUG=${GIT_SLUG}" >> ${GITHUB_ENV} + echo "DOCKER_TAG=${DOCKER_TAG}" >> ${GITHUB_ENV} + env: + VERSION: ${{ matrix.version }} + + + # ------------------------------------------------------------ + # Build + # ------------------------------------------------------------ + - name: Build + run: | + retry() { + for n in $(seq ${RETRIES}); do + echo "[${n}/${RETRIES}] ${*}"; + if eval "${*}"; then + echo "[SUCC] ${n}/${RETRIES}"; + return 0; + fi; + sleep 2; + echo "[FAIL] ${n}/${RETRIES}"; + done; + return 1; + } + retry make build VERSION=${VERSION} + env: + VERSION: ${{ matrix.version }} + RETRIES: 20 + + - name: Test + run: | + retry() { + for n in $(seq ${RETRIES}); do + echo "[${n}/${RETRIES}] ${*}"; + if eval "${*}"; then + echo "[SUCC] ${n}/${RETRIES}"; + return 0; + fi; + sleep 2; + echo "[FAIL] ${n}/${RETRIES}"; + done; + return 1; + } + retry make test VERSION=${VERSION} + git diff --quiet || { echo "Build Changes"; git diff; git status; false; } + env: + VERSION: ${{ matrix.version }} + RETRIES: 20 + + + # ------------------------------------------------------------ + # Deploy + # ------------------------------------------------------------ + - name: Publish images (only repo owner) + run: | + retry() { + for n in $(seq ${RETRIES}); do + echo "[${n}/${RETRIES}] ${*}"; + if eval "${*}"; then + echo "[SUCC] ${n}/${RETRIES}"; + return 0; + fi; + sleep ${PAUSE}; + echo "[FAIL] ${n}/${RETRIES}"; + done; + return 1; + } + + # Output + echo "GIT_TYPE=${GIT_TYPE}" + echo "GIT_SLUG=${GIT_SLUG}" + echo "DOCKER_TAG=${DOCKER_TAG}" + + # Tag image + retry make tag TAG=${DOCKER_TAG} + docker images + + # Login and Push + retry make login USER=${{ secrets.DOCKERHUB_USERNAME }} PASS=${{ secrets.DOCKERHUB_PASSWORD }} + retry make push TAG=${DOCKER_TAG} + env: + RETRIES: 20 + PAUSE: 10 + # https://help.github.com/en/github/automating-your-workflow-with-github-actions/contexts-and-expression-syntax-for-github-actions#functions + if: github.event.pull_request.base.repo.id == github.event.pull_request.head.repo.id + && ( + (github.event_name == 'schedule' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/'))) + || + (github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/'))) + || + (github.event_name == 'push' && startsWith(github.ref, 'refs/heads/release-')) + ) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1223bb2 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,53 @@ +FROM python:3.8-slim-buster as builder + +RUN set -eux \ + && apt update \ + && apt install -y \ + bc \ + gcc + +ARG VERSION=latest +RUN set -eux \ + && if [ "${VERSION}" = "latest" ]; then \ + pip3 install --no-cache-dir --no-compile bandit; \ + else \ + pip3 install --no-cache-dir --no-compile "bandit>=${VERSION},<$(echo "${VERSION}+0.1" | bc)"; \ + fi \ + \ + && bandit --version | grep -E '^bandit\s[0-9]+' \ + \ + && pip3 install --no-cache-dir \ + lxml \ + \ + && find /usr/lib/ -name '__pycache__' -print0 | xargs -0 -n1 rm -rf \ + && find /usr/lib/ -name '*.pyc' -print0 | xargs -0 -n1 rm -rf + +RUN set -eux && ls -lap /usr/lib +RUN set -eux && ls -lap /usr/local/lib + +FROM alpine:3 as production +# https://github.com/opencontainers/image-spec/blob/master/annotations.md +#LABEL "org.opencontainers.image.created"="" +#LABEL "org.opencontainers.image.version"="" +#LABEL "org.opencontainers.image.revision"="" +LABEL "maintainer"="cytopia " +LABEL "org.opencontainers.image.authors"="cytopia " +LABEL "org.opencontainers.image.vendor"="cytopia" +LABEL "org.opencontainers.image.licenses"="MIT" +LABEL "org.opencontainers.image.url"="https://github.com/cytopia/docker-bandit" +LABEL "org.opencontainers.image.documentation"="https://github.com/cytopia/docker-bandit" +LABEL "org.opencontainers.image.source"="https://github.com/cytopia/docker-bandit" +LABEL "org.opencontainers.image.ref.name"="bandit ${VERSION}" +LABEL "org.opencontainers.image.title"="bandit ${VERSION}" +LABEL "org.opencontainers.image.description"="bandit ${VERSION}" + +RUN set -eux \ + && apk add --no-cache python3 \ + && ln -sf /usr/bin/python3 /usr/bin/python \ + && ln -sf /usr/bin/python3 /usr/local/bin/python \ + && find /usr/lib/ -name '__pycache__' -print0 | xargs -0 -n1 rm -rf \ + && find /usr/lib/ -name '*.pyc' -print0 | xargs -0 -n1 rm -rf +COPY --from=builder /usr/local/lib/python3.8/site-packages/ /usr/lib/python3.8/site-packages/ +COPY --from=builder /usr/local/bin/bandit /usr/bin/bandit +WORKDIR /data +ENTRYPOINT ["bandit"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c8a6e85 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 cytopia + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..1a6d861 --- /dev/null +++ b/Makefile @@ -0,0 +1,147 @@ +ifneq (,) +.error This Makefile requires GNU Make. +endif + +.PHONY: build rebuild lint test _test-version tag pull login push enter + +CURRENT_DIR = $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) + +DIR = . +FILE = Dockerfile +IMAGE = cytopia/bandit +TAG = latest +VERSION = latest +NO_CACHE = + + +# -------------------------------------------------------------------------------------------------- +# Default Target +# -------------------------------------------------------------------------------------------------- +help: + @echo "lint Lint project files and repository" + @echo "build [VERSION=...] Build bandit docker image" + @echo "rebuild [VERSION=...] Build bandit docker image without cache" + @echo "test [VERSION=...] Test built bandit docker image" + @echo "tag TAG=... Retag Docker image" + @echo "login USER=... PASS=... Login to Docker hub" + @echo "push [TAG=...] Push Docker image to Docker hub" + + +# -------------------------------------------------------------------------------------------------- +# Lint Targets +# -------------------------------------------------------------------------------------------------- +lint: lint-workflow +lint: lint-files + +.PHONY: lint-workflow +lint-workflow: + @echo "################################################################################" + @echo "# Lint Workflow" + @echo "################################################################################" + @\ + GIT_CURR_MAJOR="$$( git tag | sort -V | tail -1 | sed 's|\.[0-9]*$$||g' )"; \ + GIT_CURR_MINOR="$$( git tag | sort -V | tail -1 | sed 's|^[0-9]*\.||g' )"; \ + GIT_NEXT_TAG="$${GIT_CURR_MAJOR}.$$(( GIT_CURR_MINOR + 1 ))"; \ + if ! grep 'refs:' -A 100 .github/workflows/nightly.yml \ + | grep " - '$${GIT_NEXT_TAG}'" >/dev/null; then \ + echo "[ERR] New Tag required in .github/workflows/nightly.yml: $${GIT_NEXT_TAG}"; \ + exit 1; \ + else \ + echo "[OK] Git Tag present in .github/workflows/nightly.yml: $${GIT_NEXT_TAG}"; \ + fi + @echo + +.PHONY: lint-files +lint-files: + @echo "################################################################################" + @echo "# Lint Files" + @echo "################################################################################" + @docker run --rm -v $(PWD):/data cytopia/file-lint file-cr --text --ignore '.git/,.github/,tests/' --path . + @docker run --rm -v $(PWD):/data cytopia/file-lint file-crlf --text --ignore '.git/,.github/,tests/' --path . + @docker run --rm -v $(PWD):/data cytopia/file-lint file-trailing-single-newline --text --ignore '.git/,.github/,tests/' --path . + @docker run --rm -v $(PWD):/data cytopia/file-lint file-trailing-space --text --ignore '.git/,.github/,tests/' --path . + @docker run --rm -v $(PWD):/data cytopia/file-lint file-utf8 --text --ignore '.git/,.github/,tests/' --path . + @docker run --rm -v $(PWD):/data cytopia/file-lint file-utf8-bom --text --ignore '.git/,.github/,tests/' --path . + @echo + + +# -------------------------------------------------------------------------------------------------- +# Build Targets +# -------------------------------------------------------------------------------------------------- +build: + docker build $(NO_CACHE) \ + --label "org.opencontainers.image.created"="$$(date --rfc-3339=s)" \ + --label "org.opencontainers.image.revision"="$$(git rev-parse HEAD)" \ + --label "org.opencontainers.image.version"="${VERSION}" \ + --build-arg VERSION=$(VERSION) \ + -t $(IMAGE) \ + -f $(DIR)/$(FILE) $(DIR) + +rebuild: NO_CACHE=--no-cache +rebuild: pull-base-image +rebuild: build + + +# -------------------------------------------------------------------------------------------------- +# Test Targets +# -------------------------------------------------------------------------------------------------- +test: + @$(MAKE) --no-print-directory _test-version + +_test-version: + @echo "------------------------------------------------------------" + @echo "- Testing correct version" + @echo "------------------------------------------------------------" + @if [ "$(VERSION)" = "latest" ]; then \ + echo "Fetching latest version from GitHub"; \ + LATEST="$$( \ + curl -Ss https://github.com/PyCQA/bandit/releases \ + | tac \ + | tac \ + | grep -Eo 'archive/v[.0-9]+\.zip' \ + | grep -Eo '[.0-9]+[0-9]' \ + | sort -V \ + | tail -1 \ + )"; \ + echo "Testing for latest: $${LATEST}"; \ + if ! docker run --rm $(IMAGE) --version | grep -E "^bandit $${LATEST}"; then \ + echo "Failed"; \ + exit 1; \ + fi; \ + else \ + echo "Testing for version: $(VERSION)"; \ + if ! docker run --rm $(IMAGE) --version | grep -E "^bandit $(VERSION)"; then \ + echo "Failed"; \ + exit 1; \ + fi; \ + fi; \ + echo "Success"; + + +# ------------------------------------------------------------------------------------------------- +# Deploy Targets +# ------------------------------------------------------------------------------------------------- +tag: + docker tag $(IMAGE) $(IMAGE):$(TAG) + +login: + yes | docker login --username $(USER) --password $(PASS) + +push: + docker push $(IMAGE):$(TAG) + + +# -------------------------------------------------------------------------------------------------- +# Helper Targets +# -------------------------------------------------------------------------------------------------- +pull-base-image: + @grep -E '^\s*FROM' Dockerfile-0.11 \ + | sed -e 's/^FROM//g' -e 's/[[:space:]]*as[[:space:]]*.*$$//g' \ + | xargs -n1 docker pull; + @grep -E '^\s*FROM' Dockerfile-0.12 \ + | sed -e 's/^FROM//g' -e 's/[[:space:]]*as[[:space:]]*.*$$//g' \ + | xargs -n1 docker pull; + +enter: + docker run --rm --name $(subst /,-,$(IMAGE)) -it --entrypoint=/bin/sh $(ARG) $(IMAGE):$(VERSION) +