Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(WIP): enhance CI/CD workflow #1028

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
171 changes: 171 additions & 0 deletions .github/actions/build-container-image/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# Copyright 2024 Specter Ops, Inc.
#
# Licensed under the Apache License, Version 2.0
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

---
name: Build and Publish Container Image

description: |-
This composite action builds a container image based on the specified Dockerfile and metadata.
It can optionally push the built image to a container registry.
Ensure you have the necessary Docker and QEMU setup steps in your workflow for cross-platform builds.

inputs:
dockerhub_account:
required: true
description: |-
TBD ...
dockerhub_token:
required: true
description: |-
TBD ...
ghcr_account:
required: true
description: |-
TBD ...
ghcr_token:
required: true
description: |-
TBD ...
build_platforms:
required: true
default: "linux/amd64,linux/arm64"
description: |-
TBD ...
image_labels:
required: true
default: "false"
description: |-
A JSON object containing image labels and metadata.
These labels help describe the image and can include information like
version, author, and licenses.
image_tags:
required: true
default: "false"
description: |-
A comma-separated list of tags to assign to the built image.
These tags help identify different versions or variants of the image.
image_provenance:
required: true
default: "false"
description: |-
Whether to include image provenance information in the image metadata.
Provenance information provides details about how the image was built and can be useful for auditing.
image_sbom:
required: true
default: "false"
description: |-
Whether to include a Software Bill of Materials (SBOM) in the image metadata.
An SBOM lists all the software components used in the image, enhancing transparency and security.
dockerfile:
default: Dockerfile
description: |-
The name of the Dockerfile used for building the container image.
If not specified, it defaults to 'Dockerfile' in the repository root.

Example: 'Dockerfile.prod' for a production-specific Dockerfile.
build_context:
default: "{{defaultContext}}"
description: |-
Build's context is the set of files located in the specified PATH or URL (default Git context)
build_target:
description: |-
The build stage target for multi-stage Docker builds, if applicable.
Specify this if your Dockerfile has multiple stages, and you want to build a specific one.

Example: 'production' for a multi-stage Dockerfile with a 'production' stage.
build_args:
description: |-
Additional build arguments to pass to the Docker build process.
These arguments can be used to customize the build based on your requirements.

Example: 'MY_VARIABLE=value' to set an environment variable during the build.
build_contexts:
description: |-
Additional build contexts to pass to Docker build process.

Define additional build context with specified contents. In Dockerfile the
context can be accessed when FROM name or --from=name is used. When
Dockerfile defines a stage with the same name it is overwritten.

Example: 'name=path'
build_outputs:
required: true
description: |-
Set build outputs.
cache_from:
description: |-
The source image repository from which to cache layers during the build.
This can help improve build speed by reusing layers from a previously built image.

Default: type=gha

Example: 'docker.io/my-app:cache' to cache from a specific image.
default: |-
type=gha
cache_to:
description: |-
The destination image cache settings to optimize the caching strategy during the build.
This input specifies where to store cached layers and how they are scoped.

Default: type=gha,mode=max

Example: "type=gha,mode=max,scope=\$\{\{ github.workflow \}\}"
default: |-
type=gha,mode=max

runs:
using: composite
steps:
- uses: docker/login-action@v3
name: Authenticate with DockerHub Registry
with:
registry: docker.io
username: ${{ inputs.dockerhub_account }}
password: ${{ inputs.dockerhub_token }}

- uses: docker/login-action@v3
name: Authenticate with GitHub Container Registry
with:
registry: ghcr.io
username: ${{ inputs.ghcr_account }}
password: ${{ inputs.ghcr_token }}

- name: Set up QEMU
uses: docker/setup-qemu-action@v3
with:
platforms: ${{ inputs.build_platforms }}

- name: Set up buildx
id: buildx
uses: docker/setup-buildx-action@v3
with:
platforms: ${{ inputs.build_platforms }}

- name: Build
uses: docker/build-push-action@v6
with:
build-args: ${{ inputs.build_args }}
build-contexts: ${{ inputs.build_contexts }}
cache-from: ${{ inputs.cache_from }}
cache-to: ${{ inputs.cache_to }}
context: ${{ inputs.build_context }}
file: ${{ inputs.dockerfile }}
labels: ${{ inputs.image_labels }}
outputs: ${{ inputs.build_outputs }}
provenance: ${{ inputs.image_provenance }}
sbom: ${{ inputs.image_sbom }}
tags: ${{ inputs.image_tags }}
target: ${{ inputs.build_target }}
100 changes: 100 additions & 0 deletions .github/actions/container-image-metadata/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Copyright 2024 Specter Ops, Inc.
#
# Licensed under the Apache License, Version 2.0
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0

---
name: Generate Container Image Metadata

description: |-
This composite action generates metadata for a container image and extracts useful information,
such as JSON data, tags, labels, revision, version, and the container image reference.
The metadata is essential for tracking and managing container images effectively.

inputs:
container_image_repository_name:
required: true
description: |-
TBD ...

image_flavor:
description: |-
See: https://github.com/docker/metadata-action#flavor-input

image_tags:
description: |-
See: https://github.com/docker/metadata-action#tags-input

outputs:
json:
value: ${{ steps.generate-metadata.outputs.json }}
description: |-
The JSON metadata for the container image, including details about the image and its layers.

tags:
value: ${{ steps.generate-metadata.outputs.tags }}
description: |-
A list of tags associated with the container image, which may include version and branch information.

labels:
value: ${{ steps.generate-metadata.outputs.labels }}
description: |-
Custom labels associated with the container image, providing additional information and metadata.

revision:
value: ${{ fromJSON(steps.generate-metadata.outputs.json).labels['org.opencontainers.image.revision'] }}
description: |-
The revision of the container image, if available, typically extracted from metadata labels.

version:
value: ${{ steps.generate-metadata.outputs.version }}
description: |-
The version of the container image, often derived from tags or other versioning patterns.

image_reference:
value: ${{ steps.set-image-reference.outputs.image_reference }}
description: |-
The full image reference, including registry, repository, and tag.
This fully qualified name is used to pull or locate a specific image
from a particular registry (e.g., docker.io/myrepo/myimage:tag).

image_name:
value: ${{ steps.set-image-reference.outputs.image_name }}
description: |-
The image name with repository and tag, typically used locally or
with the default registry. This shorthand version omits the registry
and assumes the default registry if unspecified (e.g., myimage:tag).

runs:
using: composite
steps:
- name: Generate metadata
id: generate-metadata
uses: docker/metadata-action@v5
with:
images: ${{ inputs.container_image_repository_name }}
flavor: ${{ inputs.image_flavor }}
tags: |-
type=raw,value=sha-{{sha}}-{{date 'YYYYMMDD-HHmmss'}},priority=1500
type=sha,format=long,priority=1450
${{ inputs.image_tags }}

- name: Set Container Image Reference
id: set-image-reference
shell: bash
run: |-
image_reference=${{ fromJSON(steps.generate-metadata.outputs.json).tags[0] }}
echo "image_reference=$image_reference" >> $GITHUB_OUTPUT
image_name=$(echo "$image_reference" | sed 's/.*\///')
echo "image_name=$image_name" >> $GITHUB_OUTPUT
100 changes: 100 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
---
# Copyright 2024 Specter Ops, Inc.
#
# Licensed under the Apache License, Version 2.0
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
name: Continuous Integration (CI)

on:
pull_request:
branches:
- main
- develop
types:
- assigned
- opened
- synchronize
- reopened
- closed
# https://stephencharlesweiss.com/github-actions-run-on-merge-only
push:
branches:
- main
- develop

permissions: write-all

jobs:
cla-check:
if: ${{ !github.event.act }}
name: Process CLA
runs-on: ubuntu-latest
steps:
- name: CLA Assistant
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
uses: contributor-assistant/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PERSONAL_ACCESS_TOKEN: ${{ secrets.REPO_SCOPE }}

bloodhound-container-image:
needs: cla-check
name: Build BloodHound Container Image
uses: ./.github/workflows/reusable.build-container-image.yml
with:
container_image_repository_name: docker.io/specterops/bloodhound
build_target: bloodhound
image_sbom: true
image_provenance: mode=max
build_outputs: type=image,push=true
dockerfile: dockerfiles/bloodhound.Dockerfile
image_cache_from: |-
type=registry,ref=docker.io/specterops/bloodhound:buildcache
type=registry,ref=ghcr.io/specterops/bloodhound:buildcache
image_cache_to: |-
type=registry,ref=docker.io/specterops/bloodhound:buildcache,mode=max
type=registry,ref=ghcr.io/specterops/bloodhound:buildcache,mode=max
docker_content_trust_repository_key_id: 0eb658e566aa45e90de85600c9cfb9b9df7049434003d13cb9466a1a5f61b09f
docker_content_trust_server: https://notary.docker.io
secrets:
dockerhub_account: ${{ secrets.DOCKERHUB_USERNAME }}
dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }}
ghcr_account: ${{ github.actor }}
ghcr_token: ${{ secrets.GITHUB_TOKEN }}
gh_access_token: ${{ secrets.GITHUB_TOKEN }}
docker_content_trust_repository_passphrase: ${{ secrets.DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE }}
docker_content_trust_repository_key: ${{ secrets.DOCKER_CONTENT_TRUST_REPOSITORY_KEY }}
docker_content_trust_repository_public_key: ${{ secrets.DOCKER_CONTENT_TRUST_REPOSITORY_PUBLIC_KEY }}

# static-code-analysis:
# name: Static Code Analysis
# needs: cla-check
# uses: ./.github/workflows/static-code-analysis.yml
# with:
# bloodhound_image_tar_artifact_name: ${{ needs.build-container-images.outputs.bloodhound_image_tar_artifact_name }}
# bloodhound_image_tar_path: ${{ needs.build-container-images.outputs.bloodhound_image_tar_path }}
# secrets:
# dockerhub_account: ${{ secrets.DOCKERHUB_USERNAME }}
# dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }}
# ghcr_account: ${{ github.actor }}
# ghcr_token: ${{ secrets.GITHUB_TOKEN }}
# gh_access_token: ${{ secrets.GITHUB_TOKEN }}
#
# test-suite:
# name: Test Suite
# needs: [cla-check, build-container-images]
# uses: ./.github/workflows/test-suite.yml
# with:
# bloodhound_image_tar_artifact_name: ${{ needs.build-container-images.outputs.bloodhound_image_tar_artifact_name }}
# bloodhound_image_tar_path: ${{ needs.build-container-images.outputs.bloodhound_image_tar_path }}
Loading
Loading