Skip to content
Closed
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
16 changes: 13 additions & 3 deletions .github/workflows/build_and_publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,12 @@ jobs:
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
-
name: Login to DockerHub
if: github.event_name != 'pull_request'
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
Copy link
Preview

Copilot AI Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the conditional check for pull requests means Docker registry credentials will be exposed during PR builds from forks, which poses a security risk. The original condition 'if: github.event_name != 'pull_request'' should be restored to prevent credential exposure in untrusted contexts.

Copilot uses AI. Check for mistakes.

with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Login to GHCR
Copy link
Preview

Copilot AI Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the conditional check for pull requests means GHCR registry credentials will be exposed during PR builds from forks, which poses a security risk. The original condition 'if: github.event_name != 'pull_request'' should be restored to prevent credential exposure in untrusted contexts.

Suggested change
name: Login to GHCR
name: Login to GHCR
if: github.event_name != 'pull_request'

Copilot uses AI. Check for mistakes.

if: github.event_name != 'pull_request'
uses: docker/login-action@184bdaa0721073962dff0199f1fb9940f07167d1 # v3.5.0
with:
registry: ghcr.io
Expand All @@ -53,6 +51,18 @@ jobs:
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
push: true
Copy link
Preview

Copilot AI Sep 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unconditionally pushing images for all events including pull requests can lead to unwanted image publications and potential security issues. Consider restoring the original condition 'push: ${{ github.event_name != 'pull_request' }}' to prevent pushing images from PR builds.

Suggested change
push: true
push: ${{ github.event_name != 'pull_request' }}

Copilot uses AI. Check for mistakes.

tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

-
name: Install BATS
run: |
sudo apt-get update
sudo apt-get install -y bats

-
name: Run BATS tests
run: |
IMAGE_REF="${{ steps.meta.outputs.tags }}"
IMAGE_NAME=$(echo "$IMAGE_REF" | head -n1) bats envplate.bats
7 changes: 4 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
# syntax=docker/dockerfile:1
# Build docker-gen from scratch
FROM golang:1.23-alpine AS ep-builder
FROM golang:1.25-alpine AS ep-builder

ARG VERSION=v1.0.3
ARG VERSION=v1.0.4-rc.1

ADD https://github.com/kreuzwerker/envplate.git#${VERSION} /build
# Pinning at https://github.com/kreuzwerker/envplate/commit/ec00ede3ca03c6bbbe0412bf4b84eacdcdabba11
ADD https://github.com/kreuzwerker/envplate.git#ec00ede3ca03c6bbbe0412bf4b84eacdcdabba11 /build

WORKDIR /build

Expand Down
153 changes: 153 additions & 0 deletions envplate.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
#!/usr/bin/env bats

# Setup and teardown
setup() {
export TEST_DIR=$(mktemp -d)
export IMAGE_NAME="${IMAGE_NAME:-local/ep:latest}"
}

teardown() {
rm -rf "$TEST_DIR"
}

@test "basic variable substitution" {
echo 'Value: ${TEST_VAR}' > "$TEST_DIR/config.txt"

run docker run --rm \
-e TEST_VAR=hello \
-v "$TEST_DIR:/test" \
"$IMAGE_NAME" \
ep /test/config.txt

[ "$status" -eq 0 ]

result=$(cat "$TEST_DIR/config.txt")
[ "$result" = "Value: hello" ]
}

@test "default value handling" {
echo 'Database: ${DB_HOST:-localhost}' > "$TEST_DIR/config.txt"

run docker run --rm \
-v "$TEST_DIR:/test" \
"$IMAGE_NAME" \
ep /test/config.txt

[ "$status" -eq 0 ]

result=$(cat "$TEST_DIR/config.txt")
[ "$result" = "Database: localhost" ]
}

@test "backup creation" {
echo 'Value: ${TEST_VAR}' > "$TEST_DIR/config.txt"

run docker run --rm \
-e TEST_VAR=hello \
-v "$TEST_DIR:/test" \
"$IMAGE_NAME" \
ep -b /test/config.txt

[ "$status" -eq 0 ]
[ -f "$TEST_DIR/config.txt.bak" ]

# Original content should be in backup
backup_content=$(cat "$TEST_DIR/config.txt.bak")
[ "$backup_content" = "Value: \${TEST_VAR}" ]

# Processed content should be in original file
processed_content=$(cat "$TEST_DIR/config.txt")
[ "$processed_content" = "Value: hello" ]
}

@test "strict mode fails on missing variables" {
echo 'Value: ${MISSING_VAR}' > "$TEST_DIR/config.txt"

run docker run --rm \
-v "$TEST_DIR:/test" \
"$IMAGE_NAME" \
ep -s /test/config.txt

[ "$status" -ne 0 ]
}

@test "escaped variables are not processed" {
echo 'Escaped: \${TEST_VAR}' > "$TEST_DIR/config.txt"

run docker run --rm \
-e TEST_VAR=hello \
-v "$TEST_DIR:/test" \
"$IMAGE_NAME" \
ep /test/config.txt

[ "$status" -eq 0 ]

result=$(cat "$TEST_DIR/config.txt")
[ "$result" = "Escaped: \${TEST_VAR}" ]
}

@test "dry run outputs to stdout" {
echo 'Value: ${TEST_VAR}' > "$TEST_DIR/config.txt"

run docker run --rm \
-e TEST_VAR=hello \
-v "$TEST_DIR:/test" \
"$IMAGE_NAME" \
ep -d /test/config.txt

[ "$status" -eq 0 ]
[[ "$output" =~ "Value: hello" ]]

# Original file should be unchanged
original_content=$(cat "$TEST_DIR/config.txt")
[ "$original_content" = "Value: \${TEST_VAR}" ]
}

@test "multiple files with glob pattern" {
echo 'env=${ENV}' > "$TEST_DIR/app.conf"
echo 'environment=${ENV}' > "$TEST_DIR/db.conf"

run docker run --rm \
-e ENV=production \
-v "$TEST_DIR:/test" \
"$IMAGE_NAME" \
ep '/test/*.conf'

[ "$status" -eq 0 ]

app_result=$(cat "$TEST_DIR/app.conf")
db_result=$(cat "$TEST_DIR/db.conf")
[ "$app_result" = "env=production" ]
[ "$db_result" = "environment=production" ]
}

@test "exec functionality works" {
echo 'Message: ${MESSAGE}' > "$TEST_DIR/output.txt"
echo 'Message: ${MESSAGE}${MESSAGE}' > "$TEST_DIR/output_exec.txt"

run docker run --rm \
-e MESSAGE=hello \
-v "$TEST_DIR:/test" \
"$IMAGE_NAME" \
ep -b /test/output.txt -- /usr/local/bin/ep -d /test/output_exec.txt

[ "$status" -eq 0 ]
[[ "$output" =~ "Message: hellohello" ]]
}

@test "version information available" {
run docker run --rm "$IMAGE_NAME" ep --help

[ "$status" -eq 0 ]
[[ "$output" =~ "envplate" ]]
}

@test "container uses scratch base (minimal size)" {
run docker images "$IMAGE_NAME" --format "{{.Size}}"

[ "$status" -eq 0 ]
# Size should be less than 20MB for a scratch-based image
size_mb=$(echo "$output" | sed 's/MB//' | cut -d'.' -f1)
[ -n "$size_mb" ]
[ "$size_mb" -lt 20 ]
}