Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 41 additions & 8 deletions .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,16 @@ jobs:
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
- name: Enable auto-merge for Dependabot PRs
# if: contains(steps.metadata.outputs.dependency-names, 'my-dependency') && steps.metadata.outputs.update-type == 'version-update:semver-patch'
if: contains(steps.metadata.outputs.dependency-names, 'my-dependency') && steps.metadata.outputs.update-type == 'version-update:semver-patch'
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
docker-build-push:
docker-build-scan-push:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
env:
BASE_IMAGE: abhisheksr01/companieshouse
needs:
- unit-test
- mutation-test
Expand All @@ -182,13 +184,13 @@ jobs:
with:
dry-run: true # Since we are setting dryrun argument the bump-version will always be available until 'current-version' is pushed as release
- name: check-bump-version-output
shell: bash
run: |
echo "previous-version: ${{ steps.bump-version.outputs.previous-version }}"
echo "bump-version: ${{ steps.bump-version.outputs.bump-version }}"
echo "current-version: ${{ steps.bump-version.outputs.current-version }}"
echo "is-version-bumped: ${{ steps.bump-version.outputs.is-version-bumped }}"
echo "is-dryrun-version-bumped: ${{ steps.bump-version.outputs.is-dryrun-version-bumped }}"
shell: bash
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
Expand All @@ -201,7 +203,7 @@ jobs:
id: meta
uses: docker/metadata-action@v5
with:
images: abhisheksr01/companieshouse
images: ${{ env.BASE_IMAGE }}
context: git
tags: |
type=ref,event=pr
Expand All @@ -212,25 +214,56 @@ jobs:
"org.opencontainers.image.url": "https://github.com/abhisheksr01/spring-boot-microservice-best-practices",
"org.opencontainers.image.source": "https://github.com/abhisheksr01/spring-boot-microservice-best-practices",
"org.opencontainers.image.version": ${{ steps.bump-version.outputs.bump-version }},
"org.opencontainers.image.created": "2020-01-10T00:30:00.000Z",
"org.opencontainers.image.created": "$(date +"%Y%m%d%H%M%S")",
"org.opencontainers.image.revision": ${{ github.sha }},
"org.opencontainers.image.licenses": "MIT"
- name: Build and push
- name: Build Image
if: ${{ steps.bump-version.outputs.is-dryrun-version-bumped == 'true' }}
uses: docker/build-push-action@v6
with:
push: ${{ github.event_name != 'pull_request' && steps.bump-version.outputs.is-dryrun-version-bumped == 'true' }} # Only push on main branch & when version is bumped with dryrun. We will create tags and creates separately after proper testing
load: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-to: type=registry,ref=${{ env.BASE_IMAGE }}:cache
cache-from: type=registry,ref=${{ env.BASE_IMAGE }}:cache,mode=max
- name: Scan Image
uses: aquasecurity/[email protected]
with:
versin: 0.66.0
image-ref: ${{ steps.meta.outputs.tags }}
format: 'table'
exit-code: '1'
ignore-unfixed: true
vuln-type: 'os,library'
scanners: 'vuln,secret,misconfig'
- name: Validate Container Image
run: |
docker run -d -p 8080:8080 ${{ steps.meta.outputs.tags }}
sleep 5 # Wait for container to start
HEALTH_STATUS=$(curl -s http://localhost:8080/companieshouse/actuator/health | jq -r '.status')
if [ "$HEALTH_STATUS" != "UP" ]; then
echo "Health check failed. Status: $HEALTH_STATUS"
exit 1
fi
echo "Health check passed. Status: $HEALTH_STATUS"
- name: Re-Build & Push Image
uses: docker/build-push-action@v6
with:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-to: type=registry,ref=${{ env.BASE_IMAGE }}:cache
cache-from: type=registry,ref=${{ env.BASE_IMAGE }}:cache,mode=max
sbom: true
provenance: true

create-release:
if: ${{ needs.docker-build-push.outputs.is-dryrun-version-bumped == 'true' }} # Only release when new version is available
runs-on: ubuntu-latest
permissions:
contents: write # to be able to publish a GitHub release
needs:
- docker-build-push
- docker-build-scan-push
environment:
name: approve-release # Manual Approval to decide if we are ready to push tags and release
steps:
Expand Down
56 changes: 43 additions & 13 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,25 +1,55 @@
# Stage 1: Build the jar
FROM gradle:8.12-jdk21 AS build
# Copy source code into the container and set the ownership to 'gradle' user
FROM gradle:8.14.3-jdk21-jammy AS build

# Update system packages
RUN apt-get update && \
apt-get upgrade -y && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Copy source code and build
COPY --chown=gradle:gradle . /home/gradle/src
WORKDIR /home/gradle/src
RUN gradle build -x test --no-daemon

# Stage 2: Production image
FROM openjdk:21-slim AS production
FROM openjdk:21-slim-bookworm AS production
EXPOSE 8080

# Create a non-root user and group (using 'appuser' as an example)
RUN groupadd -r appgroup && useradd -r -g appgroup -m appuser
# Update system packages and install fixed versions
RUN apt-get update && \

Check failure on line 20 in Dockerfile

View workflow job for this annotation

GitHub Actions / sast-iac-trivy-hadolint

DL3008 warning: Pin versions in apt get install. Instead of `apt-get install <package>` use `apt-get install <package>=<version>`
apt-get upgrade -y && \
apt-get install -y --no-install-recommends \
libc6 \
util-linux \
&& apt-get clean && \
rm -rf /var/lib/apt/lists/*

# Create non-root user with fixed UID/GID
RUN groupadd -r appgroup -g 10001 && \
useradd -r -g appgroup -u 10001 appuser && \
mkdir /app && \
chown 10001:10001 /app

# Copy jar with specific name
COPY --from=build --chown=10001:10001 /home/gradle/src/build/libs/*.jar /app/companieshouse.jar

# Create the /app directory and set permissions
RUN mkdir /app && chown appuser:appgroup /app
WORKDIR /app
USER 10001

# Copy the jar file from the build stage into the production image
COPY --from=build /home/gradle/src/build/libs/*.jar /app/companieshouse-*.jar
# Security-focused Java options
ENV JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom \
-Djava.awt.headless=true \
-Dfile.encoding=UTF-8 \
-XX:+ExitOnOutOfMemoryError \
-XX:+UseContainerSupport \
-XX:MaxRAMPercentage=75.0 \
-Dspring.profiles.active=production \
-Dserver.tomcat.accesslog.enabled=true"

# Change to non-root user
USER appuser
# Add healthcheck
HEALTHCHECK --interval=30s --timeout=3s \
CMD curl -f http://localhost:8080/companieshouse/actuator/health || exit 1

# Set the entrypoint to run the Java application
ENTRYPOINT ["java", "-jar", "/app/companieshouse-*.jar"]
# Use specific jar name in entrypoint
ENTRYPOINT ["java", "-jar", "/app/companieshouse.jar"]
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading