Skip to content

Commit 41076b8

Browse files
Merge pull request #128 from blacklanternsecurity/helmifying
Helmification
2 parents 1f79259 + 512c534 commit 41076b8

15 files changed

Lines changed: 890 additions & 23 deletions

.github/workflows/docker-tests.yml

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
docker-publish:
2929
runs-on: ubuntu-latest
3030
needs: docker-test
31-
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/stable' }}
31+
if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev') }}
3232

3333
steps:
3434
- name: Checkout code
@@ -61,39 +61,46 @@ jobs:
6161
images: blacklanternsecurity/bbot-server
6262
tags: |
6363
type=ref,event=branch
64-
type=ref,event=pr
6564
type=sha,prefix=sha-
66-
type=raw,value=latest,enable={{is_default_branch}}
67-
type=raw,value=v${{ steps.version.outputs.major }}
68-
type=raw,value=v${{ steps.version.outputs.minor }}
69-
type=raw,value=v${{ steps.version.outputs.version }}
65+
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/stable' }}
66+
type=raw,value=v${{ steps.version.outputs.major }},enable=${{ github.ref == 'refs/heads/stable' }}
67+
type=raw,value=v${{ steps.version.outputs.minor }},enable=${{ github.ref == 'refs/heads/stable' }}
68+
type=raw,value=v${{ steps.version.outputs.version }},enable=${{ github.ref == 'refs/heads/stable' }}
7069
7170
- name: Build and push Docker image
7271
uses: docker/build-push-action@v6
7372
with:
73+
context: .
7474
push: true
7575
tags: ${{ steps.meta.outputs.tags }}
7676
labels: ${{ steps.meta.outputs.labels }}
7777
cache-from: type=gha
7878
cache-to: type=gha,mode=max
7979

80-
- name: Clean up old Docker Hub tags (up to 50 most recent tags plus 'latest')
80+
- name: Clean up old Docker Hub tags (keep 50 most recent plus protected tags)
8181
run: |
8282
# Install jq for JSON processing
8383
sudo apt-get update && sudo apt-get install -y jq
8484
8585
echo "Cleaning up bbot-server tags..."
8686
87+
# Protected tags that should never be deleted
88+
PROTECTED="latest stable dev v${{ steps.version.outputs.major }} v${{ steps.version.outputs.minor }} v${{ steps.version.outputs.version }}"
89+
8790
tags_response=$(curl -s -H "Authorization: Bearer ${{ secrets.DOCKER_TOKEN }}" \
88-
"https://hub.docker.com/v2/repositories/bbot-server}/tags/?page_size=100")
91+
"https://hub.docker.com/v2/repositories/blacklanternsecurity/bbot-server/tags/?page_size=100")
8992
90-
tags_to_delete=$(echo "$tags_response" | jq -r '.results[] | select(.name != "latest") | [.last_updated, .name] | @tsv' | \
91-
sort -r | tail -n +51 | cut -f2)
93+
tags_to_delete=$(echo "$tags_response" | jq -r '.results[].name' | sort -r | tail -n +51)
9294
9395
for tag in $tags_to_delete; do
96+
# Skip protected tags
97+
if echo "$PROTECTED" | grep -qw "$tag"; then
98+
echo "Skipping protected tag: $tag"
99+
continue
100+
fi
94101
echo "Deleting bbot-server tag: $tag"
95102
curl -X DELETE -H "Authorization: Bearer ${{ secrets.DOCKER_TOKEN }}" \
96-
"https://hub.docker.com/v2/repositories/bbot-server/tags/$tag/"
103+
"https://hub.docker.com/v2/repositories/blacklanternsecurity/bbot-server/tags/$tag/"
97104
done
98105
99-
echo "Cleanup completed for bbot-server. Kept 50 most recent tags plus 'latest'."
106+
echo "Cleanup completed for bbot-server."

