Repository: cloudflare/cloudflare-go
Pull request #2698 (2024-06-24 20:03:01)

FLPROD-1370: Add client for CloudConnectorAPI
FL Team: new product CloudConnector designed to create rules similar to ERE rules for connecting cloud providers for a zone.
Supports: GET and PUT methods.

github-actions[bot]: Oops! It looks like no changelog entry is attached to this PR. Please include a release note as described in https://github.com/cloudflare/cloudflare-go/blob/master/docs/changelog-process.md.

Example: 

~~~
```release-note:TYPE
Release note
```
~~~

If you do not require a release note to be included, please add the `workflow/skip-changelog-entry` label.
jacobbednarz: can you link to the external API schemas for this one? i'm not seeing it in api-schemas which suggests we don't have this documented yet.
WowVeryLogin: Schemas are in: https://bitbucket.cfdata.org/projects/FL/repos/cloud-connector-api/browse/schemas/openapi.yaml
I'll try to publish them today

Patch:
diff --git a/.changelog/2698.txt b/.changelog/2698.txt
new file mode 100644
index 000000000..3202a1e1f
--- /dev/null
+++ b/.changelog/2698.txt
@@ -0,0 +1,3 @@
+```release-note:enhancement
+Add CloudConnectorAPI Client
+```
diff --git a/.changelog/2699.txt b/.changelog/2699.txt
deleted file mode 100644
index 591c8c796..000000000
--- a/.changelog/2699.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:dependency
-deps: bumps github.com/hashicorp/go-retryablehttp from 0.7.1 to 0.7.7
-```
diff --git a/.changelog/2713.txt b/.changelog/2713.txt
deleted file mode 100644
index 5d8e2be06..000000000
--- a/.changelog/2713.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:enhancement
-teams: added per account certificate setting to teams gateway configuration
-```
diff --git a/.changelog/2722.txt b/.changelog/2722.txt
deleted file mode 100644
index 974f083d7..000000000
--- a/.changelog/2722.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:enhancement
-gateway_categories: add ListGatewayCategories which returns all gateway categories.
-```
diff --git a/.changelog/2726.txt b/.changelog/2726.txt
deleted file mode 100644
index fb9f4df19..000000000
--- a/.changelog/2726.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:dependency
-deps: bumps golang.org/x/net from 0.26.0 to 0.27.0
-```
diff --git a/.changelog/2727.txt b/.changelog/2727.txt
deleted file mode 100644
index 18b0909f6..000000000
--- a/.changelog/2727.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-```release-note:dependency
-deps: bumps dependabot/fetch-metadata from 2.1.0 to 2.2.0
-```
diff --git a/.github/workflows/dependabot-changelog.yml b/.github/workflows/dependabot-changelog.yml
index f27f21e78..8c8d83877 100644
--- a/.github/workflows/dependabot-changelog.yml
+++ b/.github/workflows/dependabot-changelog.yml
@@ -12,7 +12,7 @@ jobs:
     steps:
       - name: Fetch dependabot metadata
         id: dependabot-metadata
