Skip to content
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
35 changes: 29 additions & 6 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,36 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Go 1.24
uses: actions/setup-go@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Go 1.26
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: 1.24
go-version: 1.26
- name: Lint
uses: golangci/golangci-lint-action@v7
uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9.2.0
with:
only-new-issues: true
version: v2.1.5
version: v2.12.2
check-manifests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Go 1.26
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: 1.26
- name: Run make manifests
run: make manifests
- name: Check for uncommitted changes
run: |
if ! git diff --exit-code; then
echo "❌ Generated manifests are out of sync!"
echo ""
echo "Please run 'make manifests' locally and commit the changes:"
echo " make manifests"
echo " git add -A"
echo " git commit -m 'chore: update generated manifests'"
echo ""
exit 1
fi
echo "✅ Generated manifests are up to date"
90 changes: 77 additions & 13 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,86 @@ on:
branches:
- "main"
create:
tags:
- "v*"
pull_request:
branches:
- "main"
workflow_dispatch:

jobs:
publish-charts:
# Package and push Helm charts to ghcr.io as OCI artifacts.
# Runs on pushes to main and feat/helm-charts (for testing), and on version tags.
# Charts are published to oci://ghcr.io/<owner>/charts, so the registry path
# automatically resolves to the correct owner regardless of which fork runs it.
# On a version tag (e.g. v0.14.0) the chart version is set to the tag (0.14.0),
# otherwise the chart version from Chart.yaml is used as-is.
runs-on: ubuntu-latest
if: github.event_name == 'push' || (github.event_name == 'create' && github.event.ref_type == 'tag')
permissions:
packages: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Set up Helm
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5
- name: Login to GitHub Container Registry
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Derive chart version
id: chart_version
run: |
if [[ "${{ github.event_name }}" == "create" && "${{ github.event.ref_type }}" == "tag" ]]; then
# Strip leading 'v' from the tag (e.g. v0.14.0 -> 0.14.0)
echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"
else
echo "version=" >> "$GITHUB_OUTPUT"
fi
- name: Package and push charts
run: |
REGISTRY="oci://ghcr.io/${{ github.repository_owner }}/charts"
VERSION="${{ steps.chart_version.outputs.version }}"
for chart in charts/*/; do
if [[ -n "$VERSION" ]]; then
helm package "$chart" --destination /tmp/helm-packages --version "$VERSION" --app-version "$VERSION"
else
helm package "$chart" --destination /tmp/helm-packages
fi
done
for pkg in /tmp/helm-packages/*.tgz; do
helm push "$pkg" "$REGISTRY"
done

release-charts:
# Publish Helm charts to the gh-pages branch via chart-releaser on version tags.
runs-on: ubuntu-latest
if: github.event_name == 'create' && github.event.ref_type == 'tag' && startsWith(github.event.ref, 'v')
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
fetch-depth: 0
- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
- name: Run chart-releaser
uses: helm/chart-releaser-action@cae68fefc6b5f367a0275617c9f83181ba54714f # v1.7.0
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"

docker:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Docker meta
id: meta
uses: docker/metadata-action@v3
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6
with:
# list of Docker images to use as base name for tags
images: |
Expand All @@ -35,24 +99,24 @@ jobs:
type=semver,pattern={{major}}
type=sha
- name: Set up QEMU
uses: docker/setup-qemu-action@v1
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4
- name: Login to DockerHub
uses: docker/login-action@v1
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
if: github.event.ref_type == 'tag' || github.event_name == 'workflow_dispatch'
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Login to GitHub Container Registry
uses: docker/login-action@v1
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4
if: github.event.ref_type == 'tag' || github.event_name == 'workflow_dispatch'
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v2
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
with:
context: .
platforms: ${{ github.event.ref_type == 'tag' && 'linux/amd64,linux/arm64' || 'linux/amd64' }}
Expand All @@ -61,18 +125,18 @@ jobs:
labels: ${{ steps.meta.outputs.labels }}
- name: Docker Hub Description
if: github.event.ref_type == 'tag' || github.event_name == 'workflow_dispatch'
uses: peter-evans/dockerhub-description@v3
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

appreciate you didn't set this up but it would produce meaningful security guarantees if we switch to a hash for actions

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done ✔️ I'll disclaim though that there's a lot of them so I let Claude do these updates for me. All seems to be working though.

uses: peter-evans/dockerhub-description@1b9a80c056b620d92cedb9d9b5a223409c68ddfa # v5
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: adyanth/cloudflare-operator
readme-filepath: ./README.md
short-description: "Cloudflare Operator Controller Manager"
- name: Setup Go 1.24
uses: actions/setup-go@v5
- name: Setup Go 1.26
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
if: github.event.ref_type == 'tag'
with:
go-version: 1.24
go-version: 1.26
- name: Build installer
if: github.event.ref_type == 'tag'
run: make build-installer
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Setup Go 1.24
uses: actions/setup-go@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Go 1.26
uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: 1.24
go-version: 1.26
- name: Test
run: make test
- name: Archive code coverage results
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: code-coverage
path: cover.out
Expand All @@ -33,8 +33,8 @@ jobs:
actions: read
pull-requests: write
steps:
- uses: actions/checkout@v2
- uses: fgrosse/go-coverage-report@v1.1.1
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- uses: fgrosse/go-coverage-report@cbeb2ab2e32591d690337146ba02a911cc566f3f # v1.3.0
with:
coverage-artifact-name: "code-coverage"
coverage-file-name: "cover.out"
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: "2"

run:
go: '1.24'
go: '1.26'
timeout: 5m
allow-parallel-runners: true

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build the manager binary
FROM golang:1.24 AS builder
FROM golang:1.26 AS builder
ARG TARGETOS
ARG TARGETARCH

Expand Down
12 changes: 10 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,17 @@ help: ## Display this help.
##@ Development

.PHONY: manifests
manifests: controller-gen ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
manifests: controller-gen helm-sync-crds helm-sync-versions ## Generate WebhookConfiguration, ClusterRole and CustomResourceDefinition objects.
$(CONTROLLER_GEN) rbac:roleName=manager-role crd webhook paths="./..." output:crd:artifacts:config=config/crd/bases

.PHONY: helm-sync-crds
helm-sync-crds: ## Sync CRD YAMLs from config/crd/bases into charts/cloudflare-operator/crds/
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

possibly I missed it, but we'll want some kind of CI time check to ensure that this has been run. something that runs the makefile command, and asserts that doing so doesn't produce a diff

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added a step to the lint workflow that should do this and give a helpful message if it fails

cp config/crd/bases/*.yaml charts/cloudflare-operator/crds/

.PHONY: helm-sync-versions
helm-sync-versions: ## Sync appVersion in charts/cloudflare-operator/Chart.yaml from VERSION
sed -i "s/^appVersion:.*/appVersion: \"$(VERSION)\"/" charts/cloudflare-operator/Chart.yaml

