Skip to content

Commit 926d159

Browse files
authored
support an optional custom dockerfile input (#41)
adds new `dockerfile_template` and `docker_extra_files` inputs for the shared release workflow. allows connectors like `baton-sap-grc` to use custom Dockerfiles (e.g., Java-based) for building container images pushed to the public ECR registry
1 parent f50a13a commit 926d159

12 files changed

Lines changed: 150 additions & 16 deletions

.cursorrules

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ Before modifying this repository, read:
3333
These require extra care when modifying:
3434

3535
- Sigstore/cosign signing steps
36-
- Provenance predicate generation (`templates/.slsa-provenance-predicate-template.json`)
36+
- Provenance predicate generation (`templates/.slsa-provenance-predicate-template.json.tmpl`)
3737
- Attestation bundle creation and upload
3838
- OIDC credential configuration

.github/workflows/release.yaml

Lines changed: 84 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ on:
2727
type: boolean
2828
default: true
2929
description: "Whether to release with Docker image support."
30+
dockerfile_template:
31+
required: false
32+
type: string
33+
default: ""
34+
description: "Path to a custom Dockerfile template in the caller repo (relative to repo root). Only valid when lambda is false. Supports ${REPO_NAME} substitution."
35+
docker_extra_files:
36+
required: false
37+
type: string
38+
default: ""
39+
description: "Comma-separated list of extra files/directories from the caller repo to include in the Docker build context (e.g., 'java,config'). Only valid when dockerfile_template is set."
3040
secrets:
3141
RELENG_GITHUB_TOKEN:
3242
required: true
@@ -47,7 +57,35 @@ env:
4757
GENERATED_DIR: "_generated"
4858

4959
jobs:
60+
validate-inputs:
61+
runs-on: ubuntu-latest
62+
steps:
63+
- name: Validate tag format
64+
run: |
65+
TAG="${{ inputs.tag }}"
66+
# Strict semver regex with 'v' prefix (per https://semver.org)
67+
# Supports: v1.2.3, v1.2.3-alpha, v1.2.3-alpha.1, v1.2.3+build, v1.2.3-rc.1+build.123
68+
SEMVER_REGEX='^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-((0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(\.(0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?(\+([0-9a-zA-Z-]+(\.[0-9a-zA-Z-]+)*))?$'
69+
if [[ ! "$TAG" =~ $SEMVER_REGEX ]]; then
70+
echo "::error::Tag must be valid semver starting with 'v' (e.g., v1.2.3, v1.0.0-rc.1). Got: $TAG"
71+
exit 1
72+
fi
73+
echo "✅ Tag format valid: $TAG"
74+
75+
- name: Validate dockerfile_template requires lambda=false
76+
if: inputs.dockerfile_template != '' && inputs.lambda == true
77+
run: |
78+
echo "::error::dockerfile_template can only be used when lambda is false"
79+
exit 1
80+
81+
- name: Validate docker_extra_files requires dockerfile_template
82+
if: inputs.docker_extra_files != '' && inputs.dockerfile_template == ''
83+
run: |
84+
echo "::error::docker_extra_files can only be used when dockerfile_template is set"
85+
exit 1
86+
5087
determine-workflows-ref:
88+
needs: validate-inputs
5189
runs-on: ubuntu-latest
5290
permissions:
5391
actions: read
@@ -116,8 +154,8 @@ jobs:
116154
117155
envsubst < .gon-amd64-template.json | tee "${GENERATED_DIR}/.gon-amd64.json"
118156
envsubst < .gon-arm64-template.json | tee "${GENERATED_DIR}/.gon-arm64.json"
119-
envsubst < templates/.goreleaser-binaries-template.yaml | tee "${GENERATED_DIR}/.goreleaser.binaries.yaml"
120-
envsubst < templates/.slsa-provenance-predicate-template.json | tee "${GENERATED_DIR}/predicate.json"
157+
envsubst < templates/.goreleaser-binaries-template.yaml.tmpl | tee "${GENERATED_DIR}/.goreleaser.binaries.yaml"
158+
envsubst < templates/.slsa-provenance-predicate-template.json.tmpl | tee "${GENERATED_DIR}/predicate.json"
121159
122160
- name: Set up Gon
123161
run: brew tap conductorone/gon && brew install conductorone/gon/gon
@@ -345,13 +383,52 @@ jobs:
345383
# For provenance predicate template
346384
WORKFLOWS_REF: ${{ needs.determine-workflows-ref.outputs.ref }}
347385
RELEASE_TAG: ${{ inputs.tag }}
386+
# Custom Dockerfile template from caller repo (if provided)
387+
CUSTOM_DOCKERFILE_TEMPLATE: ${{ inputs.dockerfile_template }}
388+
# Extra files to include in Docker build context (comma-separated)
389+
DOCKER_EXTRA_FILES: ${{ inputs.docker_extra_files }}
348390
run: |
349391
mkdir -p "${GENERATED_DIR}"
350392
export BUILD_STARTED_ON=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
351393
352-
envsubst '$REPO_NAME' < templates/.Dockerfile-template | tee "${GENERATED_DIR}/Dockerfile"
353-
envsubst < templates/.goreleaser-docker-oci-template.yaml | tee "${GENERATED_DIR}/.goreleaser.docker.yaml"
354-
envsubst < templates/.slsa-provenance-predicate-template.json | tee "${GENERATED_DIR}/predicate.json"
394+
# Generate Dockerfile from custom template or default
395+
if [ -n "${CUSTOM_DOCKERFILE_TEMPLATE}" ]; then
396+
CUSTOM_PATH="../_caller/${CUSTOM_DOCKERFILE_TEMPLATE}"
397+
if [ ! -f "${CUSTOM_PATH}" ]; then
398+
echo "::error::Custom Dockerfile template not found: ${CUSTOM_DOCKERFILE_TEMPLATE}"
399+
exit 1
400+
fi
401+
echo "Using custom Dockerfile template: ${CUSTOM_DOCKERFILE_TEMPLATE}"
402+
envsubst '$REPO_NAME' < "${CUSTOM_PATH}" | tee "${GENERATED_DIR}/Dockerfile"
403+
else
404+
echo "Using default Dockerfile template"
405+
envsubst '$REPO_NAME' < templates/.Dockerfile-template.tmpl | tee "${GENERATED_DIR}/Dockerfile"
406+
fi
407+
408+
# Build EXTRA_FILES_BLOCK for goreleaser template substitution
409+
# This will be empty string if no extra files, or the YAML block if specified
410+
export EXTRA_FILES_BLOCK=""
411+
if [ -n "${DOCKER_EXTRA_FILES}" ]; then
412+
echo "Adding extra files to Docker build context: ${DOCKER_EXTRA_FILES}"
413+
414+
# Validate files exist and build the YAML block
415+
EXTRA_FILES_BLOCK=" extra_files:"$'\n'
416+
IFS=',' read -ra FILES <<< "${DOCKER_EXTRA_FILES}"
417+
for file in "${FILES[@]}"; do
418+
file=$(echo "$file" | xargs) # trim whitespace
419+
if [ ! -e "../_caller/${file}" ]; then
420+
echo "::error::Extra file/directory not found: ${file}"
421+
exit 1
422+
fi
423+
EXTRA_FILES_BLOCK="${EXTRA_FILES_BLOCK} - ${file}"$'\n'
424+
done
425+
export EXTRA_FILES_BLOCK
426+
fi
427+
428+
# Generate goreleaser config with all substitutions
429+
envsubst < templates/.goreleaser-docker-oci-template.yaml.tmpl | tee "${GENERATED_DIR}/.goreleaser.docker.yaml"
430+
431+
envsubst < templates/.slsa-provenance-predicate-template.json.tmpl | tee "${GENERATED_DIR}/predicate.json"
355432
356433
- name: Generate configs for Lambda
357434
if: inputs.lambda == true
@@ -362,8 +439,8 @@ jobs:
362439
DIST_DIR: dist/lambda
363440
run: |
364441
mkdir -p "${GENERATED_DIR}"
365-
envsubst '$REPO_NAME' < templates/.Dockerfile-lambda-template | tee "${GENERATED_DIR}/Dockerfile.lambda"
366-
envsubst < templates/.goreleaser-docker-lambda-template.yaml | tee "${GENERATED_DIR}/.goreleaser.lambda.yaml"
442+
envsubst '$REPO_NAME' < templates/.Dockerfile-lambda-template.tmpl | tee "${GENERATED_DIR}/Dockerfile.lambda"
443+
envsubst < templates/.goreleaser-docker-lambda-template.yaml.tmpl | tee "${GENERATED_DIR}/.goreleaser.lambda.yaml"
367444
368445
- name: Docker Login
369446
if: inputs.docker == true

README.md

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,13 @@ jobs:
3434
3535
The release workflow accepts the following input parameters:
3636
37-
| Parameter | Required | Default | Description |
38-
| --------- | -------- | ------- | -------------------------------------------- |
39-
| `tag` | Yes | - | The release tag (e.g., "v1.0.0") |
40-
| `lambda` | No | `true` | Whether to release with Lambda image support |
41-
| `docker` | No | `true` | Whether to release with Docker image support |
37+
| Parameter | Required | Default | Description |
38+
| --------------------- | -------- | ------- | --------------------------------------------------------------------------- |
39+
| `tag` | Yes | - | The release tag (must be valid semver with `v` prefix, e.g., `v1.0.0`) |
40+
| `lambda` | No | `true` | Whether to release with Lambda image support |
41+
| `docker` | No | `true` | Whether to release with Docker image support |
42+
| `dockerfile_template` | No | `""` | Path to a custom Dockerfile in your repo (only valid when `lambda: false`) |
43+
| `docker_extra_files` | No | `""` | Comma-separated list of extra files/dirs to include in Docker build context |
4244

4345
2. Ensure your repository has the following secrets configured:
4446

@@ -51,6 +53,47 @@ The release workflow accepts the following input parameters:
5153

5254
3. Remove all GoReleaser, gon files, Dockerfile, and Dockerfile.lambda files from your connector repository, if they were previously created there.
5355

56+
### Custom Dockerfiles
57+
58+
For connectors that require a non-standard base image (e.g., Java runtime), you can provide a custom Dockerfile:
59+
60+
```yaml
61+
jobs:
62+
release:
63+
uses: ConductorOne/github-workflows/.github/workflows/release.yaml@v4
64+
with:
65+
tag: ${{ github.ref_name }}
66+
lambda: false
67+
dockerfile_template: Dockerfile
68+
docker_extra_files: java # Include the java/ directory in the build context
69+
secrets:
70+
# ... secrets ...
71+
```
72+
73+
Your custom Dockerfile must:
74+
75+
1. Use `ARG TARGETPLATFORM` for multi-arch build support
76+
2. Copy the binary from `${TARGETPLATFORM}/<connector-name>`
77+
78+
Example for a Java-based connector:
79+
80+
```dockerfile
81+
FROM gcr.io/distroless/java17-debian11:nonroot
82+
ARG TARGETPLATFORM
83+
ENTRYPOINT ["/baton-example"]
84+
85+
COPY ${TARGETPLATFORM}/baton-example /baton-example
86+
COPY java /java
87+
```
88+
89+
The workflow substitutes `${REPO_NAME}` in your Dockerfile if present, so you can also use:
90+
91+
```dockerfile
92+
COPY ${TARGETPLATFORM}/${REPO_NAME} /${REPO_NAME}
93+
```
94+
95+
**Note:** Use `docker_extra_files` to include additional files or directories (comma-separated) in the Docker build context. These are paths relative to your connector repository root.
96+
5497
## Available Actions
5598

5699
### Get Baton

docs/diagrams/release-workflow.dot

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ digraph ReleaseWorkflow {
1313
style="filled";
1414
color="#dbeafe";
1515

16+
validate [label="validate-inputs\n• semver tag, input constraints", fillcolor="#f9fafb"];
17+
1618
determine_ref [label="determine-workflows-ref\n• resolve workflow SHA", fillcolor="#f9fafb"];
1719

1820
binaries [label="goreleaser-binaries\n• build archives\n• gon codesign\n• SBOMs (syft)\n• provenance attestations\n• SBOM attestations\n• upload to S3", fillcolor="#ecfeff"];
@@ -33,7 +35,8 @@ digraph ReleaseWorkflow {
3335

3436
// Flow
3537
connector_repo -> tag;
36-
tag -> determine_ref;
38+
tag -> validate;
39+
validate -> determine_ref;
3740
determine_ref -> binaries;
3841
determine_ref -> docker;
3942
binaries -> record;

docs/diagrams/release-workflow.png

7.71 KB
Loading

docs/release-workflow.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ When a tag is pushed to a connector repository, the shared release workflow:
1717

1818
## Jobs
1919

20+
### validate-inputs
21+
22+
Validates workflow inputs before proceeding:
23+
24+
- Ensures tag is valid semver starting with 'v' (e.g., `v1.2.3`)
25+
- Ensures `dockerfile_template` is only used when `lambda: false`
26+
- Ensures `docker_extra_files` is only used when `dockerfile_template` is set
27+
2028
### determine-workflows-ref
2129

2230
Resolves the exact SHA of the shared workflow being used. This pinned reference is embedded in all provenance attestations, ensuring verifiability.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)