.github/workflows/helm-tests.yml

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
name: helm tests
2+
on:
3+
push:
4+
branches:
5+
- stable
6+
- dev
7+
pull_request:
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.event.pull_request.number || github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
helm-test:
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- name: Checkout code
19+
uses: actions/checkout@v6
20+
21+
- name: Set up Python
22+
uses: actions/setup-python@v6
23+
with:
24+
python-version: '3.x'
25+
26+
- name: Install Python dependencies
27+
run: pip install requests
28+
29+
- name: Install kubectl
30+
uses: azure/setup-kubectl@v4
31+
32+
- name: Install Helm
33+
uses: azure/setup-helm@v4
34+
35+
- name: Install minikube
36+
uses: medyagh/setup-minikube@latest
37+
38+
- name: Run helm deployment tests
39+
run: python test_helm_deployment.py
40+
41+
- name: Cleanup minikube
42+
if: always()
43+
run: minikube delete
44+
45+
helm-publish:
46+
runs-on: ubuntu-latest
47+
needs: helm-test
48+
if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/stable' || github.ref == 'refs/heads/dev') }}
49+
50+
steps:
51+
- name: Checkout code
52+
uses: actions/checkout@v6
53+
54+
- name: Install uv
55+
uses: astral-sh/setup-uv@v7
56+
57+
- name: Get version from pyproject.toml
58+
id: version
59+
run: |
60+
VERSION=$(uv version --short)
61+
echo "version=$VERSION" >> $GITHUB_OUTPUT
62+
63+
- name: Install Helm
64+
uses: azure/setup-helm@v4
65+
66+
- name: Update Chart.yaml version and appVersion
67+
run: |
68+
VERSION="${{ steps.version.outputs.version }}"
69+
CHART_VERSION="$VERSION"
70+
IMAGE_TAG="stable"
71+
if [ "${{ github.ref }}" = "refs/heads/dev" ]; then
72+
CHART_VERSION="${VERSION}-dev"
73+
IMAGE_TAG="dev"
74+
fi
75+
sed -i "s/^version:.*/version: ${CHART_VERSION}/" helm/Chart.yaml
76+
sed -i "s/^appVersion:.*/appVersion: \"${VERSION}\"/" helm/Chart.yaml
77+
# ensure the packaged chart defaults to the correct docker image tag
78+
sed -i "s/^ tag:.*/ tag: \"${IMAGE_TAG}\"/" helm/values.yaml
79+
echo "Chart version: $CHART_VERSION"
80+
echo "App version: $VERSION"
81+
echo "Image tag: $IMAGE_TAG"
82+
cat helm/Chart.yaml
83+
84+
- name: Build Helm dependencies
85+
run: helm dependency build helm/
86+
87+
- name: Package Helm chart
88+
run: helm package helm/
89+
90+
- name: Login to Docker Hub OCI registry
91+
run: echo "${{ secrets.DOCKER_TOKEN }}" | helm registry login registry-1.docker.io -u blacklanternsecurity --password-stdin
92+
93+
- name: Push Helm chart to Docker Hub
94+
run: helm push bbot-server-*.tgz oci://registry-1.docker.io/blacklanternsecurity

Dockerfile

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
FROM ghcr.io/astral-sh/uv:python3.11-trixie
22
RUN apt-get -y update && apt-get -y install curl jq
3-
COPY . /app
43
WORKDIR /app
4+
COPY pyproject.toml uv.lock ./
5+
RUN uv sync --frozen --no-install-project
6+
COPY . .
57
RUN uv sync --frozen
8+
RUN useradd -u 1000 -m bbot && chown -R bbot:bbot /app
9+
USER bbot
610
ENV PATH="/app/.venv/bin:$PATH"
711
EXPOSE 8807
812
CMD ["uv", "run", "bbctl", "server", "start", "--api-only"]

bbot_server/config.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,10 @@
2626
if not BBOT_SERVER_CONFIG_PATH.exists():
2727
try:
2828
BBOT_SERVER_CONFIG_PATH.parent.mkdir(parents=True, exist_ok=True)
29-
BBOT_SERVER_CONFIG_PATH.touch(mode=0o600)
29+
# 644 permissions are necessary because we cannot predict the UID of the user running `bbctl`.
30+
# since the config is mapped into the Docker container, BBOT server must have permissions to read it
31+
# the alternative is running the BBOT server container as root
32+
BBOT_SERVER_CONFIG_PATH.touch(mode=0o644)
3033
# fill with commented defaults
3134
with open(BBOT_SERVER_CONFIG_PATH, "w") as f:
3235
with open(BBOT_SERVER_DEFAULTS_PATH, "r") as defaults_file:

