From d9e13ab2ab670719735b9481ecadf996444e18d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20=22Pisco=22=20Fernandes?= Date: Thu, 4 Sep 2025 15:59:44 +0100 Subject: [PATCH 1/3] TUN-9803: Add windows builds to gitlab-ci --- .ci/ci-image.gitlab-ci.yml | 33 ++++ .ci/commons.gitlab-ci.yml | 31 ++++ .ci/image/.docker-images | 2 + .ci/image/Dockerfile | 25 +++ .ci/mac.gitlab-ci.yml | 66 ++++++++ .ci/release.gitlab-ci.yml | 39 +++++ {.teamcity => .ci/scripts}/mac/build.sh | 0 {.teamcity => .ci/scripts}/mac/install-go.sh | 0 {.teamcity => .ci/scripts}/package-windows.sh | 10 +- {.teamcity => .ci/scripts}/windows/builds.ps1 | 24 ++- .ci/scripts/windows/component-test.ps1 | 40 +++++ .ci/scripts/windows/go-wrapper.ps1 | 69 ++++++++ .ci/windows.gitlab-ci.yml | 80 +++++++++ .gitlab-ci.yml | 154 ++++-------------- .teamcity/windows/component-test.ps1 | 47 ------ Makefile | 14 +- cfsetup.yaml | 22 --- component-tests/test_token.py | 2 +- component-tests/util.py | 1 + 19 files changed, 443 insertions(+), 216 deletions(-) create mode 100644 .ci/ci-image.gitlab-ci.yml create mode 100644 .ci/commons.gitlab-ci.yml create mode 100644 .ci/image/.docker-images create mode 100644 .ci/image/Dockerfile create mode 100644 .ci/mac.gitlab-ci.yml create mode 100644 .ci/release.gitlab-ci.yml rename {.teamcity => .ci/scripts}/mac/build.sh (100%) rename {.teamcity => .ci/scripts}/mac/install-go.sh (100%) rename {.teamcity => .ci/scripts}/package-windows.sh (75%) rename {.teamcity => .ci/scripts}/windows/builds.ps1 (59%) create mode 100644 .ci/scripts/windows/component-test.ps1 create mode 100644 .ci/scripts/windows/go-wrapper.ps1 create mode 100644 .ci/windows.gitlab-ci.yml delete mode 100644 .teamcity/windows/component-test.ps1 diff --git a/.ci/ci-image.gitlab-ci.yml b/.ci/ci-image.gitlab-ci.yml new file mode 100644 index 00000000..ea5a8623 --- /dev/null +++ b/.ci/ci-image.gitlab-ci.yml @@ -0,0 +1,33 @@ +# Builds a custom CI Image when necessary + +include: + ##################################################### + ############## Build and Push CI Image ############## + ##################################################### + - component: $CI_SERVER_FQDN/cloudflare/ci/docker-image/build-push-image@~latest + inputs: + stage: pre-build + jobPrefix: ci-image + # runOnChangesTo: [".ci/image/**"] + # runOnMR: true + # runOnBranches: '^master$' + runOnBranches: "^.+$" + commentImageRefs: false + runner: vm-linux-x86-4cpu-8gb + EXTRA_DIB_ARGS: "--manifest=.ci/image/.docker-images" + + ##################################################### + ## Resolve the image reference for downstream jobs ## + ##################################################### + - component: $CI_SERVER_FQDN/cloudflare/ci/docker-image/get-image-ref@~latest + inputs: + stage: pre-build + jobPrefix: ci-image + # runOnMR: true + # runOnBranches: '^master$' + runOnBranches: "^.+$" + IMAGE_PATH: "$REGISTRY_HOST/stash/tun/cloudflared/ci-image/master" + VARIABLE_NAME: BUILD_IMAGE + needs: + - job: ci-image-build-push-image + optional: true diff --git a/.ci/commons.gitlab-ci.yml b/.ci/commons.gitlab-ci.yml new file mode 100644 index 00000000..7eea1e5e --- /dev/null +++ b/.ci/commons.gitlab-ci.yml @@ -0,0 +1,31 @@ +## A set of predefined rules to use on the different jobs +.default-rules: + # Rules to run the job only on the master branch + run-on-master: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + when: always + - when: never + # Rules to run the job only on branches that are not master. This is needed because for now + # we need to keep a similar behavior due to the integration with teamcity, which requires us + # to not trigger pipelines on tags and/or merge requests. + run-on-branch: + - if: $CI_COMMIT_TAG + when: never + - if: $CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH + when: always + - when: never + +# This before_script is injected into every job that runs on master meaning that if there is no tag the step +# will succeed but only write "No tag present - Skipping" to the console. +.check-tag: + before_script: + - | + # Check if there is a Git tag pointing to HEAD + echo "Tag found: $(git tag --points-at HEAD | grep .)" + if git tag --points-at HEAD | grep .; then + echo "Tag found: $(git tag --points-at HEAD | grep .)" + export "VERSION=$(git tag --points-at HEAD | grep .)" + else + echo "No tag present — skipping." + exit 0 + fi \ No newline at end of file diff --git a/.ci/image/.docker-images b/.ci/image/.docker-images new file mode 100644 index 00000000..efa11f35 --- /dev/null +++ b/.ci/image/.docker-images @@ -0,0 +1,2 @@ +images: + - name: ci-image diff --git a/.ci/image/Dockerfile b/.ci/image/Dockerfile new file mode 100644 index 00000000..28513023 --- /dev/null +++ b/.ci/image/Dockerfile @@ -0,0 +1,25 @@ +ARG CLOUDFLARE_DOCKER_REGISTRY_HOST + +FROM ${CLOUDFLARE_DOCKER_REGISTRY_HOST:-registry.cfdata.org}/stash/cf/debian-images/bookworm/main:2025.7.0@sha256:6350da2f7e728dae2c1420f6dafc38e23cacc0b399d3d5b2f40fe48d9c8ff1ca + +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get install --no-install-recommends --allow-downgrades -y \ + build-essential \ + git \ + go-boring=1.24.4-1 \ + libffi-dev \ + python3-dev \ + python3-pip \ + python3-setuptools \ + python3-venv \ + # libmsi and libgcab are libraries the wixl binary depends on. + libmsi-dev \ + libgcab-dev && \ + rm -rf /var/lib/apt/lists/* && \ + # Install wixl + curl -o /usr/local/bin/wixl -L https://pkg.cloudflare.com/binaries/wixl && \ + chmod a+x /usr/local/bin/wixl && \ + mkdir -p opt + +WORKDIR /opt diff --git a/.ci/mac.gitlab-ci.yml b/.ci/mac.gitlab-ci.yml new file mode 100644 index 00000000..1fc433de --- /dev/null +++ b/.ci/mac.gitlab-ci.yml @@ -0,0 +1,66 @@ +include: + - local: .ci/commons.gitlab-ci.yml + +############################### +### Defaults for Mac Builds ### +############################### +.mac-build-defaults: &mac-build-defaults + rules: + - !reference [.default-rules, run-on-branch] + tags: + - "macstadium-${RUNNER_ARCH}" + parallel: + matrix: + - RUNNER_ARCH: [arm, intel] + cache: {} + +###################################### +### Build Cloudflared Mac Binaries ### +###################################### +build-cloudflared-macos: &build-mac + <<: *mac-build-defaults + stage: build + artifacts: + paths: + - artifacts/* + script: + - '[ "${RUNNER_ARCH}" = "arm" ] && export TARGET_ARCH=arm64' + - '[ "${RUNNER_ARCH}" = "intel" ] && export TARGET_ARCH=amd64' + - ARCH=$(uname -m) + - echo ARCH=$ARCH - TARGET_ARCH=$TARGET_ARCH + - ./.ci/scripts/mac/install-go.sh + - BUILD_SCRIPT=.ci/scripts/mac/build.sh + - if [[ ! -x ${BUILD_SCRIPT} ]] ; then exit ; fi + - set -euo pipefail + - echo "Executing ${BUILD_SCRIPT}" + - exec ${BUILD_SCRIPT} + +############################################### +### Build and Sign Cloudflared Mac Binaries ### +############################################### +build-and-sign-cloudflared-macos: + <<: *build-mac + rules: + - !reference [.default-rules, run-on-master] + secrets: + APPLE_DEV_CA_CERT: + vault: gitlab/cloudflare/tun/cloudflared/_branch/master/apple_dev_ca_cert_v2/data@kv + file: false + CFD_CODE_SIGN_CERT: + vault: gitlab/cloudflare/tun/cloudflared/_branch/master/cfd_code_sign_cert_v2/data@kv + file: false + CFD_CODE_SIGN_KEY: + vault: gitlab/cloudflare/tun/cloudflared/_branch/master/cfd_code_sign_key_v2/data@kv + file: false + CFD_CODE_SIGN_PASS: + vault: gitlab/cloudflare/tun/cloudflared/_branch/master/cfd_code_sign_pass_v2/data@kv + file: false + CFD_INSTALLER_CERT: + vault: gitlab/cloudflare/tun/cloudflared/_branch/master/cfd_installer_cert_v2/data@kv + file: false + CFD_INSTALLER_KEY: + vault: gitlab/cloudflare/tun/cloudflared/_branch/master/cfd_installer_key_v2/data@kv + file: false + CFD_INSTALLER_PASS: + vault: gitlab/cloudflare/tun/cloudflared/_branch/master/cfd_installer_pass_v2/data@kv + file: false diff --git a/.ci/release.gitlab-ci.yml b/.ci/release.gitlab-ci.yml new file mode 100644 index 00000000..a41247cb --- /dev/null +++ b/.ci/release.gitlab-ci.yml @@ -0,0 +1,39 @@ +include: + - local: .ci/commons.gitlab-ci.yml + +########################################### +### Push Cloudflared Binaries to Github ### +########################################### +release-cloudflared-to-github: + stage: release + image: $BUILD_IMAGE + extends: .check-tag + needs: + - ci-image-get-image-ref + - package-windows + - build-and-sign-cloudflared-macos + rules: + - !reference [.default-rules, run-on-master] + cache: + paths: + - .cache/pip + variables: + PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" + KV_NAMESPACE: 380e19aa04314648949b6ad841417ebe + KV_ACCOUNT: 5ab4e9dfbd435d24068829fda0077963 + secrets: + KV_API_TOKEN: + vault: gitlab/cloudflare/tun/cloudflared/_dev/cfd_kv_api_token/data@kv + file: false + API_KEY: + vault: gitlab/cloudflare/tun/cloudflared/_dev/cfd_github_api_key/data@kv + file: false + script: + - python3 --version ; pip --version # For debugging + - python3 -m venv venv + - source venv/bin/activate + - pip install pynacl==1.4.0 pygithub==1.55 + - echo $VERSION + - echo $TAG_EXISTS + - echo "Running release because tag exists." + - make gitlab-release diff --git a/.teamcity/mac/build.sh b/.ci/scripts/mac/build.sh similarity index 100% rename from .teamcity/mac/build.sh rename to .ci/scripts/mac/build.sh diff --git a/.teamcity/mac/install-go.sh b/.ci/scripts/mac/install-go.sh similarity index 100% rename from .teamcity/mac/install-go.sh rename to .ci/scripts/mac/install-go.sh diff --git a/.teamcity/package-windows.sh b/.ci/scripts/package-windows.sh similarity index 75% rename from .teamcity/package-windows.sh rename to .ci/scripts/package-windows.sh index 6715af92..d0020f03 100755 --- a/.teamcity/package-windows.sh +++ b/.ci/scripts/package-windows.sh @@ -1,19 +1,23 @@ +#!/bin/bash +python3 -m venv env +. env/bin/activate +pip install pynacl==1.4.0 pygithub==1.55 + VERSION=$(git describe --tags --always --match "[0-9][0-9][0-9][0-9].*.*") echo $VERSION export TARGET_OS=windows # This controls the directory the built artifacts go into -export BUILT_ARTIFACT_DIR=built_artifacts/ +export BUILT_ARTIFACT_DIR=artifacts/ export FINAL_ARTIFACT_DIR=artifacts/ mkdir -p $BUILT_ARTIFACT_DIR mkdir -p $FINAL_ARTIFACT_DIR windowsArchs=("amd64" "386") for arch in ${windowsArchs[@]}; do export TARGET_ARCH=$arch - # Copy exe into final directory + # Copy .exe from artifacts directory cp $BUILT_ARTIFACT_DIR/cloudflared-windows-$arch.exe ./cloudflared.exe make cloudflared-msi # Copy msi into final directory mv cloudflared-$VERSION-$arch.msi $FINAL_ARTIFACT_DIR/cloudflared-windows-$arch.msi - cp $BUILT_ARTIFACT_DIR/cloudflared-windows-$arch.exe $FINAL_ARTIFACT_DIR/cloudflared-windows-$arch.exe done diff --git a/.teamcity/windows/builds.ps1 b/.ci/scripts/windows/builds.ps1 similarity index 59% rename from .teamcity/windows/builds.ps1 rename to .ci/scripts/windows/builds.ps1 index ee43493f..e4a42ea2 100644 --- a/.teamcity/windows/builds.ps1 +++ b/.ci/scripts/windows/builds.ps1 @@ -2,27 +2,23 @@ Set-StrictMode -Version Latest $ErrorActionPreference = "Stop" $ProgressPreference = "SilentlyContinue" -# Relative path to working directory -$CloudflaredDirectory = "go\src\github.com\cloudflare\cloudflared" +$env:TARGET_OS = "windows" +$env:LOCAL_OS = "windows" -cd $CloudflaredDirectory +New-Item -Path ".\artifacts" -ItemType Directory Write-Output "Building for amd64" -$env:TARGET_OS = "windows" -$env:CGO_ENABLED = 1 $env:TARGET_ARCH = "amd64" -$env:Path = "$Env:Temp\go\bin;$($env:Path)" - -go env -go version - +$env:LOCAL_ARCH = "amd64" +$env:CGO_ENABLED = 1 & make cloudflared if ($LASTEXITCODE -ne 0) { throw "Failed to build cloudflared for amd64" } -copy .\cloudflared.exe .\cloudflared-windows-amd64.exe +copy .\cloudflared.exe .\artifacts\cloudflared-windows-amd64.exe Write-Output "Building for 386" -$env:CGO_ENABLED = 0 $env:TARGET_ARCH = "386" -make cloudflared +$env:LOCAL_ARCH = "386" +$env:CGO_ENABLED = 0 +& make cloudflared if ($LASTEXITCODE -ne 0) { throw "Failed to build cloudflared for 386" } -copy .\cloudflared.exe .\cloudflared-windows-386.exe \ No newline at end of file +copy .\cloudflared.exe .\artifacts\cloudflared-windows-386.exe diff --git a/.ci/scripts/windows/component-test.ps1 b/.ci/scripts/windows/component-test.ps1 new file mode 100644 index 00000000..abf024ff --- /dev/null +++ b/.ci/scripts/windows/component-test.ps1 @@ -0,0 +1,40 @@ +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +$env:TARGET_OS = "windows" +$env:LOCAL_OS = "windows" +$env:TARGET_ARCH = "amd64" +$env:LOCAL_ARCH = "amd64" +$env:CGO_ENABLED = 1 + +python --version +python -m pip --version + + +Write-Host "Building cloudflared" +& make cloudflared +if ($LASTEXITCODE -ne 0) { throw "Failed to build cloudflared" } + + +Write-Host "Running unit tests" +# Not testing with race detector because of https://github.com/golang/go/issues/61058 +# We already test it on other platforms +go test -failfast -v -mod=vendor ./... +if ($LASTEXITCODE -ne 0) { throw "Failed unit tests" } + + +# On Gitlab runners we need to add all of this addresses to the NO_PROXY list in order for the tests to run. +$env:NO_PROXY = "pypi.org,files.pythonhosted.org,api.cloudflare.com,argotunneltest.com,argotunnel.com,trycloudflare.com,${env:NO_PROXY}" +Write-Host "No Proxy: ${env:NO_PROXY}" +Write-Host "Running component tests" +try { + python -m pip --disable-pip-version-check install --upgrade -r component-tests/requirements.txt --use-pep517 + python component-tests/setup.py --type create + python -m pytest component-tests -o log_cli=true --log-cli-level=INFO + if ($LASTEXITCODE -ne 0) { + throw "Failed component tests" + } +} finally { + python component-tests/setup.py --type cleanup +} diff --git a/.ci/scripts/windows/go-wrapper.ps1 b/.ci/scripts/windows/go-wrapper.ps1 new file mode 100644 index 00000000..217553a3 --- /dev/null +++ b/.ci/scripts/windows/go-wrapper.ps1 @@ -0,0 +1,69 @@ +Param( + [string]$GoVersion, + [string]$ScriptToExecute +) + +# This script its a wrapper that downloads a specific version +# of go, adds it to the PATH and executes a script with that go +# version in the path. + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" + +# Get the path to the system's temporary directory. +$tempPath = [System.IO.Path]::GetTempPath() + +# Create a unique name for the new temporary folder. +$folderName = "go_" + (Get-Random) + +# Join the temp path and the new folder name to create the full path. +$fullPath = Join-Path -Path $tempPath -ChildPath $folderName + +# Store the current value of PATH environment variable. +$oldPath = $env:Path + +# Use a try...finally block to ensure the temporrary folder and PATH are cleaned up. +try { + # Create the temporary folder. + Write-Host "Creating temporary folder at: $fullPath" + $newTempFolder = New-Item -ItemType Directory -Path $fullPath -Force + + # Download go + $url = "https://go.dev/dl/$GoVersion.windows-amd64.zip" + $destinationFile = Join-Path -Path $newTempFolder.FullName -ChildPath "go$GoVersion.windows-amd64.zip" + Write-Host "Downloading go from: $url" + Invoke-WebRequest -Uri $url -OutFile $destinationFile + Write-Host "File downloaded to: $destinationFile" + + # Unzip the downloaded file. + Write-Host "Unzipping the file..." + Expand-Archive -Path $destinationFile -DestinationPath $newTempFolder.FullName -Force + Write-Host "File unzipped successfully." + + # Define the go/bin path wich is inside the temporary folder + $goBinPath = Join-Path -Path $fullPath -ChildPath "go\bin" + + # Add the go/bin path to the PATH environment variable. + $env:Path = "$goBinPath;$($env:Path)" + Write-Host "Added $goBinPath to the environment PATH." + + go env + go version + + & $ScriptToExecute +} finally { + # Cleanup: Remove the path from the environment variable and then the temporary folder. + Write-Host "Starting cleanup..." + + $env:Path = $oldPath + Write-Host "Reverted changes in the environment PATH." + + # Remove the temporary folder and its contents. + if (Test-Path -Path $fullPath) { + Remove-Item -Path $fullPath -Recurse -Force + Write-Host "Temporary folder and its contents have been removed." + } else { + Write-Host "Temporary folder does not exist, no cleanup needed." + } +} diff --git a/.ci/windows.gitlab-ci.yml b/.ci/windows.gitlab-ci.yml new file mode 100644 index 00000000..256c7ff4 --- /dev/null +++ b/.ci/windows.gitlab-ci.yml @@ -0,0 +1,80 @@ +include: + - local: .ci/commons.gitlab-ci.yml + +################################### +### Defaults for Windows Builds ### +################################### +.windows-build-defaults: &windows-build-defaults + rules: + - !reference [.default-rules, run-on-branch] + tags: + - windows-x86 + cache: {} + +########################################## +### Build Cloudflared Windows Binaries ### +########################################## +build-cloudflared-windows: + <<: *windows-build-defaults + stage: build + script: + - powershell -ExecutionPolicy Bypass -File ".\.ci\scripts\windows\go-wrapper.ps1" "${GO_VERSION}" ".\.ci\scripts\windows\builds.ps1" + artifacts: + paths: + - artifacts/* + +###################################################### +### Load Environment Variables for Component Tests ### +###################################################### +load-windows-env-variables: + rules: + - !reference [.default-rules, run-on-branch] + stage: pre-build + script: + - echo "COMPONENT_TESTS_CONFIG=component-test-config.yaml" >> windows.env + - echo "COMPONENT_TESTS_CONFIG_CONTENT=Y2xvdWRmbGFyZWRfYmluYXJ5OiBjbG91ZGZsYXJlZC5leGUKY3JlZGVudGlhbHNfZmlsZTogY3JlZC5qc29uCm9yaWdpbmNlcnQ6IGNlcnQucGVtCnpvbmVfZG9tYWluOiBhcmdvdHVubmVsdGVzdC5jb20Kem9uZV90YWc6IDQ4Nzk2ZjFlNzBiYjc2NjljMjliYjUxYmEyODJiZjY1" >> windows.env + - echo "DNS_API_TOKEN=$DNS_API_TOKEN" >> windows.env + # We have to encode the `COMPONENT_TESTS_ORIGINCERT` secret, because it content is a file, otherwise we can't export it using gitlab + - echo "COMPONENT_TESTS_ORIGINCERT=$(echo "$COMPONENT_TESTS_ORIGINCERT" | base64 -w0)" >> windows.env + secrets: + DNS_API_TOKEN: + vault: gitlab/cloudflare/tun/cloudflared/_dev/_terraform_atlantis/component_tests_token/data@kv + file: false + COMPONENT_TESTS_ORIGINCERT: + vault: gitlab/cloudflare/tun/cloudflared/_dev/component_tests_cert_pem/data@kv + file: false + artifacts: + access: 'none' + reports: + dotenv: windows.env + cache: {} + +################################### +### Run Windows Component Tests ### +################################### +component-tests-cloudflared-windows: + <<: *windows-build-defaults + stage: test + needs: ["load-windows-env-variables"] + script: + # We have to decode the secret we encoded on the `load-windows-env-variables` job + - $env:COMPONENT_TESTS_ORIGINCERT = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($env:COMPONENT_TESTS_ORIGINCERT)) + - powershell -ExecutionPolicy Bypass -File ".\.ci\scripts\windows\go-wrapper.ps1" "${GO_VERSION}" ".\.ci\scripts\windows\component-test.ps1" + +################################ +### Package Windows Binaries ### +################################ +package-windows: + rules: + - !reference [.default-rules, run-on-master] + stage: package + needs: + - ci-image-get-image-ref + - build-cloudflared-windows + image: $BUILD_IMAGE + script: + - .ci/scripts/package-windows.sh + cache: {} + artifacts: + paths: + - artifacts/* diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 9059de5e..a4ea2864 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -5,6 +5,7 @@ variables: GOPATH: "$CI_PROJECT_DIR/.go" GOMODCACHE: "$GOPATH/pkg/mod" GO_BIN_DIR: "$GOPATH/bin" + GO_VERSION: "go1.24.4" cache: # Cache Go modules and the binaries. @@ -15,49 +16,42 @@ cache: - ${GOPATH}/pkg/mod/ # For Go modules - ${GO_BIN_DIR}/ -stages: [build, release] - default: id_tokens: VAULT_ID_TOKEN: aud: https://vault.cfdata.org -# This before_script is injected into every job that runs on master meaning that if there is no tag the step -# will succeed but only write "No tag present - Skipping" to the console. -.check_tag: - before_script: - - | - # Check if there is a Git tag pointing to HEAD - echo "Tag found: $(git tag --points-at HEAD | grep .)" - if git tag --points-at HEAD | grep .; then - echo "Tag found: $(git tag --points-at HEAD | grep .)" - export "VERSION=$(git tag --points-at HEAD | grep .)" - else - echo "No tag present — skipping." - exit 0 - fi +stages: [pre-build, build, test, package, release] -## A set of predefined rules to use on the different jobs -.default_rules: - # Rules to run the job only on the master branch - run_on_master: - - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH - when: always - - when: never - # Rules to run the job only on branches that are not master. This is needed because for now - # we need to keep a similar behavior due to the integration with teamcity, which requires us - # to not trigger pipelines on tags and/or merge requests. - run_on_branch: - - if: $CI_COMMIT_TAG - when: never - - if: $CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH - when: always - - when: never +include: + ##################################################### + ########## Import Commons Configurations ############ + ##################################################### + - local: .ci/commons.gitlab-ci.yml + ##################################################### + ############# Build or Fetch CI Image ############### + ##################################################### + - local: .ci/ci-image.gitlab-ci.yml + + ##################################################### + ################## Windows Builds ################### + ##################################################### + - local: .ci/windows.gitlab-ci.yml + + ##################################################### + ################### macOS Builds #################### + ##################################################### + - local: .ci/mac.gitlab-ci.yml + + ##################################################### + ################# Release Packages ################## + ##################################################### + - local: .ci/release.gitlab-ci.yml # Template for Go setup, including caching and installation .go_setup: - image: docker-registry.cfdata.org/stash/devtools/ci-builders/golang-1.24/master:3090-3e32590@sha256:fc81df4f8322f022d93712ee40bb1e5752fdbe9868d1e5a23fd851ad6fbecb91 + image: docker-registry.cfdata.org/stash/devtools/ci-builders/golang-1.24/master:3219-cc8b513@sha256:4fe3ff47ba07f9b23429f49fbd063cc1a34156dd11b8113e325ad3762f94a1db before_script: - mkdir -p ${GOPATH} ${GOMODCACHE} ${GO_BIN_DIR} - export PATH=$PATH:${GO_BIN_DIR} @@ -71,102 +65,10 @@ default: echo "govulncheck found in cache, skipping installation."; fi -# ----------------------------------------------- -# Stage 1: Build on every PR -# ----------------------------------------------- -build_cloudflared_macos: &build - stage: build - rules: - - !reference [.default_rules, run_on_branch] - tags: - - "macstadium-${RUNNER_ARCH}" - parallel: - matrix: - - RUNNER_ARCH: [arm, intel] - artifacts: - paths: - - artifacts/* - script: - - '[ "${RUNNER_ARCH}" = "arm" ] && export TARGET_ARCH=arm64' - - '[ "${RUNNER_ARCH}" = "intel" ] && export TARGET_ARCH=amd64' - - ARCH=$(uname -m) - - echo ARCH=$ARCH - TARGET_ARCH=$TARGET_ARCH - - ./.teamcity/mac/install-go.sh - - BUILD_SCRIPT=.teamcity/mac/build.sh - - if [[ ! -x ${BUILD_SCRIPT} ]] ; then exit ; fi - - set -euo pipefail - - echo "Executing ${BUILD_SCRIPT}" - - exec ${BUILD_SCRIPT} - vulncheck: stage: build extends: .go_setup rules: - - !reference [.default_rules, run_on_branch] + - !reference [.default-rules, run-on-branch] script: - make vulncheck - -# ----------------------------------------------- -# Stage 1: Build and sign only on releases -# ----------------------------------------------- -build_and_sign_cloudflared_macos: - <<: *build - rules: - - !reference [.default_rules, run_on_master] - secrets: - APPLE_DEV_CA_CERT: - vault: gitlab/cloudflare/tun/cloudflared/_branch/master/apple_dev_ca_cert_v2/data@kv - file: false - CFD_CODE_SIGN_CERT: - vault: gitlab/cloudflare/tun/cloudflared/_branch/master/cfd_code_sign_cert_v2/data@kv - file: false - CFD_CODE_SIGN_KEY: - vault: gitlab/cloudflare/tun/cloudflared/_branch/master/cfd_code_sign_key_v2/data@kv - file: false - CFD_CODE_SIGN_PASS: - vault: gitlab/cloudflare/tun/cloudflared/_branch/master/cfd_code_sign_pass_v2/data@kv - file: false - CFD_INSTALLER_CERT: - vault: gitlab/cloudflare/tun/cloudflared/_branch/master/cfd_installer_cert_v2/data@kv - file: false - CFD_INSTALLER_KEY: - vault: gitlab/cloudflare/tun/cloudflared/_branch/master/cfd_installer_key_v2/data@kv - file: false - CFD_INSTALLER_PASS: - vault: gitlab/cloudflare/tun/cloudflared/_branch/master/cfd_installer_pass_v2/data@kv - file: false - -# ----------------------------------------------- -# Stage 2: Release to Github after building and signing -# ----------------------------------------------- -release_cloudflared_macos_to_github: - stage: release - image: docker-registry.cfdata.org/stash/tun/docker-images/cloudflared-ci/main:6-8616fe631b76-amd64@sha256:96f4fd05e66cec03e0864c1bcf09324c130d4728eef45ee994716da499183614 - extends: .check_tag - dependencies: - - build_and_sign_cloudflared_macos - rules: - - !reference [.default_rules, run_on_master] - cache: - paths: - - .cache/pip - variables: - PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" - KV_NAMESPACE: 380e19aa04314648949b6ad841417ebe - KV_ACCOUNT: 5ab4e9dfbd435d24068829fda0077963 - secrets: - KV_API_TOKEN: - vault: gitlab/cloudflare/tun/cloudflared/_dev/cfd_kv_api_token/data@kv - file: false - API_KEY: - vault: gitlab/cloudflare/tun/cloudflared/_dev/cfd_github_api_key/data@kv - file: false - script: - - python3 --version ; pip --version # For debugging - - python3 -m venv venv - - source venv/bin/activate - - pip install pynacl==1.4.0 pygithub==1.55 - - echo $VERSION - - echo $TAG_EXISTS - - echo "Running release because tag exists." - - make macos-release diff --git a/.teamcity/windows/component-test.ps1 b/.teamcity/windows/component-test.ps1 deleted file mode 100644 index f8e716d0..00000000 --- a/.teamcity/windows/component-test.ps1 +++ /dev/null @@ -1,47 +0,0 @@ -Set-StrictMode -Version Latest -$ErrorActionPreference = "Stop" -$ProgressPreference = "SilentlyContinue" - -$WorkingDirectory = Get-Location -$CloudflaredDirectory = "$WorkingDirectory\go\src\github.com\cloudflare\cloudflared" - -go env -go version - -$env:TARGET_OS = "windows" -$env:CGO_ENABLED = 1 -$env:TARGET_ARCH = "amd64" -$env:Path = "$Env:Temp\go\bin;$($env:Path)" - -python --version -python -m pip --version - -cd $CloudflaredDirectory - -go env -go version - -Write-Output "Building cloudflared" - -& make cloudflared -if ($LASTEXITCODE -ne 0) { throw "Failed to build cloudflared" } - -echo $LASTEXITCODE - -Write-Output "Running unit tests" - -# Not testing with race detector because of https://github.com/golang/go/issues/61058 -# We already test it on other platforms -go test -failfast -v -mod=vendor ./... -if ($LASTEXITCODE -ne 0) { throw "Failed unit tests" } - -Write-Output "Running component tests" - -python -m pip --disable-pip-version-check install --upgrade -r component-tests/requirements.txt --use-pep517 -python component-tests/setup.py --type create -python -m pytest component-tests -o log_cli=true --log-cli-level=INFO -if ($LASTEXITCODE -ne 0) { - python component-tests/setup.py --type cleanup - throw "Failed component tests" -} -python component-tests/setup.py --type cleanup diff --git a/Makefile b/Makefile index e9b411dc..fa694c94 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,13 @@ else DEB_PACKAGE_NAME := $(BINARY_NAME) endif -DATE := $(shell date -u -r RELEASE_NOTES '+%Y-%m-%d-%H%M UTC') +# Use git in windows since we don't have access to the `date` tool +ifeq ($(TARGET_OS), windows) + DATE := $(shell git log -1 --format="%ad" --date=format-local:'%Y-%m-%dT%H:%M UTC' -- RELEASE_NOTES) +else + DATE := $(shell date -u -r RELEASE_NOTES '+%Y-%m-%d-%H:%M UTC') +endif + VERSION_FLAGS := -X "main.Version=$(VERSION)" -X "main.BuildTime=$(DATE)" ifdef PACKAGE_MANAGER VERSION_FLAGS := $(VERSION_FLAGS) -X "github.com/cloudflare/cloudflared/cmd/cloudflared/updater.BuiltForPackageManager=$(PACKAGE_MANAGER)" @@ -64,6 +70,8 @@ else ifeq ($(LOCAL_ARCH),x86_64) TARGET_ARCH ?= amd64 else ifeq ($(LOCAL_ARCH),amd64) TARGET_ARCH ?= amd64 +else ifeq ($(LOCAL_ARCH),386) + TARGET_ARCH ?= 386 else ifeq ($(LOCAL_ARCH),i686) TARGET_ARCH ?= amd64 else ifeq ($(shell echo $(LOCAL_ARCH) | head -c 5),armv8) @@ -230,8 +238,8 @@ github-release: python3 github_release.py --path $(PWD)/built_artifacts --release-version $(VERSION) python3 github_message.py --release-version $(VERSION) -.PHONY: macos-release -macos-release: +.PHONY: gitlab-release +gitlab-release: python3 github_release.py --path $(PWD)/artifacts/ --release-version $(VERSION) .PHONY: r2-linux-release diff --git a/cfsetup.yaml b/cfsetup.yaml index dd01f650..aba6925e 100644 --- a/cfsetup.yaml +++ b/cfsetup.yaml @@ -123,28 +123,6 @@ bookworm: &bookworm - export GOOS=linux - export GOARCH=arm64 - make cloudflared-deb - package-windows: - build_dir: *build_dir - builddeps: - - *pinned_go - - build-essential - - python3-dev - - libffi-dev - - python3-setuptools - - python3-pip - - wget - # libmsi and libgcab are libraries the wixl binary depends on. - - libmsi-dev - - libgcab-dev - - python3-venv - pre-cache: - - wget https://github.com/sudarshan-reddy/msitools/releases/download/v0.101b/wixl -P /usr/local/bin - - chmod a+x /usr/local/bin/wixl - post-cache: - - python3 -m venv env - - . env/bin/activate - - pip install pynacl==1.4.0 pygithub==1.55 - - .teamcity/package-windows.sh test: build_dir: *build_dir builddeps: &build_deps_tests diff --git a/component-tests/test_token.py b/component-tests/test_token.py index ed99cb05..36b37239 100644 --- a/component-tests/test_token.py +++ b/component-tests/test_token.py @@ -1,7 +1,7 @@ import base64 import json -from setup import get_config_from_file, persist_origin_cert +from setup import get_config_from_file from util import start_cloudflared diff --git a/component-tests/util.py b/component-tests/util.py index ee63c24a..c7fd59c4 100644 --- a/component-tests/util.py +++ b/component-tests/util.py @@ -111,6 +111,7 @@ def inner_wait_tunnel_ready(tunnel_url=None, require_min_connections=1): metrics_url = f'http://localhost:{METRICS_PORT}/ready' with requests.Session() as s: + LOGGER.debug("Waiting for tunnel to be ready...") resp = send_request(s, metrics_url, True) ready_connections = resp.json()["readyConnections"] From 173396be90eb54181892848c31fbc9a11515de11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20=22Pisco=22=20Fernandes?= Date: Thu, 11 Sep 2025 11:33:24 +0100 Subject: [PATCH 2/3] TUN-9800: Migrate cloudflared-ci pipelines to Gitlab CI ## Summary This commit migrates the cloduflared ci pipelines, that built, tested and component tested the linux binaries to gitlab ci. The only thing that is remaining to move from teamcity to gitlab are now the release pipelines that run on master. Relates to TUN-9800 --- .ci/ci-image.gitlab-ci.yml | 12 ++-- .ci/commons.gitlab-ci.yml | 34 +++++++-- .ci/image/Dockerfile | 3 +- .ci/linux.gitlab-ci.yml | 90 ++++++++++++++++++++++++ .ci/mac.gitlab-ci.yml | 2 +- .ci/scripts/component-tests.sh | 25 +++++++ fmt-check.sh => .ci/scripts/fmt-check.sh | 3 +- .ci/scripts/windows/component-test.ps1 | 2 +- .ci/scripts/windows/go-wrapper.ps1 | 2 +- .ci/windows.gitlab-ci.yml | 22 +++--- .gitlab-ci.yml | 49 +++---------- Makefile | 36 +++++++--- component-tests/test_service.py | 5 +- component-tests/util.py | 7 +- 14 files changed, 209 insertions(+), 83 deletions(-) create mode 100644 .ci/linux.gitlab-ci.yml create mode 100755 .ci/scripts/component-tests.sh rename fmt-check.sh => .ci/scripts/fmt-check.sh (54%) diff --git a/.ci/ci-image.gitlab-ci.yml b/.ci/ci-image.gitlab-ci.yml index ea5a8623..e5202586 100644 --- a/.ci/ci-image.gitlab-ci.yml +++ b/.ci/ci-image.gitlab-ci.yml @@ -8,10 +8,9 @@ include: inputs: stage: pre-build jobPrefix: ci-image - # runOnChangesTo: [".ci/image/**"] - # runOnMR: true - # runOnBranches: '^master$' - runOnBranches: "^.+$" + runOnChangesTo: [".ci/image/**"] + runOnMR: true + runOnBranches: '^master$' commentImageRefs: false runner: vm-linux-x86-4cpu-8gb EXTRA_DIB_ARGS: "--manifest=.ci/image/.docker-images" @@ -23,9 +22,8 @@ include: inputs: stage: pre-build jobPrefix: ci-image - # runOnMR: true - # runOnBranches: '^master$' - runOnBranches: "^.+$" + runOnMR: true + runOnBranches: '^master$' IMAGE_PATH: "$REGISTRY_HOST/stash/tun/cloudflared/ci-image/master" VARIABLE_NAME: BUILD_IMAGE needs: diff --git a/.ci/commons.gitlab-ci.yml b/.ci/commons.gitlab-ci.yml index 7eea1e5e..990c5709 100644 --- a/.ci/commons.gitlab-ci.yml +++ b/.ci/commons.gitlab-ci.yml @@ -5,13 +5,19 @@ - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH when: always - when: never - # Rules to run the job only on branches that are not master. This is needed because for now - # we need to keep a similar behavior due to the integration with teamcity, which requires us - # to not trigger pipelines on tags and/or merge requests. - run-on-branch: + # Rules to run the job only on merge requests + run-on-mr: - if: $CI_COMMIT_TAG when: never - - if: $CI_PIPELINE_SOURCE != "merge_request_event" && $CI_COMMIT_BRANCH != $CI_DEFAULT_BRANCH + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + when: always + - when: never + # Rules to run the job on merge_requests and master branch + run-always: + - if: $CI_COMMIT_TAG + when: never + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + - if: $CI_COMMIT_BRANCH != null && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH when: always - when: never @@ -28,4 +34,20 @@ else echo "No tag present — skipping." exit 0 - fi \ No newline at end of file + fi + +.component-tests: + image: $BUILD_IMAGE + rules: + - !reference [.default-rules, run-always] + variables: + COMPONENT_TESTS_CONFIG: component-test-config.yaml + COMPONENT_TESTS_CONFIG_CONTENT: Y2xvdWRmbGFyZWRfYmluYXJ5OiBjbG91ZGZsYXJlZC5leGUKY3JlZGVudGlhbHNfZmlsZTogY3JlZC5qc29uCm9yaWdpbmNlcnQ6IGNlcnQucGVtCnpvbmVfZG9tYWluOiBhcmdvdHVubmVsdGVzdC5jb20Kem9uZV90YWc6IDQ4Nzk2ZjFlNzBiYjc2NjljMjliYjUxYmEyODJiZjY1 + secrets: + DNS_API_TOKEN: + vault: gitlab/cloudflare/tun/cloudflared/_dev/_terraform_atlantis/component_tests_token/data@kv + file: false + COMPONENT_TESTS_ORIGINCERT: + vault: gitlab/cloudflare/tun/cloudflared/_dev/component_tests_cert_pem/data@kv + file: false + cache: {} diff --git a/.ci/image/Dockerfile b/.ci/image/Dockerfile index 28513023..4e92860e 100644 --- a/.ci/image/Dockerfile +++ b/.ci/image/Dockerfile @@ -7,8 +7,9 @@ RUN apt-get update && \ apt-get install --no-install-recommends --allow-downgrades -y \ build-essential \ git \ - go-boring=1.24.4-1 \ + go-boring=1.24.6-1 \ libffi-dev \ + procps \ python3-dev \ python3-pip \ python3-setuptools \ diff --git a/.ci/linux.gitlab-ci.yml b/.ci/linux.gitlab-ci.yml new file mode 100644 index 00000000..e1104145 --- /dev/null +++ b/.ci/linux.gitlab-ci.yml @@ -0,0 +1,90 @@ +.golang-inputs: &golang_inputs + runOnMR: true + runOnBranches: '^master$' + outputDir: artifacts + runner: linux-x86-8cpu-16gb + stage: build + golangVersion: "boring-1.24" + CGO_ENABLED: 1 + +include: + ################### + ### Linux Build ### + ################### + - component: $CI_SERVER_FQDN/cloudflare/ci/golang/boring-make@~latest + inputs: + <<: *golang_inputs + jobPrefix: linux-build + GOLANG_MAKE_TARGET: ci-build + + ######################## + ### Linux FIPS Build ### + ######################## + - component: $CI_SERVER_FQDN/cloudflare/ci/golang/boring-make@~latest + inputs: + <<: *golang_inputs + jobPrefix: linux-fips-build + GOLANG_MAKE_TARGET: ci-fips-build + + ################# + ### Unit Tests ## + ################# + - component: $CI_SERVER_FQDN/cloudflare/ci/golang/boring-make@~latest + inputs: + <<: *golang_inputs + stage: test + jobPrefix: test + GOLANG_MAKE_TARGET: ci-test + + ###################### + ### Unit Tests FIPS ## + ###################### + - component: $CI_SERVER_FQDN/cloudflare/ci/golang/boring-make@~latest + inputs: + <<: *golang_inputs + stage: test + jobPrefix: test-fips + GOLANG_MAKE_TARGET: ci-fips-test + + ################# + ### Vuln Check ## + ################# + - component: $CI_SERVER_FQDN/cloudflare/ci/golang/boring-make@~latest + inputs: + <<: *golang_inputs + runOnBranches: '^$' + stage: validate + jobPrefix: vulncheck + GOLANG_MAKE_TARGET: vulncheck + +################################# +### Run Linux Component Tests ### +################################# +component-tests-linux: &component-tests-linux + stage: test + extends: .component-tests + needs: + - ci-image-get-image-ref + - linux-build-boring-make + script: + - ./.ci/scripts/component-tests.sh + variables: &component-tests-variables + CI: 1 + COMPONENT_TESTS_CONFIG_CONTENT: Y2xvdWRmbGFyZWRfYmluYXJ5OiBjbG91ZGZsYXJlZApjcmVkZW50aWFsc19maWxlOiBjcmVkLmpzb24Kb3JpZ2luY2VydDogY2VydC5wZW0Kem9uZV9kb21haW46IGFyZ290dW5uZWx0ZXN0LmNvbQp6b25lX3RhZzogNDg3OTZmMWU3MGJiNzY2OWMyOWJiNTFiYTI4MmJmNjU= + tags: + - linux-x86-8cpu-16gb + artifacts: + reports: + junit: report.xml + +###################################### +### Run Linux FIPS Component Tests ### +###################################### +component-tests-linux-fips: + <<: *component-tests-linux + needs: + - ci-image-get-image-ref + - linux-fips-build-boring-make + variables: + <<: *component-tests-variables + COMPONENT_TESTS_FIPS: 1 diff --git a/.ci/mac.gitlab-ci.yml b/.ci/mac.gitlab-ci.yml index 1fc433de..94e16fbd 100644 --- a/.ci/mac.gitlab-ci.yml +++ b/.ci/mac.gitlab-ci.yml @@ -6,7 +6,7 @@ include: ############################### .mac-build-defaults: &mac-build-defaults rules: - - !reference [.default-rules, run-on-branch] + - !reference [.default-rules, run-on-mr] tags: - "macstadium-${RUNNER_ARCH}" parallel: diff --git a/.ci/scripts/component-tests.sh b/.ci/scripts/component-tests.sh new file mode 100755 index 00000000..68abbf1d --- /dev/null +++ b/.ci/scripts/component-tests.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -e -o pipefail + +# Fetch cloudflared from the artifacts folder +mv ./artifacts/cloudflared ./cloudflared + +python3 -m venv env +. env/bin/activate + +pip install --upgrade -r component-tests/requirements.txt + +# Creates and routes a Named Tunnel for this build. Also constructs +# config file from env vars. +python3 component-tests/setup.py --type create + +# Define the cleanup function +cleanup() { + # The Named Tunnel is deleted and its route unprovisioned here. + python3 component-tests/setup.py --type cleanup +} + +# The trap will call the cleanup function on script exit +trap cleanup EXIT + +pytest component-tests -o log_cli=true --log-cli-level=INFO --junit-xml=report.xml diff --git a/fmt-check.sh b/.ci/scripts/fmt-check.sh similarity index 54% rename from fmt-check.sh rename to .ci/scripts/fmt-check.sh index 31fc7abc..4c1cbad0 100755 --- a/fmt-check.sh +++ b/.ci/scripts/fmt-check.sh @@ -1,8 +1,7 @@ #!/bin/bash - set -e -o pipefail -OUTPUT=$(goimports -l -d -local github.com/cloudflare/cloudflared $(go list -mod=vendor -f '{{.Dir}}' -a ./... | fgrep -v tunnelrpc)) +OUTPUT=$(go run -mod=readonly golang.org/x/tools/cmd/goimports@v0.30.0 -l -d -local github.com/cloudflare/cloudflared $(go list -mod=vendor -f '{{.Dir}}' -a ./... | fgrep -v tunnelrpc)) if [ -n "$OUTPUT" ] ; then PAGER=$(which colordiff || echo cat) diff --git a/.ci/scripts/windows/component-test.ps1 b/.ci/scripts/windows/component-test.ps1 index abf024ff..dea9e115 100644 --- a/.ci/scripts/windows/component-test.ps1 +++ b/.ci/scripts/windows/component-test.ps1 @@ -31,7 +31,7 @@ Write-Host "Running component tests" try { python -m pip --disable-pip-version-check install --upgrade -r component-tests/requirements.txt --use-pep517 python component-tests/setup.py --type create - python -m pytest component-tests -o log_cli=true --log-cli-level=INFO + python -m pytest component-tests -o log_cli=true --log-cli-level=INFO --junit-xml=report.xml if ($LASTEXITCODE -ne 0) { throw "Failed component tests" } diff --git a/.ci/scripts/windows/go-wrapper.ps1 b/.ci/scripts/windows/go-wrapper.ps1 index 217553a3..8eca1ae8 100644 --- a/.ci/scripts/windows/go-wrapper.ps1 +++ b/.ci/scripts/windows/go-wrapper.ps1 @@ -3,7 +3,7 @@ Param( [string]$ScriptToExecute ) -# This script its a wrapper that downloads a specific version +# The script is a wrapper that downloads a specific version # of go, adds it to the PATH and executes a script with that go # version in the path. diff --git a/.ci/windows.gitlab-ci.yml b/.ci/windows.gitlab-ci.yml index 256c7ff4..fdc5ac0a 100644 --- a/.ci/windows.gitlab-ci.yml +++ b/.ci/windows.gitlab-ci.yml @@ -6,7 +6,7 @@ include: ################################### .windows-build-defaults: &windows-build-defaults rules: - - !reference [.default-rules, run-on-branch] + - !reference [.default-rules, run-always] tags: - windows-x86 cache: {} @@ -27,27 +27,20 @@ build-cloudflared-windows: ### Load Environment Variables for Component Tests ### ###################################################### load-windows-env-variables: - rules: - - !reference [.default-rules, run-on-branch] stage: pre-build + extends: .component-tests script: - - echo "COMPONENT_TESTS_CONFIG=component-test-config.yaml" >> windows.env - - echo "COMPONENT_TESTS_CONFIG_CONTENT=Y2xvdWRmbGFyZWRfYmluYXJ5OiBjbG91ZGZsYXJlZC5leGUKY3JlZGVudGlhbHNfZmlsZTogY3JlZC5qc29uCm9yaWdpbmNlcnQ6IGNlcnQucGVtCnpvbmVfZG9tYWluOiBhcmdvdHVubmVsdGVzdC5jb20Kem9uZV90YWc6IDQ4Nzk2ZjFlNzBiYjc2NjljMjliYjUxYmEyODJiZjY1" >> windows.env + - echo "COMPONENT_TESTS_CONFIG=$COMPONENT_TESTS_CONFIG" >> windows.env + - echo "COMPONENT_TESTS_CONFIG_CONTENT=$COMPONENT_TESTS_CONFIG_CONTENT" >> windows.env - echo "DNS_API_TOKEN=$DNS_API_TOKEN" >> windows.env # We have to encode the `COMPONENT_TESTS_ORIGINCERT` secret, because it content is a file, otherwise we can't export it using gitlab - echo "COMPONENT_TESTS_ORIGINCERT=$(echo "$COMPONENT_TESTS_ORIGINCERT" | base64 -w0)" >> windows.env - secrets: - DNS_API_TOKEN: - vault: gitlab/cloudflare/tun/cloudflared/_dev/_terraform_atlantis/component_tests_token/data@kv - file: false - COMPONENT_TESTS_ORIGINCERT: - vault: gitlab/cloudflare/tun/cloudflared/_dev/component_tests_cert_pem/data@kv - file: false + variables: + COMPONENT_TESTS_CONFIG_CONTENT: Y2xvdWRmbGFyZWRfYmluYXJ5OiBjbG91ZGZsYXJlZC5leGUKY3JlZGVudGlhbHNfZmlsZTogY3JlZC5qc29uCm9yaWdpbmNlcnQ6IGNlcnQucGVtCnpvbmVfZG9tYWluOiBhcmdvdHVubmVsdGVzdC5jb20Kem9uZV90YWc6IDQ4Nzk2ZjFlNzBiYjc2NjljMjliYjUxYmEyODJiZjY1 artifacts: access: 'none' reports: dotenv: windows.env - cache: {} ################################### ### Run Windows Component Tests ### @@ -60,6 +53,9 @@ component-tests-cloudflared-windows: # We have to decode the secret we encoded on the `load-windows-env-variables` job - $env:COMPONENT_TESTS_ORIGINCERT = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($env:COMPONENT_TESTS_ORIGINCERT)) - powershell -ExecutionPolicy Bypass -File ".\.ci\scripts\windows\go-wrapper.ps1" "${GO_VERSION}" ".\.ci\scripts\windows\component-test.ps1" + artifacts: + reports: + junit: report.xml ################################ ### Package Windows Binaries ### diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a4ea2864..09826a2c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,27 +1,13 @@ variables: - # Define GOPATH within the project directory to allow GitLab CI to cache it. - # By default, Go places modules in GOMODCACHE, often outside the project. - # Explicitly setting GOMODCACHE ensures it's within the cached path. - GOPATH: "$CI_PROJECT_DIR/.go" - GOMODCACHE: "$GOPATH/pkg/mod" - GO_BIN_DIR: "$GOPATH/bin" - GO_VERSION: "go1.24.4" - -cache: - # Cache Go modules and the binaries. - # The 'key' ensures a unique cache per branch, or you can use a fixed key - # for a shared cache across all branches if that fits your workflow. - key: "$CI_COMMIT_REF_SLUG" - paths: - - ${GOPATH}/pkg/mod/ # For Go modules - - ${GO_BIN_DIR}/ + GO_VERSION: "go1.24.6" + GIT_DEPTH: "0" default: id_tokens: VAULT_ID_TOKEN: aud: https://vault.cfdata.org -stages: [pre-build, build, test, package, release] +stages: [pre-build, build, validate, test, package, release] include: ##################################################### @@ -34,6 +20,11 @@ include: ##################################################### - local: .ci/ci-image.gitlab-ci.yml + ##################################################### + ################## Linux Builds ################### + ##################################################### + - local: .ci/linux.gitlab-ci.yml + ##################################################### ################## Windows Builds ################### ##################################################### @@ -48,27 +39,3 @@ include: ################# Release Packages ################## ##################################################### - local: .ci/release.gitlab-ci.yml - -# Template for Go setup, including caching and installation -.go_setup: - image: docker-registry.cfdata.org/stash/devtools/ci-builders/golang-1.24/master:3219-cc8b513@sha256:4fe3ff47ba07f9b23429f49fbd063cc1a34156dd11b8113e325ad3762f94a1db - before_script: - - mkdir -p ${GOPATH} ${GOMODCACHE} ${GO_BIN_DIR} - - export PATH=$PATH:${GO_BIN_DIR} - - go env -w GOMODCACHE=${GOMODCACHE} # Ensure go uses the cached module path - - # Check if govulncheck is already installed and install it if not - - if [ ! -f ${GO_BIN_DIR}/govulncheck ]; then - echo "govulncheck not found in cache, installing..."; - go install golang.org/x/vuln/cmd/govulncheck@latest; - else - echo "govulncheck found in cache, skipping installation."; - fi - -vulncheck: - stage: build - extends: .go_setup - rules: - - !reference [.default-rules, run-on-branch] - script: - - make vulncheck diff --git a/Makefile b/Makefile index fa694c94..96271ae7 100644 --- a/Makefile +++ b/Makefile @@ -128,6 +128,8 @@ endif #for FIPS compliance, FPM defaults to MD5. RPM_DIGEST := --rpm-digest sha256 +GO_TEST_LOG_OUTPUT = /tmp/gotest.log + .PHONY: all all: cloudflared test @@ -137,7 +139,7 @@ clean: .PHONY: vulncheck vulncheck: - @govulncheck ./... + @go run -mod=readonly golang.org/x/vuln/cmd/govulncheck@latest ./... .PHONY: cloudflared cloudflared: @@ -160,11 +162,9 @@ generate-docker-version: .PHONY: test test: vet -ifndef CI - go test -v -mod=vendor -race $(LDFLAGS) ./... -else - @mkdir -p .cover - go test -v -mod=vendor -race $(LDFLAGS) -coverprofile=".cover/c.out" ./... + $Q go test -json -v -mod=vendor -race $(LDFLAGS) ./... 2>&1 | tee $(GO_TEST_LOG_OUTPUT) +ifneq ($(FIPS), true) + @go run -mod=readonly github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest -input $(GO_TEST_LOG_OUTPUT) endif .PHONY: cover @@ -254,7 +254,7 @@ capnp: .PHONY: vet vet: - go vet -mod=vendor github.com/cloudflare/cloudflared/... + $Q go vet -mod=vendor github.com/cloudflare/cloudflared/... .PHONY: fmt fmt: @@ -263,7 +263,7 @@ fmt: .PHONY: fmt-check fmt-check: - @./fmt-check.sh + @./.ci/scripts/fmt-check.sh .PHONY: lint lint: @@ -272,3 +272,23 @@ lint: .PHONY: mocks mocks: go generate mocks/mockgen.go + +.PHONY: ci-build +ci-build: + @GOOS=linux GOARCH=amd64 $(MAKE) cloudflared + @mkdir -p artifacts + @mv cloudflared artifacts/cloudflared + +.PHONY: ci-fips-build +ci-fips-build: + @FIPS=true GOOS=linux GOARCH=amd64 $(MAKE) cloudflared + @mkdir -p artifacts + @mv cloudflared artifacts/cloudflared + +.PHONY: ci-test +ci-test: fmt-check lint test + @go run -mod=readonly github.com/jstemmer/go-junit-report/v2@latest -in $(GO_TEST_LOG_OUTPUT) -parser gojson -out report.xml -set-exit-code + +.PHONY: ci-fips-test +ci-fips-test: + @FIPS=true $(MAKE) ci-test diff --git a/component-tests/test_service.py b/component-tests/test_service.py index e1c155e6..e992be33 100644 --- a/component-tests/test_service.py +++ b/component-tests/test_service.py @@ -9,7 +9,7 @@ import pytest import test_logging from conftest import CfdModes -from util import select_platform, start_cloudflared, wait_tunnel_ready, write_config +from util import select_platform, skip_on_ci, start_cloudflared, wait_tunnel_ready, write_config def default_config_dir(): @@ -82,6 +82,7 @@ class TestServiceMode: os.remove(default_config_file()) self.launchctl_cmd("list", success=False) + @skip_on_ci("we can't run sudo command on CI") @select_platform("Linux") @pytest.mark.skipif(os.path.exists("/etc/cloudflared/config.yml"), reason=f"There is already a config file in default path") @@ -98,6 +99,7 @@ class TestServiceMode: self.sysv_service_scenario(config, tmp_path, assert_log_file) + @skip_on_ci("we can't run sudo command on CI") @select_platform("Linux") @pytest.mark.skipif(os.path.exists("/etc/cloudflared/config.yml"), reason=f"There is already a config file in default path") @@ -116,6 +118,7 @@ class TestServiceMode: self.sysv_service_scenario(config, tmp_path, assert_rotating_log) + @skip_on_ci("we can't run sudo command on CI") @select_platform("Linux") @pytest.mark.skipif(os.path.exists("/etc/cloudflared/config.yml"), reason=f"There is already a config file in default path") diff --git a/component-tests/util.py b/component-tests/util.py index c7fd59c4..b4c9b51b 100644 --- a/component-tests/util.py +++ b/component-tests/util.py @@ -10,7 +10,6 @@ import pytest import requests import yaml -import json from retrying import retry from constants import METRICS_PORT, MAX_RETRIES, BACKOFF_SECS @@ -35,6 +34,12 @@ def fips_enabled(): nofips = pytest.mark.skipif( fips_enabled(), reason=f"Only runs without FIPS (COMPONENT_TESTS_FIPS=0)") +def skip_on_ci(reason): + env_ci = os.getenv("CI") + running_in_ci = env_ci is not None and env_ci != "0" + return pytest.mark.skipif( + running_in_ci, reason=f"This test can't run on CI due to: {reason}") + def write_config(directory, config): config_path = directory / "config.yml" with open(config_path, 'w') as outfile: From 9e94122d2b876c8b89e4632f2f6d4b2f7efcb989 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gon=C3=A7alo=20Garcia?= Date: Mon, 15 Sep 2025 11:11:23 +0000 Subject: [PATCH 3/3] TUN-9820: Add support for FedRAMP in originRequest Access config * TUN-9820: Add support for FedRAMP in originRequest Access config Closes TUN-9820 --- cmd/cloudflared/tunnel/configuration.go | 1 - config/configuration.go | 2 ++ ingress/ingress.go | 2 +- ingress/middleware/jwtvalidator.go | 13 ++++++++++--- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/cmd/cloudflared/tunnel/configuration.go b/cmd/cloudflared/tunnel/configuration.go index 63f78426..b38f79da 100644 --- a/cmd/cloudflared/tunnel/configuration.go +++ b/cmd/cloudflared/tunnel/configuration.go @@ -36,7 +36,6 @@ import ( const ( secretValue = "*****" icmpFunnelTimeout = time.Second * 10 - fedRampRegion = "fed" // const string denoting the region used to connect to FEDRamp servers ) var ( diff --git a/config/configuration.go b/config/configuration.go index a3b65ad3..cb0b0ade 100644 --- a/config/configuration.go +++ b/config/configuration.go @@ -242,6 +242,8 @@ type AccessConfig struct { // AudTag is the AudTag to verify access JWT against. AudTag []string `yaml:"audTag" json:"audTag"` + + Environment string `yaml:"environment" json:"environment,omitempty"` } type IngressIPRule struct { diff --git a/ingress/ingress.go b/ingress/ingress.go index eaad7dce..a325271a 100644 --- a/ingress/ingress.go +++ b/ingress/ingress.go @@ -317,7 +317,7 @@ func validateIngress(ingress []config.UnvalidatedIngressRule, defaults OriginReq return Ingress{}, err } if access.Required { - verifier := middleware.NewJWTValidator(access.TeamName, "", access.AudTag) + verifier := middleware.NewJWTValidator(access.TeamName, access.Environment, access.AudTag) handlers = append(handlers, verifier) } } diff --git a/ingress/middleware/jwtvalidator.go b/ingress/middleware/jwtvalidator.go index 8ee9b789..93ca8c61 100644 --- a/ingress/middleware/jwtvalidator.go +++ b/ingress/middleware/jwtvalidator.go @@ -6,6 +6,8 @@ import ( "net/http" "github.com/coreos/go-oidc/v3/oidc" + + "github.com/cloudflare/cloudflared/credentials" ) const ( @@ -13,7 +15,8 @@ const ( ) var ( - cloudflareAccessCertsURL = "https://%s.cloudflareaccess.com" + cloudflareAccessCertsURL = "https://%s.cloudflareaccess.com" + cloudflareAccessFedCertsURL = "https://%s.fed.cloudflareaccess.com" ) // JWTValidator is an implementation of Verifier that validates access based JWT tokens. @@ -22,10 +25,14 @@ type JWTValidator struct { audTags []string } -func NewJWTValidator(teamName string, certsURL string, audTags []string) *JWTValidator { - if certsURL == "" { +func NewJWTValidator(teamName string, environment string, audTags []string) *JWTValidator { + var certsURL string + if environment == credentials.FedEndpoint { + certsURL = fmt.Sprintf(cloudflareAccessFedCertsURL, teamName) + } else { certsURL = fmt.Sprintf(cloudflareAccessCertsURL, teamName) } + certsEndpoint := fmt.Sprintf("%s/cdn-cgi/access/certs", certsURL) config := &oidc.Config{