Skip to content

Commit 6c75af2

Browse files
JAORMXclaude
andcommitted
feat: add GitHub Actions CI pipeline and ko release workflow (#4, #5)
Add reusable lint/test/build workflows composed by PR and main triggers, Trivy security scanning, and a ko+cosign container release on v* tags. All actions SHA-pinned, propolis sibling checkout for the go.mod replace directive, and script injection mitigations in run blocks. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0ecdb30 commit 6c75af2

9 files changed

Lines changed: 338 additions & 1 deletion

File tree

.github/workflows/build.yml

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
name: Build artifacts
5+
6+
on:
7+
workflow_call:
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
build:
14+
name: Build and Test
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout code
18+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
19+
20+
- name: Checkout propolis (sibling dependency)
21+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
22+
with:
23+
repository: stacklok/propolis
24+
ref: 6a81046b0472c54c877b965c34c97c094f373d74 # v0.1.0
25+
path: ../propolis
26+
27+
- name: Set up Go
28+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
29+
with:
30+
go-version-file: 'go.mod'
31+
cache: true
32+
33+
- name: Install Task
34+
uses: arduino/setup-task@b91d5d2c96a56797b48ac1e0e89220bf64044611 # v2
35+
with:
36+
version: '3.x'
37+
repo-token: ${{ secrets.GITHUB_TOKEN }}
38+
39+
- name: Build
40+
run: task build
41+
42+
- name: Test
43+
run: task test
44+
45+
- name: Upload build artifacts
46+
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6
47+
with:
48+
name: waggle
49+
path: bin/waggle
50+
retention-days: 7

.github/workflows/lint.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
name: Linting
5+
6+
on:
7+
workflow_call:
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
lint:
14+
name: Lint
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
18+
19+
- name: Checkout propolis (sibling dependency)
20+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
21+
with:
22+
repository: stacklok/propolis
23+
ref: 6a81046b0472c54c877b965c34c97c094f373d74 # v0.1.0
24+
path: ../propolis
25+
26+
- name: Set up Go
27+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
28+
with:
29+
go-version-file: 'go.mod'
30+
cache: true
31+
32+
- name: Lint
33+
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
34+
with:
35+
args: --timeout=5m

.github/workflows/release.yml

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
name: Release
5+
6+
on:
7+
push:
8+
tags:
9+
- 'v*'
10+
11+
permissions: {}
12+
13+
jobs:
14+
release:
15+
name: Release Container
16+
runs-on: ubuntu-latest
17+
permissions:
18+
contents: read
19+
packages: write
20+
id-token: write
21+
steps:
22+
- name: Checkout code
23+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
24+
with:
25+
fetch-depth: 0
26+
27+
- name: Checkout propolis (sibling dependency)
28+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
29+
with:
30+
repository: stacklok/propolis
31+
ref: 6a81046b0472c54c877b965c34c97c094f373d74 # v0.1.0
32+
path: ../propolis
33+
34+
- name: Set up Go
35+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
36+
with:
37+
go-version-file: 'go.mod'
38+
cache: true
39+
40+
- name: Install Task
41+
uses: arduino/setup-task@b91d5d2c96a56797b48ac1e0e89220bf64044611 # v2
42+
with:
43+
version: '3.x'
44+
repo-token: ${{ secrets.GITHUB_TOKEN }}
45+
46+
- name: Test
47+
run: task test
48+
49+
- name: Setup Ko
50+
uses: ko-build/setup-ko@d006021bd0c28d1ce33a07e7943d48b079944c8d # v0.9
51+
52+
- name: Log in to GitHub Container Registry
53+
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3
54+
with:
55+
registry: ghcr.io
56+
username: ${{ github.actor }}
57+
password: ${{ secrets.GITHUB_TOKEN }}
58+
59+
- name: Extract tag version
60+
id: tag
61+
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
62+
63+
- name: Set repository owner lowercase
64+
id: repo_owner
65+
env:
66+
REPO_OWNER: ${{ github.repository_owner }}
67+
run: echo "OWNER=$(echo "$REPO_OWNER" | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT
68+
69+
- name: Build and push container
70+
env:
71+
KO_DOCKER_REPO: ghcr.io/${{ steps.repo_owner.outputs.OWNER }}/waggle
72+
VERSION: ${{ steps.tag.outputs.VERSION }}
73+
CREATION_TIME: ${{ github.event.head_commit.timestamp }}
74+
run: |
75+
ko build \
76+
--bare \
77+
--sbom=spdx \
78+
--platform=linux/amd64,linux/arm64 \
79+
--tags $VERSION,latest \
80+
./cmd/waggle
81+
82+
- name: Install Cosign
83+
uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0
84+
85+
- name: Sign Image with Cosign
86+
env:
87+
KO_DOCKER_REPO: ghcr.io/${{ steps.repo_owner.outputs.OWNER }}/waggle
88+
TAG_VERSION: ${{ steps.tag.outputs.VERSION }}
89+
GH_REF: ${{ github.ref }}
90+
run: |
91+
TAG=$(echo "$TAG_VERSION" | sed 's/+/_/g')
92+
cosign sign -y "$KO_DOCKER_REPO:$TAG"
93+
if [[ "$GH_REF" == refs/tags/* ]]; then
94+
cosign sign -y "$KO_DOCKER_REPO:latest"
95+
fi

.github/workflows/run-on-main.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# These set of workflows run on every push to the main branch
5+
name: Main build
6+
permissions:
7+
contents: read
8+
9+
on:
10+
workflow_dispatch:
11+
push:
12+
branches: [ main ]
13+
14+
jobs:
15+
linting:
16+
name: Linting
17+
uses: ./.github/workflows/lint.yml
18+
tests:
19+
name: Tests
20+
uses: ./.github/workflows/test.yml
21+
build:
22+
name: Build
23+
uses: ./.github/workflows/build.yml

.github/workflows/run-on-pr.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
# These set of workflows run on every pull request
5+
name: PR Checks
6+
permissions:
7+
contents: read
8+
9+
on:
10+
workflow_dispatch:
11+
pull_request:
12+
13+
jobs:
14+
linting:
15+
name: Linting
16+
uses: ./.github/workflows/lint.yml
17+
tests:
18+
name: Tests
19+
uses: ./.github/workflows/test.yml

.github/workflows/security.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
name: Security Scan
5+
6+
on:
7+
pull_request:
8+
branches: [ main ]
9+
schedule:
10+
- cron: '0 0 * * 0' # Run weekly on Sundays at midnight
11+
12+
permissions:
13+
contents: read
14+
security-events: write
15+
16+
jobs:
17+
trivy-scan:
18+
name: Trivy Security Scan
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout code
22+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
23+
24+
- name: Run Trivy vulnerability scanner in repo mode
25+
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
26+
with:
27+
scan-type: 'fs'
28+
ignore-unfixed: true
29+
format: 'sarif'
30+
output: 'trivy-results.sarif'
31+
severity: 'CRITICAL,HIGH'
32+
33+
- name: Upload Trivy scan results to GitHub Security tab
34+
uses: github/codeql-action/upload-sarif@19b2f06db2b6f5108140aeb04014ef02b648f789 # v4
35+
if: always()
36+
with:
37+
sarif_file: 'trivy-results.sarif'
38+
category: 'trivy-fs'
39+
40+
- name: Run Trivy vulnerability scanner in IaC mode
41+
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
42+
with:
43+
scan-type: 'config'
44+
hide-progress: false
45+
format: 'sarif'
46+
output: 'trivy-config-results.sarif'
47+
exit-code: '1'
48+
severity: 'CRITICAL,HIGH'
49+
50+
- name: Upload Trivy IaC scan results to GitHub Security tab
51+
uses: github/codeql-action/upload-sarif@19b2f06db2b6f5108140aeb04014ef02b648f789 # v4
52+
if: always()
53+
with:
54+
sarif_file: 'trivy-config-results.sarif'
55+
category: 'trivy-config'

.github/workflows/test.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
name: Tests
5+
6+
on:
7+
workflow_call:
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
test:
14+
name: Test
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
18+
19+
- name: Checkout propolis (sibling dependency)
20+
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
21+
with:
22+
repository: stacklok/propolis
23+
ref: 6a81046b0472c54c877b965c34c97c094f373d74 # v0.1.0
24+
path: ../propolis
25+
26+
- name: Set up Go
27+
uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6
28+
with:
29+
go-version-file: 'go.mod'
30+
cache: true
31+
32+
- name: Install Task
33+
uses: arduino/setup-task@b91d5d2c96a56797b48ac1e0e89220bf64044611 # v2
34+
with:
35+
version: '3.x'
36+
repo-token: ${{ secrets.GITHUB_TOKEN }}
37+
38+
- name: Test
39+
run: task test

.ko.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# SPDX-FileCopyrightText: Copyright 2025 Stacklok, Inc.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
builds:
5+
- id: waggle
6+
dir: .
7+
main: ./cmd/waggle
8+
ldflags:
9+
- -X main.version={{.Env.VERSION}}
10+
- -X main.commit={{.Env.GITHUB_SHA}}
11+
- -X main.buildDate={{.Env.CREATION_TIME}}
12+
labels:
13+
org.opencontainers.image.created: "{{.Env.CREATION_TIME}}"
14+
org.opencontainers.image.description: "Waggle - MCP server for isolated code execution via propolis microVMs"
15+
org.opencontainers.image.licenses: "Apache-2.0"
16+
org.opencontainers.image.revision: "{{.Env.GITHUB_SHA}}"
17+
org.opencontainers.image.source: "{{.Env.GITHUB_SERVER_URL}}/{{.Env.GITHUB_REPOSITORY}}"
18+
org.opencontainers.image.title: "waggle"
19+
org.opencontainers.image.url: "{{.Env.GITHUB_SERVER_URL}}/{{.Env.GITHUB_REPOSITORY}}"
20+
org.opencontainers.image.version: "{{.Env.VERSION}}"

renovate.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
33
"extends": [
4-
"config:recommended"
4+
"config:recommended",
5+
"helpers:pinGitHubActionDigests"
56
]
67
}

0 commit comments

Comments
 (0)