Skip to content

Commit 3b7d98c

Browse files
Initial commit
0 parents  commit 3b7d98c

11 files changed

Lines changed: 454 additions & 0 deletions

.dive-ci

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
rules:
2+
# If the efficiency is measured below X%, mark as failed.
3+
# Expressed as a ratio between 0-1.
4+
lowestEfficiency: 0.95
5+
6+
# If the amount of wasted space is at least X or larger than X, mark as failed.
7+
# Expressed in B, KB, MB, and GB.
8+
highestWastedBytes: 20MB
9+
10+
# If the amount of wasted space makes up for X% or more of the image, mark as failed.
11+
# Note: the base image layer is NOT included in the total image size.
12+
# Expressed as a ratio between 0-1; fails if the threshold is met or crossed.
13+
highestUserWastedPercent: 0.20

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
build
3+
.env

Containerfile

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
ARG UBUNTU_VERSION=24.04
2+
3+
FROM docker.io/library/ubuntu:$UBUNTU_VERSION as base
4+
5+
ARG APP_UID=1000
6+
ARG APP_HOME=/home/appuser
7+
8+
# Setup the non-root user
9+
RUN userdel --remove ubuntu \
10+
&& useradd \
11+
--no-log-init \
12+
--uid $APP_UID \
13+
--home-dir ${APP_HOME} \
14+
--create-home \
15+
--user-group \
16+
appuser && \
17+
chown -R appuser:appuser ${APP_HOME}
18+
19+
# Update and upgrade the system
20+
RUN apt-get update \
21+
&& apt-get upgrade -y \
22+
&& apt-get clean \
23+
&& rm -rf /var/lib/apt/lists/* \
24+
&& apt-get autoremove -y \
25+
&& apt-get autoclean -y
26+
27+
FROM base as runtime
28+
29+
USER ${APP_UID}
30+
WORKDIR ${APP_HOME}
31+
32+
CMD ["/bin/bash -c 'while true; do sleep 1; done'"]

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 Deer Hide
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Deerhide / Template for Container Image
2+
3+
## Pre-requisites
4+
5+
### Install `docker`
6+
[See Docker documentation](https://docs.docker.com/get-docker/)
7+
8+
### Install tools
9+
10+
```bash
11+
./scripts/install_tools.sh
12+
```
13+
14+
## How to build the container image
15+
16+
### Update `manifest.yaml`
17+
18+
```yaml
19+
name: deerhide_container_example
20+
tags:
21+
- latest
22+
registry: ghcr.io/deerhide/template_container_image
23+
build:
24+
format: oci
25+
args:
26+
- APP_UID=1000
27+
- UBUNTU_VERSION=24.04
28+
```
29+
30+
### Authenticate to the container registry
31+
32+
```bash
33+
skopeo login ghcr.io
34+
```
35+
36+
### Launch Builder
37+
38+
```bash
39+
./scripts/builder.sh
40+
```

install-man-page.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#!/bin/sh
2+
3+
my_path="$(command -v yq)"
4+
5+
if [ -z "$my_path" ]; then
6+
echo "'yq' wasn't found in your PATH, so we don't know where to put the man pages."
7+
echo "Please update your PATH to include yq, and run this script again."
8+
exit 1
9+
fi
10+
11+
# ex: ~/.local/bin/yq => ~/.local/
12+
my_prefix="$(dirname "$(dirname "$(command -v yq)")")"
13+
mkdir -p "$my_prefix/share/man/man1/"
14+
cp yq.1 "$my_prefix/share/man/man1/"

manifest.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
name: deerhide_container_example
2+
tags:
3+
- latest
4+
registry: ghcr.io/deerhide/template_container_image
5+
build:
6+
format: oci
7+
args:
8+
- APP_UID=1000
9+
- UBUNTU_VERSION=24.04

scripts/builder.sh

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
#!/usr/bin/env bash
2+
3+
set -eo pipefail
4+
5+
# Include the utils library
6+
source scripts/lib_utils.sh
7+
8+
CLI="docker"
9+
10+
MANIFEST_FILE="manifest.yaml"
11+
12+
IMAGE_TAG="latest"
13+
IMAGE_FORMAT="oci"
14+
UBUNTU_VERSION="24.04"
15+
APP_UID="1000"
16+
17+
BUILD_DIR="./build"
18+
19+
check_for_manifest(){
20+
if [[ ! -f "$MANIFEST_FILE" ]]; then
21+
log_error "Manifest file not found"
22+
exit 1
23+
fi
24+
}
25+
26+
retrieve_name_from_manifest(){
27+
local name
28+
name=$(yq e '.name' $MANIFEST_FILE)
29+
echo $name
30+
}
31+
32+
retrieve_registry_from_manifest(){
33+
local registry
34+
registry=$(yq e '.registry' $MANIFEST_FILE)
35+
echo $registry
36+
}
37+
38+
39+
clean_build_dir(){
40+
if [[ -d "${BUILD_DIR}" ]]; then
41+
log_trace "Removing existing build directory"
42+
rm -rf "${BUILD_DIR}"
43+
fi
44+
mkdir -p "${BUILD_DIR}"
45+
}
46+
47+
hadolint_validate(){
48+
local hadolint_exec
49+
local hadolint_exit_code
50+
log_info "Validating Dockerfile with hadolint"
51+
${CLI} pull -q ghcr.io/hadolint/hadolint:latest > /dev/null
52+
log_trace "$(${CLI} run --rm -i hadolint/hadolint:latest hadolint -v)"
53+
54+
set +e
55+
hadolint_exec=$(
56+
${CLI} run --rm -i hadolint/hadolint:latest < Containerfile \
57+
2>&1
58+
)
59+
hadolint_exit_code=$?
60+
set -e
61+
if [[ $hadolint_exit_code -ne 0 ]]; then
62+
echo -e "${WHITE_GRAY}${hadolint_exec}${NC}"
63+
log_error "Hadolint validation failed"
64+
exit 1
65+
else
66+
log_success "Hadolint validation passed"
67+
fi
68+
}
69+
70+
buildah_build(){
71+
local buildah_exec
72+
local buildah_exit_code
73+
local buildah_args
74+
local manifest_args
75+
log_info "Build Containerfile for ${IMAGE_NAME}:${IMAGE_TAG}"
76+
log_trace "$(buildah --version)"
77+
78+
79+
# Extract build args from manifest
80+
buildah_args=()
81+
for arg in $(yq e '.build.args[]' $MANIFEST_FILE); do
82+
buildah_args+="--build-arg ${arg} "
83+
done
84+
85+
log_trace "Buildah args: ${buildah_args}"
86+
set +e
87+
buildah_exec=$(
88+
buildah build \
89+
--squash \
90+
--pull-always \
91+
--format ${IMAGE_FORMAT} \
92+
${buildah_args} \
93+
--tag docker-daemon:${IMAGE_NAME}:${IMAGE_TAG} \
94+
. \
95+
2>&1
96+
)
97+
buildah_exit_code=$?
98+
set -e
99+
if [[ $buildah_exit_code -ne 0 ]]; then
100+
log_error "Build failed"
101+
log_error "${buildah_exec}"
102+
exit 1
103+
else
104+
log_success "Build completed successfully"
105+
fi
106+
}
107+
108+
podman_save_image_to_tar(){
109+
local podman_exec
110+
local podman_exit_code
111+
log_info "Saving image to tar ${IMAGE_NAME}:${IMAGE_TAG}"
112+
log_trace "$(podman --version)"
113+
114+
set +e
115+
podman_exec=$(
116+
${CLI} save \
117+
--output ${BUILD_DIR}/${IMAGE_NAME}-${IMAGE_TAG}.tar \
118+
${IMAGE_NAME}:${IMAGE_TAG} \
119+
2>&1
120+
)
121+
podman_exit_code=$?
122+
set -e
123+
if [[ $podman_exit_code -ne 0 ]]; then
124+
echo -e "${WHITE_GRAY}${podman_exec}${NC}"
125+
log_error "Saving image to tar failed"
126+
exit 1
127+
else
128+
log_success "Image saved to ${BUILD_DIR}/${IMAGE_NAME}-${IMAGE_TAG}.tar"
129+
fi
130+
}
131+
132+
docker_save_image_to_tar(){
133+
local docker_exec
134+
local docker_exit_code
135+
log_info "Saving image to tar ${IMAGE_NAME}:${IMAGE_TAG}"
136+
log_trace "$(docker --version)"
137+
138+
set +e
139+
docker_exec=$(
140+
${CLI} save \
141+
--output ${BUILD_DIR}/${IMAGE_NAME}-${IMAGE_TAG}.tar \
142+
${IMAGE_NAME}:${IMAGE_TAG} \
143+
2>&1
144+
)
145+
docker_exit_code=$?
146+
set -e
147+
if [[ $docker_exit_code -ne 0 ]]; then
148+
echo -e "${WHITE_GRAY}${docker_exec}${NC}"
149+
log_error "Saving image to tar failed"
150+
exit 1
151+
else
152+
log_success "Image saved to ${BUILD_DIR}/${IMAGE_NAME}-${IMAGE_TAG}.tar"
153+
fi
154+
}
155+
156+
dive_scan() {
157+
local dive_scan
158+
log_info "Running dive scan on ${IMAGE_NAME}:${IMAGE_TAG}"
159+
log_trace "$(dive --version)"
160+
161+
set +e
162+
dive_scan=$(\
163+
dive \
164+
--ci \
165+
--source=${CLI} \
166+
${IMAGE_NAME}:${IMAGE_TAG} \
167+
2>&1 \
168+
)
169+
set -e
170+
171+
if [[ $dive_scan == *"FAIL"* ]]; then
172+
echo -e "${WHITE_GRAY}${dive_scan}${NC}"
173+
log_error "Dive scan failed"
174+
exit 1
175+
else
176+
log_success "Dive scan passed"
177+
fi
178+
}
179+
180+
trivy_scan () {
181+
182+
local trivy_scan_exec
183+
local trivy_scan_exit_code
184+
185+
log_info "Running trivy scan on ${IMAGE_NAME}:${IMAGE_TAG}"
186+
log_trace "$(trivy --version)"
187+
188+
set +e
189+
trivy_scan_exec=$(\
190+
trivy image \
191+
--input ${BUILD_DIR}/${IMAGE_NAME}-${IMAGE_TAG}.tar \
192+
--format github \
193+
--severity HIGH,CRITICAL \
194+
--exit-code 2 \
195+
${IMAGE_NAME}:${IMAGE_TAG} \
196+
2>&1
197+
)
198+
# Detect exit code
199+
trivy_scan_exit_code=$?
200+
set -e
201+
if [[ $trivy_scan_exit_code -eq 2 ]]; then
202+
echo -e "${WHITE_GRAY}${trivy_scan_exec}${NC}"
203+
log_error "Trivy scan failed"
204+
exit 1
205+
elif [[ $trivy_scan_exit_code -eq 1 ]]; then
206+
echo -e "${WHITE_GRAY}${trivy_scan_exec}${NC}"
207+
log_error "Trivy scan error"
208+
else
209+
log_success "Trivy scan passed"
210+
fi
211+
}
212+
213+
# Main
214+
clean_build_dir
215+
check_for_manifest # Check for manifest file existence\
216+
IMAGE_NAME=$(retrieve_name_from_manifest) # Retrieve image name from manifest
217+
218+
log_info "Starting build process"
219+
log_trace "CLI: ${CLI}"
220+
log_trace "IMAGE_NAME: ${IMAGE_NAME}"
221+
log_trace "IMAGE_TAG: ${IMAGE_TAG}"
222+
log_trace "IMAGE_FORMAT: ${IMAGE_FORMAT}"
223+
224+
225+
hadolint_validate # Validate/Lint Containerfile
226+
buildah_build # Build Containerfile
227+
228+
if [[ $CLI == "podman" ]]; then
229+
podman_save_image_to_tar # Save image to tar (for trivy scan)
230+
elif [[ $CLI == "docker" ]]; then
231+
docker_save_image_to_tar # Save image to tar (for trivy scan)
232+
else
233+
log_error "Invalid CLI"
234+
exit 1
235+
fi
236+
237+
dive_scan # Filesystem scan and analysis
238+
trivy_scan # Vulnerability scan
239+
240+
# Deploy to registry with skopeo using tags in manifest
241+
registry=$(retrieve_registry_from_manifest)
242+
skopeo copy docker-daemon:${IMAGE_NAME}:${IMAGE_TAG} docker://${registry}:${IMAGE_TAG}

0 commit comments

Comments
 (0)