mirror of
https://github.com/cloudflare/cloudflared
synced 2026-06-08 13:33:07 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 40dc601e9d | |||
| e5578cb74e | |||
| bb765e741d | |||
| 10081602a4 | |||
| 236fcf56d6 | |||
| 73a9980f38 | |||
| 86e8585563 | |||
| d8a066628b | |||
| 553e77e061 | |||
| 8f94f54ec7 | |||
| 2827b2fe8f | |||
| 6dc8ed710e | |||
| e0b1ac0d05 | |||
| e7c5eb54af | |||
| cfec602fa7 | |||
| 6fceb94998 | |||
| cf817f7036 | |||
| c8724a290a | |||
| e7586153be | |||
| 11777db304 |
+131
@@ -0,0 +1,131 @@
|
||||
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
|
||||
|
||||
## 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
|
||||
|
||||
# -----------------------------------------------
|
||||
# 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-cloudflare-go.sh
|
||||
- export PATH="/tmp/go/bin:$PATH"
|
||||
- BUILD_SCRIPT=.teamcity/mac/build.sh
|
||||
- if [[ ! -x ${BUILD_SCRIPT} ]] ; then exit ; fi
|
||||
- set -euo pipefail
|
||||
- echo "Executing ${BUILD_SCRIPT}"
|
||||
- exec ${BUILD_SCRIPT}
|
||||
|
||||
# -----------------------------------------------
|
||||
# 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
|
||||
Vendored
+46
-7
@@ -49,7 +49,7 @@ import_certificate() {
|
||||
echo -n -e ${CERTIFICATE_ENV_VAR} | base64 -D > ${CERTIFICATE_FILE_NAME}
|
||||
# we set || true here and for every `security import invoke` because the "duplicate SecKeychainItemImport" error
|
||||
# will cause set -e to exit 1. It is okay we do this because we deliberately handle this error in the lines below.
|
||||
local out=$(security import ${CERTIFICATE_FILE_NAME} -A 2>&1) || true
|
||||
local out=$(security import ${CERTIFICATE_FILE_NAME} -T /usr/bin/pkgbuild -A 2>&1) || true
|
||||
local exitcode=$?
|
||||
# delete the certificate from disk
|
||||
rm -rf ${CERTIFICATE_FILE_NAME}
|
||||
@@ -68,6 +68,28 @@ import_certificate() {
|
||||
fi
|
||||
}
|
||||
|
||||
create_cloudflared_build_keychain() {
|
||||
# Reusing the private key password as the keychain key
|
||||
local PRIVATE_KEY_PASS=$1
|
||||
|
||||
# Create keychain only if it doesn't already exist
|
||||
if [ ! -f "$HOME/Library/Keychains/cloudflared_build_keychain.keychain-db" ]; then
|
||||
security create-keychain -p "$PRIVATE_KEY_PASS" cloudflared_build_keychain
|
||||
else
|
||||
echo "Keychain already exists: cloudflared_build_keychain"
|
||||
fi
|
||||
|
||||
# Append temp keychain to the user domain
|
||||
security list-keychains -d user -s cloudflared_build_keychain $(security list-keychains -d user | sed s/\"//g)
|
||||
|
||||
# Remove relock timeout
|
||||
security set-keychain-settings cloudflared_build_keychain
|
||||
|
||||
# Unlock keychain so it doesn't require password
|
||||
security unlock-keychain -p "$PRIVATE_KEY_PASS" cloudflared_build_keychain
|
||||
|
||||
}
|
||||
|
||||
# Imports private keys to the Apple KeyChain
|
||||
import_private_keys() {
|
||||
local PRIVATE_KEY_NAME=$1
|
||||
@@ -83,7 +105,7 @@ import_private_keys() {
|
||||
echo -n -e ${PRIVATE_KEY_ENV_VAR} | base64 -D > ${PRIVATE_KEY_FILE_NAME}
|
||||
# we set || true here and for every `security import invoke` because the "duplicate SecKeychainItemImport" error
|
||||
# will cause set -e to exit 1. It is okay we do this because we deliberately handle this error in the lines below.
|
||||
local out=$(security import ${PRIVATE_KEY_FILE_NAME} -A -P "${PRIVATE_KEY_PASS}" 2>&1) || true
|
||||
local out=$(security import ${PRIVATE_KEY_FILE_NAME} -k cloudflared_build_keychain -P "$PRIVATE_KEY_PASS" -T /usr/bin/pkgbuild -A -P "${PRIVATE_KEY_PASS}" 2>&1) || true
|
||||
local exitcode=$?
|
||||
rm -rf ${PRIVATE_KEY_FILE_NAME}
|
||||
if [ -n "$out" ]; then
|
||||
@@ -100,6 +122,9 @@ import_private_keys() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Create temp keychain only for this build
|
||||
create_cloudflared_build_keychain "${CFD_CODE_SIGN_PASS}"
|
||||
|
||||
# Add Apple Root Developer certificate to the key chain
|
||||
import_certificate "Apple Developer CA" "${APPLE_DEV_CA_CERT}" "${APPLE_CA_CERT}"
|
||||
|
||||
@@ -119,8 +144,8 @@ import_certificate "Developer ID Installer" "${CFD_INSTALLER_CERT}" "${INSTALLER
|
||||
if [[ ! -z "$CFD_CODE_SIGN_NAME" ]]; then
|
||||
CODE_SIGN_NAME="${CFD_CODE_SIGN_NAME}"
|
||||
else
|
||||
if [[ -n "$(security find-certificate -c "Developer ID Application" | cut -d'"' -f 4 -s | grep "Developer ID Application:" | head -1)" ]]; then
|
||||
CODE_SIGN_NAME=$(security find-certificate -c "Developer ID Application" | cut -d'"' -f 4 -s | grep "Developer ID Application:" | head -1)
|
||||
if [[ -n "$(security find-certificate -c "Developer ID Application" cloudflared_build_keychain | cut -d'"' -f 4 -s | grep "Developer ID Application:" | head -1)" ]]; then
|
||||
CODE_SIGN_NAME=$(security find-certificate -c "Developer ID Application" cloudflared_build_keychain | cut -d'"' -f 4 -s | grep "Developer ID Application:" | head -1)
|
||||
else
|
||||
CODE_SIGN_NAME=""
|
||||
fi
|
||||
@@ -130,8 +155,8 @@ fi
|
||||
if [[ ! -z "$CFD_INSTALLER_NAME" ]]; then
|
||||
PKG_SIGN_NAME="${CFD_INSTALLER_NAME}"
|
||||
else
|
||||
if [[ -n "$(security find-certificate -c "Developer ID Installer" | cut -d'"' -f 4 -s | grep "Developer ID Installer:" | head -1)" ]]; then
|
||||
PKG_SIGN_NAME=$(security find-certificate -c "Developer ID Installer" | cut -d'"' -f 4 -s | grep "Developer ID Installer:" | head -1)
|
||||
if [[ -n "$(security find-certificate -c "Developer ID Installer" cloudflared_build_keychain | cut -d'"' -f 4 -s | grep "Developer ID Installer:" | head -1)" ]]; then
|
||||
PKG_SIGN_NAME=$(security find-certificate -c "Developer ID Installer" cloudflared_build_keychain | cut -d'"' -f 4 -s | grep "Developer ID Installer:" | head -1)
|
||||
else
|
||||
PKG_SIGN_NAME=""
|
||||
fi
|
||||
@@ -142,9 +167,16 @@ rm -rf "${TARGET_DIRECTORY}"
|
||||
export TARGET_OS="darwin"
|
||||
GOCACHE="$PWD/../../../../" GOPATH="$PWD/../../../../" CGO_ENABLED=1 make cloudflared
|
||||
|
||||
|
||||
# This allows apple tools to use the certificates in the keychain without requiring password input.
|
||||
# This command always needs to run after the certificates have been loaded into the keychain
|
||||
if [[ ! -z "$CFD_CODE_SIGN_PASS" ]]; then
|
||||
security set-key-partition-list -S apple-tool:,apple: -s -k "${CFD_CODE_SIGN_PASS}" cloudflared_build_keychain
|
||||
fi
|
||||
|
||||
# sign the cloudflared binary
|
||||
if [[ ! -z "$CODE_SIGN_NAME" ]]; then
|
||||
codesign -s "${CODE_SIGN_NAME}" -f -v --timestamp --options runtime ${BINARY_NAME}
|
||||
codesign --keychain $HOME/Library/Keychains/cloudflared_build_keychain.keychain-db -s "${CODE_SIGN_NAME}" -fv --options runtime --timestamp ${BINARY_NAME}
|
||||
|
||||
# notarize the binary
|
||||
# TODO: TUN-5789
|
||||
@@ -165,11 +197,13 @@ tar czf "$FILENAME" "${BINARY_NAME}"
|
||||
|
||||
# build the installer package
|
||||
if [[ ! -z "$PKG_SIGN_NAME" ]]; then
|
||||
|
||||
pkgbuild --identifier com.cloudflare.${PRODUCT} \
|
||||
--version ${VERSION} \
|
||||
--scripts ${ARCH_TARGET_DIRECTORY}/scripts \
|
||||
--root ${ARCH_TARGET_DIRECTORY}/contents \
|
||||
--install-location /usr/local/bin \
|
||||
--keychain cloudflared_build_keychain \
|
||||
--sign "${PKG_SIGN_NAME}" \
|
||||
${PKGNAME}
|
||||
|
||||
@@ -187,3 +221,8 @@ fi
|
||||
# cleanup build directory because this script is not ran within containers,
|
||||
# which might lead to future issues in subsequent runs.
|
||||
rm -rf "${TARGET_DIRECTORY}"
|
||||
|
||||
# cleanup the keychain
|
||||
security default-keychain -d user -s login.keychain-db
|
||||
security list-keychains -d user -s login.keychain-db
|
||||
security delete-keychain cloudflared_build_keychain
|
||||
|
||||
@@ -24,7 +24,7 @@ else
|
||||
DEB_PACKAGE_NAME := $(BINARY_NAME)
|
||||
endif
|
||||
|
||||
DATE := $(shell date -u '+%Y-%m-%d-%H%M UTC')
|
||||
DATE := $(shell date -u -r RELEASE_NOTES '+%Y-%m-%d-%H%M UTC')
|
||||
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)"
|
||||
@@ -237,6 +237,10 @@ 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:
|
||||
python3 github_release.py --path $(PWD)/artifacts/ --release-version $(VERSION)
|
||||
|
||||
.PHONY: r2-linux-release
|
||||
r2-linux-release:
|
||||
python3 ./release_pkgs.py
|
||||
|
||||
@@ -40,7 +40,7 @@ User documentation for Cloudflare Tunnel can be found at https://developers.clou
|
||||
|
||||
Once installed, you can authenticate `cloudflared` into your Cloudflare account and begin creating Tunnels to serve traffic to your origins.
|
||||
|
||||
* Create a Tunnel with [these instructions](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/create-tunnel)
|
||||
* Create a Tunnel with [these instructions](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/get-started/)
|
||||
* Route traffic to that Tunnel:
|
||||
* Via public [DNS records in Cloudflare](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/routing-to-tunnel/dns)
|
||||
* Or via a public hostname guided by a [Cloudflare Load Balancer](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/routing-to-tunnel/lb)
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
2025.4.2
|
||||
- 2025-04-30 chore: Do not use gitlab merge request pipelines
|
||||
- 2025-04-30 DEVTOOLS-16383: Create GitlabCI pipeline to release Mac builds
|
||||
- 2025-04-24 TUN-9255: Improve flush on write conditions in http2 tunnel type to match what is done on the edge
|
||||
- 2025-04-10 SDLC-3727 - Adding FIPS status to backstage
|
||||
|
||||
2025.4.0
|
||||
- 2025-04-02 Fix broken links in `cmd/cloudflared/*.go` related to running tunnel as a service
|
||||
- 2025-04-02 chore: remove repetitive words
|
||||
- 2025-04-01 Fix messages to point to one.dash.cloudflare.com
|
||||
- 2025-04-01 feat: emit explicit errors for the `service` command on unsupported OSes
|
||||
- 2025-04-01 Use RELEASE_NOTES date instead of build date
|
||||
- 2025-04-01 chore: Update tunnel configuration link in the readme
|
||||
- 2025-04-01 fix: expand home directory for credentials file
|
||||
- 2025-04-01 fix: Use path and filepath operation appropriately
|
||||
- 2025-04-01 feat: Adds a new command line for tunnel run for token file
|
||||
- 2025-04-01 chore: fix linter rules
|
||||
- 2025-03-17 TUN-9101: Don't ignore errors on `cloudflared access ssh`
|
||||
- 2025-03-06 TUN-9089: Pin go import to v0.30.0, v0.31.0 requires go 1.23
|
||||
|
||||
2025.2.1
|
||||
- 2025-02-26 TUN-9016: update base-debian to v12
|
||||
- 2025-02-25 TUN-8960: Connect to FED API GW based on the OriginCert's endpoint
|
||||
|
||||
@@ -13,3 +13,5 @@ spec:
|
||||
type: "service"
|
||||
lifecycle: "Active"
|
||||
owner: "teams/tunnel-teams-routing"
|
||||
cf:
|
||||
FIPS: "required"
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ bullseye: &bullseye
|
||||
- golangci-lint
|
||||
pre-cache: &build_pre_cache
|
||||
- export GOCACHE=/cfsetup_build/.cache/go-build
|
||||
- go install golang.org/x/tools/cmd/goimports@latest
|
||||
- go install golang.org/x/tools/cmd/goimports@v0.30.0
|
||||
post-cache:
|
||||
# Linting
|
||||
- make lint
|
||||
|
||||
@@ -104,7 +104,7 @@ func ssh(c *cli.Context) error {
|
||||
case 3:
|
||||
options.OriginURL = fmt.Sprintf("https://%s:%s", parts[2], parts[1])
|
||||
options.TLSClientConfig = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
InsecureSkipVerify: true, // #nosec G402
|
||||
ServerName: parts[0],
|
||||
}
|
||||
log.Warn().Msgf("Using insecure SSL connection because SNI overridden to %s", parts[0])
|
||||
@@ -141,6 +141,5 @@ func ssh(c *cli.Context) error {
|
||||
logger := log.With().Str("host", url.Host).Logger()
|
||||
s = stream.NewDebugStream(s, &logger, maxMessages)
|
||||
}
|
||||
carrier.StartClient(wsConn, s, options)
|
||||
return nil
|
||||
return carrier.StartClient(wsConn, s, options)
|
||||
}
|
||||
|
||||
@@ -3,11 +3,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
cli "github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/cloudflare/cloudflared/cmd/cloudflared/cliutil"
|
||||
)
|
||||
|
||||
func runApp(app *cli.App, graceShutdownC chan struct{}) {
|
||||
app.Commands = append(app.Commands, &cli.Command{
|
||||
Name: "service",
|
||||
Usage: "Manages the cloudflared system service (not supported on this operating system)",
|
||||
Subcommands: []*cli.Command{
|
||||
{
|
||||
Name: "install",
|
||||
Usage: "Install cloudflared as a system service (not supported on this operating system)",
|
||||
Action: cliutil.ConfiguredAction(installGenericService),
|
||||
},
|
||||
{
|
||||
Name: "uninstall",
|
||||
Usage: "Uninstall the cloudflared service (not supported on this operating system)",
|
||||
Action: cliutil.ConfiguredAction(uninstallGenericService),
|
||||
},
|
||||
},
|
||||
})
|
||||
app.Run(os.Args)
|
||||
}
|
||||
|
||||
func installGenericService(c *cli.Context) error {
|
||||
return fmt.Errorf("service installation is not supported on this operating system")
|
||||
}
|
||||
|
||||
func uninstallGenericService(c *cli.Context) error {
|
||||
return fmt.Errorf("service uninstallation is not supported on this operating system")
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ func installLaunchd(c *cli.Context) error {
|
||||
log.Info().Msg("Installing cloudflared client as an user launch agent. " +
|
||||
"Note that cloudflared client will only run when the user is logged in. " +
|
||||
"If you want to run cloudflared client at boot, install with root permission. " +
|
||||
"For more information, visit https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/run-as-service")
|
||||
"For more information, visit https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/configure-tunnels/local-management/as-a-service/macos/")
|
||||
}
|
||||
etPath, err := os.Executable()
|
||||
if err != nil {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
|
||||
homedir "github.com/mitchellh/go-homedir"
|
||||
@@ -44,7 +44,7 @@ func (st *ServiceTemplate) Generate(args *ServiceTemplateArgs) error {
|
||||
return err
|
||||
}
|
||||
if _, err = os.Stat(resolvedPath); err == nil {
|
||||
return fmt.Errorf(serviceAlreadyExistsWarn(resolvedPath))
|
||||
return errors.New(serviceAlreadyExistsWarn(resolvedPath))
|
||||
}
|
||||
|
||||
var buffer bytes.Buffer
|
||||
@@ -57,7 +57,7 @@ func (st *ServiceTemplate) Generate(args *ServiceTemplateArgs) error {
|
||||
fileMode = st.FileMode
|
||||
}
|
||||
|
||||
plistFolder := path.Dir(resolvedPath)
|
||||
plistFolder := filepath.Dir(resolvedPath)
|
||||
err = os.MkdirAll(plistFolder, 0o755)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating %s: %v", plistFolder, err)
|
||||
@@ -118,49 +118,6 @@ func ensureConfigDirExists(configDir string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// openFile opens the file at path. If create is set and the file exists, returns nil, true, nil
|
||||
func openFile(path string, create bool) (file *os.File, exists bool, err error) {
|
||||
expandedPath, err := homedir.Expand(path)
|
||||
if err != nil {
|
||||
return nil, false, err
|
||||
}
|
||||
if create {
|
||||
fileInfo, err := os.Stat(expandedPath)
|
||||
if err == nil && fileInfo.Size() > 0 {
|
||||
return nil, true, nil
|
||||
}
|
||||
file, err = os.OpenFile(expandedPath, os.O_RDWR|os.O_CREATE, 0600)
|
||||
} else {
|
||||
file, err = os.Open(expandedPath)
|
||||
}
|
||||
return file, false, err
|
||||
}
|
||||
|
||||
func copyCredential(srcCredentialPath, destCredentialPath string) error {
|
||||
destFile, exists, err := openFile(destCredentialPath, true)
|
||||
if err != nil {
|
||||
return err
|
||||
} else if exists {
|
||||
// credentials already exist, do nothing
|
||||
return nil
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
srcFile, _, err := openFile(srcCredentialPath, false)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
// Copy certificate
|
||||
_, err = io.Copy(destFile, srcFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to copy %s to %s: %v", srcCredentialPath, destCredentialPath, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyFile(src, dest string) error {
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
@@ -187,36 +144,3 @@ func copyFile(src, dest string) error {
|
||||
ok = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func copyConfig(srcConfigPath, destConfigPath string) error {
|
||||
// Copy or create config
|
||||
destFile, exists, err := openFile(destConfigPath, true)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot open %s with error: %s", destConfigPath, err)
|
||||
} else if exists {
|
||||
// config already exists, do nothing
|
||||
return nil
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
srcFile, _, err := openFile(srcConfigPath, false)
|
||||
if err != nil {
|
||||
fmt.Println("Your service needs a config file that at least specifies the hostname option.")
|
||||
fmt.Println("Type in a hostname now, or leave it blank and create the config file later.")
|
||||
fmt.Print("Hostname: ")
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
input, _ := reader.ReadString('\n')
|
||||
if input == "" {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(destFile, "hostname: %s\n", input)
|
||||
} else {
|
||||
defer srcFile.Close()
|
||||
_, err = io.Copy(destFile, srcFile)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to copy %s to %s: %v", srcConfigPath, destConfigPath, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -208,7 +208,7 @@ then protect with Cloudflare Access).
|
||||
B) Locally reachable TCP/UDP-based private services to Cloudflare connected private users in the same account, e.g.,
|
||||
those enrolled to a Zero Trust WARP Client.
|
||||
|
||||
You can manage your Tunnels via dash.teams.cloudflare.com. This approach will only require you to run a single command
|
||||
You can manage your Tunnels via one.dash.cloudflare.com. This approach will only require you to run a single command
|
||||
later in each machine where you wish to run a Tunnel.
|
||||
|
||||
Alternatively, you can manage your Tunnels via the command line. Begin by obtaining a certificate to be able to do so:
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/urfave/cli/v2"
|
||||
@@ -54,7 +55,12 @@ func newSubcommandContext(c *cli.Context) (*subcommandContext, error) {
|
||||
// Returns something that can find the given tunnel's credentials file.
|
||||
func (sc *subcommandContext) credentialFinder(tunnelID uuid.UUID) CredFinder {
|
||||
if path := sc.c.String(CredFileFlag); path != "" {
|
||||
return newStaticPath(path, sc.fs)
|
||||
// Expand path if CredFileFlag contains `~`
|
||||
absPath, err := homedir.Expand(path)
|
||||
if err != nil {
|
||||
return newStaticPath(path, sc.fs)
|
||||
}
|
||||
return newStaticPath(absPath, sc.fs)
|
||||
}
|
||||
return newSearchByID(tunnelID, sc.c, sc.log, sc.fs)
|
||||
}
|
||||
@@ -106,7 +112,7 @@ func (sc *subcommandContext) readTunnelCredentials(credFinder CredFinder) (conne
|
||||
|
||||
var credentials connection.Credentials
|
||||
if err = json.Unmarshal(body, &credentials); err != nil {
|
||||
if strings.HasSuffix(filePath, ".pem") {
|
||||
if filepath.Ext(filePath) == ".pem" {
|
||||
return connection.Credentials{}, fmt.Errorf("The tunnel credentials file should be .json but you gave a .pem. " +
|
||||
"The tunnel credentials file was originally created by `cloudflared tunnel create`. " +
|
||||
"You may have accidentally used the filepath to cert.pem, which is generated by `cloudflared tunnel " +
|
||||
|
||||
@@ -41,6 +41,7 @@ const (
|
||||
CredFileFlag = "credentials-file"
|
||||
CredContentsFlag = "credentials-contents"
|
||||
TunnelTokenFlag = "token"
|
||||
TunnelTokenFileFlag = "token-file"
|
||||
overwriteDNSFlagName = "overwrite-dns"
|
||||
noDiagLogsFlagName = "no-diag-logs"
|
||||
noDiagMetricsFlagName = "no-diag-metrics"
|
||||
@@ -126,9 +127,14 @@ var (
|
||||
})
|
||||
tunnelTokenFlag = altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: TunnelTokenFlag,
|
||||
Usage: "The Tunnel token. When provided along with credentials, this will take precedence.",
|
||||
Usage: "The Tunnel token. When provided along with credentials, this will take precedence. Also takes precedence over token-file",
|
||||
EnvVars: []string{"TUNNEL_TOKEN"},
|
||||
})
|
||||
tunnelTokenFileFlag = altsrc.NewStringFlag(&cli.StringFlag{
|
||||
Name: TunnelTokenFileFlag,
|
||||
Usage: "Filepath at which to read the tunnel token. When provided along with credentials, this will take precedence.",
|
||||
EnvVars: []string{"TUNNEL_TOKEN_FILE"},
|
||||
})
|
||||
forceDeleteFlag = &cli.BoolFlag{
|
||||
Name: flags.Force,
|
||||
Aliases: []string{"f"},
|
||||
@@ -708,6 +714,7 @@ func buildRunCommand() *cli.Command {
|
||||
selectProtocolFlag,
|
||||
featuresFlag,
|
||||
tunnelTokenFlag,
|
||||
tunnelTokenFileFlag,
|
||||
icmpv4SrcFlag,
|
||||
icmpv6SrcFlag,
|
||||
maxActiveFlowsFlag,
|
||||
@@ -748,12 +755,22 @@ func runCommand(c *cli.Context) error {
|
||||
"your origin will not be reachable. You should remove the `hostname` property to avoid this warning.")
|
||||
}
|
||||
|
||||
tokenStr := c.String(TunnelTokenFlag)
|
||||
// Check if tokenStr is blank before checking for tokenFile
|
||||
if tokenStr == "" {
|
||||
if tokenFile := c.String(TunnelTokenFileFlag); tokenFile != "" {
|
||||
data, err := os.ReadFile(tokenFile)
|
||||
if err != nil {
|
||||
return cliutil.UsageError("Failed to read token file: " + err.Error())
|
||||
}
|
||||
tokenStr = strings.TrimSpace(string(data))
|
||||
}
|
||||
}
|
||||
// Check if token is provided and if not use default tunnelID flag method
|
||||
if tokenStr := c.String(TunnelTokenFlag); tokenStr != "" {
|
||||
if tokenStr != "" {
|
||||
if token, err := ParseToken(tokenStr); err == nil {
|
||||
return sc.runWithCredentials(token.Credentials())
|
||||
}
|
||||
|
||||
return cliutil.UsageError("Provided Tunnel token is not valid.")
|
||||
} else {
|
||||
tunnelRef := c.Args().First()
|
||||
|
||||
@@ -22,7 +22,7 @@ var (
|
||||
Usage: "The ID or name of the virtual network to which the route is associated to.",
|
||||
}
|
||||
|
||||
routeAddError = errors.New("You must supply exactly one argument, the ID or CIDR of the route you want to delete")
|
||||
errAddRoute = errors.New("You must supply exactly one argument, the ID or CIDR of the route you want to delete")
|
||||
)
|
||||
|
||||
func buildRouteIPSubcommand() *cli.Command {
|
||||
@@ -32,7 +32,7 @@ func buildRouteIPSubcommand() *cli.Command {
|
||||
UsageText: "cloudflared tunnel [--config FILEPATH] route COMMAND [arguments...]",
|
||||
Description: `cloudflared can provision routes for any IP space in your corporate network. Users enrolled in
|
||||
your Cloudflare for Teams organization can reach those IPs through the Cloudflare WARP
|
||||
client. You can then configure L7/L4 filtering on https://dash.teams.cloudflare.com to
|
||||
client. You can then configure L7/L4 filtering on https://one.dash.cloudflare.com to
|
||||
determine who can reach certain routes.
|
||||
By default IP routes all exist within a single virtual network. If you use the same IP
|
||||
space(s) in different physical private networks, all meant to be reachable via IP routes,
|
||||
@@ -187,7 +187,7 @@ func deleteRouteCommand(c *cli.Context) error {
|
||||
}
|
||||
|
||||
if c.NArg() != 1 {
|
||||
return routeAddError
|
||||
return errAddRoute
|
||||
}
|
||||
|
||||
var routeId uuid.UUID
|
||||
@@ -195,7 +195,7 @@ func deleteRouteCommand(c *cli.Context) error {
|
||||
if err != nil {
|
||||
_, network, err := net.ParseCIDR(c.Args().First())
|
||||
if err != nil || network == nil {
|
||||
return routeAddError
|
||||
return errAddRoute
|
||||
}
|
||||
|
||||
var vnetId *uuid.UUID
|
||||
|
||||
@@ -22,7 +22,7 @@ import (
|
||||
|
||||
const (
|
||||
DefaultCheckUpdateFreq = time.Hour * 24
|
||||
noUpdateInShellMessage = "cloudflared will not automatically update when run from the shell. To enable auto-updates, run cloudflared as a service: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/as-a-service/"
|
||||
noUpdateInShellMessage = "cloudflared will not automatically update when run from the shell. To enable auto-updates, run cloudflared as a service: https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configure-tunnels/local-management/as-a-service/"
|
||||
noUpdateOnWindowsMessage = "cloudflared will not automatically update on Windows systems."
|
||||
noUpdateManagedPackageMessage = "cloudflared will not automatically update if installed by a package manager."
|
||||
isManagedInstallFile = ".installedFromPackageManager"
|
||||
|
||||
@@ -10,9 +10,9 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
@@ -134,7 +134,7 @@ func (v *WorkersVersion) Apply() error {
|
||||
|
||||
if err := os.Rename(newFilePath, v.targetPath); err != nil {
|
||||
//attempt rollback
|
||||
os.Rename(oldFilePath, v.targetPath)
|
||||
_ = os.Rename(oldFilePath, v.targetPath)
|
||||
return err
|
||||
}
|
||||
os.Remove(oldFilePath)
|
||||
@@ -181,7 +181,7 @@ func download(url, filepath string, isCompressed bool) error {
|
||||
tr := tar.NewReader(gr)
|
||||
|
||||
// advance the reader pass the header, which will be the single binary file
|
||||
tr.Next()
|
||||
_, _ = tr.Next()
|
||||
|
||||
r = tr
|
||||
}
|
||||
@@ -198,7 +198,7 @@ func download(url, filepath string, isCompressed bool) error {
|
||||
|
||||
// isCompressedFile is a really simple file extension check to see if this is a macos tar and gzipped
|
||||
func isCompressedFile(urlstring string) bool {
|
||||
if strings.HasSuffix(urlstring, ".tgz") {
|
||||
if path.Ext(urlstring) == ".tgz" {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -206,7 +206,7 @@ func isCompressedFile(urlstring string) bool {
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return strings.HasSuffix(u.Path, ".tgz")
|
||||
return path.Ext(u.Path) == ".tgz"
|
||||
}
|
||||
|
||||
// writeBatchFile writes a batch file out to disk
|
||||
@@ -249,7 +249,6 @@ func runWindowsBatch(batchFile string) error {
|
||||
if exitError, ok := err.(*exec.ExitError); ok {
|
||||
return fmt.Errorf("Error during update : %s;", string(exitError.Stderr))
|
||||
}
|
||||
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ import (
|
||||
const (
|
||||
windowsServiceName = "Cloudflared"
|
||||
windowsServiceDescription = "Cloudflared agent"
|
||||
windowsServiceUrl = "https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/run-tunnel/as-a-service/windows/"
|
||||
windowsServiceUrl = "https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/configure-tunnels/local-management/as-a-service/windows/"
|
||||
|
||||
recoverActionDelay = time.Second * 20
|
||||
failureCountResetPeriod = time.Hour * 24
|
||||
|
||||
@@ -26,14 +26,20 @@ const (
|
||||
MaxGracePeriod = time.Minute * 3
|
||||
MaxConcurrentStreams = math.MaxUint32
|
||||
|
||||
contentTypeHeader = "content-type"
|
||||
sseContentType = "text/event-stream"
|
||||
grpcContentType = "application/grpc"
|
||||
contentTypeHeader = "content-type"
|
||||
contentLengthHeader = "content-length"
|
||||
transferEncodingHeader = "transfer-encoding"
|
||||
|
||||
sseContentType = "text/event-stream"
|
||||
grpcContentType = "application/grpc"
|
||||
sseJsonContentType = "application/x-ndjson"
|
||||
|
||||
chunkTransferEncoding = "chunked"
|
||||
)
|
||||
|
||||
var (
|
||||
switchingProtocolText = fmt.Sprintf("%d %s", http.StatusSwitchingProtocols, http.StatusText(http.StatusSwitchingProtocols))
|
||||
flushableContentTypes = []string{sseContentType, grpcContentType}
|
||||
flushableContentTypes = []string{sseContentType, grpcContentType, sseJsonContentType}
|
||||
)
|
||||
|
||||
// TunnelConnection represents the connection to the edge.
|
||||
@@ -274,6 +280,22 @@ type ConnectedFuse interface {
|
||||
// Helper method to let the caller know what content-types should require a flush on every
|
||||
// write to a ResponseWriter.
|
||||
func shouldFlush(headers http.Header) bool {
|
||||
// When doing Server Side Events (SSE), some frameworks don't respect the `Content-Type` header.
|
||||
// Therefore, we need to rely on other ways to know whether we should flush on write or not. A good
|
||||
// approach is to assume that responses without `Content-Length` or with `Transfer-Encoding: chunked`
|
||||
// are streams, and therefore, should be flushed right away to the eyeball.
|
||||
// References:
|
||||
// - https://datatracker.ietf.org/doc/html/rfc7230#section-4.1
|
||||
// - https://datatracker.ietf.org/doc/html/rfc9112#section-6.1
|
||||
if contentLength := headers.Get(contentLengthHeader); contentLength == "" {
|
||||
return true
|
||||
}
|
||||
if transferEncoding := headers.Get(transferEncodingHeader); transferEncoding != "" {
|
||||
transferEncoding = strings.ToLower(transferEncoding)
|
||||
if strings.Contains(transferEncoding, chunkTransferEncoding) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if contentType := headers.Get(contentTypeHeader); contentType != "" {
|
||||
contentType = strings.ToLower(contentType)
|
||||
for _, c := range flushableContentTypes {
|
||||
@@ -282,7 +304,6 @@ func shouldFlush(headers http.Header) bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,12 @@ import (
|
||||
"io"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
pkgerrors "github.com/pkg/errors"
|
||||
"github.com/rs/zerolog"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
cfdflow "github.com/cloudflare/cloudflared/flow"
|
||||
|
||||
@@ -209,3 +211,48 @@ func (mcf mockConnectedFuse) Connected() {}
|
||||
func (mcf mockConnectedFuse) IsConnected() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func TestShouldFlushHeaders(t *testing.T) {
|
||||
tests := []struct {
|
||||
headers map[string]string
|
||||
shouldFlush bool
|
||||
}{
|
||||
{
|
||||
headers: map[string]string{contentTypeHeader: "application/json", contentLengthHeader: "1"},
|
||||
shouldFlush: false,
|
||||
},
|
||||
{
|
||||
headers: map[string]string{contentTypeHeader: "text/html", contentLengthHeader: "1"},
|
||||
shouldFlush: false,
|
||||
},
|
||||
{
|
||||
headers: map[string]string{contentTypeHeader: "text/event-stream", contentLengthHeader: "1"},
|
||||
shouldFlush: true,
|
||||
},
|
||||
{
|
||||
headers: map[string]string{contentTypeHeader: "application/grpc", contentLengthHeader: "1"},
|
||||
shouldFlush: true,
|
||||
},
|
||||
{
|
||||
headers: map[string]string{contentTypeHeader: "application/x-ndjson", contentLengthHeader: "1"},
|
||||
shouldFlush: true,
|
||||
},
|
||||
{
|
||||
headers: map[string]string{contentTypeHeader: "application/json"},
|
||||
shouldFlush: true,
|
||||
},
|
||||
{
|
||||
headers: map[string]string{contentTypeHeader: "application/json", contentLengthHeader: "-1", transferEncodingHeader: "chunked"},
|
||||
shouldFlush: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
headers := http.Header{}
|
||||
for k, v := range test.headers {
|
||||
headers.Add(k, v)
|
||||
}
|
||||
|
||||
require.Equal(t, test.shouldFlush, shouldFlush(headers))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ package credentials
|
||||
import (
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
@@ -13,8 +13,8 @@ func TestCredentialsRead(t *testing.T) {
|
||||
file, err := os.ReadFile("test-cloudflare-tunnel-cert-json.pem")
|
||||
require.NoError(t, err)
|
||||
dir := t.TempDir()
|
||||
certPath := path.Join(dir, originCertFile)
|
||||
os.WriteFile(certPath, file, fs.ModePerm)
|
||||
certPath := filepath.Join(dir, originCertFile)
|
||||
_ = os.WriteFile(certPath, file, fs.ModePerm)
|
||||
user, err := Read(certPath, &nopLog)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, certPath, user.CertPath())
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/rs/zerolog"
|
||||
@@ -63,7 +63,7 @@ func TestFindOriginCert_Valid(t *testing.T) {
|
||||
file, err := os.ReadFile("test-cloudflare-tunnel-cert-json.pem")
|
||||
require.NoError(t, err)
|
||||
dir := t.TempDir()
|
||||
certPath := path.Join(dir, originCertFile)
|
||||
certPath := filepath.Join(dir, originCertFile)
|
||||
_ = os.WriteFile(certPath, file, fs.ModePerm)
|
||||
path, err := FindOriginCert(certPath, &nopLog)
|
||||
require.NoError(t, err)
|
||||
@@ -72,7 +72,7 @@ func TestFindOriginCert_Valid(t *testing.T) {
|
||||
|
||||
func TestFindOriginCert_Missing(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
certPath := path.Join(dir, originCertFile)
|
||||
certPath := filepath.Join(dir, originCertFile)
|
||||
_, err := FindOriginCert(certPath, &nopLog)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
+11
-4
@@ -61,7 +61,7 @@ def assert_tag_exists(repo, version):
|
||||
raise Exception("Tag {} not found".format(version))
|
||||
|
||||
|
||||
def get_or_create_release(repo, version, dry_run=False):
|
||||
def get_or_create_release(repo, version, dry_run=False, is_draft=False):
|
||||
"""
|
||||
Get a Github Release matching the version tag or create a new one.
|
||||
If a conflict occurs on creation, attempt to fetch the Release on last time
|
||||
@@ -81,8 +81,11 @@ def get_or_create_release(repo, version, dry_run=False):
|
||||
return
|
||||
|
||||
try:
|
||||
logging.info("Creating release %s", version)
|
||||
return repo.create_git_release(version, version, "")
|
||||
if is_draft:
|
||||
logging.info("Drafting release %s", version)
|
||||
else:
|
||||
logging.info("Creating release %s", version)
|
||||
return repo.create_git_release(version, version, "", is_draft)
|
||||
except GithubException as e:
|
||||
errors = e.data.get("errors", [])
|
||||
if e.status == 422 and any(
|
||||
@@ -129,6 +132,10 @@ def parse_args():
|
||||
"--dry-run", action="store_true", help="Do not create release or upload asset"
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--draft", action="store_true", help="Create a draft release"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
is_valid = True
|
||||
if not args.release_version:
|
||||
@@ -292,7 +299,7 @@ def main():
|
||||
for filename in onlyfiles:
|
||||
binary_path = os.path.join(args.path, filename)
|
||||
assert_asset_version(binary_path, args.release_version)
|
||||
release = get_or_create_release(repo, args.release_version, args.dry_run)
|
||||
release = get_or_create_release(repo, args.release_version, args.dry_run, args.draft)
|
||||
for filename in onlyfiles:
|
||||
binary_path = os.path.join(args.path, filename)
|
||||
upload_asset(release, binary_path, filename, args.release_version, args.kv_account_id, args.namespace_id,
|
||||
|
||||
+1
-2
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -249,7 +248,7 @@ func createRollingLogger(config RollingConfig) (io.Writer, error) {
|
||||
}
|
||||
|
||||
rotatingFileInit.writer = &lumberjack.Logger{
|
||||
Filename: path.Join(config.Dirname, config.Filename),
|
||||
Filename: filepath.Join(config.Dirname, config.Filename),
|
||||
MaxBackups: config.maxBackups,
|
||||
MaxSize: config.maxSize,
|
||||
MaxAge: config.maxAge,
|
||||
|
||||
@@ -74,7 +74,7 @@ type EventLog struct {
|
||||
type LogEventType int8
|
||||
|
||||
const (
|
||||
// Cloudflared events are signficant to cloudflared operations like connection state changes.
|
||||
// Cloudflared events are significant to cloudflared operations like connection state changes.
|
||||
// Cloudflared is also the default event type for any events that haven't been separated into a proper event type.
|
||||
Cloudflared LogEventType = iota
|
||||
HTTP
|
||||
@@ -129,7 +129,7 @@ func (e *LogEventType) UnmarshalJSON(data []byte) error {
|
||||
|
||||
// LogLevel corresponds to the zerolog logging levels
|
||||
// "panic", "fatal", and "trace" are exempt from this list as they are rarely used and, at least
|
||||
// the the first two are limited to failure conditions that lead to cloudflared shutting down.
|
||||
// the first two are limited to failure conditions that lead to cloudflared shutting down.
|
||||
type LogLevel int8
|
||||
|
||||
const (
|
||||
|
||||
@@ -79,8 +79,8 @@ func (b *BackoffHandler) BackoffTimer() <-chan time.Time {
|
||||
} else {
|
||||
b.retries++
|
||||
}
|
||||
maxTimeToWait := time.Duration(b.GetBaseTime() * 1 << (b.retries))
|
||||
timeToWait := time.Duration(rand.Int63n(maxTimeToWait.Nanoseconds()))
|
||||
maxTimeToWait := b.GetBaseTime() * (1 << b.retries)
|
||||
timeToWait := time.Duration(rand.Int63n(maxTimeToWait.Nanoseconds())) // #nosec G404
|
||||
return b.Clock.After(timeToWait)
|
||||
}
|
||||
|
||||
@@ -99,11 +99,11 @@ func (b *BackoffHandler) Backoff(ctx context.Context) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// Sets a grace period within which the the backoff timer is maintained. After the grace
|
||||
// Sets a grace period within which the backoff timer is maintained. After the grace
|
||||
// period expires, the number of retries & backoff duration is reset.
|
||||
func (b *BackoffHandler) SetGracePeriod() time.Duration {
|
||||
maxTimeToWait := b.GetBaseTime() * 2 << (b.retries + 1)
|
||||
timeToWait := time.Duration(rand.Int63n(maxTimeToWait.Nanoseconds()))
|
||||
timeToWait := time.Duration(rand.Int63n(maxTimeToWait.Nanoseconds())) // #nosec G404
|
||||
b.resetDeadline = b.Clock.Now().Add(timeToWait)
|
||||
|
||||
return timeToWait
|
||||
@@ -118,7 +118,7 @@ func (b BackoffHandler) GetBaseTime() time.Duration {
|
||||
|
||||
// Retries returns the number of retries consumed so far.
|
||||
func (b *BackoffHandler) Retries() int {
|
||||
return int(b.retries)
|
||||
return int(b.retries) // #nosec G115
|
||||
}
|
||||
|
||||
func (b *BackoffHandler) ReachedMaxRetries() bool {
|
||||
|
||||
Reference in New Issue
Block a user