diff --git a/.changelog/1490.txt b/.changelog/1490.txt new file mode 100644 index 00000000000..20f833089ce --- /dev/null +++ b/.changelog/1490.txt @@ -0,0 +1,3 @@ +```release-note:note +zaraz: replace deprecated neoEvents with Actions on Zaraz Config tools schema +``` diff --git a/.changelog/1499.txt b/.changelog/1499.txt new file mode 100644 index 00000000000..8272eb845b1 --- /dev/null +++ b/.changelog/1499.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +teams_rules: `AntiVirus` settings includes notification settings +``` diff --git a/.changelog/1500.txt b/.changelog/1500.txt new file mode 100644 index 00000000000..af3eba15b87 --- /dev/null +++ b/.changelog/1500.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +access_application: Add support for OIDC SaaS Applications +``` diff --git a/.changelog/1501.txt b/.changelog/1501.txt new file mode 100644 index 00000000000..91b8d37a4b9 --- /dev/null +++ b/.changelog/1501.txt @@ -0,0 +1,3 @@ +```release-note:bug +hyperdrive: password should be nested in origin +``` diff --git a/.changelog/1502.txt b/.changelog/1502.txt new file mode 100644 index 00000000000..09eb13b8586 --- /dev/null +++ b/.changelog/1502.txt @@ -0,0 +1,3 @@ +```release-note:dependency +deps: bumps golang.org/x/net from 0.20.0 to 0.21.0 +``` diff --git a/.changelog/1504.txt b/.changelog/1504.txt new file mode 100644 index 00000000000..c7a53d1b268 --- /dev/null +++ b/.changelog/1504.txt @@ -0,0 +1,3 @@ +```release-note:dependency +deps: bumps golangci/golangci-lint-action from 3 to 4 +``` diff --git a/.changelog/1505.txt b/.changelog/1505.txt new file mode 100644 index 00000000000..4e307037a6d --- /dev/null +++ b/.changelog/1505.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +access_application: add support for `name_id_transform_jsonata` in saas apps +``` diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4aa33807060..074cad6e259 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,7 +17,7 @@ jobs: path: ~/go/pkg/mod key: ${{ runner.os }}-go${{ matrix.go-version }}-${{ hashFiles('**/go.mod') }}-${{ hashFiles('**/go.sum') }} - name: golangci-lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@v4 with: version: latest args: "--config .golintci.yaml" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index bf1fe45a354..1405737f7fd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -4,7 +4,7 @@ jobs: test: strategy: matrix: - go-version: ["1.19", "1.20", "1.21"] + go-version: ["1.20", "1.21", "1.22"] runs-on: ubuntu-latest steps: - uses: actions/setup-go@v5 diff --git a/CHANGELOG.md b/CHANGELOG.md index b641307ef53..0ab55e5098c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,25 @@ -## 0.88.0 (Unreleased) +## 0.89.0 (Unreleased) + +## 0.88.0 (February 14th, 2023) ENHANCEMENTS: +* access_application: Add support for OIDC SaaS Applications ([#1500](https://github.com/cloudflare/cloudflare-go/issues/1500)) * access_application: Add support for `allow_authenticate_via_warp` ([#1496](https://github.com/cloudflare/cloudflare-go/issues/1496)) +* access_application: add support for `name_id_transform_jsonata` in saas apps ([#1505](https://github.com/cloudflare/cloudflare-go/issues/1505)) * access_organization: Add support for `allow_authenticate_via_warp` and `warp_auth_session_duration` ([#1496](https://github.com/cloudflare/cloudflare-go/issues/1496)) * hyperdrive: Add support for hyperdrive CRUD operations ([#1492](https://github.com/cloudflare/cloudflare-go/issues/1492)) * images_variants: Add support for Images Variants CRUD operations ([#1494](https://github.com/cloudflare/cloudflare-go/issues/1494)) +* teams_rules: `AntiVirus` settings includes notification settings ([#1499](https://github.com/cloudflare/cloudflare-go/issues/1499)) + +BUG FIXES: + +* hyperdrive: password should be nested in origin ([#1501](https://github.com/cloudflare/cloudflare-go/issues/1501)) + +DEPENDENCIES: + +* deps: bumps golang.org/x/net from 0.20.0 to 0.21.0 ([#1502](https://github.com/cloudflare/cloudflare-go/issues/1502)) +* deps: bumps golangci/golangci-lint-action from 3 to 4 ([#1504](https://github.com/cloudflare/cloudflare-go/issues/1504)) ## 0.87.0 (January 31st, 2024) diff --git a/access_application.go b/access_application.go index ecbbaa02667..6749500029b 100644 --- a/access_application.go +++ b/access_application.go @@ -106,17 +106,31 @@ type SAMLAttributeConfig struct { } type SaasApplication struct { - AppID string `json:"app_id,omitempty"` - ConsumerServiceUrl string `json:"consumer_service_url,omitempty"` - SPEntityID string `json:"sp_entity_id,omitempty"` - PublicKey string `json:"public_key,omitempty"` - IDPEntityID string `json:"idp_entity_id,omitempty"` - NameIDFormat string `json:"name_id_format,omitempty"` - SSOEndpoint string `json:"sso_endpoint,omitempty"` - DefaultRelayState string `json:"default_relay_state,omitempty"` - UpdatedAt *time.Time `json:"updated_at,omitempty"` - CreatedAt *time.Time `json:"created_at,omitempty"` - CustomAttributes []SAMLAttributeConfig `json:"custom_attributes,omitempty"` + // Items common to both SAML and OIDC + AppID string `json:"app_id,omitempty"` + UpdatedAt *time.Time `json:"updated_at,omitempty"` + CreatedAt *time.Time `json:"created_at,omitempty"` + PublicKey string `json:"public_key,omitempty"` + AuthType string `json:"auth_type,omitempty"` + + // SAML saas app + ConsumerServiceUrl string `json:"consumer_service_url,omitempty"` + SPEntityID string `json:"sp_entity_id,omitempty"` + IDPEntityID string `json:"idp_entity_id,omitempty"` + NameIDFormat string `json:"name_id_format,omitempty"` + SSOEndpoint string `json:"sso_endpoint,omitempty"` + DefaultRelayState string `json:"default_relay_state,omitempty"` + CustomAttributes []SAMLAttributeConfig `json:"custom_attributes,omitempty"` + NameIDTransformJsonata string `json:"name_id_transform_jsonata,omitempty"` + + // OIDC saas app + ClientID string `json:"client_id,omitempty"` + ClientSecret string `json:"client_secret,omitempty"` + RedirectURIs []string `json:"redirect_uris,omitempty"` + GrantTypes []string `json:"grant_types,omitempty"` + Scopes []string `json:"scopes,omitempty"` + AppLauncherURL string `json:"app_launcher_url,omitempty"` + GroupFilterRegex string `json:"group_filter_regex,omitempty"` } type AccessAppLauncherCustomization struct { diff --git a/access_application_test.go b/access_application_test.go index 4bf414b2b0a..67be75e9413 100644 --- a/access_application_test.go +++ b/access_application_test.go @@ -620,7 +620,7 @@ func TestCreatePrivateAccessApplication(t *testing.T) { } } -func TestCreateSaasAccessApplications(t *testing.T) { +func TestCreateSAMLSaasAccessApplications(t *testing.T) { setup() defer teardown() @@ -678,7 +678,8 @@ func TestCreateSaasAccessApplications(t *testing.T) { "name": "test3" } } - ] + ], + "name_id_transform_jsonata": "$substringBefore(email, '@') & '+sandbox@' & $substringAfter(email, '@')" } } } @@ -731,6 +732,7 @@ func TestCreateSaasAccessApplications(t *testing.T) { }, }, }, + NameIDTransformJsonata: "$substringBefore(email, '@') & '+sandbox@' & $substringAfter(email, '@')", }, CreatedAt: &createdAt, UpdatedAt: &updatedAt, @@ -771,6 +773,121 @@ func TestCreateSaasAccessApplications(t *testing.T) { } } +func TestCreateOIDCSaasAccessApplications(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPost, r.Method, "Expected method 'POST', got %s", r.Method) + w.Header().Set("content-type", "application/json") + fmt.Fprintf(w, `{ + "success": true, + "errors": [], + "messages": [], + "result": { + "id": "480f4f69-1a28-4fdd-9240-1ed29f0ac1db", + "created_at": "2014-01-01T05:20:00.12345Z", + "updated_at": "2014-01-01T05:20:00.12345Z", + "aud": "737646a56ab1df6ec9bddc7e5ca84eaf3b0768850f3ffb5d74f1534911fe3893", + "name": "Admin OIDC Saas App", + "domain": "example.cloudflareaccess.com/cdn-cgi/access/sso/oidc/737646a56ab1df6ec9bddc7e5ca84eaf3b0768850f3ffb5d74f1534911fe3893", + "type": "saas", + "session_duration": "24h", + "allowed_idps": [], + "auto_redirect_to_identity": false, + "enable_binding_cookie": false, + "custom_deny_url": "https://www.example.com", + "custom_deny_message": "denied!", + "logo_url": "https://www.example.com/example.png", + "skip_interstitial": true, + "app_launcher_visible": true, + "service_auth_401_redirect": true, + "custom_non_identity_deny_url": "https://blocked.com", + "tags": ["engineers"], + "saas_app": { + "auth_type": "oidc", + "client_id": "737646a56ab1df6ec9bddc7e5ca84eaf3b0768850f3ffb5d74f1534911fe3893", + "client_secret": "secret", + "redirect_uris": ["https://saas.example.com"], + "grant_types": ["authorization_code"], + "scopes": ["openid", "email", "profile", "groups"], + "app_launcher_url": "https://saas.example.com", + "group_filter_regex": ".*" + } + } + } + `) + } + + createdAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z") + updatedAt, _ := time.Parse(time.RFC3339, "2014-01-01T05:20:00.12345Z") + fullAccessApplication := AccessApplication{ + ID: "480f4f69-1a28-4fdd-9240-1ed29f0ac1db", + Name: "Admin OIDC Saas App", + Domain: "example.cloudflareaccess.com/cdn-cgi/access/sso/oidc/737646a56ab1df6ec9bddc7e5ca84eaf3b0768850f3ffb5d74f1534911fe3893", + Type: "saas", + SessionDuration: "24h", + AUD: "737646a56ab1df6ec9bddc7e5ca84eaf3b0768850f3ffb5d74f1534911fe3893", + AllowedIdps: []string{}, + AutoRedirectToIdentity: BoolPtr(false), + EnableBindingCookie: BoolPtr(false), + AppLauncherVisible: BoolPtr(true), + ServiceAuth401Redirect: BoolPtr(true), + CustomDenyMessage: "denied!", + CustomDenyURL: "https://www.example.com", + LogoURL: "https://www.example.com/example.png", + SkipInterstitial: BoolPtr(true), + SaasApplication: &SaasApplication{ + AuthType: "oidc", + ClientID: "737646a56ab1df6ec9bddc7e5ca84eaf3b0768850f3ffb5d74f1534911fe3893", + ClientSecret: "secret", + RedirectURIs: []string{"https://saas.example.com"}, + GrantTypes: []string{"authorization_code"}, + Scopes: []string{"openid", "email", "profile", "groups"}, + AppLauncherURL: "https://saas.example.com", + GroupFilterRegex: ".*", + }, + CreatedAt: &createdAt, + UpdatedAt: &updatedAt, + CustomNonIdentityDenyURL: "https://blocked.com", + Tags: []string{"engineers"}, + } + + mux.HandleFunc("/accounts/"+testAccountID+"/access/apps", handler) + + actual, err := client.CreateAccessApplication(context.Background(), AccountIdentifier(testAccountID), CreateAccessApplicationParams{ + Name: "Admin Saas Site", + SaasApplication: &SaasApplication{ + AuthType: "oidc", + RedirectURIs: []string{"https://saas.example.com"}, + AppLauncherURL: "https://saas.example.com", + GroupFilterRegex: ".*", + }, + SessionDuration: "24h", + }) + + if assert.NoError(t, err) { + assert.Equal(t, fullAccessApplication, actual) + } + + mux.HandleFunc("/zones/"+testZoneID+"/access/apps", handler) + + actual, err = client.CreateAccessApplication(context.Background(), ZoneIdentifier(testZoneID), CreateAccessApplicationParams{ + Name: "Admin Saas Site", + SaasApplication: &SaasApplication{ + AuthType: "oidc", + RedirectURIs: []string{"https://saas.example.com"}, + AppLauncherURL: "https://saas.example.com", + GroupFilterRegex: ".*", + }, + SessionDuration: "24h", + }) + + if assert.NoError(t, err) { + assert.Equal(t, fullAccessApplication, actual) + } +} + func TestCreateApplicationWithAccessAppLauncherCustomization(t *testing.T) { setup() defer teardown() diff --git a/go.mod b/go.mod index 9d9d7f8ecc3..9a99bfffd8c 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/olekukonko/tablewriter v0.0.5 github.com/stretchr/testify v1.8.4 github.com/urfave/cli/v2 v2.27.1 - golang.org/x/net v0.20.0 + golang.org/x/net v0.21.0 golang.org/x/time v0.5.0 ) diff --git a/go.sum b/go.sum index d3961c9233a..e93bfe8b76a 100644 --- a/go.sum +++ b/go.sum @@ -59,15 +59,15 @@ github.com/urfave/cli/v2 v2.27.1 h1:8xSQ6szndafKVRmfyeUMxkNUJQMjL1F2zmsZ+qHpfho= github.com/urfave/cli/v2 v2.27.1/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU= github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8= -golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= -golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= +golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y= golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= diff --git a/hyperdrive.go b/hyperdrive.go index 346eb1ccb1a..c1ddbc9a5f3 100644 --- a/hyperdrive.go +++ b/hyperdrive.go @@ -10,9 +10,13 @@ import ( ) var ( - ErrMissingHyperdriveConfigID = errors.New("required hyperdrive config id is missing") - ErrMissingHyperdriveConfigName = errors.New("required hyperdrive config name is missing") - ErrMissingHyperdriveConfigPassword = errors.New("required hyperdrive config password is missing") + ErrMissingHyperdriveConfigID = errors.New("required hyperdrive config id is missing") + ErrMissingHyperdriveConfigName = errors.New("required hyperdrive config name is missing") + ErrMissingHyperdriveConfigOriginDatabase = errors.New("required hyperdrive config origin database is missing") + ErrMissingHyperdriveConfigOriginPassword = errors.New("required hyperdrive config origin password is missing") + ErrMissingHyperdriveConfigOriginHost = errors.New("required hyperdrive config origin host is missing") + ErrMissingHyperdriveConfigOriginScheme = errors.New("required hyperdrive config origin scheme is missing") + ErrMissingHyperdriveConfigOriginUser = errors.New("required hyperdrive config origin user is missing") ) type HyperdriveConfig struct { @@ -24,6 +28,7 @@ type HyperdriveConfig struct { type HyperdriveConfigOrigin struct { Database string `json:"database,omitempty"` + Password string `json:"password"` Host string `json:"host,omitempty"` Port int `json:"port,omitempty"` Scheme string `json:"scheme,omitempty"` @@ -42,10 +47,9 @@ type HyperdriveConfigListResponse struct { } type CreateHyperdriveConfigParams struct { - Name string `json:"name"` - Password string `json:"password"` - Origin HyperdriveConfigOrigin `json:"origin"` - Caching HyperdriveConfigCaching `json:"caching,omitempty"` + Name string `json:"name"` + Origin HyperdriveConfigOrigin `json:"origin"` + Caching HyperdriveConfigCaching `json:"caching,omitempty"` } type HyperdriveConfigResponse struct { @@ -56,7 +60,6 @@ type HyperdriveConfigResponse struct { type UpdateHyperdriveConfigParams struct { HyperdriveID string `json:"-"` Name string `json:"name"` - Password string `json:"password"` Origin HyperdriveConfigOrigin `json:"origin"` Caching HyperdriveConfigCaching `json:"caching,omitempty"` } @@ -99,10 +102,6 @@ func (api *API) CreateHyperdriveConfig(ctx context.Context, rc *ResourceContaine return HyperdriveConfig{}, ErrMissingHyperdriveConfigName } - if params.Password == "" { - return HyperdriveConfig{}, ErrMissingHyperdriveConfigPassword - } - uri := fmt.Sprintf("/accounts/%s/hyperdrive/configs", rc.Identifier) res, err := api.makeRequestContext(ctx, http.MethodPost, uri, params) @@ -178,6 +177,26 @@ func (api *API) UpdateHyperdriveConfig(ctx context.Context, rc *ResourceContaine return HyperdriveConfig{}, ErrMissingHyperdriveConfigID } + if params.Origin.Database == "" { + return HyperdriveConfig{}, ErrMissingHyperdriveConfigOriginDatabase + } + + if params.Origin.Password == "" { + return HyperdriveConfig{}, ErrMissingHyperdriveConfigOriginPassword + } + + if params.Origin.Host == "" { + return HyperdriveConfig{}, ErrMissingHyperdriveConfigOriginHost + } + + if params.Origin.Scheme == "" { + return HyperdriveConfig{}, ErrMissingHyperdriveConfigOriginScheme + } + + if params.Origin.User == "" { + return HyperdriveConfig{}, ErrMissingHyperdriveConfigOriginUser + } + uri := fmt.Sprintf("/accounts/%s/hyperdrive/configs/%s", rc.Identifier, params.HyperdriveID) res, err := api.makeRequestContext(ctx, http.MethodPut, uri, params) diff --git a/hyperdrive_test.go b/hyperdrive_test.go index 633ce9cbbdc..c19378f1490 100644 --- a/hyperdrive_test.go +++ b/hyperdrive_test.go @@ -164,16 +164,11 @@ func TestHyperdriveConfig_Create(t *testing.T) { assert.Equal(t, ErrMissingHyperdriveConfigName, err) } - _, err = client.CreateHyperdriveConfig(context.Background(), AccountIdentifier(testAccountID), CreateHyperdriveConfigParams{Name: "example-hyperdrive"}) - if assert.Error(t, err) { - assert.Equal(t, ErrMissingHyperdriveConfigPassword, err) - } - result, err := client.CreateHyperdriveConfig(context.Background(), AccountIdentifier(testAccountID), CreateHyperdriveConfigParams{ - Name: "example-hyperdrive", - Password: "password", + Name: "example-hyperdrive", Origin: HyperdriveConfigOrigin{ Database: "postgres", + Password: "password", Host: "database.example.com", Port: 5432, Scheme: "postgres", @@ -264,9 +259,9 @@ func TestHyperdriveConfig_Update(t *testing.T) { result, err := client.UpdateHyperdriveConfig(context.Background(), AccountIdentifier(testAccountID), UpdateHyperdriveConfigParams{ HyperdriveID: "6b7efc370ea34ded8327fa20698dfe3a", Name: "example-hyperdrive", - Password: "password", Origin: HyperdriveConfigOrigin{ Database: "postgres", + Password: "password", Host: "database.example.com", Port: 5432, Scheme: "postgres", diff --git a/teams_accounts.go b/teams_accounts.go index 90ae7d347f4..fc8fbb984fd 100644 --- a/teams_accounts.go +++ b/teams_accounts.go @@ -54,9 +54,10 @@ type BrowserIsolation struct { } type TeamsAntivirus struct { - EnabledDownloadPhase bool `json:"enabled_download_phase"` - EnabledUploadPhase bool `json:"enabled_upload_phase"` - FailClosed bool `json:"fail_closed"` + EnabledDownloadPhase bool `json:"enabled_download_phase"` + EnabledUploadPhase bool `json:"enabled_upload_phase"` + FailClosed bool `json:"fail_closed"` + NotificationSettings *TeamsNotificationSettings `json:"notification_settings"` } type TeamsFIPS struct { diff --git a/teams_accounts_test.go b/teams_accounts_test.go index 010e0059e64..a7d096d1cf4 100644 --- a/teams_accounts_test.go +++ b/teams_accounts_test.go @@ -54,8 +54,13 @@ func TestTeamsAccountConfiguration(t *testing.T) { "result": { "settings": { "antivirus": { - "enabled_download_phase": true - }, + "enabled_download_phase": true, + "notification_settings": { + "enabled":true, + "msg":"msg", + "support_url":"https://hi.com" + } + }, "tls_decrypt": { "enabled": true }, @@ -82,7 +87,7 @@ func TestTeamsAccountConfiguration(t *testing.T) { "browser_isolation": { "url_browser_isolation_enabled": true, "non_identity_enabled": true - }, + }, "body_scanning": { "inspection_mode": "deep" }, @@ -101,7 +106,14 @@ func TestTeamsAccountConfiguration(t *testing.T) { if assert.NoError(t, err) { assert.Equal(t, actual.Settings, TeamsAccountSettings{ - Antivirus: &TeamsAntivirus{EnabledDownloadPhase: true}, + Antivirus: &TeamsAntivirus{ + EnabledDownloadPhase: true, + NotificationSettings: &TeamsNotificationSettings{ + Enabled: &trueValue, + Message: "msg", + SupportURL: "https://hi.com", + }, + }, ActivityLog: &TeamsActivityLog{Enabled: true}, TLSDecrypt: &TeamsTLSDecrypt{Enabled: true}, ProtocolDetection: &TeamsProtocolDetection{Enabled: true}, diff --git a/zaraz.go b/zaraz.go index dedfdc4c977..3ffc4f5ede9 100644 --- a/zaraz.go +++ b/zaraz.go @@ -44,6 +44,7 @@ type ZarazConfigSettings struct { ContextEnricher ZarazWorker `json:"contextEnricher,omitempty"` } +// Deprecated: To be removed pending migration of existing configs. type ZarazNeoEvent struct { BlockingTriggers []string `json:"blockingTriggers"` FiringTriggers []string `json:"firingTriggers"` @@ -51,6 +52,13 @@ type ZarazNeoEvent struct { ActionType string `json:"actionType,omitempty"` } +type ZarazAction struct { + BlockingTriggers []string `json:"blockingTriggers"` + FiringTriggers []string `json:"firingTriggers"` + Data map[string]any `json:"data"` + ActionType string `json:"actionType,omitempty"` +} + type ZarazToolType string const ( @@ -60,18 +68,19 @@ const ( ) type ZarazTool struct { - BlockingTriggers []string `json:"blockingTriggers"` - Enabled *bool `json:"enabled"` - DefaultFields map[string]any `json:"defaultFields"` - Name string `json:"name"` - NeoEvents []ZarazNeoEvent `json:"neoEvents"` - Type ZarazToolType `json:"type"` - DefaultPurpose string `json:"defaultPurpose,omitempty"` - Library string `json:"library,omitempty"` - Component string `json:"component,omitempty"` - Permissions []string `json:"permissions,omitempty"` - Settings map[string]any `json:"settings,omitempty"` - Worker ZarazWorker `json:"worker,omitempty"` + BlockingTriggers []string `json:"blockingTriggers"` + Enabled *bool `json:"enabled"` + DefaultFields map[string]any `json:"defaultFields"` + Name string `json:"name"` + NeoEvents []ZarazNeoEvent `json:"neoEvents"` + Actions map[string]ZarazAction `json:"actions"` + Type ZarazToolType `json:"type"` + DefaultPurpose string `json:"defaultPurpose,omitempty"` + Library string `json:"library,omitempty"` + Component string `json:"component,omitempty"` + Permissions []string `json:"permissions"` + Settings map[string]any `json:"settings"` + Worker ZarazWorker `json:"worker,omitempty"` } type ZarazTriggerSystem string diff --git a/zaraz_test.go b/zaraz_test.go index a59115e3efb..0087c9334a4 100644 --- a/zaraz_test.go +++ b/zaraz_test.go @@ -30,8 +30,8 @@ var expectedConfig ZarazConfig = ZarazConfig{ Enabled: &trueValue, DefaultFields: map[string]any{}, Name: "Custom HTML", - NeoEvents: []ZarazNeoEvent{ - { + Actions: map[string]ZarazAction{ + "7ccae28d-5e00-4f0b-a491-519ecde998c8": { ActionType: "event", BlockingTriggers: []string{}, Data: map[string]any{ @@ -179,19 +179,19 @@ func TestGetZarazConfig(t *testing.T) { "trigger": "pageload" }, "name": "Custom HTML", - "neoEvents": [ - { - "actionType": "event", - "blockingTriggers": [], - "data": { - "__zaraz_setting_name": "pageview1", - "htmlCode": "" - }, - "firingTriggers": [ - "Pageview" - ] + "actions": { + "7ccae28d-5e00-4f0b-a491-519ecde998c8": { + "actionType": "event", + "blockingTriggers": [], + "data": { + "__zaraz_setting_name": "pageview1", + "htmlCode": "" + }, + "firingTriggers": [ + "Pageview" + ] } - ], + }, "permissions": [ "execute_unsafe_scripts" ], @@ -340,19 +340,274 @@ func TestUpdateZarazConfig(t *testing.T) { "trigger": "pageload" }, "name": "Custom HTML", - "neoEvents": [ + "actions": { + "7ccae28d-5e00-4f0b-a491-519ecde998c8": { + "actionType": "event", + "blockingTriggers": [], + "data": { + "__zaraz_setting_name": "pageview1", + "htmlCode": "" + }, + "firingTriggers": [ + "Pageview" + ] + } + }, + "permissions": [ + "execute_unsafe_scripts" + ], + "settings": {}, + "type": "component" + } + }, + "triggers": { + "Pageview": { + "clientRules": [], + "description": "All page loads", + "excludeRules": [], + "loadRules": [ { - "actionType": "event", - "blockingTriggers": [], - "data": { - "__zaraz_setting_name": "pageview1", - "htmlCode": "" - }, - "firingTriggers": [ - "Pageview" - ] + "match": "{{ client.__zarazTrack }}", + "op": "EQUALS", + "value": "Pageview" + } + ], + "name": "Pageview", + "system": "pageload" + }, + "TFOl": { + "description": "", + "excludeRules": [], + "loadRules": [ + { + "id": "Kqsc", + "match": "test", + "op": "CONTAINS", + "value": "test" + }, + { + "action": "clickListener", + "id": "EDnV", + "settings": { + "selector": "test", + "type": "css", + "waitForTags": 0 + } } ], + "name": "test" + } + }, + "variables": { + "jwIx": { + "name": "test", + "type": "string", + "value": "sss" + }, + "pAuL": { + "name": "test-worker-var", + "type": "worker", + "value": { + "escapedWorkerName": "worker-var-example", + "mutableId": "m.zpt3q__WyW-61WM2qwgGoBl4Nxg-sfBsaMhu9NayjwU", + "workerTag": "68aba570db9d4ec5b159624e2f7ad8bf" + } + } + }, + "zarazVersion": 44 + } + }`) + } + + mux.HandleFunc("/zones/"+testZoneID+"/settings/zaraz/v2/config", handler) + payload := UpdateZarazConfigParams{ + DebugKey: "cheese", + ZarazVersion: 44, + DataLayer: &trueValue, + Dlp: []any{}, + HistoryChange: &trueValue, + Settings: ZarazConfigSettings{ + AutoInjectScript: &trueValue, + }, + Tools: map[string]ZarazTool{ + "PBQr": { + BlockingTriggers: []string{}, + Enabled: &trueValue, + DefaultFields: map[string]any{}, + Name: "Custom HTML", + Actions: map[string]ZarazAction{ + "7ccae28d-5e00-4f0b-a491-519ecde998c8": { + ActionType: "event", + BlockingTriggers: []string{}, + Data: map[string]any{ + "__zaraz_setting_name": "pageview1", + "htmlCode": "", + }, + FiringTriggers: []string{"Pageview"}, + }, + }, + Type: ZarazToolComponent, + DefaultPurpose: "rJJC", + Component: "html", + Permissions: []string{"execute_unsafe_scripts"}, + Settings: map[string]any{}, + }, + }, + Triggers: map[string]ZarazTrigger{ + "Pageview": { + Name: "Pageview", + Description: "All page loads", + LoadRules: []ZarazTriggerRule{{Match: "{{ client.__zarazTrack }}", Op: "EQUALS", Value: "Pageview"}}, + ExcludeRules: []ZarazTriggerRule{}, + ClientRules: []any{}, + System: ZarazPageload, + }, + "TFOl": { + Name: "test", + Description: "", + LoadRules: []ZarazTriggerRule{{Id: "Kqsc", Match: "test", Op: "CONTAINS", Value: "test"}, {Id: "EDnV", Action: ZarazClickListener, Settings: ZarazRuleSettings{Selector: "test", Type: ZarazCSS}}}, + ExcludeRules: []ZarazTriggerRule{}, + }, + }, + Variables: map[string]ZarazVariable{ + "jwIx": { + Name: "test", + Type: ZarazVarString, + Value: "sss", + }, + "pAuL": { + Name: "test-worker-var", + Type: ZarazVarWorker, + Value: map[string]interface{}{ + "escapedWorkerName": "worker-var-example", + "mutableId": "m.zpt3q__WyW-61WM2qwgGoBl4Nxg-sfBsaMhu9NayjwU", + "workerTag": "68aba570db9d4ec5b159624e2f7ad8bf", + }, + }, + }, + Consent: ZarazConsent{ + Enabled: &trueValue, + ButtonTextTranslations: ZarazButtonTextTranslations{ + AcceptAll: map[string]string{"en": "Accept ALL"}, + ConfirmMyChoices: map[string]string{"en": "YES!"}, + RejectAll: map[string]string{"en": "Reject ALL"}, + }, + CompanyEmail: "email@example.com", + ConsentModalIntroHTMLWithTranslations: map[string]string{"en": "Lorem ipsum dolar set Amet?"}, + CookieName: "zaraz-consent", + CustomCSS: ".test {\n color: red;\n}", + CustomIntroDisclaimerDismissed: &trueValue, + DefaultLanguage: "en", + HideModal: &falseValue, + PurposesWithTranslations: map[string]ZarazPurposeWithTranslations{ + "rJJC": { + Description: map[string]string{"en": "Blah blah"}, + Name: map[string]string{"en": "Analytics"}, + Order: 0, + }, + }, + }, + } + payload.DebugKey = "butter" // Updating config + modifiedConfig := expectedConfig + modifiedConfig.DebugKey = "butter" // Updating config + expected := ZarazConfigResponse{ + Result: modifiedConfig, + } + + actual, err := client.UpdateZarazConfig(context.Background(), ZoneIdentifier(testZoneID), payload) + require.NoError(t, err) + + assert.Equal(t, expected.Result, actual.Result) +} + +func TestUpdateDeprecatedZarazConfig(t *testing.T) { + setup() + defer teardown() + + handler := func(w http.ResponseWriter, r *http.Request) { + assert.Equal(t, http.MethodPut, r.Method, "Expected method 'PUT', got %s", r.Method) + + w.Header().Set("content-type", "application/json") + fmt.Fprint(w, `{ + "errors": [], + "messages": [], + "success": true, + "result": { + "consent": { + "buttonTextTranslations": { + "accept_all": { + "en": "Accept ALL" + }, + "confirm_my_choices": { + "en": "YES!" + }, + "reject_all": { + "en": "Reject ALL" + } + }, + "companyEmail": "email@example.com", + "consentModalIntroHTMLWithTranslations": { + "en": "Lorem ipsum dolar set Amet?" + }, + "cookieName": "zaraz-consent", + "customCSS": ".test {\n color: red;\n}", + "customIntroDisclaimerDismissed": true, + "defaultLanguage": "en", + "enabled": true, + "hideModal": false, + "purposesWithTranslations": { + "rJJC": { + "description": { + "en": "Blah blah" + }, + "name": { + "en": "Analytics" + }, + "order": 0 + } + } + }, + "dataLayer": true, + "debugKey": "butter", + "dlp": [], + "historyChange": true, + "invalidKey": "cheese", + "settings": { + "autoInjectScript": true + }, + "tools": { + "PBQr": { + "blockingTriggers": [], + "component": "html", + "defaultFields": {}, + "defaultPurpose": "rJJC", + "enabled": true, + "mode": { + "cloud": false, + "ignoreSPA": true, + "light": false, + "sample": false, + "segment": { + "end": 100, + "start": 0 + }, + "trigger": "pageload" + }, + "name": "Custom HTML", + "actions": { + "7ccae28d-5e00-4f0b-a491-519ecde998c8": { + "actionType": "event", + "blockingTriggers": [], + "data": { + "__zaraz_setting_name": "pageview1", + "htmlCode": "" + }, + "firingTriggers": [ + "Pageview" + ] + } + }, "permissions": [ "execute_unsafe_scripts" ], @@ -435,8 +690,8 @@ func TestUpdateZarazConfig(t *testing.T) { Enabled: &trueValue, DefaultFields: map[string]any{}, Name: "Custom HTML", - NeoEvents: []ZarazNeoEvent{ - { + Actions: map[string]ZarazAction{ + "7ccae28d-5e00-4f0b-a491-519ecde998c8": { ActionType: "event", BlockingTriggers: []string{}, Data: map[string]any{