-        uses: dependabot/fetch-metadata@v2.2.0
+        uses: dependabot/fetch-metadata@v2.1.0
       - uses: actions/checkout@v4
       - run: |
           gh pr checkout $PR_URL
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 723adb315..8f6c1b5c3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,16 +1,4 @@
-## 0.100.0 (Unreleased)
-
-## 0.99.0 (July 3rd, 2024)
-
-ENHANCEMENTS:
-
-* teams: added per account certificate setting to teams gateway configuration ([#2713](https://github.com/cloudflare/cloudflare-go/issues/2713))
-* teams_list: Added description to ZT list item ([#2621](https://github.com/cloudflare/cloudflare-go/issues/2621))
-* teams_rules: Added ZT rule settings `ignore_cname_category_matches` ([#2621](https://github.com/cloudflare/cloudflare-go/issues/2621))
-
-DEPENDENCIES:
-
-* deps: bumps github.com/hashicorp/go-retryablehttp from 0.7.1 to 0.7.7 ([#2699](https://github.com/cloudflare/cloudflare-go/issues/2699))
+## 0.99.0 (Unreleased)
 
 ## 0.98.0 (June 19th, 2024)
 
diff --git a/cloud_connector.go b/cloud_connector.go
new file mode 100644
index 000000000..8c6e3b960
--- /dev/null
+++ b/cloud_connector.go
@@ -0,0 +1,71 @@
+package cloudflare
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+
+	"github.com/goccy/go-json"
+)
+
+type CloudConnectorRulesResponse struct {
+	Response
+	Result []CloudConnectorRule `json:"result"`
+}
+
+type CloudConnectorRuleParameters struct {
+	Host string `json:"host"`
+}
+
+type CloudConnectorRule struct {
+	ID          string                       `json:"id"`
+	Enabled     *bool                        `json:"enabled,omitempty"`
+	Expression  string                       `json:"expression"`
+	Provider    string                       `json:"provider"`
+	Parameters  CloudConnectorRuleParameters `json:"parameters"`
+	Description string                       `json:"description"`
+}
+
+func (api *API) ListZoneCloudConnectorRules(ctx context.Context, rc *ResourceContainer) ([]CloudConnectorRule, error) {
+	if rc.Identifier == "" {
+		return nil, ErrMissingZoneID
+	}
+
+	uri := buildURI(fmt.Sprintf("/zones/%s/cloud_connector/rules", rc.Identifier), nil)
+	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return nil, err
+	}
+
+	result := CloudConnectorRulesResponse{}
+	if err := json.Unmarshal(res, &result); err != nil {
+		return nil, fmt.Errorf("%s: %w", errUnmarshalError, err)
+	}
+
+	return result.Result, nil
+}
+
+func (api *API) UpdateZoneCloudConnectorRules(ctx context.Context, rc *ResourceContainer, params []CloudConnectorRule) ([]CloudConnectorRule, error) {
+	if rc.Identifier == "" {
+		return nil, ErrMissingZoneID
+	}
+
+	uri := fmt.Sprintf("/zones/%s/cloud_connector/rules", rc.Identifier)
+
+	payload, err := json.Marshal(params)
+	if err != nil {
+		return nil, err
+	}
+
+	res, err := api.makeRequestContext(ctx, http.MethodPut, uri, payload)
+	if err != nil {
+		return nil, err
+	}
+
+	result := CloudConnectorRulesResponse{}
+	if err := json.Unmarshal(res, &result); err != nil {
+		return nil, fmt.Errorf("%s: %w", errUnmarshalError, err)
+	}
+
+	return result.Result, nil
+}
diff --git a/gateway_categories.go b/gateway_categories.go
deleted file mode 100644
index da23a74e1..000000000
--- a/gateway_categories.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package cloudflare
-
-import (
-	"context"
-	"fmt"
-	"net/http"
-
-	"github.com/goccy/go-json"
-)
-
-// GatewayCategory represents a single gateway category.
-type GatewayCategory struct {
-	Beta          *bool             `json:"beta,omitempty"`
-	Class         string            `json:"class"`
-	Description   string            `json:"description"`
-	ID            int               `json:"id"`
-	Name          string            `json:"name"`
-	Subcategories []GatewayCategory `json:"subcategories"`
-}
-
-// GatewayCategoriesResponse represents the response from the list
-// gateway categories endpoint.
-type GatewayCategoriesResponse struct {
-	Success    bool              `json:"success"`
-	Result     []GatewayCategory `json:"result"`
-	Errors     []string          `json:"errors"`
-	Messages   []string          `json:"messages"`
-	ResultInfo ResultInfo        `json:"result_info"`
-}
-
-// ListGatewayCategoriesParams represents the parameters for listing gateway categories.
-type ListGatewayCategoriesParams struct {
-	ResultInfo
-}
-
-// ListGatewayCategories returns all gateway categories within an account.
-//
-// API reference: https://developers.cloudflare.com/api/operations/zero-trust-gateway-categories-list-categories
-func (api *API) ListGatewayCategories(ctx context.Context, rc *ResourceContainer, params ListGatewayCategoriesParams) ([]GatewayCategory, ResultInfo, error) {
-	uri := fmt.Sprintf("/accounts/%s/gateway/categories", rc.Identifier)
-
-	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
-	if err != nil {
-		return []GatewayCategory{}, ResultInfo{}, err
-	}
-
-	var gResponse GatewayCategoriesResponse
-	err = json.Unmarshal(res, &gResponse)
-	if err != nil {
-		return []GatewayCategory{}, ResultInfo{}, fmt.Errorf("%s: %w", errUnmarshalError, err)
-	}
-
-	return gResponse.Result, gResponse.ResultInfo, nil
-}
diff --git a/go.mod b/go.mod
index 92ffadc4f..5524d6975 100644
--- a/go.mod
+++ b/go.mod
@@ -9,7 +9,7 @@ require (
 	github.com/olekukonko/tablewriter v0.0.5
 	github.com/stretchr/testify v1.9.0
 	github.com/urfave/cli/v2 v2.27.2
-	golang.org/x/net v0.27.0
+	golang.org/x/net v0.26.0
 	golang.org/x/time v0.5.0
 )
 
diff --git a/go.sum b/go.sum
index 0900ecd50..b1a05597d 100644
--- a/go.sum
+++ b/go.sum
@@ -47,9 +47,9 @@ github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI=
 github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM=
 github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw=
 github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk=
-golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys=
-golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE=
-golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
+golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
+golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
 golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
 golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
 golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
diff --git a/internal/tools/go.mod b/internal/tools/go.mod
index bf856580d..c59259042 100644
--- a/internal/tools/go.mod
+++ b/internal/tools/go.mod
@@ -69,7 +69,7 @@ require (
 	github.com/emirpasic/gods v1.18.1 // indirect
 	github.com/esimonov/ifshort v1.0.4 // indirect
 	github.com/ettle/strcase v0.1.1 // indirect
-	github.com/fatih/color v1.16.0 // indirect
+	github.com/fatih/color v1.13.0 // indirect
 	github.com/fatih/structtag v1.2.0 // indirect
 	github.com/firefart/nonamedreturns v1.0.4 // indirect
 	github.com/fsnotify/fsnotify v1.5.4 // indirect
@@ -114,7 +114,7 @@ require (
 	github.com/hashicorp/go-checkpoint v0.5.0 // indirect
 	github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
 	github.com/hashicorp/go-multierror v1.1.1 // indirect
-	github.com/hashicorp/go-retryablehttp v0.7.7 // indirect
+	github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
 	github.com/hashicorp/go-uuid v1.0.3 // indirect
 	github.com/hashicorp/go-version v1.6.0 // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
@@ -144,8 +144,8 @@ require (
 	github.com/magiconair/properties v1.8.6 // indirect
 	github.com/maratori/testpackage v1.1.0 // indirect
 	github.com/matoous/godox v0.0.0-20210227103229-6504466cf951 // indirect
-	github.com/mattn/go-colorable v0.1.13 // indirect
-	github.com/mattn/go-isatty v0.0.20 // indirect
+	github.com/mattn/go-colorable v0.1.12 // indirect
+	github.com/mattn/go-isatty v0.0.14 // indirect
 	github.com/mattn/go-runewidth v0.0.13 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
 	github.com/mbilski/exhaustivestruct v1.2.0 // indirect
@@ -230,7 +230,7 @@ require (
 	golang.org/x/mod v0.12.0 // indirect
 	golang.org/x/net v0.23.0 // indirect
 	golang.org/x/sync v0.3.0 // indirect
-	golang.org/x/sys v0.20.0 // indirect
+	golang.org/x/sys v0.18.0 // indirect
 	golang.org/x/text v0.14.0 // indirect
 	golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect
 	golang.org/x/vuln v0.0.0-20220725105440-4151a5aca1df // indirect
diff --git a/internal/tools/go.sum b/internal/tools/go.sum
index ab0c7aadf..8375f5d09 100644
--- a/internal/tools/go.sum
+++ b/internal/tools/go.sum
@@ -214,9 +214,8 @@ github.com/esimonov/ifshort v1.0.4/go.mod h1:Pe8zjlRrJ80+q2CxHLfEOfTwxCZ4O+MuhcH
 github.com/ettle/strcase v0.1.1 h1:htFueZyVeE1XNnMEfbqp5r67qAN/4r6ya1ysq8Q+Zcw=
 github.com/ettle/strcase v0.1.1/go.mod h1:hzDLsPC7/lwKyBOywSHEP89nt2pDgdy+No1NBA9o9VY=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
 github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
-github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
-github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
 github.com/fatih/structtag v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
 github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94=
 github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y=
@@ -434,7 +433,7 @@ github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9
 github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
 github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
 github.com/hashicorp/go-hclog v0.15.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
-github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k=
+github.com/hashicorp/go-hclog v1.2.0 h1:La19f8d7WIlm4ogzNHB0JGqs5AUDAZ2UfCY4sJXcJdM=
 github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
 github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
 github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
@@ -442,8 +441,8 @@ github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+l
 github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
 github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0=
 github.com/hashicorp/go-plugin v1.4.0/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ=
-github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU=
-github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk=
+github.com/hashicorp/go-retryablehttp v0.7.1 h1:sUiuQAnLlbvmExtFQs72iFW/HXeUn8Z1aJLQ4LJJbTQ=
+github.com/hashicorp/go-retryablehttp v0.7.1/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
 github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
 github.com/hashicorp/go-safetemp v1.0.0/go.mod h1:oaerMy3BhqiTbVye6QuFhFtIceqFoDHxNAB65b+Rj1I=
 github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
@@ -594,18 +593,16 @@ github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaO
 github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
 github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
 github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
-github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
-github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
+github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
 github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
 github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
 github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
-github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
 github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
@@ -1137,6 +1134,7 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211105183446-c75c47738b0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1148,13 +1146,12 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220702020025-31831981b65f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
-golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
+golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
diff --git a/teams_accounts.go b/teams_accounts.go
index f426c68ba..3472fa487 100644
--- a/teams_accounts.go
+++ b/teams_accounts.go
@@ -47,7 +47,6 @@ type TeamsAccountSettings struct {
 	BodyScanning          *TeamsBodyScanning          `json:"body_scanning,omitempty"`
 	ExtendedEmailMatching *TeamsExtendedEmailMatching `json:"extended_email_matching,omitempty"`
 	CustomCertificate     *TeamsCustomCertificate     `json:"custom_certificate,omitempty"`
-	Certificate           *TeamsCertificate           `json:"certificate,omitempty"`
 }
 
 type BrowserIsolation struct {
@@ -113,10 +112,6 @@ type TeamsCustomCertificate struct {
 	UpdatedAt     *time.Time `json:"updated_at,omitempty"`
 }
 
-type TeamsCertificate struct {
-	ID string `json:"id"`
-}
-
 type TeamsRuleType = string
 
 const (


Test patch:
diff --git a/cloud_connector_test.go b/cloud_connector_test.go
new file mode 100644
index 000000000..c727a6daf
--- /dev/null
+++ b/cloud_connector_test.go
@@ -0,0 +1,161 @@
+package cloudflare
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestCloudConnectorRules(t *testing.T) {
+	setup()
+	defer teardown()
+
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprint(w, `{
+      "result": [
+		{
+			"id": "some_id_1",
+			"provider": "aws_s3",
+			"expression": "true",
+			"enabled": true,
+			"description": "some description",
+			"parameters": {
+				"host": "aws.s3.bucket"
+			}
+	  	},
+		{
+			"id": "some_id_2",
+			"provider": "r2",
+			"expression": "true",
+			"enabled": true,
+			"description": "some description",
+			"parameters": {
+				"host": "r2.hostname"
+			}
+	  	}
+	  ],
+      "success": true,
+      "errors": [],
+      "messages": []
+    }`)
+	}
+	mux.HandleFunc("/zones/"+testZoneID+"/cloud_connector/rules", handler)
+
+	want := []CloudConnectorRule{
+		{
+			ID:          "some_id_1",
+			Provider:    "aws_s3",
+			Expression:  "true",
+			Enabled:     BoolPtr(true),
+			Description: "some description",
+			Parameters: CloudConnectorRuleParameters{
+				Host: "aws.s3.bucket",
+			},
+		},
+		{
+			ID:          "some_id_2",
+			Provider:    "r2",
+			Expression:  "true",
+			Enabled:     BoolPtr(true),
+			Description: "some description",
+			Parameters: CloudConnectorRuleParameters{
+				Host: "r2.hostname",
+			},
+		},
+	}
+
+	zoneActual, err := client.ListZoneCloudConnectorRules(context.Background(), ZoneIdentifier(testZoneID))
+	if assert.NoError(t, err) {
+		assert.Equal(t, want, zoneActual)
+	}
+}
+
+func TestUpdateCloudConnectorRules(t *testing.T) {
+	setup()
+	defer teardown()
+
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PATCH', got %s", r.Method)
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprint(w, `{
+      "result": [
+		{
+			"id": "some_id_1",
+			"provider": "aws_s3",
+			"expression": "true",
+			"enabled": true,
+			"description": "some description",
+			"parameters": {
+				"host": "aws.s3.bucket"
+			}
+	  	},
+		{
+			"id": "some_id_2",
+			"provider": "r2",
+			"expression": "true",
+			"enabled": true,
+			"description": "some description",
+			"parameters": {
+				"host": "r2.hostname"
+			}
+	  	}
+	  ],
+      "success": true,
+      "errors": [],
+      "messages": []
+    }`)
+	}
+
+	mux.HandleFunc("/zones/"+testZoneID+"/cloud_connector/rules", handler)
+	toUpdate := []CloudConnectorRule{
+		{
+			Provider:    "aws_s3",
+			Expression:  "true",
+			Enabled:     BoolPtr(true),
+			Description: "some description",
+			Parameters: CloudConnectorRuleParameters{
+				Host: "aws.s3.bucket",
+			},
+		},
+		{
+			Provider:    "r2",
+			Expression:  "true",
+			Enabled:     BoolPtr(true),
+			Description: "some description",
+			Parameters: CloudConnectorRuleParameters{
+				Host: "r2.hostname",
+			},
+		},
+	}
+	want := []CloudConnectorRule{
+		{
+			ID:          "some_id_1",
+			Provider:    "aws_s3",
+			Expression:  "true",
+			Enabled:     BoolPtr(true),
+			Description: "some description",
+			Parameters: CloudConnectorRuleParameters{
+				Host: "aws.s3.bucket",
+			},
+		},
+		{
+			ID:          "some_id_2",
+			Provider:    "r2",
+			Expression:  "true",
+			Enabled:     BoolPtr(true),
+			Description: "some description",
+			Parameters: CloudConnectorRuleParameters{
+				Host: "r2.hostname",
+			},
+		},
+	}
+	zoneActual, err := client.UpdateZoneCloudConnectorRules(context.Background(), ZoneIdentifier(testZoneID), toUpdate)
+	if assert.NoError(t, err) {
+		assert.Equal(t, want, zoneActual)
+	}
+}
diff --git a/gateway_categories_test.go b/gateway_categories_test.go
deleted file mode 100644
index e1b4f2bcc..000000000
--- a/gateway_categories_test.go
+++ /dev/null
@@ -1,76 +0,0 @@
-package cloudflare
-
-import (
-	"context"
-	"fmt"
-	"net/http"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestListGatewayCategories(t *testing.T) {
-	setup()
-	defer teardown()
-
-	handler := func(w http.ResponseWriter, r *http.Request) {
-		assert.Equal(t, http.MethodGet, r.Method, "Expected method 'GET', got %s", r.Method)
-		w.Header().Set("content-type", "application/json")
-		fmt.Fprintf(w, `{
-			"success": true,
-			"errors": [],
-			"messages": [],
-			"result": [
-				{
-					"beta": false,
-					"class": "premium",
-					"description": "Sites related to educational content.",
-					"id": 0,
-					"name": "Education",
-					"subcategories": [
-						{
-							"beta": true,
-							"class": "premium",
-							"description": "Sites related to educational content.",
-							"id": 0,
-							"name": "Education"
-						}
-					]
-				}
-			],
-			"result_info": {
-				"count": 1,
-				"page": 1,
-				"per_page": 20,
-				"total_count": 2000
-			}
-		}`)
-	}
-
-	want := []GatewayCategory{
-		{
-			Beta:        BoolPtr(false),
-			Class:       "premium",
-			Description: "Sites related to educational content.",
-			ID:          0,
-			Name:        "Education",
-			Subcategories: []GatewayCategory{
-				{
-					Beta:        BoolPtr(true),
-					Class:       "premium",
-					Description: "Sites related to educational content.",
-					ID:          0,
-					Name:        "Education",
-				},
-			},
-		},
-	}
-
-	mux.HandleFunc("/accounts/"+testAccountID+"/gateway/categories", handler)
-
-	actual, _, err := client.ListGatewayCategories(context.Background(), AccountIdentifier(testAccountID), ListGatewayCategoriesParams{})
-
-	if assert.NoError(t, err) {
-		assert.Equal(t, want, actual)
-	}
-}
diff --git a/teams_accounts_test.go b/teams_accounts_test.go
index 52873da6c..5fd3686ac 100644
--- a/teams_accounts_test.go
+++ b/teams_accounts_test.go
@@ -93,9 +93,6 @@ func TestTeamsAccountConfiguration(t *testing.T) {
 					},
 					"extended_email_matching": {
 						"enabled": true
-					},
-					"certificate": {
-						"id": "7559a944-3dd7-41bf-b183-360a814a8c36"
 					}
 				}
 			}
@@ -141,9 +138,6 @@ func TestTeamsAccountConfiguration(t *testing.T) {
 			ExtendedEmailMatching: &TeamsExtendedEmailMatching{
 				Enabled: BoolPtr(true),
 			},
-			Certificate: &TeamsCertificate{
-				ID: "7559a944-3dd7-41bf-b183-360a814a8c36",
-			},
 		})
 	}
 }