diff --git a/Makefile b/Makefile
index 3647b1e5..aa159b18 100644
--- a/Makefile
+++ b/Makefile
@@ -42,8 +42,8 @@ build: .env
 
 .PHONY: lint
 lint: .env
-	docker-compose -f ./docker-compose.lint.yaml build \
-		--build-arg userid=${CTMS_UID} --build-arg groupid=${CTMS_GID}
+	docker-compose -f ./docker-compose.yaml -f ./tests/docker-compose.lint.yaml build \
+		--build-arg userid=${CTMS_UID} --build-arg groupid=${CTMS_GID} lint
 
 .PHONY: db-only
 db-only: .env
diff --git a/docker/Dockerfile b/docker/Dockerfile
index cf272f5a..17e48ed4 100644
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -78,14 +78,15 @@ ENTRYPOINT ["/docker-entrypoint.sh"]
 CMD uvicorn ctms.app:app --reload --host=0.0.0.0 --port=$PORT
 
 
-# 'lint' stage runs black and isort
+# 'lint' stage runs similar checks to pre-commit / scripts/lint.sh
 # running in check mode means build will fail if any linting errors occur
 FROM development AS lint
-RUN isort --settings-path ./pyproject.toml --recursive --check-only
-RUN black --config ./pyproject.toml --check ctms tests
-RUN mypy --no-strict-optional --ignore-missing-imports ctms
 RUN bandit -lll --recursive ctms --exclude "ctms/poetry.lock,ctms/.venv,ctms/.mypy,ctms/build"
-CMD ["tail", "-f", "/dev/null"]
+RUN mypy ctms
+RUN black --config ./pyproject.toml --check ctms tests
+RUN isort --recursive --settings-path ./pyproject.toml --check-only ctms
+RUN pylint ctms tests/unit
+CMD ./scripts/lint.sh
 
 
 # 'test' stage runs our unit tests with pytest and
diff --git a/scripts/lint.sh b/scripts/lint.sh
index 335c00bb..949681ee 100755
--- a/scripts/lint.sh
+++ b/scripts/lint.sh
@@ -4,12 +4,16 @@ set -e
 
 CURRENT_DIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
 BASE_DIR="$(dirname "$CURRENT_DIR")"
+HAS_GIT="$(command -v git || echo '')"
+echo $HAS_GIT
 
 bandit -lll --recursive "${BASE_DIR}" --exclude "${BASE_DIR}/poetry.lock,${BASE_DIR}/.venv,${BASE_DIR}/.mypy,${BASE_DIR}/build"
 
-# Scan only files checked into the repo, omit poetry.lock
-SECRETS_TO_SCAN=`git ls-tree --full-tree -r --name-only HEAD | grep -v poetry.lock`
-detect-secrets-hook $SECRETS_TO_SCAN --baseline .secrets.baseline
+if [ -n "$HAS_GIT" ]; then
+    # Scan only files checked into the repo, omit poetry.lock
+    SECRETS_TO_SCAN=`git ls-tree --full-tree -r --name-only HEAD | grep -v poetry.lock`
+    detect-secrets-hook $SECRETS_TO_SCAN --baseline .secrets.baseline
+fi
 
 mypy "${BASE_DIR}"
 black --config "${BASE_DIR}/pyproject.toml" "${BASE_DIR}"
diff --git a/docker-compose.lint.yaml b/tests/docker-compose.lint.yaml
similarity index 100%
rename from docker-compose.lint.yaml
rename to tests/docker-compose.lint.yaml