Skip to content

feat(ci): sign + SBOM + SLSA L3 provenance for images and tarballs #562

feat(ci): sign + SBOM + SLSA L3 provenance for images and tarballs

feat(ci): sign + SBOM + SLSA L3 provenance for images and tarballs #562

Workflow file for this run

name: Build simple-container in branch
# GitHub does not pass repository secrets to workflows triggered by fork
# PRs (only same-repo branches), so the practical attack surface for the
# rule below is limited to internal collaborators with push access. The
# PR-validation job requires `secrets.SC_CONFIG` to decrypt the SC config
# and run integration-style tests against shared infra. Splitting this
# into a workflow_run-gated secret-using job is the proper fix and is
# tracked separately; until then this is accepted defense-in-depth risk
# for trusted contributors.
# nosemgrep: gha-pull-request-uses-non-token-secret
on:
workflow_dispatch:
pull_request:
branches:
- 'main'
- 'staging'
# Least-privilege root: every job inherits read-only unless it explicitly
# grants more (CIS GHA 1.2). Only `finalize` actually needs `contents: write`
# (sticky comment / notify), and it grants that itself further down.
permissions:
contents: read
jobs:
build-setup:
name: Build Setup (clean, tools, schemas, lint, fmt)
runs-on: blacksmith-8vcpu-ubuntu-2204
outputs:
cicd-bot-telegram-token: ${{ steps.telegram-secrets.outputs.cicd-bot-telegram-token }}
cicd-bot-telegram-chat-id: ${{ steps.telegram-secrets.outputs.cicd-bot-telegram-chat-id }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- uses: fregante/setup-git-user@024bc0b8e177d7e77203b48dab6fb45666854b35 # v2.0.2
- name: Set up Go with Blacksmith caching
uses: useblacksmith/setup-go@647ac649bd5b480f2a262e3e3e5f4d150ed452ad # v6.0.1
with:
go-version: '1.25'
- name: install sc tool
uses: simple-container-com/actions/install-sc@main
- name: install welder tool
uses: simple-container-com/actions/install-welder@main
- name: prepare secrets for build
run: |
cat << EOF > ./.sc/cfg.default.yaml
${{ secrets.SC_CONFIG }}
EOF
cat << EOF > ./.sc/cfg.test.yaml
${{ secrets.SC_CONFIG }}
EOF
sc secrets reveal
- name: get openai key
id: get-openai-key
run: |
echo "openai-key=$(sc stack secret-get -s dist openai-api-key 2>/dev/null || echo '')" >> $GITHUB_OUTPUT
- name: prepare sc tool (rebuild)
shell: bash
env:
OPENAI_API_KEY: ${{ steps.get-openai-key.outputs.openai-key }}
SKIP_EMBEDDINGS: "true"
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |-
gh auth setup-git
welder run rebuild
- name: clean
run: |
mkdir -p dist
rm -fR dist/*
mkdir -p .sc/stacks/dist/bundle
rm -fR .sc/stacks/dist/bundle/*
mkdir -p docs/site
rm -fR docs/site/*
mkdir -p docs/schemas
rm -fR docs/schemas/*
- name: tools
run: |
cat tools.go | grep _ | awk -F'"' '{print $2}' | xargs -tI % go get %
go mod download
go generate -tags tools
go mod tidy
- name: generate-schemas
run: |
echo "Generating JSON Schema files for Simple Container resources..."
go build -o bin/schema-gen ./cmd/schema-gen
bin/schema-gen docs/schemas
echo "Successfully generated JSON Schema files in docs/schemas/"
- name: fmt
run: |
go mod tidy
bin/gofumpt -l -w ./
bin/golangci-lint run --fix --timeout 3m -v
- name: get telegram secrets
id: telegram-secrets
run: |
echo "cicd-bot-telegram-token=$(./bin/sc stack secret-get -s dist cicd-bot-telegram-token)" >> $GITHUB_OUTPUT
echo "cicd-bot-telegram-chat-id=$(./bin/sc stack secret-get -s dist cicd-bot-telegram-chat-id)" >> $GITHUB_OUTPUT
- name: upload bin directory artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: bin-tools
path: bin
retention-days: 1
build-platforms:
name: Build sc for ${{ matrix.os }}/${{ matrix.arch }}
runs-on: blacksmith-8vcpu-ubuntu-2204
needs: build-setup
strategy:
matrix:
include:
- os: linux
arch: amd64
- os: darwin
arch: arm64
- os: darwin
arch: amd64
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go with Blacksmith caching
uses: useblacksmith/setup-go@647ac649bd5b480f2a262e3e3e5f4d150ed452ad # v6.0.1
with:
go-version: '1.25'
- name: create build directories
run: |
mkdir -p dist
mkdir -p .sc/stacks/dist/bundle
- name: build sc for ${{ matrix.os }}/${{ matrix.arch }}
env:
GOOS: ${{ matrix.os }}
GOARCH: ${{ matrix.arch }}
CGO_ENABLED: "0"
run: |
echo "Building for ${GOOS}/${GOARCH}..."
if [ "${GOOS}" = "windows" ]; then export EXT=".exe"; else export EXT=""; fi
go build -ldflags "-s -w" -o dist/${GOOS}-${GOARCH}/sc${EXT} ./cmd/sc
tar -czf .sc/stacks/dist/bundle/sc-${GOOS}-${GOARCH}.tar.gz -C dist/${GOOS}-${GOARCH} sc${EXT}
- name: upload build artifacts
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: sc-${{ matrix.os }}-${{ matrix.arch }}
path: .sc/stacks/dist/bundle/sc-${{ matrix.os }}-${{ matrix.arch }}.tar.gz
retention-days: 1
build-binaries:
name: Build ${{ matrix.target }}
runs-on: blacksmith-8vcpu-ubuntu-2204
needs: build-setup
strategy:
matrix:
include:
- target: github-actions
cmd: github-actions
output: dist/github-actions
- target: cloud-helpers
cmd: cloud-helpers
output: dist/cloud-helpers
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go with Blacksmith caching
uses: useblacksmith/setup-go@647ac649bd5b480f2a262e3e3e5f4d150ed452ad # v6.0.1
with:
go-version: '1.25'
- name: create build directories
run: |
mkdir -p dist
- name: build ${{ matrix.target }}
env:
CGO_ENABLED: "0"
run: |
go build -a -installsuffix cgo -ldflags "-s -w" -o ${{ matrix.output }} ./cmd/${{ matrix.cmd }}
- name: upload ${{ matrix.target }} binary
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: ${{ matrix.target }}-binary
path: ${{ matrix.output }}
retention-days: 1
build-github-actions-staging:
name: Build github-actions-staging
runs-on: blacksmith-8vcpu-ubuntu-2204
needs: build-setup
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go with Blacksmith caching
uses: useblacksmith/setup-go@647ac649bd5b480f2a262e3e3e5f4d150ed452ad # v6.0.1
with:
go-version: '1.25'
- name: build github-actions-staging
run: |
mkdir -p bin
go build -ldflags "-s -w" -a -installsuffix cgo -o bin/github-actions ./cmd/github-actions
- name: upload github-actions-staging binary
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
with:
name: github-actions-staging-binary
path: bin/github-actions
retention-days: 1
test:
name: Run tests
runs-on: blacksmith-8vcpu-ubuntu-2204
needs: build-setup
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Go with Blacksmith caching
uses: useblacksmith/setup-go@647ac649bd5b480f2a262e3e3e5f4d150ed452ad # v6.0.1
with:
go-version: '1.25'
- name: test
run: |
go test ./...
finalize:
name: Finalize build in branch
runs-on: ubuntu-latest
if: ${{ always() }}
permissions:
contents: write
needs:
- build-setup
- build-platforms
- build-binaries
- build-github-actions-staging
- test
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
if: ${{ always() }}
with:
persist-credentials: false
- name: Extract git reference
id: extract_git_ref
if: ${{ always() }}
shell: bash
env:
COMMIT_MESSAGE: ${{ github.event.head_commit.message || github.event.workflow_run.head_commit.message }}
run: |-
message="$(printf '%s' "$COMMIT_MESSAGE" | tr -d '\n')"
echo "branch=$GITHUB_REF_NAME" >> $GITHUB_OUTPUT
echo "message=$message" >> $GITHUB_OUTPUT
echo "author=$GITHUB_ACTOR" >> $GITHUB_OUTPUT
echo "url=$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> $GITHUB_OUTPUT
- name: Notify Telegram (success)
if: ${{ success() && !contains(needs.*.result, 'failure') }}
continue-on-error: true
uses: simple-container-com/actions/notify-telegram@main
with:
chat-id: ${{ needs.build-setup.outputs.cicd-bot-telegram-chat-id }}
token: ${{ needs.build-setup.outputs.cicd-bot-telegram-token }}
text: '✅ CI passed: '
link-url: ${{ github.event.pull_request.html_url || format('{0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id) }}
link-text: "${{ github.event.pull_request.title && format('PR #{0}: {1}', github.event.pull_request.number, github.event.pull_request.title) || github.workflow }}"
suffix: ' on ${{ github.head_ref || github.ref_name }} by ${{ steps.extract_git_ref.outputs.author }}'
- name: Notify Telegram (failure)
if: ${{ failure() || contains(needs.*.result, 'failure') }}
continue-on-error: true
uses: simple-container-com/actions/notify-telegram@main
with:
chat-id: ${{ needs.build-setup.outputs.cicd-bot-telegram-chat-id }}
token: ${{ needs.build-setup.outputs.cicd-bot-telegram-token }}
text: '❗ CI failed: '
link-url: ${{ github.event.pull_request.html_url || format('{0}/{1}/actions/runs/{2}', github.server_url, github.repository, github.run_id) }}
link-text: "${{ github.event.pull_request.title && format('PR #{0}: {1}', github.event.pull_request.number, github.event.pull_request.title) || github.workflow }}"
suffix: ' on ${{ github.head_ref || github.ref_name }} by ${{ steps.extract_git_ref.outputs.author }}'
- name: Build failed due to previously failed steps
id: fail_if_needed
if: ${{ failure() || contains(needs.*.result, 'failure') }}
shell: bash
run: |-
exit 1