compose.yml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ x-bbot-server-base: &bbot-server-base
33
context: .
44
restart: unless-stopped
55
volumes:
6-
- "${BBOT_SERVER_CONFIG:-~/.config/bbot_server/config.yml}:/root/.config/bbot_server/config.yml"
6+
- "${BBOT_SERVER_CONFIG:-~/.config/bbot_server/config.yml}:/home/bbot/.config/bbot_server/config.yml"
77
- ./bbot_server:/app/bbot_server
88
- ./bbot_server/defaults_docker.yml:/app/bbot_server/defaults.yml
99

@@ -32,14 +32,6 @@ services:
3232
server:
3333
condition: service_healthy
3434

35-
agent:
36-
<<: *bbot-server-base
37-
command: ["bbctl", "agent", "start"]
38-
entrypoint: ["bash", "/app/bbot_server/default_agent.sh"]
39-
depends_on:
40-
server:
41-
condition: service_healthy
42-
4335
mongodb:
4436
image: mongo:latest
4537
restart: unless-stopped

helm/Chart.lock

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
dependencies:
2+
- name: mongodb
3+
repository: https://charts.bitnami.com/bitnami
4+
version: 18.6.1
5+
- name: redis
6+
repository: https://charts.bitnami.com/bitnami
7+
version: 23.2.12
8+
digest: sha256:b7c9095489913f065ee0cca4ec6aee1b320e07fd089f693360d42501a1220615
9+
generated: "2026-02-25T16:20:43.56532327-05:00"

helm/Chart.yaml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
apiVersion: v2
2+
name: bbot-server
3+
description: Helm chart for BBOT Server (API + Watchdog)
4+
type: application
5+
version: 0.1.0
6+
appVersion: "0.1.0"
7+
dependencies:
8+
- name: mongodb
9+
version: "18.x.x"
10+
repository: "https://charts.bitnami.com/bitnami"
11+
- name: redis
12+
version: "23.x.x"
13+
repository: "https://charts.bitnami.com/bitnami"

helm/templates/ingress.yaml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{{- if .Values.ingress.enabled }}
2+
apiVersion: networking.k8s.io/v1
3+
kind: Ingress
4+
metadata:
5+
name: {{ .Release.Name }}-ingress
6+
labels:
7+
app: bbot-server
8+
app.kubernetes.io/instance: {{ .Release.Name | quote }}
9+
{{- with .Values.ingress.annotations }}
10+
annotations:
11+
{{- toYaml . | nindent 4 }}
12+
{{- end }}
13+
spec:
14+
{{- if .Values.ingress.className }}
15+
ingressClassName: {{ .Values.ingress.className }}
16+
{{- end }}
17+
{{- if .Values.ingress.tls }}
18+
tls:
19+
{{- range .Values.ingress.tls }}
20+
- hosts:
21+
{{- range .hosts }}
22+
- {{ . | quote }}
23+
{{- end }}
24+
secretName: {{ .secretName }}
25+
{{- end }}
26+
{{- end }}
27+
rules:
28+
{{- range .Values.ingress.hosts }}
29+
- host: {{ .host | quote }}
30+
http:
31+
paths:
32+
{{- range .paths }}
33+
- path: {{ .path }}
34+
pathType: {{ .pathType }}
35+
backend:
36+
service:
37+
name: {{ $.Release.Name }}-server
38+
port:
39+
number: {{ $.Values.server.service.port }}
40+
{{- end }}
41+
{{- end }}
42+
{{- end }}

helm/templates/secrets.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# BBOT Server API key (auto-generated on first install, preserved on upgrade)
2+
{{- $apiKeySecretName := .Values.secrets.existingApiKeySecret | default (printf "%s-api-key" .Release.Name) -}}
3+
{{- if not (lookup "v1" "Secret" .Release.Namespace $apiKeySecretName) }}
4+
apiVersion: v1
5+
kind: Secret
6+
metadata:
7+
name: {{ $apiKeySecretName }}
8+
labels:
9+
app.kubernetes.io/managed-by: "Helm"
10+
app.kubernetes.io/instance: {{ .Release.Name | quote }}
11+
annotations:
12+
helm.sh/resource-policy: keep
13+
type: Opaque
14+
data:
15+
{{- if .Values.secrets.apiKey }}
16+
api-key: {{ .Values.secrets.apiKey | b64enc }}
17+
{{- else }}
18+
api-key: {{ uuidv4 | b64enc }}
19+
{{- end }}
20+
{{- end }}

0 commit comments

Comments
 (0)