.PHONY: generate
generate: controller-gen ## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations.
$(CONTROLLER_GEN) object:headerFile="hack/boilerplate.go.txt" paths="./..."
Expand Down Expand Up @@ -215,7 +223,7 @@ GOLANGCI_LINT = $(LOCALBIN)/golangci-lint

## Tool Versions
KUSTOMIZE_VERSION ?= v5.4.3
CONTROLLER_TOOLS_VERSION ?= v0.16.1
CONTROLLER_TOOLS_VERSION ?= v0.21.0
ENVTEST_VERSION ?= release-0.19
GOLANGCI_LINT_VERSION ?= v2.1.5

Expand Down
4 changes: 4 additions & 0 deletions charts/cloudflare-operator/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.DS_Store
*.tgz
.git/
.gitignore
19 changes: 19 additions & 0 deletions charts/cloudflare-operator/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
apiVersion: v2
name: cloudflare-operator
description: >
Helm chart for the Cloudflare Operator controller manager.
Installs the controller Deployment, CRDs, RBAC, and ServiceAccount
required to manage Cloudflare Tunnels via Kubernetes custom resources.
type: application
version: 0.1.0
appVersion: "0.13.1"
keywords:
- cloudflare
- tunnel
- operator
home: https://github.com/adyanth/cloudflare-operator
sources:
- https://github.com/adyanth/cloudflare-operator
maintainers:
- name: adyanth
url: https://github.com/adyanth
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
---
apiVersion: apiextensions.k8s.io/v1
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

something just occurred to me, could these be symlinks?

kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.21.0
name: accesstunnels.networking.cfargotunnel.com
spec:
group: networking.cfargotunnel.com
names:
kind: AccessTunnel
listKind: AccessTunnelList
plural: accesstunnels
singular: accesstunnel
scope: Namespaced
versions:
- additionalPrinterColumns:
- jsonPath: .target.fqdn
name: Target
type: string
name: v1alpha1
schema:
openAPIV3Schema:
description: AccessTunnel is the Schema for the accesstunnels API
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
serviceToken:
description: AccessTunnelServiceToken defines the access auth if needed
properties:
CLOUDFLARE_ACCESS_SERVICE_TOKEN_ID:
default: CLOUDFLARE_ACCESS_SERVICE_TOKEN_ID
description: Key in the secret to use for Access Service Token ID,
defaults to CLOUDFLARE_ACCESS_SERVICE_TOKEN_ID
type: string
CLOUDFLARE_ACCESS_SERVICE_TOKEN_TOKEN:
default: CLOUDFLARE_ACCESS_SERVICE_TOKEN_TOKEN
description: Key in the secret to use for Access Service Token Token,
defaults to CLOUDFLARE_ACCESS_SERVICE_TOKEN_TOKEN
type: string
secretRef:
description: Access Service Token Secret
type: string
required:
- secretRef
type: object
status:
description: AccessTunnelStatus defines the observed state of Access
type: object
target:
description: AccessTunnelTarget defines the desired state of Access
properties:
fqdn:
description: |-
Fqdn specifies the DNS name to access
This is not validated and used as provided
type: string
image:
default: cloudflare/cloudflared:2025.4.0
description: cloudflared image to use
type: string
protocol:
default: tcp
description: Protocol to forward, better to use TCP?
enum:
- tcp
- rdp
- smb
- ssh
type: string
svc:
description: Service Config
properties:
name:
description: |-
Name of the new service to create
Defaults to the name of the Access object
type: string
port:
default: 8000
description: |-
Service port to expose with
Defaults to 8000
format: int32
maximum: 65535
minimum: 1
type: integer
type: object
required:
- fqdn
type: object
type: object
served: true
storage: true
subresources:
status: {}
Loading