diff --git a/.changeset/sour-months-post.md b/.changeset/sour-months-post.md index 88ce384c..41189db1 100644 --- a/.changeset/sour-months-post.md +++ b/.changeset/sour-months-post.md @@ -3,4 +3,4 @@ '@salesforce/b2c-tooling-sdk': minor --- -adds package.json config source for project level shared config +Add `b2c ecdn` commands for managing eCDN zones, certificates, WAF, caching, security settings, and related configurations. diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 36c06eff..35267bbb 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -35,6 +35,7 @@ const guideSidebar = [ { text: 'WebDAV Commands', link: '/cli/webdav' }, { text: 'ODS Commands', link: '/cli/ods' }, { text: 'MRT Commands', link: '/cli/mrt' }, + { text: 'eCDN Commands', link: '/cli/ecdn' }, { text: 'SLAS Commands', link: '/cli/slas' }, { text: 'Custom APIs', link: '/cli/custom-apis' }, { text: 'SCAPI Schemas', link: '/cli/scapi-schemas' }, diff --git a/docs/cli/ecdn.md b/docs/cli/ecdn.md new file mode 100644 index 00000000..b446ad09 --- /dev/null +++ b/docs/cli/ecdn.md @@ -0,0 +1,930 @@ +--- +description: Commands for managing eCDN (embedded Content Delivery Network) zones, certificates, security, WAF, and more. +--- + +# eCDN Commands + +Commands for managing eCDN (embedded Content Delivery Network) for B2C Commerce storefronts. + +## Global Flags + +All eCDN commands support these flags: + +| Flag | Description | Environment Variable | +|------|-------------|---------------------| +| `--tenant-id` | B2C Commerce tenant ID | `SFCC_TENANT_ID` | +| `--short-code` | API short code | `SFCC_SHORT_CODE` | +| `--json` | Output as JSON | - | + +### Zone Selection + +Commands that operate on a specific zone use the `--zone` / `-z` flag: + +| Flag | Description | +|------|-------------| +| `--zone`, `-z` | Zone ID (32-char hex) or zone name | + +Zone names are resolved to IDs automatically via case-insensitive lookup. + +### Authentication + +eCDN commands require OAuth authentication with these scopes: + +| Operation Type | Required Scope | +|----------------|---------------| +| Read operations | `sfcc.cdn-zones` | +| Write operations | `sfcc.cdn-zones.rw` | + +--- + +## Zone Management + +### b2c ecdn zones list + +List all CDN zones for a tenant. + +```bash +b2c ecdn zones list --tenant-id zzxy_prd +``` + +#### Output + +| Column | Description | +|--------|-------------| +| Name | Zone name | +| ID | Zone ID | +| Status | Zone status | +| Type | Zone type (storefront) | + +--- + +### b2c ecdn zones create + +Create a new storefront zone. + +```bash +b2c ecdn zones create --tenant-id zzxy_prd --storefront-hostname www.example.com --origin-hostname origin.example.com +``` + +#### Flags + +| Flag | Description | Required | +|------|-------------|----------| +| `--storefront-hostname` | Customer-facing hostname | Yes | +| `--origin-hostname` | Origin server hostname | Yes | + +--- + +## Cache Management + +### b2c ecdn cache purge + +Purge cached content from the CDN. + +```bash +# Purge by path +b2c ecdn cache purge --zone my-zone --path /products --path /categories + +# Purge by cache tag +b2c ecdn cache purge --zone my-zone --tag product-123 + +# Purge everything +b2c ecdn cache purge --zone my-zone --purge-everything +``` + +#### Flags + +| Flag | Description | +|------|-------------| +| `--path` | Path to purge (can be repeated) | +| `--tag` | Cache tag to purge (can be repeated) | +| `--host` | Host for path purging | +| `--purge-everything` | Purge all cached content | + +At least one purge method must be specified. + +--- + +### b2c ecdn cache ocapi-toggle + +Toggle OCAPI caching page rule. + +```bash +b2c ecdn cache ocapi-toggle --zone my-zone --enabled +b2c ecdn cache ocapi-toggle --zone my-zone --no-enabled +``` + +#### Flags + +| Flag | Description | +|------|-------------| +| `--enabled` | Enable or disable OCAPI caching | + +--- + +## Certificate Management + +### b2c ecdn certificates list + +List certificates for a zone. + +```bash +b2c ecdn certificates list --zone my-zone +``` + +--- + +### b2c ecdn certificates add + +Add a certificate to a zone. + +```bash +b2c ecdn certificates add --zone my-zone --hostname www.example.com --certificate-file ./cert.pem --private-key-file ./key.pem +``` + +#### Flags + +| Flag | Description | Required | +|------|-------------|----------| +| `--hostname` | Custom hostname | Yes | +| `--certificate-file` | Path to certificate PEM file | Yes | +| `--private-key-file` | Path to private key PEM file | Yes | + +--- + +### b2c ecdn certificates get + +Get certificate details. + +```bash +b2c ecdn certificates get --zone my-zone --certificate-id abc123 +``` + +--- + +### b2c ecdn certificates update + +Update a certificate. + +```bash +b2c ecdn certificates update --zone my-zone --certificate-id abc123 --certificate-file ./new-cert.pem --private-key-file ./new-key.pem +``` + +--- + +### b2c ecdn certificates delete + +Delete a certificate. + +```bash +b2c ecdn certificates delete --zone my-zone --certificate-id abc123 +``` + +--- + +### b2c ecdn certificates validate + +Validate a custom hostname certificate. + +```bash +b2c ecdn certificates validate --zone my-zone --certificate-id abc123 +``` + +--- + +## Security Settings + +### b2c ecdn security get + +Get security settings for a zone. + +```bash +b2c ecdn security get --zone my-zone +``` + +#### Output + +Displays settings including: +- SSL mode +- Always use HTTPS +- Minimum TLS version +- TLS 1.3 status +- Automatic HTTPS rewrites +- Opportunistic encryption + +--- + +### b2c ecdn security update + +Update security settings. + +```bash +b2c ecdn security update --zone my-zone --ssl-mode full --min-tls-version 1.2 --always-use-https +``` + +#### Flags + +| Flag | Description | Options | +|------|-------------|---------| +| `--ssl-mode` | SSL/TLS mode | `off`, `flexible`, `full`, `strict` | +| `--min-tls-version` | Minimum TLS version | `1.0`, `1.1`, `1.2`, `1.3` | +| `--always-use-https` / `--no-always-use-https` | Force HTTPS | - | +| `--tls-1-3` / `--no-tls-1-3` | Enable TLS 1.3 | - | +| `--automatic-https-rewrites` / `--no-automatic-https-rewrites` | Rewrite HTTP links | - | +| `--opportunistic-encryption` / `--no-opportunistic-encryption` | Enable opportunistic encryption | - | + +--- + +## Speed Settings + +### b2c ecdn speed get + +Get speed optimization settings. + +```bash +b2c ecdn speed get --zone my-zone +``` + +--- + +### b2c ecdn speed update + +Update speed optimization settings. + +```bash +b2c ecdn speed update --zone my-zone --browser-cache-ttl 14400 --auto-minify-html --auto-minify-css --auto-minify-js +``` + +#### Flags + +| Flag | Description | +|------|-------------| +| `--browser-cache-ttl` | Browser cache TTL in seconds | +| `--auto-minify-html` / `--no-auto-minify-html` | Auto-minify HTML | +| `--auto-minify-css` / `--no-auto-minify-css` | Auto-minify CSS | +| `--auto-minify-js` / `--no-auto-minify-js` | Auto-minify JavaScript | +| `--brotli` / `--no-brotli` | Enable Brotli compression | +| `--early-hints` / `--no-early-hints` | Enable Early Hints | +| `--h2-prioritization` / `--no-h2-prioritization` | HTTP/2 prioritization | +| `--image-resizing` / `--no-image-resizing` | Enable image resizing | +| `--mirage` / `--no-mirage` | Enable Mirage | +| `--polish` | Polish mode (`off`, `lossless`, `lossy`) | +| `--prefetch-preload` / `--no-prefetch-preload` | Prefetch preload | +| `--rocket-loader` / `--no-rocket-loader` | Rocket Loader | + +--- + +## WAF (Web Application Firewall) + +### WAF v1 Commands + +#### b2c ecdn waf groups list + +List WAF v1 rule groups. + +```bash +b2c ecdn waf groups list --zone my-zone +``` + +--- + +#### b2c ecdn waf groups update + +Update a WAF v1 group. + +```bash +b2c ecdn waf groups update --zone my-zone --group-id abc123 --mode on +``` + +| Flag | Description | Options | +|------|-------------|---------| +| `--mode` | Group mode | `on`, `off` | + +--- + +#### b2c ecdn waf rules list + +List WAF v1 rules in a group. + +```bash +b2c ecdn waf rules list --zone my-zone --group-id abc123 +``` + +--- + +#### b2c ecdn waf rules get + +Get details of a WAF v1 rule. + +```bash +b2c ecdn waf rules get --zone my-zone --rule-id abc123 +``` + +--- + +#### b2c ecdn waf rules update + +Update a WAF v1 rule. + +```bash +b2c ecdn waf rules update --zone my-zone --rule-id abc123 --mode on +``` + +--- + +### WAF v2 Commands + +#### b2c ecdn waf rulesets list + +List WAF v2 rulesets. + +```bash +b2c ecdn waf rulesets list --zone my-zone +``` + +--- + +#### b2c ecdn waf rulesets update + +Update a WAF v2 ruleset. + +```bash +b2c ecdn waf rulesets update --zone my-zone --ruleset-id abc123 --action block +``` + +--- + +#### b2c ecdn waf managed-rules list + +List WAF v2 managed rules. + +```bash +b2c ecdn waf managed-rules list --zone my-zone +``` + +--- + +#### b2c ecdn waf managed-rules update + +Update a WAF v2 managed rule. + +```bash +b2c ecdn waf managed-rules update --zone my-zone --rule-id abc123 --action block +``` + +--- + +### OWASP Settings + +#### b2c ecdn waf owasp get + +Get OWASP ModSecurity package settings. + +```bash +b2c ecdn waf owasp get --zone my-zone +``` + +--- + +#### b2c ecdn waf owasp update + +Update OWASP package settings. + +```bash +b2c ecdn waf owasp update --zone my-zone --sensitivity high +``` + +--- + +### WAF Migration + +#### b2c ecdn waf migrate + +Migrate a zone from WAF v1 to WAF v2. + +```bash +b2c ecdn waf migrate --zone my-zone +``` + +--- + +## Custom Firewall Rules + +### b2c ecdn firewall list + +List custom firewall rules. + +```bash +b2c ecdn firewall list --zone my-zone +``` + +--- + +### b2c ecdn firewall create + +Create a custom firewall rule. + +```bash +b2c ecdn firewall create --zone my-zone --description "Block bad bots" --action block --filter '(cf.client.bot)' +``` + +#### Flags + +| Flag | Description | Required | +|------|-------------|----------| +| `--description` | Rule description | Yes | +| `--action` | Rule action (`block`, `challenge`, `js_challenge`, `managed_challenge`, `allow`, `log`, `bypass`) | Yes | +| `--filter` | Firewall filter expression | Yes | +| `--paused` | Create rule in paused state | No | +| `--priority` | Rule priority | No | + +--- + +### b2c ecdn firewall get + +Get a firewall rule. + +```bash +b2c ecdn firewall get --zone my-zone --rule-id abc123 +``` + +--- + +### b2c ecdn firewall update + +Update a firewall rule. + +```bash +b2c ecdn firewall update --zone my-zone --rule-id abc123 --action challenge +``` + +--- + +### b2c ecdn firewall delete + +Delete a firewall rule. + +```bash +b2c ecdn firewall delete --zone my-zone --rule-id abc123 +``` + +--- + +### b2c ecdn firewall reorder + +Reorder firewall rules. + +```bash +b2c ecdn firewall reorder --zone my-zone --rule-ids id1,id2,id3 +``` + +--- + +## Rate Limiting + +### b2c ecdn rate-limit list + +List rate limiting rules. + +```bash +b2c ecdn rate-limit list --zone my-zone +``` + +--- + +### b2c ecdn rate-limit create + +Create a rate limiting rule. + +```bash +b2c ecdn rate-limit create --zone my-zone --description "API rate limit" --threshold 100 --period 60 --action block --match-url '/api/*' +``` + +#### Flags + +| Flag | Description | Required | +|------|-------------|----------| +| `--description` | Rule description | Yes | +| `--threshold` | Request threshold | Yes | +| `--period` | Period in seconds | Yes | +| `--action` | Action (`block`, `challenge`, `js_challenge`, `managed_challenge`, `log`, `simulate`) | Yes | +| `--match-url` | URL pattern to match | Yes | +| `--match-methods` | HTTP methods (comma-separated) | No | +| `--timeout` | Block timeout in seconds | No | + +--- + +### b2c ecdn rate-limit get + +Get a rate limiting rule. + +```bash +b2c ecdn rate-limit get --zone my-zone --rule-id abc123 +``` + +--- + +### b2c ecdn rate-limit update + +Update a rate limiting rule. + +```bash +b2c ecdn rate-limit update --zone my-zone --rule-id abc123 --threshold 200 +``` + +--- + +### b2c ecdn rate-limit delete + +Delete a rate limiting rule. + +```bash +b2c ecdn rate-limit delete --zone my-zone --rule-id abc123 +``` + +--- + +## Logpush + +### b2c ecdn logpush ownership + +Create a Logpush ownership challenge token for destination verification. + +```bash +b2c ecdn logpush ownership --zone my-zone --destination-path 's3://my-bucket/logs?region=us-east-1' +``` + +--- + +### b2c ecdn logpush jobs list + +List Logpush jobs. + +```bash +b2c ecdn logpush jobs list --zone my-zone +``` + +--- + +### b2c ecdn logpush jobs create + +Create a Logpush job. + +```bash +b2c ecdn logpush jobs create --zone my-zone --name "HTTP logs" --destination-path 's3://my-bucket/logs?region=us-east-1' --log-type http_requests --log-fields ClientRequestHost,ClientRequestMethod +``` + +#### Flags + +| Flag | Description | Required | +|------|-------------|----------| +| `--name` | Job name | Yes | +| `--destination-path` | Log destination path | Yes | +| `--log-type` | Type of logs (`http_requests`, `firewall_events`, `nel_reports`, `dns_logs`) | Yes | +| `--log-fields` | Comma-separated log fields | No | +| `--filter` | JSON filter expression | No | +| `--enabled` | Enable job on creation | No | + +--- + +### b2c ecdn logpush jobs get + +Get Logpush job details. + +```bash +b2c ecdn logpush jobs get --zone my-zone --job-id 123456 +``` + +--- + +### b2c ecdn logpush jobs update + +Update a Logpush job. + +```bash +b2c ecdn logpush jobs update --zone my-zone --job-id 123456 --enabled +b2c ecdn logpush jobs update --zone my-zone --job-id 123456 --no-enabled +``` + +--- + +### b2c ecdn logpush jobs delete + +Delete a Logpush job. + +```bash +b2c ecdn logpush jobs delete --zone my-zone --job-id 123456 +``` + +--- + +## Page Shield + +### Notifications (Organization Level) + +#### b2c ecdn page-shield notifications list + +List Page Shield notification webhooks. + +```bash +b2c ecdn page-shield notifications list --tenant-id zzxy_prd +``` + +--- + +#### b2c ecdn page-shield notifications create + +Create a notification webhook. + +```bash +b2c ecdn page-shield notifications create --tenant-id zzxy_prd --url https://example.com/webhook --secret my-secret --zones zone1,zone2 +``` + +--- + +#### b2c ecdn page-shield notifications delete + +Delete a notification webhook. + +```bash +b2c ecdn page-shield notifications delete --tenant-id zzxy_prd --webhook-id abc123 +``` + +--- + +### Policies (Zone Level) + +#### b2c ecdn page-shield policies list + +List Page Shield policies. + +```bash +b2c ecdn page-shield policies list --zone my-zone +``` + +--- + +#### b2c ecdn page-shield policies create + +Create a Page Shield policy. + +```bash +b2c ecdn page-shield policies create --zone my-zone --action allow --value script-src --expression 'http.request.uri.path contains "/trusted/"' +``` + +#### Flags + +| Flag | Description | Required | +|------|-------------|----------| +| `--action` | Policy action (`allow`, `log`) | Yes | +| `--value` | Policy value (e.g., `script-src`) | Yes | +| `--expression` | Policy expression | No | +| `--description` | Policy description | No | +| `--enabled` | Enable policy | No | + +--- + +#### b2c ecdn page-shield policies get + +Get a Page Shield policy. + +```bash +b2c ecdn page-shield policies get --zone my-zone --policy-id abc123 +``` + +--- + +#### b2c ecdn page-shield policies update + +Update a Page Shield policy. + +```bash +b2c ecdn page-shield policies update --zone my-zone --policy-id abc123 --enabled +``` + +--- + +#### b2c ecdn page-shield policies delete + +Delete a Page Shield policy. + +```bash +b2c ecdn page-shield policies delete --zone my-zone --policy-id abc123 +``` + +--- + +### Scripts (Zone Level) + +#### b2c ecdn page-shield scripts list + +List detected scripts. + +```bash +b2c ecdn page-shield scripts list --zone my-zone +``` + +--- + +#### b2c ecdn page-shield scripts get + +Get script details. + +```bash +b2c ecdn page-shield scripts get --zone my-zone --script-id abc123 +``` + +--- + +## MRT Rules + +### b2c ecdn mrt-rules get + +Get MRT ruleset for a zone. + +```bash +b2c ecdn mrt-rules get --zone my-zone +``` + +--- + +### b2c ecdn mrt-rules create + +Create MRT rules to route requests to a Managed Runtime environment. + +```bash +b2c ecdn mrt-rules create --zone my-zone --mrt-hostname customer-pwa.mobify-storefront.com --expressions '(http.host eq "example.com")' --descriptions "Route to PWA" +``` + +#### Flags + +| Flag | Description | Required | +|------|-------------|----------| +| `--mrt-hostname` | Managed Runtime instance hostname | Yes | +| `--expressions` | Comma-separated rule expressions | Yes | +| `--descriptions` | Comma-separated rule descriptions | No | + +--- + +### b2c ecdn mrt-rules update + +Update MRT ruleset hostname or add new rules. + +```bash +b2c ecdn mrt-rules update --zone my-zone --mrt-hostname new-customer-pwa.mobify-storefront.com +``` + +--- + +### b2c ecdn mrt-rules delete + +Delete an MRT ruleset and all rules. + +```bash +b2c ecdn mrt-rules delete --zone my-zone +``` + +--- + +### Individual MRT Rules + +#### b2c ecdn mrt-rules rules update + +Update an individual MRT rule. + +```bash +b2c ecdn mrt-rules rules update --zone my-zone --ruleset-id abc123 --rule-id def456 --enabled +``` + +--- + +#### b2c ecdn mrt-rules rules delete + +Delete an individual MRT rule. + +```bash +b2c ecdn mrt-rules rules delete --zone my-zone --ruleset-id abc123 --rule-id def456 +``` + +--- + +## mTLS Certificates (Organization Level) + +### b2c ecdn mtls list + +List mTLS certificates. + +```bash +b2c ecdn mtls list --tenant-id zzxy_prd +``` + +--- + +### b2c ecdn mtls create + +Create an mTLS certificate for code upload authentication. + +```bash +b2c ecdn mtls create --tenant-id zzxy_prd --name "Build Server" --ca-certificate-file ./ca.pem --leaf-certificate-file ./leaf.pem +``` + +#### Flags + +| Flag | Description | Required | +|------|-------------|----------| +| `--name` | Certificate name | Yes | +| `--ca-certificate-file` | Path to CA certificate PEM | Yes | +| `--leaf-certificate-file` | Path to leaf certificate PEM | Yes | + +--- + +### b2c ecdn mtls get + +Get mTLS certificate details. + +```bash +b2c ecdn mtls get --tenant-id zzxy_prd --certificate-id abc123 +``` + +--- + +### b2c ecdn mtls delete + +Delete an mTLS certificate. + +```bash +b2c ecdn mtls delete --tenant-id zzxy_prd --certificate-id abc123 +``` + +--- + +## Cipher Suites + +### b2c ecdn cipher-suites get + +Get cipher suites configuration. + +```bash +b2c ecdn cipher-suites get --zone my-zone +``` + +--- + +### b2c ecdn cipher-suites update + +Update cipher suites settings. + +```bash +# Use a preset suite type +b2c ecdn cipher-suites update --zone my-zone --suite-type Modern + +# Use custom ciphers +b2c ecdn cipher-suites update --zone my-zone --suite-type Custom --ciphers "ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256" +``` + +#### Flags + +| Flag | Description | Required | +|------|-------------|----------| +| `--suite-type` | Cipher suite type (`Compatible`, `Modern`, `Custom`, `Legacy`) | Yes | +| `--ciphers` | Comma-separated cipher list (required for Custom) | Conditional | + +--- + +## Origin Headers + +### b2c ecdn origin-headers get + +Get origin header modification settings (MRT type). + +```bash +b2c ecdn origin-headers get --zone my-zone +``` + +--- + +### b2c ecdn origin-headers set + +Set or update origin header modification. + +```bash +b2c ecdn origin-headers set --zone my-zone --header-value my-secret-value +b2c ecdn origin-headers set --zone my-zone --header-value my-secret-value --header-name x-custom-header +``` + +#### Flags + +| Flag | Description | Required | +|------|-------------|----------| +| `--header-value` | Value of the header to forward to origin | Yes | +| `--header-name` | Name of the header (cannot be changed for MRT origin) | No | + +--- + +### b2c ecdn origin-headers delete + +Delete origin header modification. + +```bash +b2c ecdn origin-headers delete --zone my-zone +``` diff --git a/packages/b2c-cli/eslint.config.mjs b/packages/b2c-cli/eslint.config.mjs index 1a0ce5a6..6a734963 100644 --- a/packages/b2c-cli/eslint.config.mjs +++ b/packages/b2c-cli/eslint.config.mjs @@ -55,6 +55,9 @@ export default [ 'import/no-named-as-default-member': 'off', // import/namespace behaves inconsistently across environments when parsing CJS modules like marked-terminal 'import/namespace': 'off', + // Disable for tests: ESLint import resolver doesn't understand conditional exports (development condition) + // but Node.js resolves them correctly at runtime + 'import/no-unresolved': 'off', }, }, { @@ -64,4 +67,12 @@ export default [ 'import/namespace': 'off', }, }, + { + files: ['src/commands/setup/**/*.ts'], + rules: { + // ESLint import resolver doesn't understand conditional exports (development condition) + // but Node.js resolves them correctly at runtime + 'import/no-unresolved': 'off', + }, + }, ]; diff --git a/packages/b2c-cli/package.json b/packages/b2c-cli/package.json index 729f48e3..f27af542 100644 --- a/packages/b2c-cli/package.json +++ b/packages/b2c-cli/package.json @@ -159,6 +159,91 @@ } } }, + "ecdn": { + "description": "Manage eCDN zones, certificates, WAF, and security settings", + "subtopics": { + "zones": { + "description": "List and create CDN zones" + }, + "cache": { + "description": "Manage CDN cache operations" + }, + "certificates": { + "description": "Manage SSL certificates" + }, + "security": { + "description": "Manage security settings" + }, + "speed": { + "description": "Manage speed optimization settings" + }, + "waf": { + "description": "Manage Web Application Firewall", + "subtopics": { + "groups": { + "description": "WAF v1 rule groups" + }, + "rules": { + "description": "WAF v1 rules" + }, + "rulesets": { + "description": "WAF v2 rulesets" + }, + "managed-rules": { + "description": "WAF v2 managed rules" + }, + "owasp": { + "description": "OWASP ModSecurity package" + } + } + }, + "firewall": { + "description": "Manage custom firewall rules" + }, + "rate-limit": { + "description": "Manage rate limiting rules" + }, + "logpush": { + "description": "Manage log export configuration", + "subtopics": { + "jobs": { + "description": "Logpush job management" + } + } + }, + "page-shield": { + "description": "Manage Page Shield security", + "subtopics": { + "notifications": { + "description": "Page Shield notification webhooks" + }, + "policies": { + "description": "Content Security Policy rules" + }, + "scripts": { + "description": "Detected script monitoring" + } + } + }, + "mrt-rules": { + "description": "Manage MRT routing rules", + "subtopics": { + "rules": { + "description": "Individual MRT rules" + } + } + }, + "mtls": { + "description": "Manage mTLS certificates" + }, + "cipher-suites": { + "description": "Manage TLS cipher configuration" + }, + "origin-headers": { + "description": "Manage origin header modifications" + } + } + }, "setup": { "description": "Setup commands for development environment" } diff --git a/packages/b2c-cli/src/commands/ecdn/cache/purge.ts b/packages/b2c-cli/src/commands/ecdn/cache/purge.ts new file mode 100644 index 00000000..a8f69160 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/cache/purge.ts @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +/** + * Response type for the purge command. + */ +interface PurgeOutput { + success: boolean; + cachePurged?: boolean; + details?: string; + purgedPath?: string; + purgedTags?: string[]; +} + +/** + * Command to purge cache for a zone. + */ +export default class EcdnCachePurge extends EcdnZoneCommand { + static description = t('commands.ecdn.cache.purge.description', 'Purge cached content for a zone by path or tags'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --path "www.example.com/dw/shop/v21_9/products"', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --tag product-123 --tag category-456', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --path "www.example.com/dw/image/v2/realm_instance/*" --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + path: Flags.string({ + char: 'p', + description: t('flags.path.description', 'Path to purge (format: hostname/path)'), + }), + tag: Flags.string({ + char: 't', + description: t('flags.tag.description', 'Cache tag to purge (can be specified multiple times)'), + multiple: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const path = this.flags.path; + const tags = this.flags.tag ?? []; + + if (!path && tags.length === 0) { + this.error(t('commands.ecdn.cache.purge.noPurgeTarget', 'Either --path or --tag must be specified')); + } + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + if (path) { + this.log(t('commands.ecdn.cache.purge.purgingPath', 'Purging path: {{path}}...', {path})); + } + if (tags.length > 0) { + this.log(t('commands.ecdn.cache.purge.purgingTags', 'Purging {{count}} tag(s)...', {count: tags.length})); + } + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + // Build the request body - API expects either path (string) or tags (array) + const body: {path?: string; tags?: string[]} = {}; + if (path) { + body.path = path; + } + if (tags.length > 0) { + body.tags = tags; + } + + const {data, error} = await client.POST('/organizations/{organizationId}/zones/{zoneId}/cachepurge', { + params: { + path: {organizationId, zoneId}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.cache.purge.error', 'Failed to purge cache: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const response = data?.data; + const output: PurgeOutput = { + success: response?.cachePurged ?? false, + cachePurged: response?.cachePurged, + details: response?.details, + purgedPath: path, + purgedTags: tags.length > 0 ? tags : undefined, + }; + + if (this.jsonEnabled()) { + return output; + } + + this.log(''); + if (response?.cachePurged) { + this.log(t('commands.ecdn.cache.purge.success', 'Cache purge completed successfully!')); + } else { + this.log(t('commands.ecdn.cache.purge.partial', 'Cache purge completed with details:')); + if (response?.details) { + this.log(` ${response.details}`); + } + } + + if (path) { + this.log(''); + this.log(`Purged path: ${path}`); + } + + if (tags.length > 0) { + this.log(''); + this.log('Purged tags:'); + for (const tag of tags) { + this.log(` - ${tag}`); + } + } + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/certificates/add.ts b/packages/b2c-cli/src/commands/ecdn/certificates/add.ts new file mode 100644 index 00000000..f0911e3a --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/certificates/add.ts @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {readFile} from 'node:fs/promises'; +import {Flags} from '@oclif/core'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type Certificate = CdnZonesComponents['schemas']['Certificate']; + +/** + * Response type for the add command. + */ +interface AddOutput { + certificate: Certificate; +} + +/** + * Command to add a certificate for a zone. + */ +export default class EcdnCertificatesAdd extends EcdnZoneCommand { + static description = t('commands.ecdn.certificates.add.description', 'Add a certificate for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --hostname example.com --type automatic', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --hostname example.com --type custom --certificate-file cert.pem --private-key-file key.pem', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + hostname: Flags.string({ + char: 'h', + description: t('flags.hostname.description', 'Hostname for the certificate'), + required: true, + }), + type: Flags.string({ + description: t('flags.certificateType.description', 'Certificate type (custom or automatic)'), + options: ['custom', 'automatic'], + default: 'automatic', + }), + 'certificate-file': Flags.string({ + description: t( + 'flags.certificateFile.description', + 'Path to certificate file (PEM format, required for custom type)', + ), + }), + 'private-key-file': Flags.string({ + description: t( + 'flags.privateKeyFile.description', + 'Path to private key file (PEM format, required for custom type)', + ), + }), + 'bundle-method': Flags.string({ + description: t('flags.bundleMethod.description', 'Bundle method for custom certificate chain verification'), + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const hostname = this.flags.hostname; + const certificateType = this.flags.type as 'automatic' | 'custom'; + const certificateFile = this.flags['certificate-file']; + const privateKeyFile = this.flags['private-key-file']; + const bundleMethod = this.flags['bundle-method']; + + // Validate custom certificate requirements + if (certificateType === 'custom' && (!certificateFile || !privateKeyFile)) { + this.error( + t( + 'commands.ecdn.certificates.add.customRequired', + 'Custom certificates require both --certificate-file and --private-key-file', + ), + ); + } + + if (!this.jsonEnabled()) { + this.log( + t('commands.ecdn.certificates.add.adding', 'Adding {{type}} certificate for {{hostname}}...', { + type: certificateType, + hostname, + }), + ); + } + + // Build request body + const body: { + hostname: string; + certificateType?: string; + certificate?: string; + privateKey?: string; + bundleMethod?: string; + } = { + hostname, + certificateType, + }; + + if (certificateType === 'custom' && certificateFile && privateKeyFile) { + body.certificate = await readFile(certificateFile, 'utf8'); + body.privateKey = await readFile(privateKeyFile, 'utf8'); + } + + if (bundleMethod) { + body.bundleMethod = bundleMethod; + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.POST('/organizations/{organizationId}/zones/{zoneId}/certificates', { + params: { + path: {organizationId, zoneId}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.certificates.add.error', 'Failed to add certificate: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const certificate = data?.data; + if (!certificate) { + this.error(t('commands.ecdn.certificates.add.noData', 'No certificate data returned from API')); + } + + const output: AddOutput = {certificate}; + + if (this.jsonEnabled()) { + return output; + } + + this.log(''); + this.log(t('commands.ecdn.certificates.add.success', 'Certificate added successfully!')); + this.log(''); + this.log(` Certificate ID: ${certificate.certificateId}`); + this.log(` Hosts: ${certificate.hosts?.join(', ') || '-'}`); + this.log(` Status: ${certificate.status}`); + this.log(` Type: ${certificate.certificateType}`); + + if (certificate.certificateVerificationTXTName) { + this.log(''); + this.log(' DNS Verification Required:'); + this.log(` TXT Name: ${certificate.certificateVerificationTXTName}`); + this.log(` TXT Value: ${certificate.certificateVerificationTXTValue || '-'}`); + } + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/certificates/delete.ts b/packages/b2c-cli/src/commands/ecdn/certificates/delete.ts new file mode 100644 index 00000000..66809050 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/certificates/delete.ts @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +/** + * Response type for the delete command. + */ +interface DeleteOutput { + success: boolean; + certificateId: string; +} + +/** + * Command to delete a certificate for a zone. + * WARNING: Deleting a certificate in use can cause site downtime. + */ +export default class EcdnCertificatesDelete extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.certificates.delete.description', + 'Delete a certificate from a zone (WARNING: can cause downtime if in use)', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --certificate-id abc123', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --certificate-id abc123 --force', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'certificate-id': Flags.string({ + description: t('flags.certificateId.description', 'Certificate ID to delete'), + required: true, + }), + force: Flags.boolean({ + char: 'f', + description: t('flags.force.description', 'Skip confirmation prompt'), + default: false, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const certificateId = this.flags['certificate-id']; + const force = this.flags.force; + + if (!force && !this.jsonEnabled()) { + this.warn( + t( + 'commands.ecdn.certificates.delete.warning', + 'WARNING: Deleting a certificate that is in use can result in downtime!', + ), + ); + this.log(t('commands.ecdn.certificates.delete.useForce', 'Use --force to confirm deletion.')); + return {success: false, certificateId}; + } + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.certificates.delete.deleting', 'Deleting certificate {{id}}...', {id: certificateId})); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {error} = await client.DELETE('/organizations/{organizationId}/zones/{zoneId}/certificates/{certificateId}', { + params: { + path: {organizationId, zoneId, certificateId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.certificates.delete.error', 'Failed to delete certificate: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const output: DeleteOutput = { + success: true, + certificateId, + }; + + if (this.jsonEnabled()) { + return output; + } + + this.log(''); + this.log(t('commands.ecdn.certificates.delete.success', 'Certificate deleted successfully.')); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/certificates/list.ts b/packages/b2c-cli/src/commands/ecdn/certificates/list.ts new file mode 100644 index 00000000..e7aaeb0f --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/certificates/list.ts @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type Certificate = CdnZonesComponents['schemas']['Certificate']; + +/** + * Response type for the list command. + */ +interface ListOutput { + certificates: Certificate[]; + total: number; +} + +const COLUMNS: Record> = { + certificateId: { + header: 'Certificate ID', + get: (c) => c.certificateId || '-', + extended: true, + }, + hosts: { + header: 'Hosts', + get: (c) => c.hosts?.join(', ') || '-', + }, + status: { + header: 'Status', + get: (c) => c.status || '-', + }, + certificateType: { + header: 'Type', + get: (c) => c.certificateType || '-', + }, + expiresOn: { + header: 'Expires', + get: (c) => (c.expiresOn ? new Date(c.expiresOn).toLocaleDateString() : '-'), + extended: true, + }, + issuer: { + header: 'Issuer', + get: (c) => c.issuer || '-', + extended: true, + }, +}; + +/** Default columns shown without --extended */ +const DEFAULT_COLUMNS = ['hosts', 'status', 'certificateType']; + +const tableRenderer = new TableRenderer(COLUMNS); + +/** + * Command to list certificates for a zone. + */ +export default class EcdnCertificatesList extends EcdnZoneCommand { + static description = t('commands.ecdn.certificates.list.description', 'List certificates for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --extended', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + columns: Flags.string({ + char: 'c', + description: `Columns to display (comma-separated). Available: ${Object.keys(COLUMNS).join(', ')}`, + }), + extended: Flags.boolean({ + char: 'x', + description: t('flags.extended.description', 'Show all columns including extended fields'), + default: false, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.certificates.list.fetching', 'Fetching certificates...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/certificates', { + params: { + path: {organizationId, zoneId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.certificates.list.error', 'Failed to fetch certificates: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const certificates = data?.data ?? []; + const output: ListOutput = { + certificates, + total: certificates.length, + }; + + if (this.jsonEnabled()) { + return output; + } + + if (certificates.length === 0) { + this.log(t('commands.ecdn.certificates.list.noCertificates', 'No certificates found.')); + return output; + } + + this.log( + t('commands.ecdn.certificates.list.count', 'Found {{count}} certificate(s):', { + count: certificates.length, + }), + ); + this.log(''); + + const columns = this.getSelectedColumns(); + tableRenderer.render(certificates, columns); + + return output; + } + + /** + * Determines which columns to display based on flags. + */ + private getSelectedColumns(): string[] { + const columnsFlag = this.flags.columns; + const extended = this.flags.extended; + + if (columnsFlag) { + const requested = columnsFlag.split(',').map((c) => c.trim()); + const valid = tableRenderer.validateColumnKeys(requested); + if (valid.length === 0) { + this.warn(`No valid columns specified. Available: ${tableRenderer.getColumnKeys().join(', ')}`); + return DEFAULT_COLUMNS; + } + return valid; + } + + if (extended) { + return tableRenderer.getColumnKeys(); + } + + return DEFAULT_COLUMNS; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/certificates/update.ts b/packages/b2c-cli/src/commands/ecdn/certificates/update.ts new file mode 100644 index 00000000..bdd544fb --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/certificates/update.ts @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {readFile} from 'node:fs/promises'; +import {Flags} from '@oclif/core'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type Certificate = CdnZonesComponents['schemas']['Certificate']; + +/** + * Response type for the update command. + */ +interface UpdateOutput { + certificate: Certificate; +} + +/** + * Command to update a certificate for a zone. + */ +export default class EcdnCertificatesUpdate extends EcdnZoneCommand { + static description = t('commands.ecdn.certificates.update.description', 'Update a certificate for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --certificate-id abc123 --hostname example.com', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --certificate-id abc123 --certificate-file cert.pem --private-key-file key.pem', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'certificate-id': Flags.string({ + description: t('flags.certificateId.description', 'Certificate ID to update'), + required: true, + }), + hostname: Flags.string({ + char: 'h', + description: t('flags.hostname.description', 'Hostname for the certificate'), + }), + type: Flags.string({ + description: t('flags.certificateType.description', 'Certificate type (custom or automatic)'), + options: ['custom', 'automatic'], + }), + 'certificate-file': Flags.string({ + description: t( + 'flags.certificateFile.description', + 'Path to certificate file (PEM format, required for custom type)', + ), + }), + 'private-key-file': Flags.string({ + description: t( + 'flags.privateKeyFile.description', + 'Path to private key file (PEM format, required for custom type)', + ), + }), + 'bundle-method': Flags.string({ + description: t('flags.bundleMethod.description', 'Bundle method for custom certificate chain verification'), + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const certificateId = this.flags['certificate-id']; + const hostname = this.flags.hostname; + const certificateType = this.flags.type as 'automatic' | 'custom' | undefined; + const certificateFile = this.flags['certificate-file']; + const privateKeyFile = this.flags['private-key-file']; + const bundleMethod = this.flags['bundle-method']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.certificates.update.updating', 'Updating certificate {{id}}...', {id: certificateId})); + } + + // Build request body - hostname is required by the API + if (!hostname) { + this.error( + t('commands.ecdn.certificates.update.hostnameRequired', 'Hostname is required for certificate update'), + ); + } + + const body: { + hostname: string; + certificateType?: string; + certificate?: string; + privateKey?: string; + bundleMethod?: string; + } = { + hostname, + }; + + if (certificateType) { + body.certificateType = certificateType; + } + + if (certificateFile && privateKeyFile) { + body.certificate = await readFile(certificateFile, 'utf8'); + body.privateKey = await readFile(privateKeyFile, 'utf8'); + } + + if (bundleMethod) { + body.bundleMethod = bundleMethod; + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PATCH( + '/organizations/{organizationId}/zones/{zoneId}/certificates/{certificateId}', + { + params: { + path: {organizationId, zoneId, certificateId}, + }, + body, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.certificates.update.error', 'Failed to update certificate: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const certificate = data?.data; + if (!certificate) { + this.error(t('commands.ecdn.certificates.update.noData', 'No certificate data returned from API')); + } + + const output: UpdateOutput = {certificate}; + + if (this.jsonEnabled()) { + return output; + } + + this.log(''); + this.log(t('commands.ecdn.certificates.update.success', 'Certificate updated successfully!')); + this.log(''); + this.log(` Certificate ID: ${certificate.certificateId}`); + this.log(` Hosts: ${certificate.hosts?.join(', ') || '-'}`); + this.log(` Status: ${certificate.status}`); + this.log(` Type: ${certificate.certificateType}`); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/certificates/validate.ts b/packages/b2c-cli/src/commands/ecdn/certificates/validate.ts new file mode 100644 index 00000000..25569bc4 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/certificates/validate.ts @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type CustomHostnameValidation = CdnZonesComponents['schemas']['CustomHostnameValidationEnvelope']['data']; + +/** + * Response type for the validate command. + */ +interface ValidateOutput { + validation: CustomHostnameValidation; +} + +/** + * Command to trigger validation of a custom hostname. + */ +export default class EcdnCertificatesValidate extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.certificates.validate.description', + 'Trigger DNS validation for a custom hostname', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --custom-hostname-id abc123', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --custom-hostname-id abc123 --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'custom-hostname-id': Flags.string({ + description: t('flags.customHostnameId.description', 'Custom hostname ID to validate'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const customHostnameId = this.flags['custom-hostname-id']; + + if (!this.jsonEnabled()) { + this.log( + t('commands.ecdn.certificates.validate.triggering', 'Triggering validation for custom hostname {{id}}...', { + id: customHostnameId, + }), + ); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PATCH( + '/organizations/{organizationId}/zones/{zoneId}/certificates/custom-hostnames/{customHostnameId}', + { + params: { + path: {organizationId, zoneId, customHostnameId}, + }, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.certificates.validate.error', 'Failed to trigger validation: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const validation = data?.data; + if (!validation) { + this.error(t('commands.ecdn.certificates.validate.noData', 'No validation data returned from API')); + } + + const output: ValidateOutput = {validation}; + + if (this.jsonEnabled()) { + return output; + } + + this.log(''); + this.log(t('commands.ecdn.certificates.validate.success', 'Validation triggered successfully!')); + this.log(''); + this.log(` Custom Hostname ID: ${validation.customHostnameId}`); + this.log(` Custom Hostname: ${validation.customHostname}`); + this.log(` Status: ${validation.customHostnameStatus}`); + this.log(''); + this.log(' DNS Verification:'); + this.log(` TXT Name: ${validation.customHostnameVerificationTXTName}`); + this.log(` TXT Value: ${validation.customHostnameVerificationTXTValue}`); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/cipher-suites/get.ts b/packages/b2c-cli/src/commands/ecdn/cipher-suites/get.ts new file mode 100644 index 00000000..351331e7 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/cipher-suites/get.ts @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type CipherSuitesResponse = CdnZonesComponents['schemas']['CipherSuitesResponse']; + +/** + * Response type for the get command. + */ +interface GetOutput { + cipherSuites: CipherSuitesResponse; +} + +/** + * Command to get cipher suites settings for a zone. + */ +export default class EcdnCipherSuitesGet extends EcdnZoneCommand { + static description = t('commands.ecdn.cipher-suites.get.description', 'Get cipher suites settings for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.cipher-suites.get.fetching', 'Fetching cipher suites settings...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/settings/ciphers', { + params: { + path: {organizationId, zoneId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.cipher-suites.get.error', 'Failed to fetch cipher suites settings: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const cipherSuites = data?.data; + if (!cipherSuites) { + this.error(t('commands.ecdn.cipher-suites.get.noData', 'No cipher suites data returned from API')); + } + + const output: GetOutput = {cipherSuites}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 18; + + ui.div(''); + ui.div({text: 'Cipher Suites:', padding: [0, 0, 1, 0]}); + ui.div({text: 'Suite Type:', width: labelWidth}, {text: cipherSuites.cipherSuiteType}); + ui.div(''); + ui.div({text: 'Ciphers:', padding: [0, 0, 0, 0]}); + + for (const cipher of cipherSuites.ciphers) { + ui.div({text: ` ${cipher}`}); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/cipher-suites/update.ts b/packages/b2c-cli/src/commands/ecdn/cipher-suites/update.ts new file mode 100644 index 00000000..ca869166 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/cipher-suites/update.ts @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type CipherSuitesResponse = CdnZonesComponents['schemas']['CipherSuitesResponse']; +type CipherSuitesRequest = CdnZonesComponents['schemas']['CipherSuitesRequest']; + +/** + * Response type for the update command. + */ +interface UpdateOutput { + cipherSuites: CipherSuitesResponse; +} + +/** + * Command to update cipher suites settings for a zone. + */ +export default class EcdnCipherSuitesUpdate extends EcdnZoneCommand { + static description = t('commands.ecdn.cipher-suites.update.description', 'Update cipher suites settings for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --suite-type Modern', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --suite-type Custom --ciphers "ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256"', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'suite-type': Flags.string({ + description: t('flags.suiteType.description', 'Cipher suite type'), + options: ['Compatible', 'Modern', 'Custom', 'Legacy'], + required: true, + }), + ciphers: Flags.string({ + description: t('flags.ciphers.description', 'Comma-separated list of ciphers (required for Custom suite type)'), + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.cipher-suites.update.updating', 'Updating cipher suites settings...')); + } + + const body: CipherSuitesRequest = { + cipherSuiteType: this.flags['suite-type'] as CipherSuitesRequest['cipherSuiteType'], + }; + + if (this.flags.ciphers) { + body.ciphers = this.flags.ciphers.split(',').map((c) => c.trim()); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PATCH('/organizations/{organizationId}/zones/{zoneId}/settings/ciphers', { + params: { + path: {organizationId, zoneId}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.cipher-suites.update.error', 'Failed to update cipher suites settings: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const cipherSuites = data?.data; + if (!cipherSuites) { + this.error(t('commands.ecdn.cipher-suites.update.noData', 'No cipher suites data returned from API')); + } + + const output: UpdateOutput = {cipherSuites}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 18; + + ui.div(''); + ui.div({text: t('commands.ecdn.cipher-suites.update.success', 'Cipher suites updated successfully!')}); + ui.div(''); + ui.div({text: 'Suite Type:', width: labelWidth}, {text: cipherSuites.cipherSuiteType}); + + if (cipherSuites.ciphers.length > 0) { + ui.div(''); + ui.div({text: 'Ciphers:', padding: [0, 0, 0, 0]}); + for (const cipher of cipherSuites.ciphers) { + ui.div({text: ` ${cipher}`}); + } + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/logpush/jobs/create.ts b/packages/b2c-cli/src/commands/ecdn/logpush/jobs/create.ts new file mode 100644 index 00000000..746bc5b7 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/logpush/jobs/create.ts @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type LogpushResponse = CdnZonesComponents['schemas']['LogpushResponse']; +type LogpushCreateRequest = CdnZonesComponents['schemas']['LogpushCreateRequest']; + +/** + * Response type for the create command. + */ +interface CreateOutput { + job: LogpushResponse; +} + +/** + * Command to create a Logpush job for a zone. + */ +export default class EcdnLogpushJobsCreate extends EcdnZoneCommand { + static description = t('commands.ecdn.logpush.jobs.create.description', 'Create a Logpush job for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --name my-job --destination-path "s3://bucket/logs/{DATE}?region=us-east-1" --log-type http_requests --log-fields ClientRequestHost,ClientRequestMethod,ClientRequestPath', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --name firewall-logs --destination-path "s3://bucket/firewall/{DATE}?region=us-west-2" --log-type firewall_events --log-fields Action,ClientIP,RuleId', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + name: Flags.string({ + description: t('flags.name.description', 'Name for the Logpush job (cannot be changed after creation)'), + required: true, + }), + 'destination-path': Flags.string({ + description: t( + 'flags.destinationPath.description', + 'S3 bucket destination path (e.g., s3://bucket/path/{DATE}?region=us-east-1)', + ), + required: true, + }), + 'log-type': Flags.string({ + description: t('flags.logType.description', 'Type of logs to push'), + options: ['http_requests', 'firewall_events', 'page_shield_events'], + required: true, + }), + 'log-fields': Flags.string({ + description: t('flags.logFields.description', 'Comma-separated list of log fields to include'), + required: true, + }), + filter: Flags.string({ + description: t('flags.filter.description', 'JSON filter expression for log selection'), + }), + 'ownership-token': Flags.string({ + description: t('flags.ownershipToken.description', 'Ownership challenge token for destination verification'), + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.logpush.jobs.create.creating', 'Creating Logpush job...')); + } + + const logFields = this.flags['log-fields'].split(',').map((f) => f.trim()); + + const body: LogpushCreateRequest = { + name: this.flags.name, + destinationPath: this.flags['destination-path'], + logType: this.flags['log-type'] as LogpushCreateRequest['logType'], + logFields, + }; + + if (this.flags.filter) { + body.filter = this.flags.filter; + } + if (this.flags['ownership-token']) { + body.ownershipChallengeToken = this.flags['ownership-token']; + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.POST('/organizations/{organizationId}/zones/{zoneId}/logpush/jobs', { + params: { + path: {organizationId, zoneId}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.logpush.jobs.create.error', 'Failed to create Logpush job: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const job = data?.data; + if (!job) { + this.error(t('commands.ecdn.logpush.jobs.create.noData', 'No Logpush job data returned from API')); + } + + const output: CreateOutput = {job}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 18; + + ui.div(''); + ui.div({text: t('commands.ecdn.logpush.jobs.create.success', 'Logpush job created successfully!')}); + ui.div(''); + ui.div({text: 'Job ID:', width: labelWidth}, {text: job.jobId === undefined ? '-' : String(job.jobId)}); + ui.div({text: 'Name:', width: labelWidth}, {text: job.name || '-'}); + ui.div({text: 'Log Type:', width: labelWidth}, {text: job.logType || '-'}); + ui.div({text: 'Enabled:', width: labelWidth}, {text: job.enabled ? 'yes' : 'no'}); + ui.div({text: 'Destination:', width: labelWidth}, {text: job.destinationPath || '-'}); + + if (job.logFields && job.logFields.length > 0) { + ui.div({text: 'Log Fields:', width: labelWidth}, {text: job.logFields.join(', ')}); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/logpush/jobs/delete.ts b/packages/b2c-cli/src/commands/ecdn/logpush/jobs/delete.ts new file mode 100644 index 00000000..19c580c6 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/logpush/jobs/delete.ts @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +/** + * Response type for the delete command. + */ +interface DeleteOutput { + deleted: boolean; + jobId: number; +} + +/** + * Command to delete a Logpush job for a zone. + */ +export default class EcdnLogpushJobsDelete extends EcdnZoneCommand { + static description = t('commands.ecdn.logpush.jobs.delete.description', 'Delete a Logpush job'); + + static enableJsonFlag = true; + + static examples = ['<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --job-id 123456']; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'job-id': Flags.integer({ + description: t('flags.jobId.description', 'Logpush job ID to delete'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const jobId = this.flags['job-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.logpush.jobs.delete.deleting', 'Deleting Logpush job {{id}}...', {id: jobId})); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {error} = await client.DELETE('/organizations/{organizationId}/zones/{zoneId}/logpush/jobs/{jobId}', { + params: { + path: {organizationId, zoneId, jobId: String(jobId)}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.logpush.jobs.delete.error', 'Failed to delete Logpush job: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const output: DeleteOutput = {deleted: true, jobId}; + + if (this.jsonEnabled()) { + return output; + } + + ux.stdout(t('commands.ecdn.logpush.jobs.delete.success', 'Logpush job {{id}} deleted successfully.', {id: jobId})); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/logpush/jobs/get.ts b/packages/b2c-cli/src/commands/ecdn/logpush/jobs/get.ts new file mode 100644 index 00000000..dd390ca3 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/logpush/jobs/get.ts @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type LogpushResponse = CdnZonesComponents['schemas']['LogpushResponse']; + +/** + * Response type for the get command. + */ +interface GetOutput { + job: LogpushResponse; +} + +/** + * Command to get a Logpush job for a zone. + */ +export default class EcdnLogpushJobsGet extends EcdnZoneCommand { + static description = t('commands.ecdn.logpush.jobs.get.description', 'Get details of a Logpush job'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --job-id 123456', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --job-id 123456 --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'job-id': Flags.integer({ + description: t('flags.jobId.description', 'Logpush job ID'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const jobId = this.flags['job-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.logpush.jobs.get.fetching', 'Fetching Logpush job...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/logpush/jobs/{jobId}', { + params: { + path: {organizationId, zoneId, jobId: String(jobId)}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.logpush.jobs.get.error', 'Failed to fetch Logpush job: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const job = data?.data; + if (!job) { + this.error(t('commands.ecdn.logpush.jobs.get.noData', 'No Logpush job data returned from API')); + } + + const output: GetOutput = {job}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 18; + + ui.div(''); + ui.div({text: 'Logpush Job:', padding: [0, 0, 1, 0]}); + ui.div({text: 'Job ID:', width: labelWidth}, {text: job.jobId === undefined ? '-' : String(job.jobId)}); + ui.div({text: 'Name:', width: labelWidth}, {text: job.name || '-'}); + ui.div({text: 'Log Type:', width: labelWidth}, {text: job.logType || '-'}); + ui.div({text: 'Enabled:', width: labelWidth}, {text: job.enabled ? 'yes' : 'no'}); + ui.div({text: 'Destination:', width: labelWidth}, {text: job.destinationPath || '-'}); + + if (job.logFields && job.logFields.length > 0) { + ui.div({text: 'Log Fields:', width: labelWidth}, {text: job.logFields.join(', ')}); + } + if (job.filter) { + ui.div({text: 'Filter:', width: labelWidth}, {text: job.filter}); + } + if (job.lastComplete) { + ui.div({text: 'Last Complete:', width: labelWidth}, {text: job.lastComplete}); + } + if (job.lastError) { + ui.div({text: 'Last Error:', width: labelWidth}, {text: job.lastError}); + } + if (job.errorMessage) { + ui.div({text: 'Error Message:', width: labelWidth}, {text: job.errorMessage}); + } + if (job.createdOn) { + ui.div({text: 'Created On:', width: labelWidth}, {text: job.createdOn}); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/logpush/jobs/list.ts b/packages/b2c-cli/src/commands/ecdn/logpush/jobs/list.ts new file mode 100644 index 00000000..a1f03a1f --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/logpush/jobs/list.ts @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type LogpushResponse = CdnZonesComponents['schemas']['LogpushResponse']; + +/** + * Response type for the list command. + */ +interface ListOutput { + jobs: LogpushResponse[]; + total: number; +} + +const COLUMNS: Record> = { + jobId: { + header: 'Job ID', + get: (r) => (r.jobId === undefined ? '-' : String(r.jobId)), + }, + name: { + header: 'Name', + get: (r) => r.name || '-', + }, + logType: { + header: 'Log Type', + get: (r) => r.logType || '-', + }, + enabled: { + header: 'Enabled', + get: (r) => (r.enabled ? 'yes' : 'no'), + }, + destinationPath: { + header: 'Destination', + get: (r) => r.destinationPath || '-', + extended: true, + }, + lastComplete: { + header: 'Last Complete', + get: (r) => r.lastComplete || '-', + extended: true, + }, + errorMessage: { + header: 'Error', + get: (r) => r.errorMessage || '-', + extended: true, + }, +}; + +const DEFAULT_COLUMNS = ['jobId', 'name', 'logType', 'enabled']; + +const tableRenderer = new TableRenderer(COLUMNS); + +/** + * Command to list Logpush jobs for a zone. + */ +export default class EcdnLogpushJobsList extends EcdnZoneCommand { + static description = t('commands.ecdn.logpush.jobs.list.description', 'List Logpush jobs for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --extended', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + columns: Flags.string({ + char: 'c', + description: `Columns to display (comma-separated). Available: ${Object.keys(COLUMNS).join(', ')}`, + }), + extended: Flags.boolean({ + char: 'x', + description: t('flags.extended.description', 'Show all columns including extended fields'), + default: false, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.logpush.jobs.list.fetching', 'Fetching Logpush jobs...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/logpush/jobs', { + params: { + path: {organizationId, zoneId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.logpush.jobs.list.error', 'Failed to fetch Logpush jobs: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const jobs = data?.data ?? []; + const output: ListOutput = { + jobs, + total: jobs.length, + }; + + if (this.jsonEnabled()) { + return output; + } + + if (jobs.length === 0) { + this.log(t('commands.ecdn.logpush.jobs.list.noJobs', 'No Logpush jobs found.')); + return output; + } + + this.log( + t('commands.ecdn.logpush.jobs.list.count', 'Found {{count}} Logpush job(s):', { + count: jobs.length, + }), + ); + this.log(''); + + const columns = this.getSelectedColumns(); + tableRenderer.render(jobs, columns); + + return output; + } + + private getSelectedColumns(): string[] { + const columnsFlag = this.flags.columns; + const extended = this.flags.extended; + + if (columnsFlag) { + const requested = columnsFlag.split(',').map((c) => c.trim()); + const valid = tableRenderer.validateColumnKeys(requested); + if (valid.length === 0) { + this.warn(`No valid columns specified. Available: ${tableRenderer.getColumnKeys().join(', ')}`); + return DEFAULT_COLUMNS; + } + return valid; + } + + if (extended) { + return tableRenderer.getColumnKeys(); + } + + return DEFAULT_COLUMNS; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/logpush/jobs/update.ts b/packages/b2c-cli/src/commands/ecdn/logpush/jobs/update.ts new file mode 100644 index 00000000..7dde9ff2 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/logpush/jobs/update.ts @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type LogpushResponse = CdnZonesComponents['schemas']['LogpushResponse']; +type LogpushUpdateRequest = CdnZonesComponents['schemas']['LogpushUpdateRequest']; + +/** + * Response type for the update command. + */ +interface UpdateOutput { + job: LogpushResponse; +} + +/** + * Command to update a Logpush job for a zone. + */ +export default class EcdnLogpushJobsUpdate extends EcdnZoneCommand { + static description = t('commands.ecdn.logpush.jobs.update.description', 'Update a Logpush job'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --job-id 123456 --enabled', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --job-id 123456 --no-enabled', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --job-id 123456 --log-fields ClientRequestHost,ClientRequestMethod,ClientRequestPath', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'job-id': Flags.integer({ + description: t('flags.jobId.description', 'Logpush job ID'), + required: true, + }), + enabled: Flags.boolean({ + description: t('flags.enabled.description', 'Enable or disable the job'), + allowNo: true, + }), + filter: Flags.string({ + description: t('flags.filter.description', 'JSON filter expression for log selection'), + }), + 'log-fields': Flags.string({ + description: t('flags.logFields.description', 'Comma-separated list of log fields to include'), + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const jobId = this.flags['job-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.logpush.jobs.update.updating', 'Updating Logpush job {{id}}...', {id: jobId})); + } + + const body: LogpushUpdateRequest = {}; + + if (this.flags.enabled !== undefined) { + body.enabled = this.flags.enabled; + } + if (this.flags.filter !== undefined) { + body.filter = this.flags.filter; + } + if (this.flags['log-fields']) { + body.logFields = this.flags['log-fields'].split(',').map((f) => f.trim()); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PUT('/organizations/{organizationId}/zones/{zoneId}/logpush/jobs/{jobId}', { + params: { + path: {organizationId, zoneId, jobId: String(jobId)}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.logpush.jobs.update.error', 'Failed to update Logpush job: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const job = data?.data; + if (!job) { + this.error(t('commands.ecdn.logpush.jobs.update.noData', 'No Logpush job data returned from API')); + } + + const output: UpdateOutput = {job}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 18; + + ui.div(''); + ui.div({text: t('commands.ecdn.logpush.jobs.update.success', 'Logpush job updated successfully!')}); + ui.div(''); + ui.div({text: 'Job ID:', width: labelWidth}, {text: job.jobId === undefined ? '-' : String(job.jobId)}); + ui.div({text: 'Name:', width: labelWidth}, {text: job.name || '-'}); + ui.div({text: 'Enabled:', width: labelWidth}, {text: job.enabled ? 'yes' : 'no'}); + + if (job.logFields && job.logFields.length > 0) { + ui.div({text: 'Log Fields:', width: labelWidth}, {text: job.logFields.join(', ')}); + } + if (job.filter) { + ui.div({text: 'Filter:', width: labelWidth}, {text: job.filter}); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/logpush/ownership.ts b/packages/b2c-cli/src/commands/ecdn/logpush/ownership.ts new file mode 100644 index 00000000..9b9fc5d7 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/logpush/ownership.ts @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +/** + * Response type for the ownership command. + */ +interface OwnershipOutput { + destinationPath: string; + fileName: string; +} + +/** + * Command to create a Logpush ownership challenge token. + */ +export default class EcdnLogpushOwnership extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.logpush.ownership.description', + 'Create a Logpush ownership challenge token for destination verification', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --destination-path "s3://my-bucket/logs/{DATE}?region=us-east-1"', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'destination-path': Flags.string({ + description: t( + 'flags.destinationPath.description', + 'S3 bucket destination path (e.g., s3://bucket/path/{DATE}?region=us-east-1)', + ), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const destinationPath = this.flags['destination-path']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.logpush.ownership.creating', 'Creating Logpush ownership challenge...')); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.POST('/organizations/{organizationId}/zones/{zoneId}/logpush/ownership', { + params: { + path: {organizationId, zoneId}, + }, + body: {destinationPath}, + }); + + if (error) { + this.error( + t('commands.ecdn.logpush.ownership.error', 'Failed to create ownership challenge: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const result = data?.data; + if (!result) { + this.error(t('commands.ecdn.logpush.ownership.noData', 'No ownership data returned from API')); + } + + const output: OwnershipOutput = { + destinationPath: result.destinationPath, + fileName: result.fileName, + }; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 20; + + ui.div(''); + ui.div({text: t('commands.ecdn.logpush.ownership.success', 'Ownership challenge created successfully!')}); + ui.div(''); + ui.div({text: 'Destination Path:', width: labelWidth}, {text: result.destinationPath}); + ui.div({text: 'Challenge File:', width: labelWidth}, {text: result.fileName}); + ui.div(''); + ui.div({ + text: t( + 'commands.ecdn.logpush.ownership.instructions', + 'Upload the ownership challenge file to your S3 bucket, then create a Logpush job with the token.', + ), + }); + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/mrt-rules/create.ts b/packages/b2c-cli/src/commands/ecdn/mrt-rules/create.ts new file mode 100644 index 00000000..c38fd525 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/mrt-rules/create.ts @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type MRTRulesResponse = CdnZonesComponents['schemas']['MRTRulesResponse']; +type MRTRulesPostRequest = CdnZonesComponents['schemas']['MRTRulesPostRequest']; + +/** + * Response type for the create command. + */ +interface CreateOutput { + ruleset: MRTRulesResponse['ruleset']; +} + +/** + * Command to create MRT rules for a zone. + */ +export default class EcdnMrtRulesCreate extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.mrt-rules.create.description', + 'Create MRT rules to route requests to a Managed Runtime environment', + ); + + static enableJsonFlag = true; + + static examples = [ + `<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --mrt-hostname customer-pwa.mobify-storefront.com --expressions '(http.host eq "example.com")'`, + `<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --mrt-hostname customer-pwa.mobify-storefront.com --expressions '(http.host eq "example.com")' --descriptions "Route to PWA"`, + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'mrt-hostname': Flags.string({ + description: t('flags.mrtHostname.description', 'Managed Runtime instance hostname'), + required: true, + }), + expressions: Flags.string({ + description: t('flags.expressions.description', 'Comma-separated list of rule expressions'), + required: true, + }), + descriptions: Flags.string({ + description: t( + 'flags.descriptions.description', + 'Comma-separated list of rule descriptions (must match expressions count)', + ), + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.mrt-rules.create.creating', 'Creating MRT rules...')); + } + + const expressions = this.flags.expressions.split(',').map((e) => e.trim()); + const body: MRTRulesPostRequest = { + mrtHostname: this.flags['mrt-hostname'], + expressions, + }; + + if (this.flags.descriptions) { + body.descriptions = this.flags.descriptions.split(',').map((d) => d.trim()); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.POST('/organizations/{organizationId}/zones/{zoneId}/mrtrules', { + params: { + path: {organizationId, zoneId}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.mrt-rules.create.error', 'Failed to create MRT rules: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const ruleset = data?.data?.ruleset; + if (!ruleset) { + this.error(t('commands.ecdn.mrt-rules.create.noData', 'No MRT ruleset data returned from API')); + } + + const output: CreateOutput = {ruleset}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 16; + + ui.div(''); + ui.div({text: t('commands.ecdn.mrt-rules.create.success', 'MRT rules created successfully!')}); + ui.div(''); + ui.div({text: 'Ruleset ID:', width: labelWidth}, {text: ruleset.id}); + ui.div({text: 'Name:', width: labelWidth}, {text: ruleset.name}); + ui.div({text: 'Rules Count:', width: labelWidth}, {text: String(ruleset.rules.length)}); + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/mrt-rules/delete.ts b/packages/b2c-cli/src/commands/ecdn/mrt-rules/delete.ts new file mode 100644 index 00000000..60bc0c55 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/mrt-rules/delete.ts @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +/** + * Response type for the delete command. + */ +interface DeleteOutput { + deleted: boolean; + rulesetId: string; +} + +/** + * Command to delete an MRT ruleset for a zone. + */ +export default class EcdnMrtRulesDelete extends EcdnZoneCommand { + static description = t('commands.ecdn.mrt-rules.delete.description', 'Delete an MRT ruleset and all rules within it'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id 12345678901234asdfasfasdf', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'ruleset-id': Flags.string({ + description: t('flags.rulesetId.description', 'MRT ruleset ID to delete'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const rulesetId = this.flags['ruleset-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.mrt-rules.delete.deleting', 'Deleting MRT ruleset {{id}}...', {id: rulesetId})); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {error} = await client.DELETE('/organizations/{organizationId}/zones/{zoneId}/mrtrules/{rulesetId}', { + params: { + path: {organizationId, zoneId, rulesetId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.mrt-rules.delete.error', 'Failed to delete MRT ruleset: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const output: DeleteOutput = {deleted: true, rulesetId}; + + if (this.jsonEnabled()) { + return output; + } + + ux.stdout(t('commands.ecdn.mrt-rules.delete.success', 'MRT ruleset {{id}} deleted successfully.', {id: rulesetId})); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/mrt-rules/get.ts b/packages/b2c-cli/src/commands/ecdn/mrt-rules/get.ts new file mode 100644 index 00000000..d92a4967 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/mrt-rules/get.ts @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {ux} from '@oclif/core'; +import {TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type MRTRulesResponse = CdnZonesComponents['schemas']['MRTRulesResponse']; +type MRTRules = CdnZonesComponents['schemas']['MRTRules']; + +/** + * Response type for the get command. + */ +interface GetOutput { + ruleset: MRTRulesResponse['ruleset']; +} + +const COLUMNS: Record> = { + id: { + header: 'Rule ID', + get: (r) => r.id || '-', + }, + enabled: { + header: 'Enabled', + get: (r) => (r.enabled ? 'yes' : 'no'), + }, + mrtHostname: { + header: 'MRT Hostname', + get: (r) => r.mrtHostname || '-', + }, + description: { + header: 'Description', + get: (r) => r.description || '-', + }, + expression: { + header: 'Expression', + get: (r) => (r.expression.length > 50 ? r.expression.slice(0, 47) + '...' : r.expression), + }, +}; + +const tableRenderer = new TableRenderer(COLUMNS); + +/** + * Command to get MRT ruleset for a zone. + */ +export default class EcdnMrtRulesGet extends EcdnZoneCommand { + static description = t('commands.ecdn.mrt-rules.get.description', 'Get MRT ruleset for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.mrt-rules.get.fetching', 'Fetching MRT ruleset...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/mrtrules', { + params: { + path: {organizationId, zoneId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.mrt-rules.get.error', 'Failed to fetch MRT ruleset: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const ruleset = data?.data?.ruleset; + if (!ruleset) { + this.error(t('commands.ecdn.mrt-rules.get.noData', 'No MRT ruleset data returned from API')); + } + + const output: GetOutput = {ruleset}; + + if (this.jsonEnabled()) { + return output; + } + + this.log(''); + ux.stdout(`Ruleset ID: ${ruleset.id}`); + ux.stdout(`Name: ${ruleset.name}`); + ux.stdout(`Last Updated: ${ruleset.lastUpdated}`); + this.log(''); + + if (ruleset.rules.length === 0) { + this.log(t('commands.ecdn.mrt-rules.get.noRules', 'No MRT rules defined in ruleset.')); + return output; + } + + this.log( + t('commands.ecdn.mrt-rules.get.count', 'Found {{count}} MRT rule(s):', { + count: ruleset.rules.length, + }), + ); + this.log(''); + + tableRenderer.render(ruleset.rules, Object.keys(COLUMNS)); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/mrt-rules/rules/delete.ts b/packages/b2c-cli/src/commands/ecdn/mrt-rules/rules/delete.ts new file mode 100644 index 00000000..84349709 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/mrt-rules/rules/delete.ts @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +/** + * Response type for the delete command. + */ +interface DeleteOutput { + deleted: boolean; + ruleId: string; +} + +/** + * Command to delete an individual MRT rule. + */ +export default class EcdnMrtRulesRulesDelete extends EcdnZoneCommand { + static description = t('commands.ecdn.mrt-rules.rules.delete.description', 'Delete an individual MRT rule'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123 --rule-id def456', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'ruleset-id': Flags.string({ + description: t('flags.rulesetId.description', 'MRT ruleset ID'), + required: true, + }), + 'rule-id': Flags.string({ + description: t('flags.ruleId.description', 'MRT rule ID to delete'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const rulesetId = this.flags['ruleset-id']; + const ruleId = this.flags['rule-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.mrt-rules.rules.delete.deleting', 'Deleting MRT rule {{id}}...', {id: ruleId})); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {error} = await client.DELETE( + '/organizations/{organizationId}/zones/{zoneId}/mrtrules/{rulesetId}/rules/{ruleId}', + { + params: { + path: {organizationId, zoneId, rulesetId, ruleId}, + }, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.mrt-rules.rules.delete.error', 'Failed to delete MRT rule: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const output: DeleteOutput = {deleted: true, ruleId}; + + if (this.jsonEnabled()) { + return output; + } + + ux.stdout(t('commands.ecdn.mrt-rules.rules.delete.success', 'MRT rule {{id}} deleted successfully.', {id: ruleId})); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/mrt-rules/rules/update.ts b/packages/b2c-cli/src/commands/ecdn/mrt-rules/rules/update.ts new file mode 100644 index 00000000..90f13f13 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/mrt-rules/rules/update.ts @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type MRTRulesResponse = CdnZonesComponents['schemas']['MRTRulesResponse']; +type MRTRulePatchRequest = CdnZonesComponents['schemas']['MRTRulePatchRequest']; + +/** + * Response type for the update command. + */ +interface UpdateOutput { + ruleset: MRTRulesResponse['ruleset']; +} + +/** + * Command to update an individual MRT rule. + */ +export default class EcdnMrtRulesRulesUpdate extends EcdnZoneCommand { + static description = t('commands.ecdn.mrt-rules.rules.update.description', 'Update an individual MRT rule'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123 --rule-id def456 --enabled', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123 --rule-id def456 --no-enabled', + `<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123 --rule-id def456 --expression '(http.host eq "new.example.com")'`, + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'ruleset-id': Flags.string({ + description: t('flags.rulesetId.description', 'MRT ruleset ID'), + required: true, + }), + 'rule-id': Flags.string({ + description: t('flags.ruleId.description', 'MRT rule ID to update'), + required: true, + }), + enabled: Flags.boolean({ + description: t('flags.enabled.description', 'Enable or disable the rule'), + allowNo: true, + }), + expression: Flags.string({ + description: t('flags.expression.description', 'Rule expression'), + }), + description: Flags.string({ + description: t('flags.description.description', 'Rule description'), + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const rulesetId = this.flags['ruleset-id']; + const ruleId = this.flags['rule-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.mrt-rules.rules.update.updating', 'Updating MRT rule {{id}}...', {id: ruleId})); + } + + const body: MRTRulePatchRequest = {}; + + if (this.flags.enabled !== undefined) { + body.enabled = this.flags.enabled; + } + if (this.flags.expression) { + body.expression = this.flags.expression; + } + if (this.flags.description !== undefined) { + body.description = this.flags.description; + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PATCH( + '/organizations/{organizationId}/zones/{zoneId}/mrtrules/{rulesetId}/rules/{ruleId}', + { + params: { + path: {organizationId, zoneId, rulesetId, ruleId}, + }, + body, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.mrt-rules.rules.update.error', 'Failed to update MRT rule: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const ruleset = data?.data?.ruleset; + if (!ruleset) { + this.error(t('commands.ecdn.mrt-rules.rules.update.noData', 'No MRT ruleset data returned from API')); + } + + const output: UpdateOutput = {ruleset}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + + ui.div(''); + ui.div({text: t('commands.ecdn.mrt-rules.rules.update.success', 'MRT rule updated successfully!')}); + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/mrt-rules/update.ts b/packages/b2c-cli/src/commands/ecdn/mrt-rules/update.ts new file mode 100644 index 00000000..b754de2d --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/mrt-rules/update.ts @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type MRTRulesResponse = CdnZonesComponents['schemas']['MRTRulesResponse']; +type MRTRulesetPatchRequest = CdnZonesComponents['schemas']['MRTRulesetPatchRequest']; + +/** + * Response type for the update command. + */ +interface UpdateOutput { + ruleset: MRTRulesResponse['ruleset']; +} + +/** + * Command to update an MRT ruleset for a zone. + */ +export default class EcdnMrtRulesUpdate extends EcdnZoneCommand { + static description = t('commands.ecdn.mrt-rules.update.description', 'Update MRT ruleset hostname or add new rules'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --mrt-hostname new-customer-pwa.mobify-storefront.com', + `<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --mrt-hostname customer-pwa.mobify-storefront.com --expressions '(http.host eq "new.example.com")'`, + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'mrt-hostname': Flags.string({ + description: t('flags.mrtHostname.description', 'New Managed Runtime instance hostname'), + required: true, + }), + 'old-mrt-hostname': Flags.string({ + description: t('flags.oldMrtHostname.description', 'Current MRT hostname (required when changing hostname)'), + }), + expressions: Flags.string({ + description: t('flags.expressions.description', 'Comma-separated list of new rule expressions to add'), + }), + descriptions: Flags.string({ + description: t( + 'flags.descriptions.description', + 'Comma-separated list of descriptions for new rules (must match expressions count)', + ), + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.mrt-rules.update.updating', 'Updating MRT ruleset...')); + } + + const body: MRTRulesetPatchRequest = { + mrtHostname: this.flags['mrt-hostname'], + }; + + if (this.flags['old-mrt-hostname']) { + body.oldMrtHostname = this.flags['old-mrt-hostname']; + } + if (this.flags.expressions) { + body.expressions = this.flags.expressions.split(',').map((e) => e.trim()); + } + if (this.flags.descriptions) { + body.descriptions = this.flags.descriptions.split(',').map((d) => d.trim()); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PATCH('/organizations/{organizationId}/zones/{zoneId}/mrtrules', { + params: { + path: {organizationId, zoneId}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.mrt-rules.update.error', 'Failed to update MRT ruleset: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const ruleset = data?.data?.ruleset; + if (!ruleset) { + this.error(t('commands.ecdn.mrt-rules.update.noData', 'No MRT ruleset data returned from API')); + } + + const output: UpdateOutput = {ruleset}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 16; + + ui.div(''); + ui.div({text: t('commands.ecdn.mrt-rules.update.success', 'MRT ruleset updated successfully!')}); + ui.div(''); + ui.div({text: 'Ruleset ID:', width: labelWidth}, {text: ruleset.id}); + ui.div({text: 'Name:', width: labelWidth}, {text: ruleset.name}); + ui.div({text: 'Rules Count:', width: labelWidth}, {text: String(ruleset.rules.length)}); + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/mtls/create.ts b/packages/b2c-cli/src/commands/ecdn/mtls/create.ts new file mode 100644 index 00000000..ba272128 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/mtls/create.ts @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import * as fs from 'node:fs'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type MtlsCertificateResponse = CdnZonesComponents['schemas']['MtlsCertificateResponse']; +type MtlsCertificateRequest = CdnZonesComponents['schemas']['MtlsCertificateRequest']; + +/** + * Response type for the create command. + */ +interface CreateOutput { + certificate: MtlsCertificateResponse; +} + +/** + * Command to create an mTLS certificate for code upload. + */ +export default class EcdnMtlsCreate extends EcdnCommand { + static description = t( + 'commands.ecdn.mtls.create.description', + 'Create an mTLS certificate for code upload authentication', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --name my-cert --certificate-file cert.pem --private-key-file key.pem', + ]; + + static flags = { + ...EcdnCommand.baseFlags, + name: Flags.string({ + description: t('flags.name.description', 'Certificate name for identification'), + required: true, + }), + 'certificate-file': Flags.string({ + description: t('flags.certificateFile.description', 'Path to PEM-encoded certificate file'), + required: true, + }), + 'private-key-file': Flags.string({ + description: t('flags.privateKeyFile.description', 'Path to PEM-encoded private key file'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.mtls.create.creating', 'Creating mTLS certificate...')); + } + + const certificate = fs.readFileSync(this.flags['certificate-file'], 'utf8'); + const privateKey = fs.readFileSync(this.flags['private-key-file'], 'utf8'); + + const body: MtlsCertificateRequest = { + name: this.flags.name, + certificate, + privateKey, + }; + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.POST('/organizations/{organizationId}/mtls/code-upload-certificates', { + params: { + path: {organizationId}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.mtls.create.error', 'Failed to create mTLS certificate: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const cert = data?.data; + if (!cert) { + this.error(t('commands.ecdn.mtls.create.noData', 'No certificate data returned from API')); + } + + const output: CreateOutput = {certificate: cert}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 20; + + ui.div(''); + ui.div({text: t('commands.ecdn.mtls.create.success', 'mTLS certificate created successfully!')}); + ui.div(''); + ui.div({text: 'Certificate ID:', width: labelWidth}, {text: cert.mtlsCertificateId || '-'}); + ui.div({text: 'Name:', width: labelWidth}, {text: cert.mtlsCertificateName || '-'}); + ui.div({text: 'Issuer:', width: labelWidth}, {text: cert.issuer || '-'}); + ui.div({text: 'Expires:', width: labelWidth}, {text: cert.expiresOn || '-'}); + + if (cert.mtlsAssociatedCodeUploadHostname) { + ui.div({text: 'Hostname:', width: labelWidth}, {text: cert.mtlsAssociatedCodeUploadHostname}); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/mtls/delete.ts b/packages/b2c-cli/src/commands/ecdn/mtls/delete.ts new file mode 100644 index 00000000..1e850d5b --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/mtls/delete.ts @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import {EcdnCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +/** + * Response type for the delete command. + */ +interface DeleteOutput { + deleted: boolean; + certificateId: string; +} + +/** + * Command to delete an mTLS certificate. + */ +export default class EcdnMtlsDelete extends EcdnCommand { + static description = t('commands.ecdn.mtls.delete.description', 'Delete an mTLS certificate'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --certificate-id 465a48f6-3d98-4c15-9312-211984ee8629', + ]; + + static flags = { + ...EcdnCommand.baseFlags, + 'certificate-id': Flags.string({ + description: t('flags.certificateId.description', 'mTLS certificate ID to delete'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const mtlsCertificateId = this.flags['certificate-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.mtls.delete.deleting', 'Deleting mTLS certificate {{id}}...', {id: mtlsCertificateId})); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {error} = await client.DELETE( + '/organizations/{organizationId}/mtls/code-upload-certificates/{mtlsCertificateId}', + { + params: { + path: {organizationId, mtlsCertificateId}, + }, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.mtls.delete.error', 'Failed to delete mTLS certificate: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const output: DeleteOutput = {deleted: true, certificateId: mtlsCertificateId}; + + if (this.jsonEnabled()) { + return output; + } + + ux.stdout( + t('commands.ecdn.mtls.delete.success', 'mTLS certificate {{id}} deleted successfully.', { + id: mtlsCertificateId, + }), + ); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/mtls/get.ts b/packages/b2c-cli/src/commands/ecdn/mtls/get.ts new file mode 100644 index 00000000..5f9c7e73 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/mtls/get.ts @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type MtlsCertificateResponse = CdnZonesComponents['schemas']['MtlsCertificateResponse']; + +/** + * Response type for the get command. + */ +interface GetOutput { + certificate: MtlsCertificateResponse; +} + +/** + * Command to get an mTLS certificate. + */ +export default class EcdnMtlsGet extends EcdnCommand { + static description = t('commands.ecdn.mtls.get.description', 'Get details of an mTLS certificate'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --certificate-id 465a48f6-3d98-4c15-9312-211984ee8629', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --certificate-id 465a48f6-3d98-4c15-9312-211984ee8629 --json', + ]; + + static flags = { + ...EcdnCommand.baseFlags, + 'certificate-id': Flags.string({ + description: t('flags.certificateId.description', 'mTLS certificate ID'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const mtlsCertificateId = this.flags['certificate-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.mtls.get.fetching', 'Fetching mTLS certificate...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET( + '/organizations/{organizationId}/mtls/code-upload-certificates/{mtlsCertificateId}', + { + params: { + path: {organizationId, mtlsCertificateId}, + }, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.mtls.get.error', 'Failed to fetch mTLS certificate: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const cert = data?.data; + if (!cert) { + this.error(t('commands.ecdn.mtls.get.noData', 'No certificate data returned from API')); + } + + const output: GetOutput = {certificate: cert}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 20; + + ui.div(''); + ui.div({text: 'mTLS Certificate:', padding: [0, 0, 1, 0]}); + ui.div({text: 'Certificate ID:', width: labelWidth}, {text: cert.mtlsCertificateId || '-'}); + ui.div({text: 'Name:', width: labelWidth}, {text: cert.mtlsCertificateName || '-'}); + ui.div({text: 'Issuer:', width: labelWidth}, {text: cert.issuer || '-'}); + ui.div({text: 'Signature:', width: labelWidth}, {text: cert.signature || '-'}); + ui.div({text: 'Serial Number:', width: labelWidth}, {text: cert.serialNumber || '-'}); + ui.div({text: 'CA Certificate:', width: labelWidth}, {text: cert.ca ? 'yes' : 'no'}); + ui.div({text: 'Expires:', width: labelWidth}, {text: cert.expiresOn || '-'}); + ui.div({text: 'Uploaded:', width: labelWidth}, {text: cert.uploadedOn || '-'}); + + if (cert.mtlsAssociatedCodeUploadHostname) { + ui.div({text: 'Hostname:', width: labelWidth}, {text: cert.mtlsAssociatedCodeUploadHostname}); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/mtls/list.ts b/packages/b2c-cli/src/commands/ecdn/mtls/list.ts new file mode 100644 index 00000000..1ce81098 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/mtls/list.ts @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type MtlsCertificateResponse = CdnZonesComponents['schemas']['MtlsCertificateResponse']; + +/** + * Response type for the list command. + */ +interface ListOutput { + certificates: MtlsCertificateResponse[]; + total: number; +} + +const COLUMNS: Record> = { + mtlsCertificateId: { + header: 'Certificate ID', + get: (r) => r.mtlsCertificateId || '-', + }, + mtlsCertificateName: { + header: 'Name', + get: (r) => r.mtlsCertificateName || '-', + }, + issuer: { + header: 'Issuer', + get: (r) => r.issuer || '-', + }, + expiresOn: { + header: 'Expires', + get: (r) => r.expiresOn || '-', + }, + mtlsAssociatedCodeUploadHostname: { + header: 'Hostname', + get: (r) => r.mtlsAssociatedCodeUploadHostname || '-', + extended: true, + }, + ca: { + header: 'CA', + get: (r) => (r.ca ? 'yes' : 'no'), + extended: true, + }, +}; + +const DEFAULT_COLUMNS = ['mtlsCertificateId', 'mtlsCertificateName', 'issuer', 'expiresOn']; + +const tableRenderer = new TableRenderer(COLUMNS); + +/** + * Command to list mTLS certificates for an organization. + */ +export default class EcdnMtlsList extends EcdnCommand { + static description = t('commands.ecdn.mtls.list.description', 'List mTLS certificates for code upload'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --extended', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --json', + ]; + + static flags = { + ...EcdnCommand.baseFlags, + columns: Flags.string({ + char: 'c', + description: `Columns to display (comma-separated). Available: ${Object.keys(COLUMNS).join(', ')}`, + }), + extended: Flags.boolean({ + char: 'x', + description: t('flags.extended.description', 'Show all columns including extended fields'), + default: false, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.mtls.list.fetching', 'Fetching mTLS certificates...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/mtls/code-upload-certificates', { + params: { + path: {organizationId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.mtls.list.error', 'Failed to fetch mTLS certificates: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const certificates = data?.data ?? []; + const output: ListOutput = { + certificates, + total: certificates.length, + }; + + if (this.jsonEnabled()) { + return output; + } + + if (certificates.length === 0) { + this.log(t('commands.ecdn.mtls.list.noCertificates', 'No mTLS certificates found.')); + return output; + } + + this.log( + t('commands.ecdn.mtls.list.count', 'Found {{count}} mTLS certificate(s):', { + count: certificates.length, + }), + ); + this.log(''); + + const columns = this.getSelectedColumns(); + tableRenderer.render(certificates, columns); + + return output; + } + + private getSelectedColumns(): string[] { + const columnsFlag = this.flags.columns; + const extended = this.flags.extended; + + if (columnsFlag) { + const requested = columnsFlag.split(',').map((c) => c.trim()); + const valid = tableRenderer.validateColumnKeys(requested); + if (valid.length === 0) { + this.warn(`No valid columns specified. Available: ${tableRenderer.getColumnKeys().join(', ')}`); + return DEFAULT_COLUMNS; + } + return valid; + } + + if (extended) { + return tableRenderer.getColumnKeys(); + } + + return DEFAULT_COLUMNS; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/origin-headers/delete.ts b/packages/b2c-cli/src/commands/ecdn/origin-headers/delete.ts new file mode 100644 index 00000000..36c5b3ea --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/origin-headers/delete.ts @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {ux} from '@oclif/core'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +/** + * Response type for the delete command. + */ +interface DeleteOutput { + deleted: boolean; +} + +/** + * Command to delete origin header modification for a zone. + */ +export default class EcdnOriginHeadersDelete extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.origin-headers.delete.description', + 'Delete origin header modification for a zone (MRT type)', + ); + + static enableJsonFlag = true; + + static examples = ['<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone']; + + static flags = { + ...EcdnZoneCommand.baseFlags, + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.origin-headers.delete.deleting', 'Deleting origin header modification...')); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + const type = 'mrt'; // Only mrt type is supported + + const {error} = await client.DELETE( + '/organizations/{organizationId}/zones/{zoneId}/origin-header-modification/{type}', + { + params: { + path: {organizationId, zoneId, type}, + }, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.origin-headers.delete.error', 'Failed to delete origin header modification: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const output: DeleteOutput = {deleted: true}; + + if (this.jsonEnabled()) { + return output; + } + + ux.stdout(t('commands.ecdn.origin-headers.delete.success', 'Origin header modification deleted successfully.')); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/origin-headers/get.ts b/packages/b2c-cli/src/commands/ecdn/origin-headers/get.ts new file mode 100644 index 00000000..24f033c4 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/origin-headers/get.ts @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type OriginHeaderModification = CdnZonesComponents['schemas']['OriginHeaderModification']; + +/** + * Response type for the get command. + */ +interface GetOutput { + header: OriginHeaderModification; +} + +/** + * Command to get origin header modification for a zone. + */ +export default class EcdnOriginHeadersGet extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.origin-headers.get.description', + 'Get origin header modification settings for a zone (MRT type)', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.origin-headers.get.fetching', 'Fetching origin header modification...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + const type = 'mrt'; // Only mrt type is supported + + const {data, error} = await client.GET( + '/organizations/{organizationId}/zones/{zoneId}/origin-header-modification/{type}', + { + params: { + path: {organizationId, zoneId, type}, + }, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.origin-headers.get.error', 'Failed to fetch origin header modification: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const header = data?.data; + if (!header) { + this.error(t('commands.ecdn.origin-headers.get.noData', 'No origin header data returned from API')); + } + + const output: GetOutput = {header}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 18; + + ui.div(''); + ui.div({text: 'Origin Header Modification:', padding: [0, 0, 1, 0]}); + ui.div({text: 'Header Name:', width: labelWidth}, {text: header.headerName}); + ui.div({text: 'Header Value:', width: labelWidth}, {text: header.headerValue}); + ui.div({text: 'Last Updated:', width: labelWidth}, {text: header.lastUpdated}); + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/origin-headers/set.ts b/packages/b2c-cli/src/commands/ecdn/origin-headers/set.ts new file mode 100644 index 00000000..e702bdb9 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/origin-headers/set.ts @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type OriginHeaderModification = CdnZonesComponents['schemas']['OriginHeaderModification']; +type OriginHeaderModificationPutRequest = CdnZonesComponents['schemas']['OriginHeaderModificationPutRequest']; + +/** + * Response type for the set command. + */ +interface SetOutput { + header: OriginHeaderModification; +} + +/** + * Command to set (create/update) origin header modification for a zone. + */ +export default class EcdnOriginHeadersSet extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.origin-headers.set.description', + 'Set origin header modification for a zone (MRT type)', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --header-value my-secret-value', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --header-value my-secret-value --header-name x-custom-header', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'header-value': Flags.string({ + description: t('flags.headerValue.description', 'Value of the header to forward to origin'), + required: true, + }), + 'header-name': Flags.string({ + description: t('flags.headerName.description', 'Name of the header (cannot be changed for MRT origin)'), + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.origin-headers.set.setting', 'Setting origin header modification...')); + } + + const body: OriginHeaderModificationPutRequest = { + headerValue: this.flags['header-value'], + }; + + if (this.flags['header-name']) { + body.headerName = this.flags['header-name']; + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + const type = 'mrt'; // Only mrt type is supported + + const {data, error} = await client.PUT( + '/organizations/{organizationId}/zones/{zoneId}/origin-header-modification/{type}', + { + params: { + path: {organizationId, zoneId, type}, + }, + body, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.origin-headers.set.error', 'Failed to set origin header modification: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const header = data?.data; + if (!header) { + this.error(t('commands.ecdn.origin-headers.set.noData', 'No origin header data returned from API')); + } + + const output: SetOutput = {header}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 18; + + ui.div(''); + ui.div({text: t('commands.ecdn.origin-headers.set.success', 'Origin header modification set successfully!')}); + ui.div(''); + ui.div({text: 'Header Name:', width: labelWidth}, {text: header.headerName}); + ui.div({text: 'Header Value:', width: labelWidth}, {text: header.headerValue}); + ui.div({text: 'Last Updated:', width: labelWidth}, {text: header.lastUpdated}); + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/page-shield/notifications/create.ts b/packages/b2c-cli/src/commands/ecdn/page-shield/notifications/create.ts new file mode 100644 index 00000000..10e7f465 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/page-shield/notifications/create.ts @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type PageShieldNotificationWebhookResponse = CdnZonesComponents['schemas']['PageShieldNotificationWebhookResponse']; +type PageShieldNotificationWebhookRequest = CdnZonesComponents['schemas']['PageShieldNotificationWebhookRequest']; + +/** + * Response type for the create command. + */ +interface CreateOutput { + webhook: PageShieldNotificationWebhookResponse; +} + +/** + * Command to create a Page Shield notification webhook. + */ +export default class EcdnPageShieldNotificationsCreate extends EcdnCommand { + static description = t( + 'commands.ecdn.page-shield.notifications.create.description', + 'Create a Page Shield notification webhook', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --webhook-url https://example.com/webhook', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --webhook-url https://example.com/webhook --secret my-secret --zones zone1,zone2', + ]; + + static flags = { + ...EcdnCommand.baseFlags, + 'webhook-url': Flags.string({ + description: t('flags.webhookUrl.description', 'Webhook URL for notifications'), + required: true, + }), + secret: Flags.string({ + description: t('flags.secret.description', 'Optional webhook secret'), + }), + zones: Flags.string({ + description: t('flags.zones.description', 'Comma-separated list of zone names to filter notifications'), + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.page-shield.notifications.create.creating', 'Creating Page Shield webhook...')); + } + + const body: PageShieldNotificationWebhookRequest = { + webhookUrl: this.flags['webhook-url'], + }; + + if (this.flags.secret) { + body.secret = this.flags.secret; + } + if (this.flags.zones) { + body.zones = this.flags.zones.split(',').map((z) => z.trim()); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.POST('/organizations/{organizationId}/page-shield/notifications', { + params: { + path: {organizationId}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.page-shield.notifications.create.error', 'Failed to create Page Shield webhook: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const webhook = data?.data; + if (!webhook) { + this.error(t('commands.ecdn.page-shield.notifications.create.noData', 'No webhook data returned from API')); + } + + const output: CreateOutput = {webhook}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 16; + + ui.div(''); + ui.div({text: t('commands.ecdn.page-shield.notifications.create.success', 'Page Shield webhook created!')}); + ui.div(''); + ui.div({text: 'Webhook ID:', width: labelWidth}, {text: webhook.id}); + ui.div({text: 'Name:', width: labelWidth}, {text: webhook.name}); + ui.div({text: 'URL:', width: labelWidth}, {text: webhook.webhookUrl}); + ui.div({text: 'Type:', width: labelWidth}, {text: webhook.type}); + + if (webhook.zones && webhook.zones.length > 0) { + ui.div({text: 'Zones:', width: labelWidth}, {text: webhook.zones.join(', ')}); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/page-shield/notifications/delete.ts b/packages/b2c-cli/src/commands/ecdn/page-shield/notifications/delete.ts new file mode 100644 index 00000000..34b6d77c --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/page-shield/notifications/delete.ts @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import {EcdnCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +/** + * Response type for the delete command. + */ +interface DeleteOutput { + deleted: boolean; + webhookId: string; +} + +/** + * Command to delete a Page Shield notification webhook. + */ +export default class EcdnPageShieldNotificationsDelete extends EcdnCommand { + static description = t( + 'commands.ecdn.page-shield.notifications.delete.description', + 'Delete a Page Shield notification webhook', + ); + + static enableJsonFlag = true; + + static examples = ['<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --webhook-id webhook_1234567890abcdef']; + + static flags = { + ...EcdnCommand.baseFlags, + 'webhook-id': Flags.string({ + description: t('flags.webhookId.description', 'Webhook ID to delete'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const webhookId = this.flags['webhook-id']; + + if (!this.jsonEnabled()) { + this.log( + t('commands.ecdn.page-shield.notifications.delete.deleting', 'Deleting Page Shield webhook {{id}}...', { + id: webhookId, + }), + ); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {error} = await client.DELETE('/organizations/{organizationId}/page-shield/notifications/{webhookId}', { + params: { + path: {organizationId, webhookId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.page-shield.notifications.delete.error', 'Failed to delete Page Shield webhook: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const output: DeleteOutput = {deleted: true, webhookId}; + + if (this.jsonEnabled()) { + return output; + } + + ux.stdout( + t('commands.ecdn.page-shield.notifications.delete.success', 'Page Shield webhook {{id}} deleted successfully.', { + id: webhookId, + }), + ); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/page-shield/notifications/list.ts b/packages/b2c-cli/src/commands/ecdn/page-shield/notifications/list.ts new file mode 100644 index 00000000..c3f22ce5 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/page-shield/notifications/list.ts @@ -0,0 +1,157 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type PageShieldNotificationWebhookResponse = CdnZonesComponents['schemas']['PageShieldNotificationWebhookResponse']; + +/** + * Response type for the list command. + */ +interface ListOutput { + webhooks: PageShieldNotificationWebhookResponse[]; + total: number; +} + +const COLUMNS: Record> = { + id: { + header: 'Webhook ID', + get: (r) => r.id || '-', + }, + name: { + header: 'Name', + get: (r) => r.name || '-', + }, + webhookUrl: { + header: 'URL', + get: (r) => r.webhookUrl || '-', + }, + type: { + header: 'Type', + get: (r) => r.type || '-', + }, + createdAt: { + header: 'Created', + get: (r) => r.createdAt || '-', + extended: true, + }, + zones: { + header: 'Zones', + get: (r) => r.zones?.join(', ') || '-', + extended: true, + }, +}; + +const DEFAULT_COLUMNS = ['id', 'name', 'webhookUrl', 'type']; + +const tableRenderer = new TableRenderer(COLUMNS); + +/** + * Command to list Page Shield notification webhooks. + */ +export default class EcdnPageShieldNotificationsList extends EcdnCommand { + static description = t( + 'commands.ecdn.page-shield.notifications.list.description', + 'List Page Shield notification webhooks', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --extended', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --json', + ]; + + static flags = { + ...EcdnCommand.baseFlags, + columns: Flags.string({ + char: 'c', + description: `Columns to display (comma-separated). Available: ${Object.keys(COLUMNS).join(', ')}`, + }), + extended: Flags.boolean({ + char: 'x', + description: t('flags.extended.description', 'Show all columns including extended fields'), + default: false, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.page-shield.notifications.list.fetching', 'Fetching Page Shield webhooks...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/page-shield/notifications', { + params: { + path: {organizationId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.page-shield.notifications.list.error', 'Failed to fetch Page Shield webhooks: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const webhooks = data?.data ?? []; + const output: ListOutput = { + webhooks, + total: webhooks.length, + }; + + if (this.jsonEnabled()) { + return output; + } + + if (webhooks.length === 0) { + this.log(t('commands.ecdn.page-shield.notifications.list.noWebhooks', 'No Page Shield webhooks found.')); + return output; + } + + this.log( + t('commands.ecdn.page-shield.notifications.list.count', 'Found {{count}} Page Shield webhook(s):', { + count: webhooks.length, + }), + ); + this.log(''); + + const columns = this.getSelectedColumns(); + tableRenderer.render(webhooks, columns); + + return output; + } + + private getSelectedColumns(): string[] { + const columnsFlag = this.flags.columns; + const extended = this.flags.extended; + + if (columnsFlag) { + const requested = columnsFlag.split(',').map((c) => c.trim()); + const valid = tableRenderer.validateColumnKeys(requested); + if (valid.length === 0) { + this.warn(`No valid columns specified. Available: ${tableRenderer.getColumnKeys().join(', ')}`); + return DEFAULT_COLUMNS; + } + return valid; + } + + if (extended) { + return tableRenderer.getColumnKeys(); + } + + return DEFAULT_COLUMNS; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/page-shield/policies/create.ts b/packages/b2c-cli/src/commands/ecdn/page-shield/policies/create.ts new file mode 100644 index 00000000..beb13569 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/page-shield/policies/create.ts @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type PageShieldPolicyResponse = CdnZonesComponents['schemas']['PageShieldPolicyResponse']; +type PageShieldPolicyRequest = CdnZonesComponents['schemas']['PageShieldPolicyRequest']; + +/** + * Response type for the create command. + */ +interface CreateOutput { + policy: PageShieldPolicyResponse; +} + +/** + * Command to create a Page Shield policy for a zone. + */ +export default class EcdnPageShieldPoliciesCreate extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.page-shield.policies.create.description', + 'Create a Page Shield policy for a zone', + ); + + static enableJsonFlag = true; + + static examples = [ + `<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --action allow --value script-src --expression 'http.request.uri.path contains "/trusted/"'`, + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --action log --value script-src --description "Log untrusted scripts"', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + action: Flags.string({ + description: t('flags.action.description', 'Action for the policy'), + options: ['allow', 'log'], + required: true, + }), + value: Flags.string({ + description: t('flags.value.description', 'Policy value (e.g., script-src)'), + required: true, + }), + expression: Flags.string({ + description: t('flags.expression.description', 'Policy expression'), + }), + description: Flags.string({ + description: t('flags.description.description', 'Policy description'), + }), + enabled: Flags.boolean({ + description: t('flags.enabled.description', 'Enable the policy'), + default: true, + allowNo: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.page-shield.policies.create.creating', 'Creating Page Shield policy...')); + } + + const body: PageShieldPolicyRequest = { + action: this.flags.action as PageShieldPolicyRequest['action'], + value: this.flags.value, + enabled: this.flags.enabled, + }; + + if (this.flags.expression) { + body.expression = this.flags.expression; + } + if (this.flags.description) { + body.description = this.flags.description; + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.POST('/organizations/{organizationId}/zones/{zoneId}/page-shield/policies', { + params: { + path: {organizationId, zoneId}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.page-shield.policies.create.error', 'Failed to create Page Shield policy: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const policy = data?.data; + if (!policy) { + this.error(t('commands.ecdn.page-shield.policies.create.noData', 'No policy data returned from API')); + } + + const output: CreateOutput = {policy}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 16; + + ui.div(''); + ui.div({text: t('commands.ecdn.page-shield.policies.create.success', 'Page Shield policy created!')}); + ui.div(''); + ui.div({text: 'Policy ID:', width: labelWidth}, {text: policy.id || '-'}); + ui.div({text: 'Action:', width: labelWidth}, {text: policy.action || '-'}); + ui.div({text: 'Enabled:', width: labelWidth}, {text: policy.enabled ? 'yes' : 'no'}); + ui.div({text: 'Value:', width: labelWidth}, {text: policy.value || '-'}); + + if (policy.description) { + ui.div({text: 'Description:', width: labelWidth}, {text: policy.description}); + } + if (policy.expression) { + ui.div({text: 'Expression:', width: labelWidth}, {text: policy.expression}); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/page-shield/policies/delete.ts b/packages/b2c-cli/src/commands/ecdn/page-shield/policies/delete.ts new file mode 100644 index 00000000..128be7e4 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/page-shield/policies/delete.ts @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +/** + * Response type for the delete command. + */ +interface DeleteOutput { + deleted: boolean; + policyId: string; +} + +/** + * Command to delete a Page Shield policy for a zone. + */ +export default class EcdnPageShieldPoliciesDelete extends EcdnZoneCommand { + static description = t('commands.ecdn.page-shield.policies.delete.description', 'Delete a Page Shield policy'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --policy-id policy_1234567890abcdef', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'policy-id': Flags.string({ + description: t('flags.policyId.description', 'Page Shield policy ID to delete'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const policyId = this.flags['policy-id']; + + if (!this.jsonEnabled()) { + this.log( + t('commands.ecdn.page-shield.policies.delete.deleting', 'Deleting Page Shield policy {{id}}...', { + id: policyId, + }), + ); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {error} = await client.DELETE( + '/organizations/{organizationId}/zones/{zoneId}/page-shield/policies/{policyId}', + { + params: { + path: {organizationId, zoneId, policyId}, + }, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.page-shield.policies.delete.error', 'Failed to delete Page Shield policy: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const output: DeleteOutput = {deleted: true, policyId}; + + if (this.jsonEnabled()) { + return output; + } + + ux.stdout( + t('commands.ecdn.page-shield.policies.delete.success', 'Page Shield policy {{id}} deleted successfully.', { + id: policyId, + }), + ); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/page-shield/policies/get.ts b/packages/b2c-cli/src/commands/ecdn/page-shield/policies/get.ts new file mode 100644 index 00000000..0144185a --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/page-shield/policies/get.ts @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type PageShieldPolicyResponse = CdnZonesComponents['schemas']['PageShieldPolicyResponse']; + +/** + * Response type for the get command. + */ +interface GetOutput { + policy: PageShieldPolicyResponse; +} + +/** + * Command to get a Page Shield policy for a zone. + */ +export default class EcdnPageShieldPoliciesGet extends EcdnZoneCommand { + static description = t('commands.ecdn.page-shield.policies.get.description', 'Get a Page Shield policy'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --policy-id policy_1234567890abcdef', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --policy-id policy_1234567890abcdef --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'policy-id': Flags.string({ + description: t('flags.policyId.description', 'Page Shield policy ID'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const policyId = this.flags['policy-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.page-shield.policies.get.fetching', 'Fetching Page Shield policy...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET( + '/organizations/{organizationId}/zones/{zoneId}/page-shield/policies/{policyId}', + { + params: { + path: {organizationId, zoneId, policyId}, + }, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.page-shield.policies.get.error', 'Failed to fetch Page Shield policy: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const policy = data?.data; + if (!policy) { + this.error(t('commands.ecdn.page-shield.policies.get.noData', 'No policy data returned from API')); + } + + const output: GetOutput = {policy}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 16; + + ui.div(''); + ui.div({text: 'Page Shield Policy:', padding: [0, 0, 1, 0]}); + ui.div({text: 'Policy ID:', width: labelWidth}, {text: policy.id || '-'}); + ui.div({text: 'Action:', width: labelWidth}, {text: policy.action || '-'}); + ui.div({text: 'Enabled:', width: labelWidth}, {text: policy.enabled ? 'yes' : 'no'}); + ui.div({text: 'Value:', width: labelWidth}, {text: policy.value || '-'}); + + if (policy.description) { + ui.div({text: 'Description:', width: labelWidth}, {text: policy.description}); + } + if (policy.expression) { + ui.div({text: 'Expression:', width: labelWidth}, {text: policy.expression}); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/page-shield/policies/list.ts b/packages/b2c-cli/src/commands/ecdn/page-shield/policies/list.ts new file mode 100644 index 00000000..fa1ae47b --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/page-shield/policies/list.ts @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type PageShieldPolicyResponse = CdnZonesComponents['schemas']['PageShieldPolicyResponse']; + +/** + * Response type for the list command. + */ +interface ListOutput { + policies: PageShieldPolicyResponse[]; + total: number; +} + +const COLUMNS: Record> = { + id: { + header: 'Policy ID', + get: (r) => r.id || '-', + }, + action: { + header: 'Action', + get: (r) => r.action || '-', + }, + enabled: { + header: 'Enabled', + get: (r) => (r.enabled ? 'yes' : 'no'), + }, + description: { + header: 'Description', + get: (r) => r.description || '-', + }, + value: { + header: 'Value', + get: (r) => r.value || '-', + extended: true, + }, + expression: { + header: 'Expression', + get: (r) => r.expression || '-', + extended: true, + }, +}; + +const DEFAULT_COLUMNS = ['id', 'action', 'enabled', 'description']; + +const tableRenderer = new TableRenderer(COLUMNS); + +/** + * Command to list Page Shield policies for a zone. + */ +export default class EcdnPageShieldPoliciesList extends EcdnZoneCommand { + static description = t('commands.ecdn.page-shield.policies.list.description', 'List Page Shield policies for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --extended', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + columns: Flags.string({ + char: 'c', + description: `Columns to display (comma-separated). Available: ${Object.keys(COLUMNS).join(', ')}`, + }), + extended: Flags.boolean({ + char: 'x', + description: t('flags.extended.description', 'Show all columns including extended fields'), + default: false, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.page-shield.policies.list.fetching', 'Fetching Page Shield policies...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/page-shield/policies', { + params: { + path: {organizationId, zoneId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.page-shield.policies.list.error', 'Failed to fetch Page Shield policies: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const policies = data?.data ?? []; + const output: ListOutput = { + policies, + total: policies.length, + }; + + if (this.jsonEnabled()) { + return output; + } + + if (policies.length === 0) { + this.log(t('commands.ecdn.page-shield.policies.list.noPolicies', 'No Page Shield policies found.')); + return output; + } + + this.log( + t('commands.ecdn.page-shield.policies.list.count', 'Found {{count}} Page Shield policy(ies):', { + count: policies.length, + }), + ); + this.log(''); + + const columns = this.getSelectedColumns(); + tableRenderer.render(policies, columns); + + return output; + } + + private getSelectedColumns(): string[] { + const columnsFlag = this.flags.columns; + const extended = this.flags.extended; + + if (columnsFlag) { + const requested = columnsFlag.split(',').map((c) => c.trim()); + const valid = tableRenderer.validateColumnKeys(requested); + if (valid.length === 0) { + this.warn(`No valid columns specified. Available: ${tableRenderer.getColumnKeys().join(', ')}`); + return DEFAULT_COLUMNS; + } + return valid; + } + + if (extended) { + return tableRenderer.getColumnKeys(); + } + + return DEFAULT_COLUMNS; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/page-shield/policies/update.ts b/packages/b2c-cli/src/commands/ecdn/page-shield/policies/update.ts new file mode 100644 index 00000000..a90f1dc2 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/page-shield/policies/update.ts @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type PageShieldPolicyResponse = CdnZonesComponents['schemas']['PageShieldPolicyResponse']; +type PageShieldPolicyRequest = CdnZonesComponents['schemas']['PageShieldPolicyRequest']; + +/** + * Response type for the update command. + */ +interface UpdateOutput { + policy: PageShieldPolicyResponse; +} + +/** + * Command to update a Page Shield policy for a zone. + */ +export default class EcdnPageShieldPoliciesUpdate extends EcdnZoneCommand { + static description = t('commands.ecdn.page-shield.policies.update.description', 'Update a Page Shield policy'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --policy-id policy_123 --enabled', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --policy-id policy_123 --action log', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --policy-id policy_123 --no-enabled', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'policy-id': Flags.string({ + description: t('flags.policyId.description', 'Page Shield policy ID to update'), + required: true, + }), + action: Flags.string({ + description: t('flags.action.description', 'Action for the policy'), + options: ['allow', 'log'], + }), + value: Flags.string({ + description: t('flags.value.description', 'Policy value (e.g., script-src)'), + }), + expression: Flags.string({ + description: t('flags.expression.description', 'Policy expression'), + }), + description: Flags.string({ + description: t('flags.description.description', 'Policy description'), + }), + enabled: Flags.boolean({ + description: t('flags.enabled.description', 'Enable or disable the policy'), + allowNo: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const policyId = this.flags['policy-id']; + + if (!this.jsonEnabled()) { + this.log( + t('commands.ecdn.page-shield.policies.update.updating', 'Updating Page Shield policy {{id}}...', { + id: policyId, + }), + ); + } + + const body: PageShieldPolicyRequest = {}; + + if (this.flags.action) { + body.action = this.flags.action as PageShieldPolicyRequest['action']; + } + if (this.flags.value) { + body.value = this.flags.value; + } + if (this.flags.expression !== undefined) { + body.expression = this.flags.expression; + } + if (this.flags.description !== undefined) { + body.description = this.flags.description; + } + if (this.flags.enabled !== undefined) { + body.enabled = this.flags.enabled; + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PUT( + '/organizations/{organizationId}/zones/{zoneId}/page-shield/policies/{policyId}', + { + params: { + path: {organizationId, zoneId, policyId}, + }, + body, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.page-shield.policies.update.error', 'Failed to update Page Shield policy: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const policy = data?.data; + if (!policy) { + this.error(t('commands.ecdn.page-shield.policies.update.noData', 'No policy data returned from API')); + } + + const output: UpdateOutput = {policy}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 16; + + ui.div(''); + ui.div({text: t('commands.ecdn.page-shield.policies.update.success', 'Page Shield policy updated!')}); + ui.div(''); + ui.div({text: 'Policy ID:', width: labelWidth}, {text: policy.id || '-'}); + ui.div({text: 'Action:', width: labelWidth}, {text: policy.action || '-'}); + ui.div({text: 'Enabled:', width: labelWidth}, {text: policy.enabled ? 'yes' : 'no'}); + ui.div({text: 'Value:', width: labelWidth}, {text: policy.value || '-'}); + + if (policy.description) { + ui.div({text: 'Description:', width: labelWidth}, {text: policy.description}); + } + if (policy.expression) { + ui.div({text: 'Expression:', width: labelWidth}, {text: policy.expression}); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/page-shield/scripts/get.ts b/packages/b2c-cli/src/commands/ecdn/page-shield/scripts/get.ts new file mode 100644 index 00000000..b9db6035 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/page-shield/scripts/get.ts @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type PageShieldScriptResponse = CdnZonesComponents['schemas']['PageShieldScriptResponse']; + +/** + * Response type for the get command. + */ +interface GetOutput { + script: PageShieldScriptResponse; +} + +/** + * Command to get details of a Page Shield script. + */ +export default class EcdnPageShieldScriptsGet extends EcdnZoneCommand { + static description = t('commands.ecdn.page-shield.scripts.get.description', 'Get details of a Page Shield script'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --script-id 12345678901234asdfasfasdf', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --script-id 12345678901234asdfasfasdf --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'script-id': Flags.string({ + description: t('flags.scriptId.description', 'Page Shield script ID'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const scriptId = this.flags['script-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.page-shield.scripts.get.fetching', 'Fetching Page Shield script...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET( + '/organizations/{organizationId}/zones/{zoneId}/page-shield/scripts/{scriptId}', + { + params: { + path: {organizationId, zoneId, scriptId}, + }, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.page-shield.scripts.get.error', 'Failed to fetch Page Shield script: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const script = data?.data; + if (!script) { + this.error(t('commands.ecdn.page-shield.scripts.get.noData', 'No script data returned from API')); + } + + const output: GetOutput = {script}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 22; + + ui.div(''); + ui.div({text: 'Page Shield Script:', padding: [0, 0, 1, 0]}); + ui.div({text: 'Script ID:', width: labelWidth}, {text: script.id || '-'}); + ui.div({text: 'URL:', width: labelWidth}, {text: script.url || '-'}); + ui.div({text: 'Host:', width: labelWidth}, {text: script.host || '-'}); + ui.div({text: 'Status:', width: labelWidth}, {text: script.status || '-'}); + + if (script.firstSeenAt) { + ui.div({text: 'First Seen:', width: labelWidth}, {text: script.firstSeenAt}); + } + if (script.lastSeenAt) { + ui.div({text: 'Last Seen:', width: labelWidth}, {text: script.lastSeenAt}); + } + if (script.hash) { + ui.div({text: 'Hash:', width: labelWidth}, {text: script.hash}); + } + + ui.div(''); + ui.div({text: 'Security Scores:', padding: [0, 0, 0, 0]}); + ui.div( + {text: 'Malware Score:', width: labelWidth}, + {text: script.malwareScore === undefined ? '-' : String(script.malwareScore)}, + ); + ui.div( + {text: 'MageCart Score:', width: labelWidth}, + {text: script.mageCartScore === undefined ? '-' : String(script.mageCartScore)}, + ); + ui.div( + {text: 'Obfuscation Score:', width: labelWidth}, + {text: script.obfuscationScore === undefined ? '-' : String(script.obfuscationScore)}, + ); + ui.div( + {text: 'Dataflow Score:', width: labelWidth}, + {text: script.dataflowScore === undefined ? '-' : String(script.dataflowScore)}, + ); + ui.div( + {text: 'Crypto Mining Score:', width: labelWidth}, + {text: script.cryptoMiningScore === undefined ? '-' : String(script.cryptoMiningScore)}, + ); + ui.div( + {text: 'JS Integrity Score:', width: labelWidth}, + {text: script.jsIntegrityScore === undefined ? '-' : String(script.jsIntegrityScore)}, + ); + + if (script.domainReportedMalicious) { + ui.div({text: 'Domain Malicious:', width: labelWidth}, {text: 'yes'}); + } + if (script.urlReportedMalicious) { + ui.div({text: 'URL Malicious:', width: labelWidth}, {text: 'yes'}); + } + + if (script.pageUrls && script.pageUrls.length > 0) { + ui.div(''); + ui.div({text: 'Page URLs:', padding: [0, 0, 0, 0]}); + for (const pageUrl of script.pageUrls.slice(0, 5)) { + ui.div({text: ` ${pageUrl}`}); + } + if (script.pageUrls.length > 5) { + ui.div({text: ` ... and ${script.pageUrls.length - 5} more`}); + } + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/page-shield/scripts/list.ts b/packages/b2c-cli/src/commands/ecdn/page-shield/scripts/list.ts new file mode 100644 index 00000000..067bb86b --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/page-shield/scripts/list.ts @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type PageShieldScriptResponse = CdnZonesComponents['schemas']['PageShieldScriptResponse']; + +/** + * Response type for the list command. + */ +interface ListOutput { + scripts: PageShieldScriptResponse[]; + total: number; +} + +const COLUMNS: Record> = { + id: { + header: 'Script ID', + get: (r) => r.id || '-', + }, + url: { + header: 'URL', + get: (r) => r.url || '-', + }, + host: { + header: 'Host', + get: (r) => r.host || '-', + }, + status: { + header: 'Status', + get: (r) => r.status || '-', + }, + malwareScore: { + header: 'Malware', + get: (r) => (r.malwareScore === undefined ? '-' : String(r.malwareScore)), + extended: true, + }, + mageCartScore: { + header: 'MageCart', + get: (r) => (r.mageCartScore === undefined ? '-' : String(r.mageCartScore)), + extended: true, + }, + lastSeenAt: { + header: 'Last Seen', + get: (r) => r.lastSeenAt || '-', + extended: true, + }, +}; + +const DEFAULT_COLUMNS = ['id', 'url', 'host', 'status']; + +const tableRenderer = new TableRenderer(COLUMNS); + +/** + * Command to list Page Shield scripts detected for a zone. + */ +export default class EcdnPageShieldScriptsList extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.page-shield.scripts.list.description', + 'List Page Shield scripts detected for a zone', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --extended', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + columns: Flags.string({ + char: 'c', + description: `Columns to display (comma-separated). Available: ${Object.keys(COLUMNS).join(', ')}`, + }), + extended: Flags.boolean({ + char: 'x', + description: t('flags.extended.description', 'Show all columns including extended fields'), + default: false, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.page-shield.scripts.list.fetching', 'Fetching Page Shield scripts...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/page-shield/scripts', { + params: { + path: {organizationId, zoneId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.page-shield.scripts.list.error', 'Failed to fetch Page Shield scripts: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const scripts = data?.data ?? []; + const output: ListOutput = { + scripts, + total: scripts.length, + }; + + if (this.jsonEnabled()) { + return output; + } + + if (scripts.length === 0) { + this.log(t('commands.ecdn.page-shield.scripts.list.noScripts', 'No Page Shield scripts found.')); + return output; + } + + this.log( + t('commands.ecdn.page-shield.scripts.list.count', 'Found {{count}} Page Shield script(s):', { + count: scripts.length, + }), + ); + this.log(''); + + const columns = this.getSelectedColumns(); + tableRenderer.render(scripts, columns); + + return output; + } + + private getSelectedColumns(): string[] { + const columnsFlag = this.flags.columns; + const extended = this.flags.extended; + + if (columnsFlag) { + const requested = columnsFlag.split(',').map((c) => c.trim()); + const valid = tableRenderer.validateColumnKeys(requested); + if (valid.length === 0) { + this.warn(`No valid columns specified. Available: ${tableRenderer.getColumnKeys().join(', ')}`); + return DEFAULT_COLUMNS; + } + return valid; + } + + if (extended) { + return tableRenderer.getColumnKeys(); + } + + return DEFAULT_COLUMNS; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/security/get.ts b/packages/b2c-cli/src/commands/ecdn/security/get.ts new file mode 100644 index 00000000..7d33b1ea --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/security/get.ts @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type SecuritySetting = CdnZonesComponents['schemas']['SecuritySetting']; + +/** + * Response type for the get command. + */ +interface GetOutput { + settings: SecuritySetting; +} + +/** + * Command to get security settings for a zone. + */ +export default class EcdnSecurityGet extends EcdnZoneCommand { + static description = t('commands.ecdn.security.get.description', 'Get security settings for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.security.get.fetching', 'Fetching security settings...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/security-settings', { + params: { + path: {organizationId, zoneId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.security.get.error', 'Failed to fetch security settings: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const settings = data?.data; + if (!settings) { + this.error(t('commands.ecdn.security.get.noData', 'No security settings returned from API')); + } + + const output: GetOutput = {settings}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 20; + + ui.div(''); + ui.div({text: 'Security Settings:', padding: [0, 0, 1, 0]}); + ui.div({text: 'Security Level:', width: labelWidth}, {text: settings.securityLevel ?? '-'}); + ui.div({text: 'Always Use HTTPS:', width: labelWidth}, {text: settings.alwaysUseHttps ? 'enabled' : 'disabled'}); + ui.div({text: 'TLS 1.3:', width: labelWidth}, {text: settings.tls13Enabled ? 'enabled' : 'disabled'}); + ui.div({text: 'WAF (OWASP):', width: labelWidth}, {text: settings.wafEnabled ? 'enabled' : 'disabled'}); + + if (settings.hsts) { + ui.div(''); + ui.div({text: 'HSTS Settings:', padding: [0, 0, 0, 2]}); + ui.div( + {text: 'Enabled:', width: labelWidth, padding: [0, 0, 0, 2]}, + {text: settings.hsts.enabled ? 'yes' : 'no'}, + ); + ui.div( + {text: 'Include Subdomains:', width: labelWidth, padding: [0, 0, 0, 2]}, + {text: settings.hsts.includeSubdomains ? 'yes' : 'no'}, + ); + ui.div( + {text: 'Max Age:', width: labelWidth, padding: [0, 0, 0, 2]}, + {text: `${settings.hsts.maxAge ?? '-'} seconds`}, + ); + ui.div( + {text: 'Preload:', width: labelWidth, padding: [0, 0, 0, 2]}, + {text: settings.hsts.preload ? 'yes' : 'no'}, + ); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/security/update.ts b/packages/b2c-cli/src/commands/ecdn/security/update.ts new file mode 100644 index 00000000..36c161fe --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/security/update.ts @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type SecuritySetting = CdnZonesComponents['schemas']['SecuritySetting']; + +/** + * Response type for the update command. + */ +interface UpdateOutput { + settings: SecuritySetting; +} + +/** + * Command to update security settings for a zone. + */ +export default class EcdnSecurityUpdate extends EcdnZoneCommand { + static description = t('commands.ecdn.security.update.description', 'Update security settings for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --security-level medium', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --always-use-https', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --tls13 --waf', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'security-level': Flags.string({ + description: t('flags.securityLevel.description', 'Security level for the zone'), + options: ['off', 'essentially_off', 'low', 'medium', 'high', 'under_attack'], + }), + 'always-use-https': Flags.boolean({ + description: t('flags.alwaysUseHttps.description', 'Redirect all HTTP requests to HTTPS'), + allowNo: true, + }), + tls13: Flags.boolean({ + description: t('flags.tls13.description', 'Enable TLS 1.3'), + allowNo: true, + }), + waf: Flags.boolean({ + description: t('flags.waf.description', 'Enable WAF (OWASP) protection'), + allowNo: true, + }), + 'hsts-enabled': Flags.boolean({ + description: t('flags.hstsEnabled.description', 'Enable HSTS'), + allowNo: true, + }), + 'hsts-include-subdomains': Flags.boolean({ + description: t('flags.hstsIncludeSubdomains.description', 'Include subdomains in HSTS'), + allowNo: true, + }), + 'hsts-max-age': Flags.integer({ + description: t('flags.hstsMaxAge.description', 'HSTS max age in seconds'), + }), + 'hsts-preload': Flags.boolean({ + description: t('flags.hstsPreload.description', 'Enable HSTS preload'), + allowNo: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + // Build the request body from flags + const body: SecuritySetting = { + alwaysUseHttps: this.flags['always-use-https'] ?? false, + }; + + if (this.flags['security-level']) { + body.securityLevel = this.flags['security-level'] as SecuritySetting['securityLevel']; + } + + if (this.flags.tls13 !== undefined) { + body.tls13Enabled = this.flags.tls13; + } + + if (this.flags.waf !== undefined) { + body.wafEnabled = this.flags.waf; + } + + // Build HSTS settings if any HSTS flags are provided + const hasHstsFlags = + this.flags['hsts-enabled'] !== undefined || + this.flags['hsts-include-subdomains'] !== undefined || + this.flags['hsts-max-age'] !== undefined || + this.flags['hsts-preload'] !== undefined; + + if (hasHstsFlags) { + body.hsts = {}; + if (this.flags['hsts-enabled'] !== undefined) { + body.hsts.enabled = this.flags['hsts-enabled']; + } + if (this.flags['hsts-include-subdomains'] !== undefined) { + body.hsts.includeSubdomains = this.flags['hsts-include-subdomains']; + } + if (this.flags['hsts-max-age'] !== undefined) { + body.hsts.maxAge = this.flags['hsts-max-age']; + } + if (this.flags['hsts-preload'] !== undefined) { + body.hsts.preload = this.flags['hsts-preload']; + } + } + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.security.update.updating', 'Updating security settings...')); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PATCH('/organizations/{organizationId}/zones/{zoneId}/security-settings', { + params: { + path: {organizationId, zoneId}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.security.update.error', 'Failed to update security settings: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const settings = data?.data; + if (!settings) { + this.error(t('commands.ecdn.security.update.noData', 'No security settings returned from API')); + } + + const output: UpdateOutput = {settings}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 20; + + ui.div(''); + ui.div({text: t('commands.ecdn.security.update.success', 'Security settings updated successfully!')}); + ui.div(''); + ui.div({text: 'Security Level:', width: labelWidth}, {text: settings.securityLevel ?? '-'}); + ui.div({text: 'Always Use HTTPS:', width: labelWidth}, {text: settings.alwaysUseHttps ? 'enabled' : 'disabled'}); + ui.div({text: 'TLS 1.3:', width: labelWidth}, {text: settings.tls13Enabled ? 'enabled' : 'disabled'}); + ui.div({text: 'WAF (OWASP):', width: labelWidth}, {text: settings.wafEnabled ? 'enabled' : 'disabled'}); + + if (settings.hsts) { + ui.div(''); + ui.div({text: 'HSTS Settings:', padding: [0, 0, 0, 2]}); + ui.div( + {text: 'Enabled:', width: labelWidth, padding: [0, 0, 0, 2]}, + {text: settings.hsts.enabled ? 'yes' : 'no'}, + ); + ui.div( + {text: 'Include Subdomains:', width: labelWidth, padding: [0, 0, 0, 2]}, + {text: settings.hsts.includeSubdomains ? 'yes' : 'no'}, + ); + ui.div( + {text: 'Max Age:', width: labelWidth, padding: [0, 0, 0, 2]}, + {text: `${settings.hsts.maxAge ?? '-'} seconds`}, + ); + ui.div( + {text: 'Preload:', width: labelWidth, padding: [0, 0, 0, 2]}, + {text: settings.hsts.preload ? 'yes' : 'no'}, + ); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/speed/get.ts b/packages/b2c-cli/src/commands/ecdn/speed/get.ts new file mode 100644 index 00000000..54e37570 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/speed/get.ts @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type SpeedSetting = CdnZonesComponents['schemas']['SpeedSetting']; + +/** + * Response type for the get command. + */ +interface GetOutput { + settings: SpeedSetting; +} + +/** + * Command to get speed settings for a zone. + */ +export default class EcdnSpeedGet extends EcdnZoneCommand { + static description = t('commands.ecdn.speed.get.description', 'Get speed/performance settings for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.speed.get.fetching', 'Fetching speed settings...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/speed-settings', { + params: { + path: {organizationId, zoneId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.speed.get.error', 'Failed to fetch speed settings: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const settings = data?.data; + if (!settings) { + this.error(t('commands.ecdn.speed.get.noData', 'No speed settings returned from API')); + } + + const output: GetOutput = {settings}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 22; + + ui.div(''); + ui.div({text: 'Speed Settings:', padding: [0, 0, 1, 0]}); + ui.div({text: 'Brotli Compression:', width: labelWidth}, {text: settings.brotliCompression}); + ui.div({text: 'HTTP/2 Prioritization:', width: labelWidth}, {text: settings.http2Prioritization}); + ui.div({text: 'HTTP/2 to Origin:', width: labelWidth}, {text: settings.http2ToOrigin}); + ui.div({text: 'HTTP/3:', width: labelWidth}, {text: settings.http3}); + ui.div({text: 'Early Hints:', width: labelWidth}, {text: settings.earlyHints}); + ui.div({text: 'WebP:', width: labelWidth}, {text: settings.webp}); + ui.div({text: 'Polish:', width: labelWidth}, {text: settings.polish}); + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/speed/update.ts b/packages/b2c-cli/src/commands/ecdn/speed/update.ts new file mode 100644 index 00000000..77135cb3 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/speed/update.ts @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type SpeedSetting = CdnZonesComponents['schemas']['SpeedSetting']; + +/** + * Response type for the update command. + */ +interface UpdateOutput { + settings: SpeedSetting; +} + +/** + * Command to update speed settings for a zone. + */ +export default class EcdnSpeedUpdate extends EcdnZoneCommand { + static description = t('commands.ecdn.speed.update.description', 'Update speed/performance settings for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --brotli on', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --http3 on --early-hints on', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --polish lossy --webp on', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + brotli: Flags.string({ + description: t('flags.brotli.description', 'Brotli compression (on/off)'), + options: ['on', 'off'], + }), + 'http2-prioritization': Flags.string({ + description: t('flags.http2Prioritization.description', 'HTTP/2 prioritization (on/off)'), + options: ['on', 'off'], + }), + 'http2-to-origin': Flags.string({ + description: t('flags.http2ToOrigin.description', 'HTTP/2 to origin (on/off)'), + options: ['on', 'off'], + }), + http3: Flags.string({ + description: t('flags.http3.description', 'HTTP/3 (on/off)'), + options: ['on', 'off'], + }), + 'early-hints': Flags.string({ + description: t('flags.earlyHints.description', 'Early hints (on/off)'), + options: ['on', 'off'], + }), + webp: Flags.string({ + description: t('flags.webp.description', 'WebP image format support (on/off)'), + options: ['on', 'off'], + }), + polish: Flags.string({ + description: t('flags.polish.description', 'Image polish level (off/lossless/lossy)'), + options: ['off', 'lossless', 'lossy'], + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + // Build the request body from flags - all fields are required + const body: SpeedSetting = { + brotliCompression: (this.flags.brotli as 'off' | 'on') ?? 'off', + http2Prioritization: (this.flags['http2-prioritization'] as 'off' | 'on') ?? 'off', + http2ToOrigin: (this.flags['http2-to-origin'] as 'off' | 'on') ?? 'off', + http3: (this.flags.http3 as 'off' | 'on') ?? 'off', + earlyHints: (this.flags['early-hints'] as 'off' | 'on') ?? 'off', + webp: (this.flags.webp as 'off' | 'on') ?? 'off', + polish: (this.flags.polish as 'lossless' | 'lossy' | 'off') ?? 'off', + }; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.speed.update.updating', 'Updating speed settings...')); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PATCH('/organizations/{organizationId}/zones/{zoneId}/speed-settings', { + params: { + path: {organizationId, zoneId}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.speed.update.error', 'Failed to update speed settings: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const settings = data?.data; + if (!settings) { + this.error(t('commands.ecdn.speed.update.noData', 'No speed settings returned from API')); + } + + const output: UpdateOutput = {settings}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 22; + + ui.div(''); + ui.div({text: t('commands.ecdn.speed.update.success', 'Speed settings updated successfully!')}); + ui.div(''); + ui.div({text: 'Brotli Compression:', width: labelWidth}, {text: settings.brotliCompression}); + ui.div({text: 'HTTP/2 Prioritization:', width: labelWidth}, {text: settings.http2Prioritization}); + ui.div({text: 'HTTP/2 to Origin:', width: labelWidth}, {text: settings.http2ToOrigin}); + ui.div({text: 'HTTP/3:', width: labelWidth}, {text: settings.http3}); + ui.div({text: 'Early Hints:', width: labelWidth}, {text: settings.earlyHints}); + ui.div({text: 'WebP:', width: labelWidth}, {text: settings.webp}); + ui.div({text: 'Polish:', width: labelWidth}, {text: settings.polish}); + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/waf/groups/list.ts b/packages/b2c-cli/src/commands/ecdn/waf/groups/list.ts new file mode 100644 index 00000000..ccb8f31b --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/waf/groups/list.ts @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type WafGroup = CdnZonesComponents['schemas']['WafGroup']; + +/** + * Response type for the list command. + */ +interface ListOutput { + groups: WafGroup[]; + total: number; +} + +const COLUMNS: Record> = { + groupId: { + header: 'Group ID', + get: (g) => g.groupId || '-', + }, + description: { + header: 'Description', + get: (g) => g.description || '-', + }, + mode: { + header: 'Mode', + get: (g) => g.mode || '-', + }, + action: { + header: 'Action', + get: (g) => g.action || '-', + }, +}; + +const DEFAULT_COLUMNS = ['groupId', 'description', 'mode', 'action']; + +const tableRenderer = new TableRenderer(COLUMNS); + +/** + * Command to list WAF groups for a zone. + * Note: This is for WAF v1. For zones created after 24.5, use waf rulesets commands. + */ +export default class EcdnWafGroupsList extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.waf.groups.list.description', + 'List WAF v1 groups for a zone (not applicable for WAFv2 zones)', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + columns: Flags.string({ + char: 'c', + description: `Columns to display (comma-separated). Available: ${Object.keys(COLUMNS).join(', ')}`, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.waf.groups.list.fetching', 'Fetching WAF groups...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/waf/groups', { + params: { + path: {organizationId, zoneId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.waf.groups.list.error', 'Failed to fetch WAF groups: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const groups = data?.data ?? []; + const output: ListOutput = { + groups, + total: groups.length, + }; + + if (this.jsonEnabled()) { + return output; + } + + if (groups.length === 0) { + this.log(t('commands.ecdn.waf.groups.list.noGroups', 'No WAF groups found.')); + return output; + } + + this.log( + t('commands.ecdn.waf.groups.list.count', 'Found {{count}} WAF group(s):', { + count: groups.length, + }), + ); + this.log(''); + + const columns = this.flags.columns + ? tableRenderer.validateColumnKeys(this.flags.columns.split(',').map((c) => c.trim())) + : DEFAULT_COLUMNS; + tableRenderer.render(groups, columns.length > 0 ? columns : DEFAULT_COLUMNS); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/waf/groups/update.ts b/packages/b2c-cli/src/commands/ecdn/waf/groups/update.ts new file mode 100644 index 00000000..d6496003 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/waf/groups/update.ts @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type WafGroup = CdnZonesComponents['schemas']['WafGroup']; + +/** + * Response type for the update command. + */ +interface UpdateOutput { + group: WafGroup; +} + +/** + * Command to update a WAF group for a zone. + * Note: This is for WAF v1. For zones created after 24.5, use waf rulesets commands. + */ +export default class EcdnWafGroupsUpdate extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.waf.groups.update.description', + 'Update a WAF v1 group for a zone (not applicable for WAFv2 zones)', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --group-id abc123 --mode on', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --group-id abc123 --action block', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'group-id': Flags.string({ + description: t('flags.groupId.description', 'WAF group ID to update'), + required: true, + }), + mode: Flags.string({ + description: t('flags.mode.description', 'Mode for the WAF group (on/off)'), + options: ['on', 'off'], + required: true, + }), + action: Flags.string({ + description: t('flags.action.description', 'Action for the WAF group'), + options: ['block', 'challenge', 'monitor', 'default'], + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const groupId = this.flags['group-id']; + const mode = this.flags.mode as 'off' | 'on'; + const action = this.flags.action as WafGroup['action']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.waf.groups.update.updating', 'Updating WAF group {{id}}...', {id: groupId})); + } + + const body: WafGroup = {mode}; + if (action) { + body.action = action; + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PUT('/organizations/{organizationId}/zones/{zoneId}/waf/groups/{groupId}', { + params: { + path: {organizationId, zoneId, groupId}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.waf.groups.update.error', 'Failed to update WAF group: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const group = data?.data; + if (!group) { + this.error(t('commands.ecdn.waf.groups.update.noData', 'No WAF group data returned from API')); + } + + const output: UpdateOutput = {group}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 14; + + ui.div(''); + ui.div({text: t('commands.ecdn.waf.groups.update.success', 'WAF group updated successfully!')}); + ui.div(''); + ui.div({text: 'Group ID:', width: labelWidth}, {text: group.groupId || '-'}); + ui.div({text: 'Description:', width: labelWidth}, {text: group.description || '-'}); + ui.div({text: 'Mode:', width: labelWidth}, {text: group.mode}); + ui.div({text: 'Action:', width: labelWidth}, {text: group.action || '-'}); + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/waf/managed-rules/list.ts b/packages/b2c-cli/src/commands/ecdn/waf/managed-rules/list.ts new file mode 100644 index 00000000..0740ba12 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/waf/managed-rules/list.ts @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type WAFManagedRule = CdnZonesComponents['schemas']['WAFManagedRule']; + +/** + * Response type for the list command. + */ +interface ListOutput { + rules: WAFManagedRule[]; + total: number; +} + +const COLUMNS: Record> = { + ruleId: { + header: 'Rule ID', + get: (r) => r.ruleId || '-', + }, + description: { + header: 'Description', + get: (r) => r.description || '-', + }, + action: { + header: 'Action', + get: (r) => r.action || '-', + }, + enabled: { + header: 'Enabled', + get: (r) => (r.enabled ? 'yes' : 'no'), + }, + categories: { + header: 'Categories', + get: (r) => r.categories?.join(', ') || '-', + extended: true, + }, + score: { + header: 'Score', + get: (r) => (r.score === undefined ? '-' : String(r.score)), + extended: true, + }, +}; + +const DEFAULT_COLUMNS = ['ruleId', 'description', 'action', 'enabled']; + +const tableRenderer = new TableRenderer(COLUMNS); + +/** + * Command to list WAF v2 managed rules within a ruleset. + */ +export default class EcdnWafManagedRulesList extends EcdnZoneCommand { + static description = t('commands.ecdn.waf.managed-rules.list.description', 'List WAF v2 managed rules in a ruleset'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123 --extended', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123 --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'ruleset-id': Flags.string({ + description: t('flags.rulesetId.description', 'WAF ruleset ID to list rules for'), + required: true, + }), + columns: Flags.string({ + char: 'c', + description: `Columns to display (comma-separated). Available: ${Object.keys(COLUMNS).join(', ')}`, + }), + extended: Flags.boolean({ + char: 'x', + description: t('flags.extended.description', 'Show all columns including extended fields'), + default: false, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const rulesetId = this.flags['ruleset-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.waf.managed-rules.list.fetching', 'Fetching WAF v2 managed rules...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET( + '/organizations/{organizationId}/zones/{zoneId}/firewall-managed/rulesets/{rulesetId}/rules', + { + params: { + path: {organizationId, zoneId, rulesetId}, + }, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.waf.managed-rules.list.error', 'Failed to fetch WAF managed rules: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const rules = data?.data ?? []; + const output: ListOutput = { + rules, + total: rules.length, + }; + + if (this.jsonEnabled()) { + return output; + } + + if (rules.length === 0) { + this.log(t('commands.ecdn.waf.managed-rules.list.noRules', 'No WAF managed rules found.')); + return output; + } + + this.log( + t('commands.ecdn.waf.managed-rules.list.count', 'Found {{count}} WAF managed rule(s):', { + count: rules.length, + }), + ); + this.log(''); + + const columns = this.getSelectedColumns(); + tableRenderer.render(rules, columns); + + return output; + } + + private getSelectedColumns(): string[] { + const columnsFlag = this.flags.columns; + const extended = this.flags.extended; + + if (columnsFlag) { + const requested = columnsFlag.split(',').map((c) => c.trim()); + const valid = tableRenderer.validateColumnKeys(requested); + if (valid.length === 0) { + this.warn(`No valid columns specified. Available: ${tableRenderer.getColumnKeys().join(', ')}`); + return DEFAULT_COLUMNS; + } + return valid; + } + + if (extended) { + return tableRenderer.getColumnKeys(); + } + + return DEFAULT_COLUMNS; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/waf/managed-rules/update.ts b/packages/b2c-cli/src/commands/ecdn/waf/managed-rules/update.ts new file mode 100644 index 00000000..dd8d85bc --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/waf/managed-rules/update.ts @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type WAFManagedRule = CdnZonesComponents['schemas']['WAFManagedRule']; +type WAFManagedRuleRequest = CdnZonesComponents['schemas']['WAFManagedRuleRequest']; + +/** + * Response type for the update command. + */ +interface UpdateOutput { + rule: WAFManagedRule; +} + +/** + * Command to update a WAF v2 managed rule within a ruleset. + */ +export default class EcdnWafManagedRulesUpdate extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.waf.managed-rules.update.description', + 'Update a WAF v2 managed rule in a ruleset', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123 --rule-id def456 --enabled', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123 --rule-id def456 --action block', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123 --rule-id def456 --no-enabled', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'ruleset-id': Flags.string({ + description: t('flags.rulesetId.description', 'WAF ruleset ID containing the rule'), + required: true, + }), + 'rule-id': Flags.string({ + description: t('flags.ruleId.description', 'WAF managed rule ID to update'), + required: true, + }), + enabled: Flags.boolean({ + description: t('flags.enabled.description', 'Enable the rule'), + allowNo: true, + }), + action: Flags.string({ + description: t('flags.action.description', 'Action for the rule (e.g., default, block, challenge)'), + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const rulesetId = this.flags['ruleset-id']; + const ruleId = this.flags['rule-id']; + + if (!this.jsonEnabled()) { + this.log( + t('commands.ecdn.waf.managed-rules.update.updating', 'Updating WAF managed rule {{id}}...', {id: ruleId}), + ); + } + + const body: WAFManagedRuleRequest = {}; + + if (this.flags.enabled !== undefined) { + body.enabled = this.flags.enabled; + } + if (this.flags.action) { + body.action = this.flags.action; + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PATCH( + '/organizations/{organizationId}/zones/{zoneId}/firewall-managed/rulesets/{rulesetId}/rules/{ruleId}', + { + params: { + path: {organizationId, zoneId, rulesetId, ruleId}, + }, + body, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.waf.managed-rules.update.error', 'Failed to update WAF managed rule: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const rule = data?.data; + if (!rule) { + this.error(t('commands.ecdn.waf.managed-rules.update.noData', 'No WAF managed rule data returned from API')); + } + + const output: UpdateOutput = {rule}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 16; + + ui.div(''); + ui.div({text: t('commands.ecdn.waf.managed-rules.update.success', 'WAF managed rule updated successfully!')}); + ui.div(''); + ui.div({text: 'Rule ID:', width: labelWidth}, {text: rule.ruleId || '-'}); + ui.div({text: 'Description:', width: labelWidth}, {text: rule.description || '-'}); + ui.div({text: 'Action:', width: labelWidth}, {text: rule.action || '-'}); + ui.div({text: 'Enabled:', width: labelWidth}, {text: rule.enabled ? 'yes' : 'no'}); + + if (rule.score !== undefined) { + ui.div({text: 'Score:', width: labelWidth}, {text: String(rule.score)}); + } + if (rule.categories && rule.categories.length > 0) { + ui.div({text: 'Categories:', width: labelWidth}, {text: rule.categories.join(', ')}); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/waf/migrate.ts b/packages/b2c-cli/src/commands/ecdn/waf/migrate.ts new file mode 100644 index 00000000..1d98489d --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/waf/migrate.ts @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {ux} from '@oclif/core'; +import {TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +type WAFManagedRuleset = CdnZonesComponents['schemas']['WAFManagedRuleset']; + +/** + * Response type for the migrate command. + */ +interface MigrateOutput { + rulesets: WAFManagedRuleset[]; + total: number; +} + +const COLUMNS: Record> = { + rulesetId: { + header: 'Ruleset ID', + get: (r) => r.rulesetId || '-', + }, + name: { + header: 'Name', + get: (r) => r.name || '-', + }, + enabled: { + header: 'Enabled', + get: (r) => (r.enabled ? 'yes' : 'no'), + }, + action: { + header: 'Action', + get: (r) => r.action || '-', + }, +}; + +const tableRenderer = new TableRenderer(COLUMNS); + +/** + * Command to migrate a zone from WAF v1 to WAF v2. + */ +export default class EcdnWafMigrate extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.waf.migrate.description', + 'Migrate a zone from WAF v1 to WAF v2 (only applicable for existing WAFv1 zones)', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.waf.migrate.migrating', 'Migrating zone to WAF v2...')); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PUT( + '/organizations/{organizationId}/zones/{zoneId}/firewall-managed/migration', + { + params: { + path: {organizationId, zoneId}, + }, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.waf.migrate.error', 'Failed to migrate zone to WAF v2: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const rulesets = data?.data ?? []; + const output: MigrateOutput = { + rulesets, + total: rulesets.length, + }; + + if (this.jsonEnabled()) { + return output; + } + + this.log(''); + ux.stdout(t('commands.ecdn.waf.migrate.success', 'Zone successfully migrated to WAF v2!')); + this.log(''); + + if (rulesets.length === 0) { + this.log(t('commands.ecdn.waf.migrate.noRulesets', 'No WAF rulesets created during migration.')); + return output; + } + + this.log( + t('commands.ecdn.waf.migrate.count', 'Created {{count}} WAF v2 ruleset(s):', { + count: rulesets.length, + }), + ); + this.log(''); + + tableRenderer.render(rulesets, Object.keys(COLUMNS)); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/waf/owasp/get.ts b/packages/b2c-cli/src/commands/ecdn/waf/owasp/get.ts new file mode 100644 index 00000000..426f410b --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/waf/owasp/get.ts @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type WAFRulePackage = CdnZonesComponents['schemas']['WAFRulePackage']; + +/** + * Response type for the get command. + */ +interface GetOutput { + package: WAFRulePackage; +} + +/** + * Command to get OWASP ModSecurity package settings for a zone. + * Note: This is for WAF v1. For zones created after 24.5, use waf rulesets commands. + */ +export default class EcdnWafOwaspGet extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.waf.owasp.get.description', + 'Get OWASP ModSecurity package settings for a zone (not applicable for WAFv2 zones)', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.waf.owasp.get.fetching', 'Fetching OWASP package settings...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET( + '/organizations/{organizationId}/zones/{zoneId}/firewall/waf/packages/owasp', + { + params: { + path: {organizationId, zoneId}, + }, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.waf.owasp.get.error', 'Failed to fetch OWASP package settings: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const pkg = data?.data; + if (!pkg) { + this.error(t('commands.ecdn.waf.owasp.get.noData', 'No OWASP package data returned from API')); + } + + const output: GetOutput = {package: pkg}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 18; + + ui.div(''); + ui.div({text: 'OWASP Package:', padding: [0, 0, 1, 0]}); + ui.div({text: 'ID:', width: labelWidth}, {text: pkg.id}); + ui.div({text: 'Name:', width: labelWidth}, {text: pkg.name}); + ui.div({text: 'Description:', width: labelWidth}, {text: pkg.description}); + ui.div({text: 'Detection Mode:', width: labelWidth}, {text: pkg.detection_mode}); + ui.div({text: 'Sensitivity:', width: labelWidth}, {text: pkg.sensitivity}); + ui.div({text: 'Action Mode:', width: labelWidth}, {text: pkg.action_mode}); + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/waf/owasp/update.ts b/packages/b2c-cli/src/commands/ecdn/waf/owasp/update.ts new file mode 100644 index 00000000..5bb2a6b5 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/waf/owasp/update.ts @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type WAFRulePackage = CdnZonesComponents['schemas']['WAFRulePackage']; +type WafPackagePatchRequest = CdnZonesComponents['schemas']['WafPackagePatchRequest']; + +/** + * Response type for the update command. + */ +interface UpdateOutput { + package: WAFRulePackage; +} + +/** + * Command to update OWASP ModSecurity package settings for a zone. + * Note: This is for WAF v1. For zones created after 24.5, use waf rulesets commands. + */ +export default class EcdnWafOwaspUpdate extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.waf.owasp.update.description', + 'Update OWASP ModSecurity package settings for a zone (not applicable for WAFv2 zones)', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --sensitivity medium --action-mode block', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --sensitivity high --action-mode challenge', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --sensitivity off', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + sensitivity: Flags.string({ + description: t('flags.sensitivity.description', 'Sensitivity level (low, medium, high, off)'), + options: ['low', 'medium', 'high', 'off'], + required: true, + }), + 'action-mode': Flags.string({ + description: t('flags.actionMode.description', 'Action mode (simulate, challenge, block)'), + options: ['simulate', 'challenge', 'block'], + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.waf.owasp.update.updating', 'Updating OWASP package settings...')); + } + + const body: WafPackagePatchRequest = { + sensitivity: this.flags.sensitivity as WafPackagePatchRequest['sensitivity'], + action_mode: this.flags['action-mode'] as WafPackagePatchRequest['action_mode'], + }; + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PATCH( + '/organizations/{organizationId}/zones/{zoneId}/firewall/waf/packages/owasp', + { + params: { + path: {organizationId, zoneId}, + }, + body, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.waf.owasp.update.error', 'Failed to update OWASP package settings: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const pkg = data?.data; + if (!pkg) { + this.error(t('commands.ecdn.waf.owasp.update.noData', 'No OWASP package data returned from API')); + } + + const output: UpdateOutput = {package: pkg}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 18; + + ui.div(''); + ui.div({text: t('commands.ecdn.waf.owasp.update.success', 'OWASP package updated successfully!')}); + ui.div(''); + ui.div({text: 'ID:', width: labelWidth}, {text: pkg.id}); + ui.div({text: 'Name:', width: labelWidth}, {text: pkg.name}); + ui.div({text: 'Sensitivity:', width: labelWidth}, {text: pkg.sensitivity}); + ui.div({text: 'Action Mode:', width: labelWidth}, {text: pkg.action_mode}); + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/waf/rules/get.ts b/packages/b2c-cli/src/commands/ecdn/waf/rules/get.ts new file mode 100644 index 00000000..d030e608 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/waf/rules/get.ts @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type WafRule = CdnZonesComponents['schemas']['WafRule']; + +/** + * Response type for the get command. + */ +interface GetOutput { + rule: WafRule; +} + +/** + * Command to get a WAF rule for a zone. + * Note: This is for WAF v1. For zones created after 24.5, use waf managed-rules commands. + */ +export default class EcdnWafRulesGet extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.waf.rules.get.description', + 'Get a WAF v1 rule for a zone (not applicable for WAFv2 zones)', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --rule-id abc123', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --rule-id abc123 --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'rule-id': Flags.string({ + description: t('flags.ruleId.description', 'WAF rule ID to get'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const ruleId = this.flags['rule-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.waf.rules.get.fetching', 'Fetching WAF rule...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/waf/rules/{ruleId}', { + params: { + path: {organizationId, zoneId, ruleId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.waf.rules.get.error', 'Failed to fetch WAF rule: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const rule = data?.data; + if (!rule) { + this.error(t('commands.ecdn.waf.rules.get.noData', 'No WAF rule data returned from API')); + } + + const output: GetOutput = {rule}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 16; + + ui.div(''); + ui.div({text: 'WAF Rule:', padding: [0, 0, 1, 0]}); + ui.div({text: 'Rule ID:', width: labelWidth}, {text: rule.ruleId || '-'}); + ui.div({text: 'Group ID:', width: labelWidth}, {text: rule.groupId || '-'}); + ui.div({text: 'Description:', width: labelWidth}, {text: rule.description || '-'}); + ui.div({text: 'Action:', width: labelWidth}, {text: rule.action || '-'}); + ui.div({text: 'Default Action:', width: labelWidth}, {text: rule.defaultAction || '-'}); + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/waf/rules/list.ts b/packages/b2c-cli/src/commands/ecdn/waf/rules/list.ts new file mode 100644 index 00000000..1e393511 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/waf/rules/list.ts @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type WafRule = CdnZonesComponents['schemas']['WafRule']; + +/** + * Response type for the list command. + */ +interface ListOutput { + rules: WafRule[]; + total: number; +} + +const COLUMNS: Record> = { + ruleId: { + header: 'Rule ID', + get: (r) => r.ruleId || '-', + }, + groupId: { + header: 'Group ID', + get: (r) => r.groupId || '-', + }, + description: { + header: 'Description', + get: (r) => r.description || '-', + }, + action: { + header: 'Action', + get: (r) => r.action || '-', + }, + defaultAction: { + header: 'Default Action', + get: (r) => r.defaultAction || '-', + extended: true, + }, +}; + +const DEFAULT_COLUMNS = ['ruleId', 'description', 'action']; + +const tableRenderer = new TableRenderer(COLUMNS); + +/** + * Command to list WAF rules for a zone. + * Note: This is for WAF v1. For zones created after 24.5, use waf managed-rules commands. + */ +export default class EcdnWafRulesList extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.waf.rules.list.description', + 'List WAF v1 rules for a zone (not applicable for WAFv2 zones)', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --group-id abc123', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --group-id abc123 --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'group-id': Flags.string({ + description: t('flags.groupId.description', 'WAF group ID to list rules for'), + required: true, + }), + columns: Flags.string({ + char: 'c', + description: `Columns to display (comma-separated). Available: ${Object.keys(COLUMNS).join(', ')}`, + }), + extended: Flags.boolean({ + char: 'x', + description: t('flags.extended.description', 'Show all columns including extended fields'), + default: false, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const groupId = this.flags['group-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.waf.rules.list.fetching', 'Fetching WAF rules...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/waf/rules', { + params: { + path: {organizationId, zoneId}, + query: {groupId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.waf.rules.list.error', 'Failed to fetch WAF rules: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const rules = data?.data ?? []; + const output: ListOutput = { + rules, + total: rules.length, + }; + + if (this.jsonEnabled()) { + return output; + } + + if (rules.length === 0) { + this.log(t('commands.ecdn.waf.rules.list.noRules', 'No WAF rules found.')); + return output; + } + + this.log( + t('commands.ecdn.waf.rules.list.count', 'Found {{count}} WAF rule(s):', { + count: rules.length, + }), + ); + this.log(''); + + const columns = this.getSelectedColumns(); + tableRenderer.render(rules, columns); + + return output; + } + + private getSelectedColumns(): string[] { + const columnsFlag = this.flags.columns; + const extended = this.flags.extended; + + if (columnsFlag) { + const requested = columnsFlag.split(',').map((c) => c.trim()); + const valid = tableRenderer.validateColumnKeys(requested); + if (valid.length === 0) { + this.warn(`No valid columns specified. Available: ${tableRenderer.getColumnKeys().join(', ')}`); + return DEFAULT_COLUMNS; + } + return valid; + } + + if (extended) { + return tableRenderer.getColumnKeys(); + } + + return DEFAULT_COLUMNS; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/waf/rules/update.ts b/packages/b2c-cli/src/commands/ecdn/waf/rules/update.ts new file mode 100644 index 00000000..b1a669ea --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/waf/rules/update.ts @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type WafRule = CdnZonesComponents['schemas']['WafRule']; + +/** + * Response type for the update command. + */ +interface UpdateOutput { + rule: WafRule; +} + +/** + * Command to update a WAF rule for a zone. + * Note: This is for WAF v1. For zones created after 24.5, use waf managed-rules commands. + */ +export default class EcdnWafRulesUpdate extends EcdnZoneCommand { + static description = t( + 'commands.ecdn.waf.rules.update.description', + 'Update a WAF v1 rule for a zone (not applicable for WAFv2 zones)', + ); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --rule-id abc123 --action block', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --rule-id abc123 --action monitor', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'rule-id': Flags.string({ + description: t('flags.ruleId.description', 'WAF rule ID to update'), + required: true, + }), + action: Flags.string({ + description: t('flags.action.description', 'Action for the WAF rule'), + options: ['block', 'challenge', 'monitor', 'disable', 'default'], + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const ruleId = this.flags['rule-id']; + const action = this.flags.action as WafRule['action']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.waf.rules.update.updating', 'Updating WAF rule {{id}}...', {id: ruleId})); + } + + const body: WafRule = {action}; + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PUT('/organizations/{organizationId}/zones/{zoneId}/waf/rules/{ruleId}', { + params: { + path: {organizationId, zoneId, ruleId}, + }, + body, + }); + + if (error) { + this.error( + t('commands.ecdn.waf.rules.update.error', 'Failed to update WAF rule: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const rule = data?.data; + if (!rule) { + this.error(t('commands.ecdn.waf.rules.update.noData', 'No WAF rule data returned from API')); + } + + const output: UpdateOutput = {rule}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 16; + + ui.div(''); + ui.div({text: t('commands.ecdn.waf.rules.update.success', 'WAF rule updated successfully!')}); + ui.div(''); + ui.div({text: 'Rule ID:', width: labelWidth}, {text: rule.ruleId || '-'}); + ui.div({text: 'Group ID:', width: labelWidth}, {text: rule.groupId || '-'}); + ui.div({text: 'Description:', width: labelWidth}, {text: rule.description || '-'}); + ui.div({text: 'Action:', width: labelWidth}, {text: rule.action || '-'}); + ui.div({text: 'Default Action:', width: labelWidth}, {text: rule.defaultAction || '-'}); + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/waf/rulesets/list.ts b/packages/b2c-cli/src/commands/ecdn/waf/rulesets/list.ts new file mode 100644 index 00000000..19343b04 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/waf/rulesets/list.ts @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type WAFManagedRuleset = CdnZonesComponents['schemas']['WAFManagedRuleset']; + +/** + * Response type for the list command. + */ +interface ListOutput { + rulesets: WAFManagedRuleset[]; + total: number; +} + +const COLUMNS: Record> = { + rulesetId: { + header: 'Ruleset ID', + get: (r) => r.rulesetId || '-', + }, + name: { + header: 'Name', + get: (r) => r.name || '-', + }, + enabled: { + header: 'Enabled', + get: (r) => (r.enabled ? 'yes' : 'no'), + }, + action: { + header: 'Action', + get: (r) => r.action || '-', + }, + paranoiaLevel: { + header: 'Paranoia', + get: (r) => (r.paranoiaLevel === undefined ? '-' : String(r.paranoiaLevel)), + extended: true, + }, + anomalyScore: { + header: 'Anomaly Score', + get: (r) => r.anomalyScore || '-', + extended: true, + }, +}; + +const DEFAULT_COLUMNS = ['name', 'enabled', 'action']; + +const tableRenderer = new TableRenderer(COLUMNS); + +/** + * Command to list WAF v2 managed rulesets for a zone. + */ +export default class EcdnWafRulesetsList extends EcdnZoneCommand { + static description = t('commands.ecdn.waf.rulesets.list.description', 'List WAF v2 managed rulesets for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --extended', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --json', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + columns: Flags.string({ + char: 'c', + description: `Columns to display (comma-separated). Available: ${Object.keys(COLUMNS).join(', ')}`, + }), + extended: Flags.boolean({ + char: 'x', + description: t('flags.extended.description', 'Show all columns including extended fields'), + default: false, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.waf.rulesets.list.fetching', 'Fetching WAF v2 rulesets...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/firewall-managed/rulesets', { + params: { + path: {organizationId, zoneId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.waf.rulesets.list.error', 'Failed to fetch WAF rulesets: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const rulesets = data?.data ?? []; + const output: ListOutput = { + rulesets, + total: rulesets.length, + }; + + if (this.jsonEnabled()) { + return output; + } + + if (rulesets.length === 0) { + this.log(t('commands.ecdn.waf.rulesets.list.noRulesets', 'No WAF rulesets found.')); + return output; + } + + this.log( + t('commands.ecdn.waf.rulesets.list.count', 'Found {{count}} WAF ruleset(s):', { + count: rulesets.length, + }), + ); + this.log(''); + + const columns = this.getSelectedColumns(); + tableRenderer.render(rulesets, columns); + + return output; + } + + private getSelectedColumns(): string[] { + const columnsFlag = this.flags.columns; + const extended = this.flags.extended; + + if (columnsFlag) { + const requested = columnsFlag.split(',').map((c) => c.trim()); + const valid = tableRenderer.validateColumnKeys(requested); + if (valid.length === 0) { + this.warn(`No valid columns specified. Available: ${tableRenderer.getColumnKeys().join(', ')}`); + return DEFAULT_COLUMNS; + } + return valid; + } + + if (extended) { + return tableRenderer.getColumnKeys(); + } + + return DEFAULT_COLUMNS; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/waf/rulesets/update.ts b/packages/b2c-cli/src/commands/ecdn/waf/rulesets/update.ts new file mode 100644 index 00000000..353ce6b8 --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/waf/rulesets/update.ts @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags, ux} from '@oclif/core'; +import cliui from 'cliui'; +import type {CdnZonesComponents} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnZoneCommand, formatApiError} from '../../../../utils/ecdn/index.js'; +import {t} from '../../../../i18n/index.js'; + +type WAFManagedRuleset = CdnZonesComponents['schemas']['WAFManagedRuleset']; +type WAFManagedRulesetRequest = CdnZonesComponents['schemas']['WAFManagedRulesetRequest']; + +/** + * Response type for the update command. + */ +interface UpdateOutput { + ruleset: WAFManagedRuleset; +} + +/** + * Command to update a WAF v2 managed ruleset for a zone. + */ +export default class EcdnWafRulesetsUpdate extends EcdnZoneCommand { + static description = t('commands.ecdn.waf.rulesets.update.description', 'Update a WAF v2 managed ruleset for a zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123 --enabled', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123 --action block', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123 --paranoia-level 2', + ]; + + static flags = { + ...EcdnZoneCommand.baseFlags, + 'ruleset-id': Flags.string({ + description: t('flags.rulesetId.description', 'WAF ruleset ID to update'), + required: true, + }), + enabled: Flags.boolean({ + description: t('flags.enabled.description', 'Enable the ruleset'), + allowNo: true, + }), + action: Flags.string({ + description: t('flags.action.description', 'Action for the ruleset (e.g., default, block, challenge)'), + }), + 'anomaly-score': Flags.string({ + description: t('flags.anomalyScore.description', 'Anomaly score threshold (for OWASP ruleset)'), + }), + 'paranoia-level': Flags.integer({ + description: t('flags.paranoiaLevel.description', 'Paranoia level 1-4 (for OWASP ruleset)'), + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const zoneId = await this.resolveZoneId(); + const rulesetId = this.flags['ruleset-id']; + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.waf.rulesets.update.updating', 'Updating WAF ruleset {{id}}...', {id: rulesetId})); + } + + const body: WAFManagedRulesetRequest = {}; + + if (this.flags.enabled !== undefined) { + body.enabled = this.flags.enabled; + } + if (this.flags.action) { + body.action = this.flags.action; + } + if (this.flags['anomaly-score']) { + body.anomalyScore = this.flags['anomaly-score']; + } + if (this.flags['paranoia-level'] !== undefined) { + body.paranoiaLevel = this.flags['paranoia-level']; + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.PATCH( + '/organizations/{organizationId}/zones/{zoneId}/firewall-managed/rulesets/{rulesetId}', + { + params: { + path: {organizationId, zoneId, rulesetId}, + }, + body, + }, + ); + + if (error) { + this.error( + t('commands.ecdn.waf.rulesets.update.error', 'Failed to update WAF ruleset: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const ruleset = data?.data; + if (!ruleset) { + this.error(t('commands.ecdn.waf.rulesets.update.noData', 'No WAF ruleset data returned from API')); + } + + const output: UpdateOutput = {ruleset}; + + if (this.jsonEnabled()) { + return output; + } + + const ui = cliui({width: process.stdout.columns || 80}); + const labelWidth = 18; + + ui.div(''); + ui.div({text: t('commands.ecdn.waf.rulesets.update.success', 'WAF ruleset updated successfully!')}); + ui.div(''); + ui.div({text: 'Ruleset ID:', width: labelWidth}, {text: ruleset.rulesetId}); + ui.div({text: 'Name:', width: labelWidth}, {text: ruleset.name}); + ui.div({text: 'Enabled:', width: labelWidth}, {text: ruleset.enabled ? 'yes' : 'no'}); + ui.div({text: 'Action:', width: labelWidth}, {text: ruleset.action}); + + if (ruleset.paranoiaLevel !== undefined) { + ui.div({text: 'Paranoia Level:', width: labelWidth}, {text: String(ruleset.paranoiaLevel)}); + } + if (ruleset.anomalyScore) { + ui.div({text: 'Anomaly Score:', width: labelWidth}, {text: ruleset.anomalyScore}); + } + + ux.stdout(ui.toString()); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/zones/create.ts b/packages/b2c-cli/src/commands/ecdn/zones/create.ts new file mode 100644 index 00000000..04cc724c --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/zones/create.ts @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {EcdnCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +/** + * Response type for the create command. + */ +interface CreateOutput { + zoneId: string; + zoneName: string; + status: string; + createdOn: string; +} + +/** + * Command to create a new storefront zone. + */ +export default class EcdnZonesCreate extends EcdnCommand { + static description = t('commands.ecdn.zones.create.description', 'Create a new storefront CDN zone'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --domain-name example.com', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --domain-name store.example.com --json', + ]; + + static flags = { + ...EcdnCommand.baseFlags, + 'domain-name': Flags.string({ + char: 'd', + description: t('flags.domainName.description', 'Domain name for the storefront zone'), + required: true, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + const domainName = this.flags['domain-name']; + + if (!this.jsonEnabled()) { + this.log( + t('commands.ecdn.zones.create.creating', 'Creating storefront zone for {{domain}}...', {domain: domainName}), + ); + } + + const client = this.getCdnZonesRwClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.POST('/organizations/{organizationId}/storefront-zones', { + params: { + path: {organizationId}, + }, + body: { + domainName, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.zones.create.error', 'Failed to create storefront zone: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const zone = data?.data; + if (!zone) { + this.error(t('commands.ecdn.zones.create.noData', 'No zone data returned from API')); + } + + const output: CreateOutput = { + zoneId: zone.zoneId, + zoneName: zone.zoneName, + status: zone.status, + createdOn: zone.createdOn, + }; + + if (this.jsonEnabled()) { + return output; + } + + this.log(''); + this.log(t('commands.ecdn.zones.create.success', 'Storefront zone created successfully!')); + this.log(''); + this.log(` Zone ID: ${output.zoneId}`); + this.log(` Zone Name: ${output.zoneName}`); + this.log(` Status: ${output.status}`); + this.log(` Created On: ${output.createdOn}`); + + return output; + } +} diff --git a/packages/b2c-cli/src/commands/ecdn/zones/list.ts b/packages/b2c-cli/src/commands/ecdn/zones/list.ts new file mode 100644 index 00000000..d4b7912c --- /dev/null +++ b/packages/b2c-cli/src/commands/ecdn/zones/list.ts @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Flags} from '@oclif/core'; +import {TableRenderer, type ColumnDef} from '@salesforce/b2c-tooling-sdk/cli'; +import type {Zone} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnCommand, formatApiError} from '../../../utils/ecdn/index.js'; +import {t} from '../../../i18n/index.js'; + +/** + * Response type for the list command. + */ +interface ListOutput { + zones: Zone[]; + total: number; +} + +const COLUMNS: Record> = { + zoneId: { + header: 'Zone ID', + get: (z) => z.zoneId || '-', + extended: true, + }, + name: { + header: 'Name', + get: (z) => z.name || '-', + }, + status: { + header: 'Status', + get: (z) => z.status || '-', + }, +}; + +/** Default columns shown without --extended */ +const DEFAULT_COLUMNS = ['name', 'status']; + +const tableRenderer = new TableRenderer(COLUMNS); + +/** + * Command to list eCDN zones. + */ +export default class EcdnZonesList extends EcdnCommand { + static description = t('commands.ecdn.zones.list.description', 'List all eCDN zones for the organization'); + + static enableJsonFlag = true; + + static examples = [ + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --extended', + '<%= config.bin %> <%= command.id %> --tenant-id zzxy_prd --json', + ]; + + static flags = { + ...EcdnCommand.baseFlags, + columns: Flags.string({ + char: 'c', + description: `Columns to display (comma-separated). Available: ${Object.keys(COLUMNS).join(', ')}`, + }), + extended: Flags.boolean({ + char: 'x', + description: t('flags.extended.description', 'Show all columns including extended fields'), + default: false, + }), + }; + + async run(): Promise { + this.requireOAuthCredentials(); + + if (!this.jsonEnabled()) { + this.log(t('commands.ecdn.zones.list.fetching', 'Fetching eCDN zones...')); + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/info', { + params: { + path: {organizationId}, + }, + }); + + if (error) { + this.error( + t('commands.ecdn.zones.list.error', 'Failed to fetch eCDN zones: {{message}}', { + message: formatApiError(error), + }), + ); + } + + const zones = data?.data ?? []; + const output: ListOutput = { + zones, + total: zones.length, + }; + + if (this.jsonEnabled()) { + return output; + } + + if (zones.length === 0) { + this.log(t('commands.ecdn.zones.list.noZones', 'No eCDN zones found.')); + return output; + } + + this.log( + t('commands.ecdn.zones.list.count', 'Found {{count}} zone(s):', { + count: zones.length, + }), + ); + this.log(''); + + const columns = this.getSelectedColumns(); + tableRenderer.render(zones, columns); + + return output; + } + + /** + * Determines which columns to display based on flags. + */ + private getSelectedColumns(): string[] { + const columnsFlag = this.flags.columns; + const extended = this.flags.extended; + + if (columnsFlag) { + // User specified explicit columns + const requested = columnsFlag.split(',').map((c) => c.trim()); + const valid = tableRenderer.validateColumnKeys(requested); + if (valid.length === 0) { + this.warn(`No valid columns specified. Available: ${tableRenderer.getColumnKeys().join(', ')}`); + return DEFAULT_COLUMNS; + } + return valid; + } + + if (extended) { + // Show all columns + return tableRenderer.getColumnKeys(); + } + + // Default columns (non-extended) + return DEFAULT_COLUMNS; + } +} diff --git a/packages/b2c-cli/src/utils/ecdn/base-command.ts b/packages/b2c-cli/src/utils/ecdn/base-command.ts new file mode 100644 index 00000000..778f59ac --- /dev/null +++ b/packages/b2c-cli/src/utils/ecdn/base-command.ts @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Command, Flags} from '@oclif/core'; +import {OAuthCommand} from '@salesforce/b2c-tooling-sdk/cli'; +import {createCdnZonesClient, toOrganizationId, type CdnZonesClient} from '@salesforce/b2c-tooling-sdk/clients'; +import {t} from '../../i18n/index.js'; + +/** + * Format API error for display. + */ +export function formatApiError(error: unknown): string { + return typeof error === 'object' ? JSON.stringify(error) : String(error); +} + +/** + * Base command for eCDN operations. + * Provides tenant-id flag and lazy-loaded CDN Zones client. + */ +export abstract class EcdnCommand extends OAuthCommand { + static baseFlags = { + ...OAuthCommand.baseFlags, + 'tenant-id': Flags.string({ + description: t('flags.tenantId.description', 'Organization/tenant ID'), + env: 'SFCC_TENANT_ID', + required: true, + }), + }; + + private _cdnZonesClient?: CdnZonesClient; + private _cdnZonesRwClient?: CdnZonesClient; + + /** + * Get the CDN Zones client (read-only). + */ + protected getCdnZonesClient(): CdnZonesClient { + if (!this._cdnZonesClient) { + const {shortCode} = this.resolvedConfig.values; + const tenantId = (this.flags as Record)['tenant-id']; + + if (!shortCode) { + this.error( + t( + 'error.shortCodeRequired', + 'SCAPI short code required. Provide --short-code, set SFCC_SHORTCODE, or configure short-code in dw.json.', + ), + ); + } + + const oauthStrategy = this.getOAuthStrategy(); + this._cdnZonesClient = createCdnZonesClient({shortCode, tenantId}, oauthStrategy); + } + return this._cdnZonesClient; + } + + /** + * Get the CDN Zones client (read-write). + */ + protected getCdnZonesRwClient(): CdnZonesClient { + if (!this._cdnZonesRwClient) { + const {shortCode} = this.resolvedConfig.values; + const tenantId = (this.flags as Record)['tenant-id']; + + if (!shortCode) { + this.error( + t( + 'error.shortCodeRequired', + 'SCAPI short code required. Provide --short-code, set SFCC_SHORTCODE, or configure short-code in dw.json.', + ), + ); + } + + const oauthStrategy = this.getOAuthStrategy(); + this._cdnZonesRwClient = createCdnZonesClient({shortCode, tenantId}, oauthStrategy, {readWrite: true}); + } + return this._cdnZonesRwClient; + } + + /** + * Get the organization ID from the tenant-id flag. + */ + protected getOrganizationId(): string { + const tenantId = (this.flags as Record)['tenant-id']; + return toOrganizationId(tenantId); + } +} diff --git a/packages/b2c-cli/src/utils/ecdn/index.ts b/packages/b2c-cli/src/utils/ecdn/index.ts new file mode 100644 index 00000000..0a3a5866 --- /dev/null +++ b/packages/b2c-cli/src/utils/ecdn/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +export {EcdnCommand, formatApiError} from './base-command.js'; +export {EcdnZoneCommand} from './zone-command.js'; diff --git a/packages/b2c-cli/src/utils/ecdn/zone-command.ts b/packages/b2c-cli/src/utils/ecdn/zone-command.ts new file mode 100644 index 00000000..d42a8bd8 --- /dev/null +++ b/packages/b2c-cli/src/utils/ecdn/zone-command.ts @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {Command, Flags} from '@oclif/core'; +import type {Zone} from '@salesforce/b2c-tooling-sdk/clients'; +import {EcdnCommand, formatApiError} from './base-command.js'; +import {t} from '../../i18n/index.js'; + +/** + * Base command for operations that require a specific zone. + * Adds --zone flag that accepts either zone ID or zone name. + */ +export abstract class EcdnZoneCommand extends EcdnCommand { + static baseFlags = { + ...EcdnCommand.baseFlags, + zone: Flags.string({ + char: 'z', + description: t('flags.zone.description', 'Zone ID or zone name'), + required: true, + }), + }; + + private _resolvedZoneId?: string; + private _zonesCache?: Zone[]; + + /** + * Fetch all zones for the organization. + * Results are cached for the duration of the command. + */ + protected async fetchZones(): Promise { + if (this._zonesCache) { + return this._zonesCache; + } + + const client = this.getCdnZonesClient(); + const organizationId = this.getOrganizationId(); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/info', { + params: {path: {organizationId}}, + }); + + if (error) { + this.error( + t('commands.ecdn.zones.fetchError', 'Failed to fetch zones: {{message}}', { + message: formatApiError(error), + }), + ); + } + + this._zonesCache = data?.data ?? []; + return this._zonesCache; + } + + /** + * Resolve zone flag to zone ID. + * If the flag looks like a zone ID (32-char hex string), use it directly. + * Otherwise, fetch zones and find by name. + */ + protected async resolveZoneId(): Promise { + if (this._resolvedZoneId) { + return this._resolvedZoneId; + } + + const zoneFlag = (this.flags as Record).zone; + + // If it's a 32-char hex string, assume it's a zone ID + if (/^[a-f0-9]{32}$/i.test(zoneFlag)) { + this._resolvedZoneId = zoneFlag; + return this._resolvedZoneId; + } + + // Otherwise, look up by name + const zones = await this.fetchZones(); + const matchedZone = zones.find( + (z) => z.name?.toLowerCase() === zoneFlag.toLowerCase() || z.zoneId?.toLowerCase() === zoneFlag.toLowerCase(), + ); + + if (!matchedZone?.zoneId) { + // List available zones to help the user + const availableZones = zones.map((z) => z.name || z.zoneId).join(', '); + this.error( + t('commands.ecdn.zone.notFound', 'Zone not found: {{zone}}. Available zones: {{available}}', { + zone: zoneFlag, + available: availableZones || 'none', + }), + ); + } + + this._resolvedZoneId = matchedZone.zoneId; + return this._resolvedZoneId; + } +} diff --git a/packages/b2c-cli/test/commands/ecdn/cache/purge.test.ts b/packages/b2c-cli/test/commands/ecdn/cache/purge.test.ts new file mode 100644 index 00000000..19eaca33 --- /dev/null +++ b/packages/b2c-cli/test/commands/ecdn/cache/purge.test.ts @@ -0,0 +1,263 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {expect} from 'chai'; +import {afterEach, beforeEach} from 'mocha'; +import sinon from 'sinon'; +import EcdnCachePurge from '../../../../src/commands/ecdn/cache/purge.js'; +import {createIsolatedConfigHooks, createTestCommand} from '../../../helpers/test-setup.js'; + +/** + * Unit tests for eCDN cache purge command CLI logic. + * Tests input validation, multiple purge modes, and output formatting. + */ +describe('ecdn cache purge', () => { + const hooks = createIsolatedConfigHooks(); + + beforeEach(hooks.beforeEach); + + afterEach(hooks.afterEach); + + async function createCommand(flags: Record = {}) { + return createTestCommand(EcdnCachePurge, hooks.getConfig(), flags, {}); + } + + function stubCommon( + command: any, + {jsonEnabled = true, zoneId = 'zone-abc123'}: {jsonEnabled?: boolean; zoneId?: string} = {}, + ) { + sinon.stub(command, 'requireOAuthCredentials').returns(void 0); + sinon.stub(command, 'getOrganizationId').returns('f_ecom_zzxy_prd'); + sinon.stub(command, 'resolveZoneId').resolves(zoneId); + sinon.stub(command, 'resolvedConfig').get(() => ({values: {shortCode: 'kv7kzm78'}, warnings: [], sources: []})); + sinon.stub(command, 'jsonEnabled').returns(jsonEnabled); + sinon.stub(command, 'log').returns(void 0); + sinon.stub(command, 'warn').returns(void 0); + Object.defineProperty(command, 'logger', { + value: {info() {}, debug() {}, warn() {}, error() {}}, + configurable: true, + }); + } + + function stubCdnClient(command: any, client: Partial<{GET: any; POST: any; PUT: any; PATCH: any; DELETE: any}>) { + Object.defineProperty(command, '_cdnZonesClient', {value: client, configurable: true, writable: true}); + Object.defineProperty(command, '_cdnZonesRwClient', {value: client, configurable: true, writable: true}); + } + + describe('input validation', () => { + it('errors when neither path nor tag is provided', async () => { + const command: any = await createCommand({'tenant-id': 'zzxy_prd', zone: 'my-zone'}); + + sinon.stub(command, 'requireOAuthCredentials').returns(void 0); + sinon.stub(command, 'resolvedConfig').get(() => ({values: {shortCode: 'kv7kzm78'}, warnings: [], sources: []})); + sinon.stub(command, 'log').returns(void 0); + sinon.stub(command, 'warn').returns(void 0); + Object.defineProperty(command, 'logger', { + value: {info() {}, debug() {}, warn() {}, error() {}}, + configurable: true, + }); + + const errorStub = sinon.stub(command, 'error').throws(new Error('--path or --tag must be specified')); + + try { + await command.run(); + expect.fail('Should have thrown an error'); + } catch { + expect(errorStub.calledOnce).to.equal(true); + } + }); + }); + + describe('path purge mode', () => { + it('purges cache by path successfully', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + path: 'www.example.com/products', + }); + stubCommon(command, {jsonEnabled: true}); + + let capturedBody: any; + stubCdnClient(command, { + async POST(_path: string, {body}: any) { + capturedBody = body; + return { + data: { + data: {cachePurged: true}, + }, + }; + }, + }); + + const result = await command.run(); + + expect(result.success).to.be.true; + expect(result.cachePurged).to.be.true; + expect(result.purgedPath).to.equal('www.example.com/products'); + expect(capturedBody).to.deep.equal({path: 'www.example.com/products'}); + }); + }); + + describe('tag purge mode', () => { + it('purges cache by tags successfully', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + tag: ['product-123', 'category-456'], + }); + stubCommon(command, {jsonEnabled: true}); + + let capturedBody: any; + stubCdnClient(command, { + async POST(_path: string, {body}: any) { + capturedBody = body; + return { + data: { + data: {cachePurged: true}, + }, + }; + }, + }); + + const result = await command.run(); + + expect(result.success).to.be.true; + expect(result.purgedTags).to.deep.equal(['product-123', 'category-456']); + expect(capturedBody).to.deep.equal({tags: ['product-123', 'category-456']}); + }); + + it('handles single tag', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + tag: ['single-tag'], + }); + stubCommon(command, {jsonEnabled: true}); + + stubCdnClient(command, { + POST: async () => ({ + data: {data: {cachePurged: true}}, + }), + }); + + const result = await command.run(); + + expect(result.purgedTags).to.deep.equal(['single-tag']); + }); + }); + + describe('combined mode', () => { + it('purges by both path and tags', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + path: 'www.example.com/products', + tag: ['product-123'], + }); + stubCommon(command, {jsonEnabled: true}); + + let capturedBody: any; + stubCdnClient(command, { + async POST(_path: string, {body}: any) { + capturedBody = body; + return { + data: {data: {cachePurged: true}}, + }; + }, + }); + + const result = await command.run(); + + expect(result.purgedPath).to.equal('www.example.com/products'); + expect(result.purgedTags).to.deep.equal(['product-123']); + expect(capturedBody).to.deep.equal({ + path: 'www.example.com/products', + tags: ['product-123'], + }); + }); + }); + + describe('output formatting', () => { + it('returns structured output in JSON mode', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + path: 'www.example.com/test', + }); + stubCommon(command, {jsonEnabled: true}); + + stubCdnClient(command, { + POST: async () => ({ + data: { + data: { + cachePurged: true, + details: 'Purge completed', + }, + }, + }), + }); + + const result = await command.run(); + + expect(result).to.have.property('success', true); + expect(result).to.have.property('cachePurged', true); + expect(result).to.have.property('details', 'Purge completed'); + expect(result).to.have.property('purgedPath', 'www.example.com/test'); + }); + + it('handles partial success', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + path: 'www.example.com/test', + }); + stubCommon(command, {jsonEnabled: true}); + + stubCdnClient(command, { + POST: async () => ({ + data: { + data: { + cachePurged: false, + details: 'Path not found in cache', + }, + }, + }), + }); + + const result = await command.run(); + + expect(result.success).to.be.false; + expect(result.cachePurged).to.be.false; + expect(result.details).to.equal('Path not found in cache'); + }); + }); + + describe('error handling', () => { + it('errors on API failure', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + path: 'www.example.com/test', + }); + stubCommon(command, {jsonEnabled: true}); + + const errorStub = sinon.stub(command, 'error').throws(new Error('Expected error')); + + stubCdnClient(command, { + POST: async () => ({ + data: undefined, + error: {title: 'Bad Request', detail: 'Invalid path format'}, + }), + }); + + try { + await command.run(); + expect.fail('Should have thrown an error'); + } catch { + expect(errorStub.calledOnce).to.equal(true); + } + }); + }); +}); diff --git a/packages/b2c-cli/test/commands/ecdn/security/get.test.ts b/packages/b2c-cli/test/commands/ecdn/security/get.test.ts new file mode 100644 index 00000000..4efe9fe7 --- /dev/null +++ b/packages/b2c-cli/test/commands/ecdn/security/get.test.ts @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {expect} from 'chai'; +import {afterEach, beforeEach} from 'mocha'; +import sinon from 'sinon'; +import EcdnSecurityGet from '../../../../src/commands/ecdn/security/get.js'; +import {createIsolatedConfigHooks, createTestCommand} from '../../../helpers/test-setup.js'; + +/** + * Unit tests for eCDN security get command CLI logic. + * Tests output formatting and error handling. + */ +describe('ecdn security get', () => { + const hooks = createIsolatedConfigHooks(); + + beforeEach(hooks.beforeEach); + + afterEach(hooks.afterEach); + + async function createCommand(flags: Record = {}) { + return createTestCommand(EcdnSecurityGet, hooks.getConfig(), flags, {}); + } + + function stubCommon( + command: any, + {jsonEnabled = true, zoneId = 'zone-abc123'}: {jsonEnabled?: boolean; zoneId?: string} = {}, + ) { + sinon.stub(command, 'requireOAuthCredentials').returns(void 0); + sinon.stub(command, 'getOrganizationId').returns('f_ecom_zzxy_prd'); + sinon.stub(command, 'resolveZoneId').resolves(zoneId); + sinon.stub(command, 'resolvedConfig').get(() => ({values: {shortCode: 'kv7kzm78'}, warnings: [], sources: []})); + sinon.stub(command, 'jsonEnabled').returns(jsonEnabled); + sinon.stub(command, 'log').returns(void 0); + sinon.stub(command, 'warn').returns(void 0); + Object.defineProperty(command, 'logger', { + value: {info() {}, debug() {}, warn() {}, error() {}}, + configurable: true, + }); + } + + function stubCdnClient(command: any, client: Partial<{GET: any; POST: any; PUT: any; PATCH: any; DELETE: any}>) { + Object.defineProperty(command, '_cdnZonesClient', {value: client, configurable: true, writable: true}); + Object.defineProperty(command, '_cdnZonesRwClient', {value: client, configurable: true, writable: true}); + } + + describe('output formatting', () => { + it('returns security settings in JSON mode', async () => { + const command: any = await createCommand({'tenant-id': 'zzxy_prd', zone: 'my-zone'}); + stubCommon(command, {jsonEnabled: true}); + + stubCdnClient(command, { + GET: async () => ({ + data: { + data: { + securityLevel: 'medium', + alwaysUseHttps: true, + tls13Enabled: true, + wafEnabled: false, + hsts: { + enabled: true, + includeSubdomains: true, + maxAge: 31_536_000, + preload: false, + }, + }, + }, + }), + }); + + const result = await command.run(); + + expect(result).to.have.property('settings'); + expect(result.settings.securityLevel).to.equal('medium'); + expect(result.settings.alwaysUseHttps).to.be.true; + expect(result.settings.tls13Enabled).to.be.true; + expect(result.settings.wafEnabled).to.be.false; + expect(result.settings.hsts?.enabled).to.be.true; + expect(result.settings.hsts?.maxAge).to.equal(31_536_000); + }); + + it('returns data in non-JSON mode', async () => { + const command: any = await createCommand({'tenant-id': 'zzxy_prd', zone: 'my-zone'}); + stubCommon(command, {jsonEnabled: false}); + + stubCdnClient(command, { + GET: async () => ({ + data: { + data: { + securityLevel: 'high', + alwaysUseHttps: true, + tls13Enabled: true, + wafEnabled: true, + }, + }, + }), + }); + + const result = await command.run(); + + expect(result.settings.securityLevel).to.equal('high'); + expect(result.settings.wafEnabled).to.be.true; + }); + + it('handles settings without HSTS', async () => { + const command: any = await createCommand({'tenant-id': 'zzxy_prd', zone: 'my-zone'}); + stubCommon(command, {jsonEnabled: true}); + + stubCdnClient(command, { + GET: async () => ({ + data: { + data: { + securityLevel: 'low', + alwaysUseHttps: false, + tls13Enabled: false, + wafEnabled: false, + }, + }, + }), + }); + + const result = await command.run(); + + expect(result.settings.hsts).to.be.undefined; + }); + }); + + describe('error handling', () => { + it('errors on API failure', async () => { + const command: any = await createCommand({'tenant-id': 'zzxy_prd', zone: 'my-zone'}); + stubCommon(command, {jsonEnabled: true}); + + const errorStub = sinon.stub(command, 'error').throws(new Error('Expected error')); + + stubCdnClient(command, { + GET: async () => ({ + data: undefined, + error: {title: 'Not Found', detail: 'Zone not found'}, + }), + }); + + try { + await command.run(); + expect.fail('Should have thrown an error'); + } catch { + expect(errorStub.calledOnce).to.equal(true); + } + }); + + it('errors when no data returned', async () => { + const command: any = await createCommand({'tenant-id': 'zzxy_prd', zone: 'my-zone'}); + stubCommon(command, {jsonEnabled: true}); + + const errorStub = sinon.stub(command, 'error').throws(new Error('Expected error')); + + stubCdnClient(command, { + GET: async () => ({ + data: {data: undefined}, + }), + }); + + try { + await command.run(); + expect.fail('Should have thrown an error'); + } catch { + expect(errorStub.calledOnce).to.equal(true); + } + }); + }); +}); diff --git a/packages/b2c-cli/test/commands/ecdn/security/update.test.ts b/packages/b2c-cli/test/commands/ecdn/security/update.test.ts new file mode 100644 index 00000000..60d87356 --- /dev/null +++ b/packages/b2c-cli/test/commands/ecdn/security/update.test.ts @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {expect} from 'chai'; +import {afterEach, beforeEach} from 'mocha'; +import sinon from 'sinon'; +import EcdnSecurityUpdate from '../../../../src/commands/ecdn/security/update.js'; +import {createIsolatedConfigHooks, createTestCommand} from '../../../helpers/test-setup.js'; + +/** + * Unit tests for eCDN security update command CLI logic. + * Tests request body building, flag handling, and output formatting. + */ +describe('ecdn security update', () => { + const hooks = createIsolatedConfigHooks(); + + beforeEach(hooks.beforeEach); + + afterEach(hooks.afterEach); + + async function createCommand(flags: Record = {}) { + return createTestCommand(EcdnSecurityUpdate, hooks.getConfig(), flags, {}); + } + + function stubCommon( + command: any, + {jsonEnabled = true, zoneId = 'zone-abc123'}: {jsonEnabled?: boolean; zoneId?: string} = {}, + ) { + sinon.stub(command, 'requireOAuthCredentials').returns(void 0); + sinon.stub(command, 'getOrganizationId').returns('f_ecom_zzxy_prd'); + sinon.stub(command, 'resolveZoneId').resolves(zoneId); + sinon.stub(command, 'resolvedConfig').get(() => ({values: {shortCode: 'kv7kzm78'}, warnings: [], sources: []})); + sinon.stub(command, 'jsonEnabled').returns(jsonEnabled); + sinon.stub(command, 'log').returns(void 0); + sinon.stub(command, 'warn').returns(void 0); + Object.defineProperty(command, 'logger', { + value: {info() {}, debug() {}, warn() {}, error() {}}, + configurable: true, + }); + } + + function stubCdnClient(command: any, client: Partial<{GET: any; POST: any; PUT: any; PATCH: any; DELETE: any}>) { + Object.defineProperty(command, '_cdnZonesClient', {value: client, configurable: true, writable: true}); + Object.defineProperty(command, '_cdnZonesRwClient', {value: client, configurable: true, writable: true}); + } + + describe('request body building', () => { + it('builds request with security-level flag', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + 'security-level': 'high', + }); + stubCommon(command, {jsonEnabled: true}); + + let capturedBody: any; + stubCdnClient(command, { + async PATCH(_path: string, {body}: any) { + capturedBody = body; + return { + data: { + data: { + securityLevel: 'high', + alwaysUseHttps: false, + }, + }, + }; + }, + }); + + await command.run(); + + expect(capturedBody.securityLevel).to.equal('high'); + }); + + it('builds request with always-use-https flag', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + 'always-use-https': true, + }); + stubCommon(command, {jsonEnabled: true}); + + let capturedBody: any; + stubCdnClient(command, { + async PATCH(_path: string, {body}: any) { + capturedBody = body; + return { + data: { + data: { + alwaysUseHttps: true, + }, + }, + }; + }, + }); + + await command.run(); + + expect(capturedBody.alwaysUseHttps).to.be.true; + }); + + it('builds request with tls13 and waf flags', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + tls13: true, + waf: true, + }); + stubCommon(command, {jsonEnabled: true}); + + let capturedBody: any; + stubCdnClient(command, { + async PATCH(_path: string, {body}: any) { + capturedBody = body; + return { + data: { + data: { + tls13Enabled: true, + wafEnabled: true, + }, + }, + }; + }, + }); + + await command.run(); + + expect(capturedBody.tls13Enabled).to.be.true; + expect(capturedBody.wafEnabled).to.be.true; + }); + + it('builds HSTS settings when HSTS flags provided', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + 'hsts-enabled': true, + 'hsts-include-subdomains': true, + 'hsts-max-age': 31_536_000, + 'hsts-preload': true, + }); + stubCommon(command, {jsonEnabled: true}); + + let capturedBody: any; + stubCdnClient(command, { + async PATCH(_path: string, {body}: any) { + capturedBody = body; + return { + data: { + data: { + hsts: { + enabled: true, + includeSubdomains: true, + maxAge: 31_536_000, + preload: true, + }, + }, + }, + }; + }, + }); + + await command.run(); + + expect(capturedBody.hsts).to.deep.include({ + enabled: true, + includeSubdomains: true, + maxAge: 31_536_000, + preload: true, + }); + }); + + it('does not include HSTS when no HSTS flags provided', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + 'security-level': 'medium', + }); + stubCommon(command, {jsonEnabled: true}); + + let capturedBody: any; + stubCdnClient(command, { + async PATCH(_path: string, {body}: any) { + capturedBody = body; + return { + data: { + data: {securityLevel: 'medium'}, + }, + }; + }, + }); + + await command.run(); + + expect(capturedBody.hsts).to.be.undefined; + }); + + it('handles --no-always-use-https flag', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + 'always-use-https': false, + }); + stubCommon(command, {jsonEnabled: true}); + + let capturedBody: any; + stubCdnClient(command, { + async PATCH(_path: string, {body}: any) { + capturedBody = body; + return { + data: { + data: {alwaysUseHttps: false}, + }, + }; + }, + }); + + await command.run(); + + expect(capturedBody.alwaysUseHttps).to.be.false; + }); + }); + + describe('output formatting', () => { + it('returns updated settings in JSON mode', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + 'security-level': 'high', + tls13: true, + }); + stubCommon(command, {jsonEnabled: true}); + + stubCdnClient(command, { + PATCH: async () => ({ + data: { + data: { + securityLevel: 'high', + alwaysUseHttps: true, + tls13Enabled: true, + wafEnabled: true, + }, + }, + }), + }); + + const result = await command.run(); + + expect(result).to.have.property('settings'); + expect(result.settings.securityLevel).to.equal('high'); + expect(result.settings.tls13Enabled).to.be.true; + }); + }); + + describe('error handling', () => { + it('errors on API failure', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + 'security-level': 'high', + }); + stubCommon(command, {jsonEnabled: true}); + + const errorStub = sinon.stub(command, 'error').throws(new Error('Expected error')); + + stubCdnClient(command, { + PATCH: async () => ({ + data: undefined, + error: {title: 'Bad Request', detail: 'Invalid security level'}, + }), + }); + + try { + await command.run(); + expect.fail('Should have thrown an error'); + } catch { + expect(errorStub.calledOnce).to.equal(true); + } + }); + + it('errors when no data returned', async () => { + const command: any = await createCommand({ + 'tenant-id': 'zzxy_prd', + zone: 'my-zone', + 'security-level': 'high', + }); + stubCommon(command, {jsonEnabled: true}); + + const errorStub = sinon.stub(command, 'error').throws(new Error('Expected error')); + + stubCdnClient(command, { + PATCH: async () => ({ + data: {data: undefined}, + }), + }); + + try { + await command.run(); + expect.fail('Should have thrown an error'); + } catch { + expect(errorStub.calledOnce).to.equal(true); + } + }); + }); +}); diff --git a/packages/b2c-cli/test/commands/ecdn/zones/list.test.ts b/packages/b2c-cli/test/commands/ecdn/zones/list.test.ts new file mode 100644 index 00000000..381108d6 --- /dev/null +++ b/packages/b2c-cli/test/commands/ecdn/zones/list.test.ts @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {expect} from 'chai'; +import {afterEach, beforeEach} from 'mocha'; +import sinon from 'sinon'; +import EcdnZonesList from '../../../../src/commands/ecdn/zones/list.js'; +import {createIsolatedConfigHooks, createTestCommand} from '../../../helpers/test-setup.js'; + +/** + * Unit tests for eCDN zones list command CLI logic. + * Tests output formatting, column selection, and error handling. + */ +describe('ecdn zones list', () => { + const hooks = createIsolatedConfigHooks(); + + beforeEach(hooks.beforeEach); + + afterEach(hooks.afterEach); + + async function createCommand(flags: Record = {}) { + return createTestCommand(EcdnZonesList, hooks.getConfig(), flags, {}); + } + + function stubCommon(command: any, {jsonEnabled = true}: {jsonEnabled?: boolean} = {}) { + sinon.stub(command, 'requireOAuthCredentials').returns(void 0); + sinon.stub(command, 'getOrganizationId').returns('f_ecom_zzxy_prd'); + sinon.stub(command, 'resolvedConfig').get(() => ({values: {shortCode: 'kv7kzm78'}, warnings: [], sources: []})); + sinon.stub(command, 'jsonEnabled').returns(jsonEnabled); + sinon.stub(command, 'log').returns(void 0); + sinon.stub(command, 'warn').returns(void 0); + Object.defineProperty(command, 'logger', { + value: {info() {}, debug() {}, warn() {}, error() {}}, + configurable: true, + }); + } + + function stubCdnClient(command: any, client: Partial<{GET: any; POST: any; PUT: any; PATCH: any; DELETE: any}>) { + Object.defineProperty(command, '_cdnZonesClient', {value: client, configurable: true, writable: true}); + Object.defineProperty(command, '_cdnZonesRwClient', {value: client, configurable: true, writable: true}); + } + + describe('getSelectedColumns', () => { + it('returns default columns when no flags provided', async () => { + const command: any = await createCommand({}); + const columns = command.getSelectedColumns(); + + expect(columns).to.deep.equal(['name', 'status']); + }); + + it('returns all columns when --extended flag is set', async () => { + const command: any = await createCommand({extended: true}); + const columns = command.getSelectedColumns(); + + expect(columns).to.include('name'); + expect(columns).to.include('status'); + expect(columns).to.include('zoneId'); + }); + + it('returns custom columns when --columns flag is set', async () => { + const command: any = await createCommand({columns: 'zoneId,name'}); + const columns = command.getSelectedColumns(); + + expect(columns).to.deep.equal(['zoneId', 'name']); + }); + + it('ignores invalid column names', async () => { + const command: any = await createCommand({columns: 'name,invalidColumn,status'}); + const columns = command.getSelectedColumns(); + + expect(columns).to.not.include('invalidColumn'); + expect(columns).to.include('name'); + expect(columns).to.include('status'); + }); + }); + + describe('output formatting', () => { + it('returns zones in JSON mode', async () => { + const command: any = await createCommand({'tenant-id': 'zzxy_prd'}); + stubCommon(command, {jsonEnabled: true}); + + stubCdnClient(command, { + GET: async () => ({ + data: { + data: [ + {zoneId: 'zone1', name: 'my-zone', status: 'active'}, + {zoneId: 'zone2', name: 'another-zone', status: 'pending'}, + ], + }, + }), + }); + + const result = await command.run(); + + expect(result).to.have.property('zones'); + expect(result).to.have.property('total', 2); + expect(result.zones).to.have.lengthOf(2); + expect(result.zones[0].name).to.equal('my-zone'); + expect(result.zones[1].status).to.equal('pending'); + }); + + it('handles empty zones list', async () => { + const command: any = await createCommand({'tenant-id': 'zzxy_prd'}); + stubCommon(command, {jsonEnabled: true}); + + stubCdnClient(command, { + GET: async () => ({ + data: {data: []}, + }), + }); + + const result = await command.run(); + + expect(result.total).to.equal(0); + expect(result.zones).to.deep.equal([]); + }); + + it('returns data in non-JSON mode', async () => { + const command: any = await createCommand({'tenant-id': 'zzxy_prd'}); + stubCommon(command, {jsonEnabled: false}); + + stubCdnClient(command, { + GET: async () => ({ + data: { + data: [{zoneId: 'zone1', name: 'test-zone', status: 'active'}], + }, + }), + }); + + const result = await command.run(); + + expect(result).to.have.property('total', 1); + expect(result.zones).to.have.lengthOf(1); + expect(result.zones[0].name).to.equal('test-zone'); + }); + }); + + describe('error handling', () => { + it('errors on API failure', async () => { + const command: any = await createCommand({'tenant-id': 'zzxy_prd'}); + stubCommon(command, {jsonEnabled: true}); + + const errorStub = sinon.stub(command, 'error').throws(new Error('Expected error')); + + stubCdnClient(command, { + GET: async () => ({ + data: undefined, + error: {title: 'Not Found', detail: 'Organization not found'}, + }), + }); + + try { + await command.run(); + expect.fail('Should have thrown an error'); + } catch { + expect(errorStub.calledOnce).to.equal(true); + } + }); + + it('handles undefined data as empty list', async () => { + const command: any = await createCommand({'tenant-id': 'zzxy_prd'}); + stubCommon(command, {jsonEnabled: true}); + + stubCdnClient(command, { + GET: async () => ({ + data: {data: undefined as any}, + }), + }); + + const result = await command.run(); + + expect(result.total).to.equal(0); + expect(result.zones).to.deep.equal([]); + }); + }); +}); diff --git a/packages/b2c-tooling-sdk/package.json b/packages/b2c-tooling-sdk/package.json index f8cd6cb3..000535a6 100644 --- a/packages/b2c-tooling-sdk/package.json +++ b/packages/b2c-tooling-sdk/package.json @@ -232,7 +232,7 @@ "data" ], "scripts": { - "generate:types": "openapi-typescript specs/data-api.json -o src/clients/ocapi.generated.ts && openapi-typescript specs/slas-admin-v1.yaml -o src/clients/slas-admin.generated.ts && openapi-typescript specs/ods-api-v1.json -o src/clients/ods.generated.ts && openapi-typescript specs/mrt-api-v1.json -o src/clients/mrt.generated.ts && openapi-typescript specs/mrt-b2c.json -o src/clients/mrt-b2c.generated.ts && openapi-typescript specs/custom-apis-v1.yaml -o src/clients/custom-apis.generated.ts && openapi-typescript specs/scapi-schemas-v1.yaml -o src/clients/scapi-schemas.generated.ts", + "generate:types": "openapi-typescript specs/data-api.json -o src/clients/ocapi.generated.ts && openapi-typescript specs/slas-admin-v1.yaml -o src/clients/slas-admin.generated.ts && openapi-typescript specs/ods-api-v1.json -o src/clients/ods.generated.ts && openapi-typescript specs/mrt-api-v1.json -o src/clients/mrt.generated.ts && openapi-typescript specs/mrt-b2c.json -o src/clients/mrt-b2c.generated.ts && openapi-typescript specs/custom-apis-v1.yaml -o src/clients/custom-apis.generated.ts && openapi-typescript specs/scapi-schemas-v1.yaml -o src/clients/scapi-schemas.generated.ts && openapi-typescript specs/cdn-zones-v1.yaml -o src/clients/cdn-zones.generated.ts", "build": "pnpm run generate:types && pnpm run build:esm && pnpm run build:cjs", "build:esm": "tsc -p tsconfig.esm.json", "build:cjs": "tsc -p tsconfig.cjs.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json", diff --git a/packages/b2c-tooling-sdk/specs/cdn-zones-v1.yaml b/packages/b2c-tooling-sdk/specs/cdn-zones-v1.yaml new file mode 100644 index 00000000..3c90049b --- /dev/null +++ b/packages/b2c-tooling-sdk/specs/cdn-zones-v1.yaml @@ -0,0 +1,9324 @@ +openapi: 3.0.3 +info: + x-api-type: Admin + x-api-family: CDN + title: CDN Zones + version: 1.0.41 + description: |- + [Download API specification](https://developer.salesforce.com/static/commercecloud/commerce-api/cdn-api-process-apis/cdn-api-process-apis-oas-v1-public.yaml) + + # API Overview + + The Content Delivery Network (CDN) API is for managing the embedded CDN (eCDN) that is included with Commerce Cloud and configured with Business Manager. + + Use the API to: + + - Ensure that traffic doesn’t circumvent proxies layered in front of your eCDN. + - Accelerate the delivery of resources to users with caching, compression, and prioritization. + - Customize how users interact with resources and how requests are processed, including custom pages and routing rules. + - Provide proactive and complete application protection against new and existing exploits from bad actors. + + ## Authentication & Authorization + + For resource access, you must use a client ID and client secret from Account Manager to request an access token. The access token is used as a bearer token and added to the `Authorization` header of your API request. + + The API client must also have at least one of the following OAuth scopes: `sfcc.cdn-zones` or `sfcc.cdn-zones.rw`. + + For detailed setup instructions, see the [Authorization for Admin APIs](https://developer.salesforce.com/docs/commerce/commerce-api/guide/authorization-for-admin-apis.html) guide. + + You must include the relevant scope(s) in the client ID used to generate the token. For details, see the [Authorization Scopes Catalog.](https://developer.salesforce.com/docs/commerce/commerce-api/guide/auth-z-scope-catalog.html) + + ## Use Cases + + For detailed usage information, refer to the [CDN Zones Guides.](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones.html) +servers: + - url: https://{shortCode}.api.commercecloud.salesforce.com/cdn/zones/v1 + variables: + shortCode: + default: shortCode +paths: + /organizations/{organizationId}/storefront-zones: + post: + summary: Create a new storefront zone. + operationId: createStorefrontZone + description: | + Create a new storefront zone for the organization. Use this endpoint to set up a new CDN zone with specific configurations for storefront applications. + parameters: + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/StorefrontZoneCreateRequest' + examples: + StorefrontZoneCreateRequestBodyExample: + $ref: '#/components/examples/StorefrontZoneCreateRequestBodyExample' + required: true + responses: + '201': + description: Successfully created new storefront zone. + content: + application/json: + schema: + $ref: '#/components/schemas/StorefrontZoneCreateEnvelope' + examples: + StorefrontZoneCreateResponse: + $ref: '#/components/examples/StorefrontZoneCreateResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/mtls/code-upload-certificates: + get: + summary: Return all the mTLS certificates for the account. + operationId: getCodeUploadCertificates + description: | + Retrieve all mTLS certificates for the account. These certificates are used for secure code upload operations and client authentication. + parameters: + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully retrieved details of the mTLS certificates requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/MtlsCertificatesResponseEnvelope' + examples: + MtlsCodeUploadGetCertificatesResponse: + $ref: '#/components/examples/MtlsCodeUploadGetCertificatesResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + post: + summary: Set up two-factor mTLS certificates for the account and associate the staging zone code upload hostname. + operationId: createCodeUploadCertificate + description: | + Create a new mTLS certificate for code upload operations. This certificate enables secure client authentication for code deployment processes. + parameters: + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MtlsCertificateRequest' + examples: + MtlsCodeUploadPostCertificateRequestBodyExample: + $ref: '#/components/examples/MtlsCodeUploadPostCertificateRequestBodyExample' + required: true + responses: + '201': + description: Returns information about the uploaded mTLS certificate. + content: + application/json: + schema: + $ref: '#/components/schemas/MtlsCertificateResponseEnvelope' + examples: + MtlsCodeUploadGetCertificateResponse: + $ref: '#/components/examples/MtlsCodeUploadGetCertificateResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/mtls/code-upload-certificates/{mtlsCertificateId}: + get: + summary: Return the mTLS certificate for the given account's mTLS certificate ID. + operationId: getCodeUploadCertificate + description: | + Retrieve a specific mTLS certificate by its ID. This endpoint provides detailed information about the certificate's configuration, status, and associated hostname. + parameters: + - $ref: '#/components/parameters/mtlsCertificateId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully retrieved mTLS certificate information from the mTLS certificate ID requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/MtlsCertificateResponseEnvelope' + examples: + MtlsCodeUploadGetCertificateResponse: + $ref: '#/components/examples/MtlsCodeUploadGetCertificateResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + delete: + summary: Remove an mTLS certificate and associated hostname. + operationId: deleteCodeUploadCertificate + description: | + Permanently delete an mTLS certificate and its associated hostname from the account. This operation cannot be undone. + parameters: + - $ref: '#/components/parameters/mtlsCertificateId' + - $ref: '#/components/parameters/organizationId' + responses: + '204': + description: Successfully deleted the mTLS certificate from the account. + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/page-shield/notifications: + get: + summary: Get page shield notification webhooks. + description: | + See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + operationId: getPageShieldNotification + parameters: + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully retrieved notification webhooks. + content: + application/json: + schema: + $ref: '#/components/schemas/PageShieldNotificationWebhookListEnvelope' + examples: + PageShieldNotificationWebhookListResponse: + $ref: '#/components/examples/PageShieldNotificationWebhookListResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + post: + summary: Setup page shield notification webhook. + description: | + See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + operationId: postPageShieldNotification + parameters: + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PageShieldNotificationWebhookRequest' + examples: + PageShieldNotificationWebhookRequest: + $ref: '#/components/examples/PageShieldNotificationWebhookRequest' + required: true + responses: + '200': + description: Successfully added notification webhook. + content: + application/json: + schema: + $ref: '#/components/schemas/PageShieldNotificationWebhookEnvelope' + examples: + PageShieldNotificationWebhookResponse: + $ref: '#/components/examples/PageShieldNotificationWebhookResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/page-shield/notifications/{webhookId}: + delete: + summary: Delete page shield notification webhook. + description: | + See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + operationId: deletePageShieldNotification + parameters: + - $ref: '#/components/parameters/webhookId' + - $ref: '#/components/parameters/organizationId' + responses: + '204': + description: Successfully deleted notification webhook. + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/page-shield/policies: + get: + summary: List page shield policies. + description: | + See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + operationId: getPageShieldPolicies + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: List current page shield policies. + content: + application/json: + schema: + $ref: '#/components/schemas/PageShieldPoliciesListEnvelope' + examples: + PageShieldPoliciesGetResponse: + $ref: '#/components/examples/PageShieldPoliciesGetResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + post: + summary: Create page shield policy. + description: | + See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + operationId: createPageShieldPolicy + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PageShieldPolicyRequest' + examples: + PageShieldPolicyRequestBodyExample: + $ref: '#/components/examples/PageShieldPolicyRequestBodyExample' + required: true + responses: + '200': + description: Successfully created page shield policy. + content: + application/json: + schema: + $ref: '#/components/schemas/PageShieldPoliciesEnvelope' + examples: + PageShieldPolicyGetResponse: + $ref: '#/components/examples/PageShieldPolicyGetResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/page-shield/policies/{policyId}: + get: + summary: Get page shield policy by policy ID. + description: | + See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + operationId: getPageShieldPolicy + parameters: + - $ref: '#/components/parameters/policyId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully retrieved the details of the page shield policy. + content: + application/json: + schema: + $ref: '#/components/schemas/PageShieldPoliciesEnvelope' + examples: + PageShieldPolicyGetResponse: + $ref: '#/components/examples/PageShieldPolicyGetResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + put: + summary: Update page shield policy by policy ID. + description: | + See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + operationId: updatePageShieldPolicy + parameters: + - $ref: '#/components/parameters/policyId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/PageShieldPolicyRequest' + examples: + PageShieldPolicyPutRequestBodyExample: + $ref: '#/components/examples/PageShieldPolicyPutRequestBodyExample' + required: true + responses: + '200': + description: Successfully updated the page shield policy. + content: + application/json: + schema: + $ref: '#/components/schemas/PageShieldPoliciesEnvelope' + examples: + PageShieldPoliciesEnvelope: + $ref: '#/components/examples/PageShieldPolicyPutResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + delete: + summary: Delete page shield policy. + description: | + See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + operationId: deletePageShieldPolicy + parameters: + - $ref: '#/components/parameters/policyId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '204': + description: Successfully deleted the page shield policy. + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/page-shield/scripts: + get: + summary: Retrieve a list of scripts detected by page shield for a specific zone. + description: | + See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + operationId: getPageShieldScripts + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/direction' + - $ref: '#/components/parameters/excludeCdnCgi' + - $ref: '#/components/parameters/excludeDuplicates' + - $ref: '#/components/parameters/excludeUrls' + - $ref: '#/components/parameters/hosts' + - $ref: '#/components/parameters/orderBy' + - $ref: '#/components/parameters/pageUrl' + - $ref: '#/components/parameters/prioritizeMalicious' + - $ref: '#/components/parameters/status' + - $ref: '#/components/parameters/urls' + - name: limit + in: query + required: false + schema: + type: integer + format: int32 + default: 200 + maximum: 200 + description: Maximum records to retrieve per request, not to exceed 200. Defaults to 200. + - name: offset + in: query + required: false + schema: + type: integer + format: int32 + default: 0 + minimum: 0 + description: Used to retrieve the results based on a particular resource offset. + responses: + '200': + description: List current page shield scripts. + content: + application/json: + schema: + $ref: '#/components/schemas/PageShieldScriptListEnvelope' + examples: + PageShieldScriptListResponse: + $ref: '#/components/examples/PageShieldScriptListResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/page-shield/scripts/{scriptId}: + get: + summary: Fetch a script detected by Page Shield by script ID. + description: | + See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + operationId: getPageShieldScript + parameters: + - $ref: '#/components/parameters/scriptId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: A script detected by Page Shield by script ID. + content: + application/json: + schema: + $ref: '#/components/schemas/PageShieldScriptEnvelope' + examples: + PageShieldScriptResponse: + $ref: '#/components/examples/PageShieldScriptResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/info: + get: + summary: Retrieve zone information. + operationId: getZonesInfo + description: | + Retrieve information about all zones for the organization. This endpoint provides an overview of all CDN zones, including their status, configuration, and basic details. + parameters: + - $ref: '#/components/parameters/organizationId' + - name: limit + in: query + required: false + schema: + type: integer + format: int32 + default: 25 + maximum: 50 + description: Maximum records to retrieve per request, not to exceed 50. Defaults to 25. + - name: offset + in: query + required: false + schema: + type: integer + format: int32 + default: 0 + minimum: 0 + description: Used to retrieve the results based on a particular resource offset. + responses: + '200': + description: Successfully retrieved zone information requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/ZonesEnvelope' + examples: + ZonesGetResponse: + $ref: '#/components/examples/ZonesGetResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/waf/groups: + get: + summary: Retrieve all WAF groups accessible to the caller. + description: | + Retrieve all Web Application Firewall (WAF) groups accessible to the caller. This endpoint provides information about WAF groups and their configurations for the specified zone. Not applicable for zones using WAFv2. For zones created after the 24.5 release, use the endpoints for WAF managed rulesets. + operationId: getWafGroups + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully retrieved details of WAF groups to which the caller has access. + content: + application/json: + schema: + $ref: '#/components/schemas/WafGroupsEnvelope' + examples: + WafGroupsGetResponse: + $ref: '#/components/examples/WafGroupsGetResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/waf/groups/{groupId}: + put: + summary: Update the action or mode of a specific WAF group. + description: | + Update the action or mode of a specific Web Application Firewall (WAF) group. Use this endpoint to modify the security settings and behavior of a WAF group. Not applicable for zones using WAFv2. For any zones created after the 24.5 release, use the endpoints for WAF managed rulesets. + operationId: updateWafGroup + parameters: + - $ref: '#/components/parameters/groupIdPath' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/WafGroup' + examples: + WafGroupPutRequestBodyExample: + $ref: '#/components/examples/WafGroupPutRequestBodyExample' + required: true + responses: + '200': + description: Successfully updated the WAF group specified by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/WafGroupEnvelope' + examples: + WafGroupPutResponse: + $ref: '#/components/examples/WafGroupPutResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/waf/rules: + get: + summary: Retrieve WAF rules for the WAF group specified by the caller. + description: | + Retrieve WAF rules for the WAF group specified by the caller. This endpoint provides information about the security rules configured for a specific WAF group. Not applicable for zones using WAFv2. For any zones created after the 24.5 release, use the endpoints for WAF managed rulesets. + operationId: getWafRules + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + - $ref: '#/components/parameters/groupIdQuery' + responses: + '200': + description: Successfully retrieved the WAF rules requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/WafRulesEnvelope' + examples: + WafGroupPutResponse: + $ref: '#/components/examples/WafRulesGetResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/waf/rules/{ruleId}: + get: + summary: Retrieve details of a specific WAF rule. + description: | + Retrieve details of a specific WAF rule by its ID. This endpoint provides comprehensive information about the rule's configuration and settings. Not applicable for zones using WAFv2. For any zones created after the 24.5 release, use the endpoints for WAF managed rulesets. + operationId: getWafRule + parameters: + - $ref: '#/components/parameters/ruleId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully retrieved details of the WAF rule requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/WafRuleEnvelope' + examples: + WafRuleGetResponse: + $ref: '#/components/examples/WafRuleGetResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + put: + summary: Update the action of a specific WAF rule. + description: | + Update the action of a specific WAF rule. Use this endpoint to modify the security behavior and response actions of a WAF rule. Not applicable for zones using WAFv2. For any zones created after the 24.5 release, use the endpoints for WAF managed rulesets. + operationId: updateWafRule + parameters: + - $ref: '#/components/parameters/ruleId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/WafRule' + examples: + WafRulePutRequestBodyExample: + $ref: '#/components/examples/WafRulePutRequestBodyExample' + required: true + responses: + '200': + description: Successfully updated the WAF rule specified by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/WafRuleEnvelope' + examples: + WafRulePutResponse: + $ref: '#/components/examples/WafRulePutResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/speed-settings: + get: + summary: Retrieve the speed settings for a zone. + operationId: getSpeedSettings + description: | + Retrieve speed settings for the specified zone. This endpoint provides information about performance optimizations. + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully returned the speed settings requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/SpeedSettingsEnvelope' + examples: + SpeedSettingsResponse: + $ref: '#/components/examples/SpeedSettingsResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + patch: + summary: Update the speed settings for a zone. + operationId: updateSpeedSettings + description: | + Update speed settings for the specified zone. Use this endpoint to modify performance optimizations. + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SpeedSetting' + examples: + SpeedSettingsPatchRequestBodyExample: + $ref: '#/components/examples/SpeedSettingsPatchRequestBodyExample' + required: true + responses: + '200': + description: Successfully updated the speed settings requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/SpeedSettingsEnvelope' + examples: + SpeedSettingsResponse: + $ref: '#/components/examples/SpeedSettingsResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/security-settings: + get: + summary: Retrieve the security settings for a zone. + operationId: getSecuritySettings + description: | + Retrieve security settings for the specified zone. This endpoint provides information about security configurations and protection settings. + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully returned security settings for zone. + content: + application/json: + schema: + $ref: '#/components/schemas/SecuritySettingsEnvelope' + examples: + SecuritySettingsResponse: + $ref: '#/components/examples/SecuritySettingsResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + patch: + summary: Update the security settings for a zone. + operationId: updateSecuritySettings + description: | + Update security settings for the specified zone. Use this endpoint to modify security configurations and protection settings. + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/SecuritySetting' + examples: + SecuritySettingsUpdateRequestBodyExample: + $ref: '#/components/examples/SecuritySettingsUpdateRequestBodyExample' + required: true + responses: + '200': + description: Successfully updated the security settings. + content: + application/json: + schema: + $ref: '#/components/schemas/SecuritySettingsEnvelope' + examples: + SecuritySettingsResponse: + $ref: '#/components/examples/SecuritySettingsResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/cachepurge: + post: + summary: Purge the cache for the host specified in the request body. + operationId: cachePurge + description: | + Purge cache for the specified zone. Use this endpoint to clear cached content and force fresh content to be fetched from origin servers. Unlike storefronts, SCAPI only uses server-side web tier caching, and eCDN edge caching is not at all applicable to SCAPI. + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CachePurgeRequest' + examples: + CachePurgeRequest: + $ref: '#/components/examples/CachePurgeRequest' + required: true + responses: + '200': + description: Successfully returned the complete operationId statuses for the rule list operations that the server processed. + content: + application/json: + schema: + $ref: '#/components/schemas/CachePurgeResponseEnvelope' + examples: + CachePurgeResponse: + $ref: '#/components/examples/CachePurgeResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/ocapicachingpagerule: + patch: + summary: Enable or disable the OCAPI Caching page rule. + description: | + Use this endpoint to toggle the caching behavior for caching requests. + operationId: toggleOcapiCachingPageRule + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/OCAPICachingToggleRequest' + examples: + CachingToggleRequest: + $ref: '#/components/examples/CachingToggleRequest' + required: true + responses: + '200': + description: Successfully returned the current state of the Caching page rule. + content: + application/json: + schema: + $ref: '#/components/schemas/OCAPICachingToggleRequest' + examples: + CachingToggleResponse: + $ref: '#/components/examples/CachingToggleResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/certificates: + get: + summary: List certificates for a zone. + description: | + For information on automatic certificates, see [eCDN Automatic Certificates](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-automatic-certs.html). + operationId: getCertificates + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + - name: limit + in: query + required: false + schema: + type: integer + format: int32 + default: 25 + maximum: 50 + description: Maximum records to retrieve per request, not to exceed 50. Defaults to 25. + - name: offset + in: query + required: false + schema: + type: integer + format: int32 + default: 0 + minimum: 0 + description: Used to retrieve the results based on a particular resource offset. + responses: + '200': + description: Successfully retrieved the list of certificates for the specified zone. + content: + application/json: + schema: + $ref: '#/components/schemas/CertificatesEnvelope' + examples: + CertificatesGetResponse1: + $ref: '#/components/examples/CertificatesGetResponse1' + CertificatesGetResponse2: + $ref: '#/components/examples/CertificatesGetResponse2' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + post: + summary: Add certificate for a zone. + description: | + For information on automatic certificates, see [eCDN Automatic Certificates](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-automatic-certs.html). + operationId: addCertificateForZone + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CertificateRequest' + examples: + CertificatePostRequestBodyExample: + $ref: '#/components/examples/CertificatePostRequestBodyExample' + required: true + responses: + '201': + description: Returned information about the added certificate. + content: + application/json: + schema: + $ref: '#/components/schemas/CertificateEnvelope' + examples: + CertificatePostResponse1: + $ref: '#/components/examples/CertificatePostResponse1' + CertificatePostResponse2: + $ref: '#/components/examples/CertificatePostResponse2' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '409': + description: | + The request sent by the caller has conflicts. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Conflict: + $ref: '#/components/examples/Conflict' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/certificates/{certificateId}: + delete: + summary: Delete a custom hostname and the certificate associated with it. Note that a valid certificate is necessary for a site to remain operational. DELETING A CERTIFICATE THAT IS IN USE CAN RESULT IN DOWNTIME. + description: | + This operation removes both the custom hostname configuration and the associated SSL certificate. + operationId: deleteCertificate + parameters: + - $ref: '#/components/parameters/certificateId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '204': + description: Successfully deleted the custom hostname and the certificate associated with it. + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + patch: + summary: Update the certificate for a given certificateId for a particular zone. + description: | + For information on automatic certificates, see [eCDN Automatic Certificates](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-automatic-certs.html). + operationId: updateCertificate + parameters: + - $ref: '#/components/parameters/certificateId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CertificateRequest' + examples: + CertificateUpdateRequestBodyExample: + $ref: '#/components/examples/CertificateUpdateRequestBodyExample' + required: true + responses: + '200': + description: Successfully updated the certificate requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/CertificateEnvelope' + examples: + CertificateUpdateResponse1: + $ref: '#/components/examples/CertificateUpdateResponse1' + CertificateUpdateResponse2: + $ref: '#/components/examples/CertificateUpdateResponse2' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/certificates/custom-hostnames/{customHostnameId}: + patch: + summary: Trigger the validation of a custom hostname. + operationId: validateCustomHostname + description: | + This endpoint initiates the DNS validation process for custom hostnames associated with the zone. + parameters: + - $ref: '#/components/parameters/customHostnameId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully triggered the custom hostname validation process. + content: + application/json: + schema: + $ref: '#/components/schemas/CustomHostnameValidationEnvelope' + examples: + CustomHostnamesPatchResponse: + $ref: '#/components/examples/CustomHostnamesPatchResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/mrtrules: + get: + summary: Get all MRT rules. + description: | + See [eCDN Rules for Hybrid Implementations](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/ecdn-rules-for-phased-headless-rollout.html). + operationId: getMrtRules + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully retrieved all MRT rules. + content: + application/json: + schema: + $ref: '#/components/schemas/MRTRulesResponseEnvelope' + examples: + MrtRulesGetResponse: + $ref: '#/components/examples/MrtRulesGetResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + post: + summary: Create MRT rules to route to a new MRT environment. + description: | + See [eCDN Rules for Hybrid Implementations](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/ecdn-rules-for-phased-headless-rollout.html). + operationId: createMrtRules + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MRTRulesPostRequest' + examples: + MrtRulesPostRequestSingleHostnameBodyExample: + $ref: '#/components/examples/MrtRulesPostRequestSingleHostnameBodyExample' + MrtRulesPostRequestMultipleHostnamesBodyExample: + $ref: '#/components/examples/MrtRulesPostRequestMultipleHostnamesBodyExample' + required: true + responses: + '201': + description: Created MRT rules to route to a new MRT environment. + content: + application/json: + schema: + $ref: '#/components/schemas/MRTRulesResponseEnvelope' + examples: + MrtRulesPostResponseSingleHostname: + $ref: '#/components/examples/MrtRulesPostResponseSingleHostname' + MrtRulesPostResponseMultipleHostnames: + $ref: '#/components/examples/MrtRulesPostResponseMultipleHostnames' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + patch: + summary: Update the MRT environment hostname or add MRT rules to route to an existing MRT environment. + description: | + See [eCDN Rules for Hybrid Implementations](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/ecdn-rules-for-phased-headless-rollout.html). + operationId: updateMrtRuleset + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MRTRulesetPatchRequest' + examples: + MrtRulesetPatchRequestUpdateHostnameBodyExample: + $ref: '#/components/examples/MrtRulesetPatchRequestUpdateHostnameBodyExample' + MrtRulesetPatchRequestAddRulesBodyExample: + $ref: '#/components/examples/MrtRulesetPatchRequestAddRulesBodyExample' + required: true + responses: + '200': + description: Updated the MRT environment hostname or added MRT rules to route to an existing MRT environment. + content: + application/json: + schema: + $ref: '#/components/schemas/MRTRulesResponseEnvelope' + examples: + MrtRulesetPatchResponseUpdateHostname: + $ref: '#/components/examples/MrtRulesetPatchResponseUpdateHostname' + MrtRulesetPatchResponseAddRules: + $ref: '#/components/examples/MrtRulesetPatchResponseAddRules' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/mrtrules/{rulesetId}: + delete: + summary: Delete the MRT ruleset and all rules within the ruleset. + description: | + See [eCDN Rules for Hybrid Implementations](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/ecdn-rules-for-phased-headless-rollout.html). + operationId: deleteMrtRuleset + parameters: + - $ref: '#/components/parameters/rulesetId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '204': + description: Deleted the MRT ruleset and all rules within the ruleset. + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/mrtrules/{rulesetId}/rules/{ruleId}: + delete: + summary: Delete an MRT rule. + description: | + See [eCDN Rules for Hybrid Implementations](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/ecdn-rules-for-phased-headless-rollout.html). + operationId: deleteMrtRule + parameters: + - $ref: '#/components/parameters/ruleId' + - $ref: '#/components/parameters/rulesetId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '204': + description: Deleted an MRT rule. + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + patch: + summary: Update an MRT rule. + description: | + See [eCDN Rules for Hybrid Implementations](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/ecdn-rules-for-phased-headless-rollout.html). + operationId: updateMrtRule + parameters: + - $ref: '#/components/parameters/ruleId' + - $ref: '#/components/parameters/rulesetId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/MRTRulePatchRequest' + examples: + MrtRulePatchRequestBodyExample: + $ref: '#/components/examples/MrtRulePatchRequestBodyExample' + required: true + responses: + '200': + description: Successfully updated the MRT rule. + content: + application/json: + schema: + $ref: '#/components/schemas/MRTRulesResponseEnvelope' + examples: + MrtRulePatchResponse: + $ref: '#/components/examples/MrtRulePatchResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/logpush/ownership: + post: + summary: Create Logpush ownership token file. + description: | + See [eCDN Logpush](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-logpush.html). + operationId: createLogpushOwnership + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/LogpushOwnershipPostRequest' + examples: + LogpushOwnershipPostRequestBodyExample: + $ref: '#/components/examples/LogpushOwnershipPostRequestBodyExample' + required: true + responses: + '201': + description: Created a new Logpush Ownership token. + content: + application/json: + schema: + $ref: '#/components/schemas/LogpushOwnershipPostResponse' + examples: + LogpushOwnershipPostResponse: + $ref: '#/components/examples/LogpushOwnershipPostResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/logpush/jobs: + get: + summary: List Logpush job. + description: | + See [eCDN Logpush](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-logpush.html). + operationId: listLogpushJob + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Returned all jobs with details for the zone. + content: + application/json: + schema: + $ref: '#/components/schemas/LogpushJobsEnvelope' + examples: + LogpushGetListJob: + $ref: '#/components/examples/LogpushGetListJob' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + post: + summary: Create Logpush job. + description: | + See [eCDN Logpush](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-logpush.html). + operationId: createLogpushJob + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/LogpushCreateRequest' + examples: + LogpushCreateRequestBodyExample1: + $ref: '#/components/examples/LogpushCreateRequestBodyExample1' + LogpushCreateRequestBodyExample2: + $ref: '#/components/examples/LogpushCreateRequestBodyExample2' + LogpushCreateRequestBodyExample3: + $ref: '#/components/examples/LogpushCreateRequestBodyExample3' + required: true + responses: + '201': + description: Successfully created the Logpush job and returned the job details. + content: + application/json: + schema: + $ref: '#/components/schemas/LogpushEnvelope' + examples: + LogpushCreateResponse1: + $ref: '#/components/examples/LogpushCreateResponse1' + LogpushCreateResponse2: + $ref: '#/components/examples/LogpushCreateResponse2' + LogpushCreateResponse3: + $ref: '#/components/examples/LogpushCreateResponse3' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to therequested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/logpush/jobs/{jobId}: + get: + summary: Get Logpush job details. + description: | + See [eCDN Logpush](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-logpush.html). + operationId: getLogpushJob + parameters: + - $ref: '#/components/parameters/jobId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Returned job details for the specified Logpush job ID. + content: + application/json: + schema: + $ref: '#/components/schemas/LogpushEnvelope' + examples: + LogpushGetJobById1: + $ref: '#/components/examples/LogpushGetJobById1' + LogpushGetJobById2: + $ref: '#/components/examples/LogpushGetJobById2' + LogpushGetJobById3: + $ref: '#/components/examples/LogpushGetJobById3' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + put: + summary: Update Logpush job. + description: | + See [eCDN Logpush](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-logpush.html). + operationId: updateLogpushJob + parameters: + - $ref: '#/components/parameters/jobId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/LogpushUpdateRequest' + examples: + LogpushUpdateRequestBodyExample: + $ref: '#/components/examples/LogpushUpdateRequestBodyExample' + required: true + responses: + '200': + description: Successfully enabled or disabled the Logpush job and returned job details. + content: + application/json: + schema: + $ref: '#/components/schemas/LogpushEnvelope' + examples: + LogpushUpdateResponse: + $ref: '#/components/examples/LogpushUpdateResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + delete: + summary: Delete Logpush job by job ID. + description: | + See [eCDN Logpush](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-logpush.html). + operationId: deleteLogpushJob + parameters: + - $ref: '#/components/parameters/jobId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '204': + description: Deleted the Logpush job for the specified job ID. + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/firewall/waf/packages/owasp: + get: + summary: Get a OWASP ModSecurity Core Rule Set. + operationId: getOwaspWafPackage + description: | + Retrieve OWASP WAF package information for the specified zone. This endpoint provides details about the OWASP security rules and configurations. + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully retrieved the OWASP ModSecurity Core Rule Set. + content: + application/json: + schema: + $ref: '#/components/schemas/WAFRulePackageEnvelope' + examples: + WafPackagesGetExample: + $ref: '#/components/examples/WafPackagesGetExample' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + patch: + summary: Patch a OWASP ModSecurity Core Rule Set. + operationId: patchOwaspWafPackage + description: | + Update OWASP WAF package settings for the specified zone. Use this endpoint to modify OWASP security rule configurations. + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/WafPackagePatchRequest' + examples: + WafPackagesPatchRequestBodyExample: + $ref: '#/components/examples/WafPackagesPatchRequestBodyExample' + required: true + responses: + '200': + description: Successfully patched the OWASP ModSecurity Core Rule Set. + content: + application/json: + schema: + $ref: '#/components/schemas/WAFRulePackageEnvelope' + examples: + WafPackagesGetExample: + $ref: '#/components/examples/WafPackagesGetExample' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/firewall-custom/rules: + get: + summary: Retrieve existing custom rules. + description: | + Retrieve existing custom rules. See [eCDN Custom Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-custom-rules.html). + operationId: getCustomRules + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + - name: limit + in: query + required: false + schema: + type: integer + format: int32 + default: 25 + maximum: 50 + description: Maximum records to retrieve per request, not to exceed 50. Defaults to 25. + - name: offset + in: query + required: false + schema: + type: integer + format: int32 + default: 0 + minimum: 0 + description: Used to retrieve the results based on a particular resource offset. + responses: + '200': + description: Successfully returned the list of custom rules requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/CustomRulesEnvelope' + examples: + CustomRulesResponse: + $ref: '#/components/examples/CustomRulesResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + post: + summary: Create a custom rule. + description: | + See [eCDN Custom Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-custom-rules.html). + operationId: createCustomRule + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CustomRulesPostRequest' + examples: + CustomRulesPostRequestBodyExample: + $ref: '#/components/examples/CustomRulesPostRequestBodyExample' + required: true + responses: + '201': + description: Successfully created the custom rule requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/CustomRuleEnvelope' + examples: + CustomRuleResponse: + $ref: '#/components/examples/CustomRuleResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + patch: + summary: Update the order of all existing custom rules. + description: | + See [eCDN Custom Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-custom-rules.html). + operationId: updateOrderOfCustomRules + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CustomRulesPatchOrderRequest' + examples: + CustomRulesPatchOrderRequest: + $ref: '#/components/examples/CustomRulesPatchOrderRequest' + required: true + responses: + '200': + description: Successfully updated the order of existing custom rules as requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/CustomRulesEnvelope' + examples: + CustomRulesResponse: + $ref: '#/components/examples/CustomRulesResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/firewall-custom/rules/{ruleId}: + get: + summary: Retrieve a specific custom rule. + description: | + See [eCDN Custom Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-custom-rules.html). + operationId: getCustomRule + parameters: + - $ref: '#/components/parameters/ruleId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully returned the custom rule requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/CustomRuleEnvelope' + examples: + CustomRuleResponse: + $ref: '#/components/examples/CustomRuleResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + delete: + summary: Delete a specific custom rule. + description: | + See [eCDN Custom Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-custom-rules.html). + operationId: deleteCustomRule + parameters: + - $ref: '#/components/parameters/ruleId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '204': + description: Successfully deleted the custom rule requested by the caller. + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + patch: + summary: Update a specific custom rule. + description: | + See [eCDN Custom Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-custom-rules.html). + operationId: updateCustomRule + parameters: + - $ref: '#/components/parameters/ruleId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CustomRulesPatchRequest' + examples: + CustomRulesPatchRequest: + $ref: '#/components/examples/CustomRulesPatchRequest' + required: true + responses: + '200': + description: Successfully updated the custom rule requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/CustomRuleEnvelope' + examples: + CustomRuleResponse: + $ref: '#/components/examples/CustomRuleResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/rate-limiting/rules: + get: + summary: Retrieve existing rate limiting rules. + description: | + See [eCDN Rate Limiting Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-rate-limiting-rules.html). + operationId: getRateLimitingRules + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully returned the list of rate limiting rules requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/RateLimitingRulesEnvelope' + examples: + RateLimitingRulesResponse: + $ref: '#/components/examples/RateLimitingRulesResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + post: + summary: Create a rate limiting rule. + description: | + See [eCDN Rate Limiting Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-rate-limiting-rules.html). + operationId: createRateLimitingRule + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RateLimitingRulesPostRequest' + examples: + RateLimitingRulesPostRequestBodyExample: + $ref: '#/components/examples/RateLimitingRulesPostRequestBodyExample' + required: true + responses: + '201': + description: Successfully created the rate limiting rule requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/RateLimitingRuleEnvelope' + examples: + RateLimitingRuleResponse: + $ref: '#/components/examples/RateLimitingRuleResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/rate-limiting/rules/{ruleId}: + get: + summary: Retrieve a specific rate limiting rule. + description: | + See [eCDN Rate Limiting Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-rate-limiting-rules.html). + operationId: getRateLimitingRule + parameters: + - $ref: '#/components/parameters/ruleId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully returned the rate limiting rule requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/RateLimitingRuleEnvelope' + examples: + RateLimitingRuleResponse: + $ref: '#/components/examples/RateLimitingRuleResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + delete: + summary: Delete a specific rate limiting rule. + description: | + See [eCDN Rate Limiting Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-rate-limiting-rules.html). + operationId: deleteRateLimitingRule + parameters: + - $ref: '#/components/parameters/ruleId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '204': + description: Successfully deleted the rate limiting rule requested by the caller. + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + patch: + summary: Update a specific rate limiting rule. + description: | + See [eCDN Rate Limiting Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-rate-limiting-rules.html). + operationId: updateRateLimitingRule + parameters: + - $ref: '#/components/parameters/ruleId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RateLimitingRulesPatchRequest' + examples: + RateLimitingRulesPatchRequest: + $ref: '#/components/examples/RateLimitingRulesPatchRequest' + required: true + responses: + '200': + description: Successfully updated the rate limiting rule requested by the caller. + content: + application/json: + schema: + $ref: '#/components/schemas/RateLimitingRuleEnvelope' + examples: + RateLimitingRuleResponse: + $ref: '#/components/examples/RateLimitingRuleResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/firewall-managed/rulesets: + get: + summary: Retrieve WAFv2 managed rulesets. + description: | + See [eCDN WAFv2](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-wafv2.html). + operationId: getWafManagedRulesets + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully returned the list of WAFv2 managed rulesets. + content: + application/json: + schema: + $ref: '#/components/schemas/WAFManagedRulesetsEnvelope' + examples: + WAFManagedRulesetsResponse: + $ref: '#/components/examples/WAFManagedRulesetsResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/firewall-managed/rulesets/{rulesetId}: + patch: + summary: Update WAFv2 managed ruleset. + description: | + See [eCDN WAFv2](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-wafv2.html). + operationId: updateWafManagedRuleset + parameters: + - $ref: '#/components/parameters/rulesetId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/WAFManagedRulesetRequest' + examples: + WAFManagedRulesetsUpdateRequestBodyExample: + $ref: '#/components/examples/WAFManagedRulesetsUpdateRequestBodyExample' + required: true + responses: + '200': + description: Successfully updated the WAFv2 managed rulesets. + content: + application/json: + schema: + $ref: '#/components/schemas/WAFManagedRulesetEnvelope' + examples: + WAFManagedRulesetsUpdateResponse: + $ref: '#/components/examples/WAFManagedRulesetsUpdateResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/firewall-managed/rulesets/{rulesetId}/rules: + get: + summary: Retrieve all rules in the specified WAFv2 managed ruleset. + description: | + See [eCDN WAFv2](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-wafv2.html). + operationId: getWafManagedRulesInRuleset + parameters: + - $ref: '#/components/parameters/rulesetId' + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully returned the rules in the WAFv2 managed ruleset. + content: + application/json: + schema: + $ref: '#/components/schemas/WAFManagedRulesEnvelope' + examples: + WAFManagedRulesResponse: + $ref: '#/components/examples/WAFManagedRulesResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/firewall-managed/rulesets/{rulesetId}/rules/{ruleId}: + patch: + summary: Update a WAF managed rule in the specified WAFv2 managed ruleset. + description: | + See [eCDN WAFv2](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-wafv2.html). + operationId: updateWafManagedRuleInRuleset + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/rulesetId' + - $ref: '#/components/parameters/ruleId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/WAFManagedRuleRequest' + examples: + WAFManagedRulesUpdateRequestBodyExample: + $ref: '#/components/examples/WAFManagedRulesUpdateRequestBodyExample' + required: true + responses: + '200': + description: Successfully updated the WAF managed rule in the specified WAFv2 managed ruleset. + content: + application/json: + schema: + $ref: '#/components/schemas/WAFManagedRuleEnvelope' + examples: + WAFManagedRulesUpdateResponse: + $ref: '#/components/examples/WAFManagedRulesUpdateResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/firewall-managed/migration: + put: + summary: Migrate a zone to WAFv2. Only applicable for existing zones using WAFv1. + description: | + See [eCDN WAFv2](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-wafv2.html). + operationId: migrateZoneToWafV2 + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully migrated the zone to WAFv2 and returned the WAF managed rulesets. + content: + application/json: + schema: + $ref: '#/components/schemas/WAFManagedRulesetsEnvelope' + examples: + WAFManagedRulesetsResponse: + $ref: '#/components/examples/WAFManagedRulesetsResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/origin-header-modification/{type}: + get: + summary: Get the origin header modification associated with a zone. Only the `mrt` type is supported. + operationId: getOriginHeaderModification + description: | + Retrieve origin header modification settings for the specified zone. This endpoint provides information about how headers are modified when forwarding requests to origin servers. + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/type' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Successfully returned the origin header modification associated with a zone. + content: + application/json: + schema: + $ref: '#/components/schemas/OriginHeaderModificationEnvelope' + examples: + MrtPutRequest: + $ref: '#/components/examples/MrtGetResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + put: + summary: Upsert an origin header modification. Only the `mrt` type is supported. + operationId: upsertOriginHeaderModification + description: | + Create or update origin header modification settings for the specified zone. Use this endpoint to configure how headers are modified when forwarding requests to origin servers. + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/type' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/OriginHeaderModificationPutRequest' + examples: + MrtPutRequestBodyExample: + $ref: '#/components/examples/MrtPutRequestBodyExample' + required: true + responses: + '200': + description: Successfully upserted the origin header modification. + content: + application/json: + schema: + $ref: '#/components/schemas/OriginHeaderModificationEnvelope' + examples: + MrtPutUpdateResponse: + $ref: '#/components/examples/MrtPutUpdateResponse' + '201': + description: Successfully created the origin header modification. + content: + application/json: + schema: + $ref: '#/components/schemas/OriginHeaderModificationEnvelope' + examples: + MrtPutCreateResponse: + $ref: '#/components/examples/MrtPutCreateResponse' + '400': + description: | + The request sent by the caller is not valid. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + BadRequest: + $ref: '#/components/examples/BadRequest' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + delete: + summary: Delete the origin header modification associated with a zone. Only the `mrt` type is supported. + operationId: deleteOriginHeaderModification + description: | + Delete origin header modification settings for the specified zone. This endpoint removes header modification configurations. + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/type' + - $ref: '#/components/parameters/organizationId' + responses: + '204': + description: Successfully deleted the origin header modification associated with a zone. + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw + /organizations/{organizationId}/zones/{zoneId}/settings/ciphers: + get: + summary: Get cipher suites settings by zoneId. + description: | + Retrieve cipher suite settings for the specified zone. This endpoint provides information about supported encryption algorithms and security protocols. See [eCDN Supported Cipher Suites](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-cipher-suite-types.html). + operationId: getCipherSuites + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + responses: + '200': + description: Retrieves current zone level cipher settings. + content: + application/json: + schema: + $ref: '#/components/schemas/CipherSuitesEnvelope' + examples: + CipherSettingsGetResponse: + $ref: '#/components/examples/CipherSettingsGetResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones + - sfcc.cdn-zones.rw + patch: + summary: Update cipher suite settings for the zone. + description: | + Update cipher suite settings for the specified zone. Use this endpoint to modify supported encryption algorithms and security protocols. See [eCDN Supported Cipher Suites](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-cipher-suite-types.html). + operationId: updateCipherSuites + parameters: + - $ref: '#/components/parameters/zoneId' + - $ref: '#/components/parameters/organizationId' + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/CipherSuitesRequest' + examples: + CipherSettingsPatchRequestBodyExample: + $ref: '#/components/examples/CipherSettingsPatchRequestBodyExample' + required: true + responses: + '200': + description: Updates current zone level cipher settings. + content: + application/json: + schema: + $ref: '#/components/schemas/CipherSuitesEnvelope' + examples: + CipherSettingsPatchResponse: + $ref: '#/components/examples/CipherSettingsPatchResponse' + '401': + description: | + The caller is not authorized to access the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Unauthorized: + $ref: '#/components/examples/Unauthorized' + '403': + description: | + The caller does not have access to the requested resource. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + Forbidden: + $ref: '#/components/examples/Forbidden' + '404': + description: | + The resource requested by the caller was not found. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + NotFound: + $ref: '#/components/examples/NotFound' + '500': + description: | + An error occurred on the server side. + content: + application/problem+json: + schema: + $ref: '#/components/schemas/ApiStandardsErrorResponse' + examples: + InternalServerError: + $ref: '#/components/examples/InternalServerError' + security: + - AmOAuth2: + - sfcc.cdn-zones.rw +components: + schemas: + ApiStandardsErrorResponse: + type: object + properties: + title: + description: "A short, human-readable summary of the problem\ntype. It will not change from occurrence to occurrence of the \nproblem, except for purposes of localization\n" + type: string + maxLength: 256 + example: You do not have enough credit + type: + description: | + A URI reference [RFC3986] that identifies the + problem type. This specification encourages that, when + dereferenced, it provide human-readable documentation for the + problem type (e.g., using HTML [W3C.REC-html5-20141028]). When + this member is not present, its value is assumed to be + "about:blank". It accepts relative URIs; this means + that they must be resolved relative to the document's base URI, as + per [RFC3986], Section 5. + type: string + maxLength: 2048 + example: NotEnoughMoney + detail: + description: A human-readable explanation specific to this occurrence of the problem. + type: string + pattern: ^.*$ + example: Your current balance is 30, but that costs 50 + instance: + description: | + A URI reference that identifies the specific + occurrence of the problem. It may or may not yield further + information if dereferenced. It accepts relative URIs; this means + that they must be resolved relative to the document's base URI, as + per [RFC3986], Section 5. + type: string + maxLength: 2048 + example: /account/12345/msgs/abc + required: + - title + - type + - detail + OrganizationId: + description: An identifier for the organization the request is being made by + example: f_ecom_zzxy_prd + type: string + minLength: 1 + maxLength: 32 + StorefrontZoneCreateRequest: + required: + - domainName + type: object + properties: + domainName: + type: string + description: Domain name for the site. + pattern: ^.*$ + example: cc-merchant.com + description: The storefront zone information to be created. + StorefrontZoneCreateResponse: + required: + - createdOn + - status + - zoneId + - zoneName + type: object + properties: + zoneId: + type: string + description: The zone id tag. + pattern: ^.*$ + example: 023e105f4ecef8ad9ca31a8372d0c353 + zoneName: + type: string + description: The domain name for the zone. + pattern: ^.*$ + example: stg-zzzz-cc-merchant-com.cc-ecdn.net + status: + type: string + description: current status of the zone + example: active + enum: + - active + - pending + - initializing + - moved + - deleted + - deactivated + createdOn: + type: string + description: Date and time of zone creation. + format: date-time + example: '2014-01-01T05:20:00.12345Z' + description: The response of create zone, includes zone and zone properties. + StorefrontZoneCreateEnvelope: + type: object + properties: + data: + $ref: '#/components/schemas/StorefrontZoneCreateResponse' + required: + - data + example: + data: + zoneId: 023e105f4ecef8ad9ca31a8372d0c353 + zoneName: stg-zzzz-cc-merchant-com.cc-ecdn.net + status: active + createdOn: '2014-01-01T05:20:00.12345Z' + additionalProperties: false + MtlsCertificateResponse: + type: object + properties: + mtlsCertificateId: + type: string + description: ID generated by the CDN provider for the certificate. + pattern: ^.*$ + example: 465a48f6-3d98-4c15-9312-211984ee8629 + expiresOn: + type: string + description: Expiration date for the mTLS certificate. + format: date-time + example: '2022-01-12T04:15:57Z' + issuer: + type: string + description: The certificate authority that issued the mTLS certificate. + pattern: ^.*$ + example: DigiCert + signature: + type: string + description: The type of hash used for the mTLS certificate. + pattern: ^.*$ + example: SHA256WithRSA + uploadedOn: + type: string + description: Date the mTLS certificate was uploaded. + format: date-time + example: '2020-01-12T04:15:57Z' + ca: + type: boolean + description: Indicates whether the mTLS certificate is a CA or leaf certificate. + example: true + serialNumber: + type: string + description: The mTLS certificate serial number. + pattern: ^.*$ + example: '432217133297895665180570788458463042229861757760' + mtlsCertificateName: + type: string + description: Optional name for the mTLS certificate used for ease of understanding. + pattern: ^.*$ + example: mtls_cert_name + mtlsAssociatedCodeUploadHostname: + type: string + description: Hostname associated with this mTLS certificate. + pattern: ^.*$ + example: mtls.cert.salesforce.com + description: mTLS certificate information. + MtlsCertificatesResponseEnvelope: + type: object + required: + - data + properties: + data: + items: + $ref: '#/components/schemas/MtlsCertificateResponse' + type: array + example: + data: + - mtlsCertificateId: 465a48f6-3d98-4c15-9312-211984ee8629 + expiresOn: '2022-01-12T04:15:57Z' + issuer: DigiCert + signature: SHA256WithRSA + uploadedOn: '2020-01-12T04:15:57Z' + ca: true + serialNumber: '432217133297895665180570788458463042229861757760' + mtlsCertificateName: mtls_cert_name + mtlsAssociatedCodeUploadHostname: mtls.cert.salesforce.com + additionalProperties: false + MtlsCertificateRequest: + required: + - certificate + - name + - privateKey + type: object + properties: + certificate: + type: string + description: Public key for the CA certificate in mTLS. + pattern: ^.*$ + example: |- + -----BEGIN CERTIFICATE----- + MIIDtTCCAp2gAwIBAgIJAMHAwfXZ5PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV + BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX + aWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF + MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 + ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB + CgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1 + CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB + KwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5 + 0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI + dZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2 + izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4 + 9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI + GKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV + BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF + MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2 + 2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP + Mlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG + SvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq + 2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw + YbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY= + -----END CERTIFICATE----- + privateKey: + type: string + description: Private key of the CA certificate in mTLS. + pattern: ^.*$ + example: |- + -----BEGIN RSA PRIVATE KEY----- + MIIEowIBAAKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmG + dtcGbg/1CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKn + abIRuGvBKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpid + tnKX/a+50GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+py + FxIXjbEIdZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pE + ewooaeO2izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABAoIBACbhTYXBZYKmYPCb + HBR1IBlCQA2nLGf0qRuJNJZg5iEzXows/6tc8YymZkQE7nolapWsQ+upk2y5Xdp/ + axiuprIs9JzkYK8Ox0r+dlwCG1kSW+UAbX0bQ/qUqlsTvU6muVuMP8vZYHxJ3wmb + +ufRBKztPTQ/rYWaYQcgC0RWI20HTFBMxlTAyNxYNWzX7RKFkGVVyB9RsAtmcc8g + +j4OdosbfNoJPS0HeIfNpAznDfHKdxDk2Yc1tV6RHBrC1ynyLE9+TaflIAdo2MVv + KLMLq51GqYKtgJFIlBRPQqKoyXdz3fGvXrTkf/WY9QNq0J1Vk5ERePZ54mN8iZB7 + 9lwy/AkCgYEA6FXzosxswaJ2wQLeoYc7ceaweX/SwTvxHgXzRyJIIT0eJWgx13Wo + /WA3Iziimsjf6qE+SI/8laxPp2A86VMaIt3Z3mJN/CqSVGw8LK2AQst+OwdPyDMu + iacE8lj/IFGC8mwNUAb9CzGU3JpU4PxxGFjS/eMtGeRXCWkK4NE+G08CgYEA1Kp9 + N2JrVlqUz+gAX+LPmE9OEMAS9WQSQsfCHGogIFDGGcNf7+uwBM7GAaSJIP01zcoe + VAgWdzXCv3FLhsaZoJ6RyLOLay5phbu1iaTr4UNYm5WtYTzMzqh8l1+MFFDl9xDB + vULuCIIrglM5MeS/qnSg1uMoH2oVPj9TVst/ir8CgYEAxrI7Ws9Zc4Bt70N1As+U + lySjaEVZCMkqvHJ6TCuVZFfQoE0r0whdLdRLU2PsLFP+q7qaeZQqgBaNSKeVcDYR + 9B+nY/jOmQoPewPVsp/vQTCnE/R81spu0mp0YI6cIheT1Z9zAy322svcc43JaWB7 + mEbeqyLOP4Z4qSOcmghZBSECgYACvR9Xs0DGn+wCsW4vze/2ei77MD4OQvepPIFX + dFZtlBy5ADcgE9z0cuVB6CiL8DbdK5kwY9pGNr8HUCI03iHkW6Zs+0L0YmihfEVe + PG19PSzK9CaDdhD9KFZSbLyVFmWfxOt50H7YRTTiPMgjyFpfi5j2q348yVT0tEQS + fhRqaQKBgAcWPokmJ7EbYQGeMbS7HC8eWO/RyamlnSffdCdSc7ue3zdVJxpAkQ8W + qu80pEIF6raIQfAf8MXiiZ7auFOSnHQTXUbhCpvDLKi0Mwq3G8Pl07l+2s6dQG6T + lv6XTQaMyf6n1yjzL+fzDrH3qXMxHMO/b13EePXpDMpY7HQpoLDi + -----END RSA PRIVATE KEY----- + name: + type: string + description: Certificate name used for ease of understanding. + pattern: ^.*$ + example: mtls_cert_name + description: mTLS certificate request information. + example: + certificate: |- + -----BEGIN CERTIFICATE----- + MIIDtTCCAp2gAwIBAgIJAMHAwfXZ5PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV + BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX + aWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF + MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 + ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB + CgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1 + CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB + KwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5 + 0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI + dZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2 + izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4 + 9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI + GKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV + BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF + MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2 + 2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP + Mlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG + SvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq + 2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw + YbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY= + -----END CERTIFICATE----- + privateKey: |- + -----BEGIN RSA PRIVATE KEY----- + MIIEowIBAAKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmG + dtcGbg/1CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKn + abIRuGvBKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpid + tnKX/a+50GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+py + FxIXjbEIdZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pE + ewooaeO2izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABAoIBACbhTYXBZYKmYPCb + HBR1IBlCQA2nLGf0qRuJNJZg5iEzXows/6tc8YymZkQE7nolapWsQ+upk2y5Xdp/ + axiuprIs9JzkYK8Ox0r+dlwCG1kSW+UAbX0bQ/qUqlsTvU6muVuMP8vZYHxJ3wmb + +ufRBKztPTQ/rYWaYQcgC0RWI20HTFBMxlTAyNxYNWzX7RKFkGVVyB9RsAtmcc8g + +j4OdosbfNoJPS0HeIfNpAznDfHKdxDk2Yc1tV6RHBrC1ynyLE9+TaflIAdo2MVv + KLMLq51GqYKtgJFIlBRPQqKoyXdz3fGvXrTkf/WY9QNq0J1Vk5ERePZ54mN8iZB7 + 9lwy/AkCgYEA6FXzosxswaJ2wQLeoYc7ceaweX/SwTvxHgXzRyJIIT0eJWgx13Wo + /WA3Iziimsjf6qE+SI/8laxPp2A86VMaIt3Z3mJN/CqSVGw8LK2AQst+OwdPyDMu + iacE8lj/IFGC8mwNUAb9CzGU3JpU4PxxGFjS/eMtGeRXCWkK4NE+G08CgYEA1Kp9 + N2JrVlqUz+gAX+LPmE9OEMAS9WQSQsfCHGogIFDGGcNf7+uwBM7GAaSJIP01zcoe + VAgWdzXCv3FLhsaZoJ6RyLOLay5phbu1iaTr4UNYm5WtYTzMzqh8l1+MFFDl9xDB + vULuCIIrglM5MeS/qnSg1uMoH2oVPj9TVst/ir8CgYEAxrI7Ws9Zc4Bt70N1As+U + lySjaEVZCMkqvHJ6TCuVZFfQoE0r0whdLdRLU2PsLFP+q7qaeZQqgBaNSKeVcDYR + 9B+nY/jOmQoPewPVsp/vQTCnE/R81spu0mp0YI6cIheT1Z9zAy322svcc43JaWB7 + mEbeqyLOP4Z4qSOcmghZBSECgYACvR9Xs0DGn+wCsW4vze/2ei77MD4OQvepPIFX + dFZtlBy5ADcgE9z0cuVB6CiL8DbdK5kwY9pGNr8HUCI03iHkW6Zs+0L0YmihfEVe + PG19PSzK9CaDdhD9KFZSbLyVFmWfxOt50H7YRTTiPMgjyFpfi5j2q348yVT0tEQS + fhRqaQKBgAcWPokmJ7EbYQGeMbS7HC8eWO/RyamlnSffdCdSc7ue3zdVJxpAkQ8W + qu80pEIF6raIQfAf8MXiiZ7auFOSnHQTXUbhCpvDLKi0Mwq3G8Pl07l+2s6dQG6T + lv6XTQaMyf6n1yjzL+fzDrH3qXMxHMO/b13EePXpDMpY7HQpoLDi + -----END RSA PRIVATE KEY----- + name: mtls_cert_name + additionalProperties: false + MtlsCertificateResponseEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/MtlsCertificateResponse' + example: + data: + mtlsCertificateId: 465a48f6-3d98-4c15-9312-211984ee8629 + expiresOn: '2022-01-12T04:15:57Z' + issuer: DigiCert + signature: SHA256WithRSA + uploadedOn: '2020-01-12T04:15:57Z' + ca: true + serialNumber: '432217133297895665180570788458463042229861757760' + mtlsCertificateName: mtls_cert_name + mtlsAssociatedCodeUploadHostname: mtls.cert.salesforce.com + additionalProperties: false + PageShieldNotificationWebhookResponse: + required: + - createdAt + - id + - name + - type + - webhookUrl + type: object + properties: + id: + type: string + description: Webhook ID. + pattern: ^.*$ + example: webhook_1234567890abcdef + name: + type: string + description: Webhook name. + pattern: ^.*$ + example: Security Alert Webhook + webhookUrl: + type: string + description: Webhook URL. + pattern: ^.*$ + example: https://example.com/webhook/security + type: + type: string + description: Webhook type. + pattern: ^.*$ + example: security_alert + createdAt: + type: string + description: Timestamp of webhook creation. + format: date-time + example: '2023-01-01T00:00:00Z' + lastSuccess: + type: string + description: Timestamp of the last successful notification. + format: date-time + example: '2023-01-01T12:00:00Z' + lastFailure: + type: string + description: Timestamp of the last failed notification. + format: date-time + example: '2023-01-01T18:00:00Z' + zones: + items: + type: string + pattern: ^.*$ + example: zone_1234567890abcdef + type: array + description: Zone IDs on which to filter notifications alerts. + description: Page shield notification for the webhook response. + example: + id: webhook_1234567890abcdef + name: Security Alert Webhook + webhookUrl: https://example.com/webhook/security + type: security_alert + createdAt: '2023-01-01T00:00:00Z' + lastSuccess: '2023-01-01T12:00:00Z' + lastFailure: '2023-01-01T18:00:00Z' + zones: + - zone_1234567890abcdef + additionalProperties: false + PageShieldNotificationWebhookListEnvelope: + type: object + required: + - data + properties: + data: + items: + $ref: '#/components/schemas/PageShieldNotificationWebhookResponse' + type: array + example: + data: + - id: webhook_1234567890abcdef + name: Security Alert Webhook + webhookUrl: https://example.com/webhook/security + type: security_alert + createdAt: '2023-01-01T00:00:00Z' + lastSuccess: '2023-01-01T12:00:00Z' + lastFailure: '2023-01-01T18:00:00Z' + zones: + - zone_1234567890abcdef + additionalProperties: false + PageShieldNotificationWebhookRequest: + type: object + required: + - webhookUrl + properties: + webhookUrl: + type: string + description: Webhook URL. + pattern: ^.*$ + example: https://example.com/webhook/security + secret: + type: string + description: Webhook optional secret. + pattern: ^.*$ + example: webhook_secret_123 + zones: + items: + type: string + pattern: ^.*$ + example: zone_1234567890abcdef + type: array + description: Zone names on which to filter notifications alerts. + description: Page shield notification for the webhook request. + example: + webhookUrl: https://example.com/webhook/security + secret: webhook_secret_123 + zones: + - zone_1234567890abcdef + additionalProperties: false + PageShieldNotificationWebhookEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/PageShieldNotificationWebhookResponse' + example: + data: + id: webhook_1234567890abcdef + name: Security Alert Webhook + webhookUrl: https://example.com/webhook/security + type: security_alert + createdAt: '2023-01-01T00:00:00Z' + lastSuccess: '2023-01-01T12:00:00Z' + lastFailure: '2023-01-01T18:00:00Z' + zones: + - zone_1234567890abcdef + additionalProperties: false + PageShieldPolicyResponse: + type: object + properties: + action: + type: string + description: Action taken when expression matches allow or log. + example: allow + enum: + - allow + - log + description: + type: string + description: Description for the policy. + pattern: ^.*$ + example: Allow scripts from trusted CDN sources + enabled: + type: boolean + description: Enable/disable the policy. + example: true + expression: + type: string + description: Expression of the policy. + pattern: ^.*$ + example: http.request.uri.path contains "/trusted-cdn/" + value: + type: string + description: Policy to be applied. + pattern: ^.*$ + example: script-src + id: + type: string + description: Policy ID + pattern: ^.*$ + example: policy_1234567890abcdef + description: Page shield policy response. + example: + action: allow + description: Allow scripts from trusted CDN sources + enabled: true + expression: http.request.uri.path contains "/trusted-cdn/" + value: script-src + id: policy_1234567890abcdef + additionalProperties: false + PageShieldPoliciesListEnvelope: + type: object + required: + - data + properties: + data: + items: + $ref: '#/components/schemas/PageShieldPolicyResponse' + type: array + example: + data: + - action: allow + description: Allow scripts from trusted CDN sources + enabled: true + expression: http.request.uri.path contains "/trusted-cdn/" + value: script-src + id: policy_1234567890abcdef + additionalProperties: false + PageShieldPolicyRequest: + type: object + properties: + action: + type: string + description: Action taken when expression matches allow or log. + example: allow + enum: + - allow + - log + description: + type: string + description: Description for the policy. + pattern: ^.*$ + example: Allow scripts from trusted CDN sources + enabled: + type: boolean + description: Enable/disable the policy. + example: true + expression: + type: string + description: Expression of the policy. + pattern: ^.*$ + example: http.request.uri.path contains "/trusted-cdn/" + value: + type: string + description: Policy to be applied. + pattern: ^.*$ + example: script-src + description: Page shield policy request object. + example: + action: allow + description: Allow scripts from trusted CDN sources + enabled: true + expression: http.request.uri.path contains "/trusted-cdn/" + value: script-src + additionalProperties: false + PageShieldPoliciesEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/PageShieldPolicyResponse' + example: + data: + action: allow + description: Allow scripts from trusted CDN sources + enabled: true + expression: http.request.uri.path contains "/trusted-cdn/" + value: script-src + id: policy_1234567890abcdef + additionalProperties: false + PageShieldScriptVersion: + type: object + required: + - isMaliciousCode + properties: + hash: + type: string + description: The computed hash of the analyzed script. + pattern: ^.*$ + example: 1243453456abc + jsIntegrityScore: + type: integer + description: The integrity score of the JavaScript content. + example: 1 + obfuscationScore: + type: integer + description: The obfuscation score of the JavaScript content. + example: 2 + dataflowScore: + type: integer + description: The dataflow score of the JavaScript content. + example: 1 + malwareScore: + type: integer + description: The malware score of the JavaScript content. + example: 1 + cryptoMiningScore: + type: integer + description: The crypto mining score of the JavaScript content. + example: 1 + mageCartScore: + type: integer + description: The Magecart score of the JavaScript content. + example: 2 + fetchedAt: + type: string + description: The timestamp of when the script was last fetched. + format: date-time + example: '2023-01-01T00:00:00Z' + isMaliciousCode: + type: boolean + description: Indicates whether the script has been reported as malicious. + example: false + description: Version details for the JavaScript script. + example: + hash: 1243453456abc + jsIntegrityScore: 1 + obfuscationScore: 2 + dataflowScore: 1 + malwareScore: 1 + cryptoMiningScore: 1 + mageCartScore: 2 + fetchedAt: '2023-01-01T00:00:00Z' + isMaliciousCode: false + additionalProperties: false + PageShieldScriptResponse: + type: object + properties: + id: + type: string + description: Page Shield script ID. + pattern: ^.*$ + example: 12345678901234asdfasfasdf + url: + type: string + description: Page Shield script URL. + pattern: ^.*$ + example: https://sfdc-test.net/on/demandware.static/Sites-SiteNemesis-Site/-/en_US//lib/jquery/ui/jquery-ui.min.js + host: + type: string + description: Hostname where the script was detected by Page Shield. + pattern: ^.*$ + example: sfdc-test.net + addedAt: + type: string + description: Date the script was added to Page Shield. + format: date-time + example: '2022-01-01T05:20:00Z' + firstSeenAt: + type: string + description: Date the script was detected by Page Shield. + format: date-time + example: '2022-01-01T05:20:00Z' + lastSeenAt: + type: string + description: Date the script was recently detected by Page Shield. + format: date-time + example: '2022-01-01T05:20:00Z' + fetchedAt: + type: string + description: The timestamp when the script was last fetched. + format: date-time + example: '2022-01-01T05:20:00Z' + domainReportedMalicious: + type: boolean + description: Reported domain is malicious. + example: false + hash: + type: string + description: The computed hash of the analyzed script. + pattern: ^.*$ + example: 1243453456abc + cryptoMiningScore: + type: integer + description: The crypto mining score of the JavaScript content. + example: 1 + dataflowScore: + type: integer + description: The dataflow score of the JavaScript content. + example: 1 + jsIntegrityScore: + type: integer + description: The integrity score of the JavaScript content. + example: 1 + mageCartScore: + type: integer + description: The Magecart score of the JavaScript content. + example: 2 + malwareScore: + type: integer + description: The malware score of the JavaScript content. + example: 1 + obfuscationScore: + type: integer + description: The obfuscation score of the JavaScript content. + example: 2 + maliciousDomainCategories: + items: + type: string + pattern: ^.*$ + example: Malware + type: array + description: Malicious domain category. + example: + - Malware + maliciousUrlCategories: + items: + type: string + pattern: ^.*$ + example: Malware + type: array + description: Malicious URL category. + example: + - Malware + urlContainsCdnCgiPath: + type: boolean + description: URL contains CDN CGI path. + example: false + urlReportedMalicious: + type: boolean + description: Reported URL is malicious. + example: false + pageUrls: + items: + type: string + pattern: ^.*$ + example: blog.test.salesforce.com/page1 + type: array + description: Page URLs + example: + - blog.test.salesforce.com/page1 + - blog.test.salesforce.com/page2 + firstPageUrl: + type: string + description: First page URL for the JavaScript. + pattern: ^.*$ + example: blog.test.salesforce.com + status: + type: string + description: The current status of the script. Possible values are active, inactive, or infrequent. + pattern: ^.*$ + example: active + versions: + items: + $ref: '#/components/schemas/PageShieldScriptVersion' + type: array + description: List of script versions. + description: Response of Page Shield script object. + example: + id: 12345678901234asdfasfasdf + url: https://sfdc-test.net/on/demandware.static/Sites-SiteNemesis-Site/-/en_US//lib/jquery/ui/jquery-ui.min.js + host: sfdc-test.net + addedAt: '2022-01-01T05:20:00Z' + firstSeenAt: '2022-01-01T05:20:00Z' + lastSeenAt: '2022-01-01T05:20:00Z' + fetchedAt: '2022-01-01T05:20:00Z' + domainReportedMalicious: false + hash: 1243453456abc + cryptoMiningScore: 1 + dataflowScore: 1 + jsIntegrityScore: 1 + mageCartScore: 2 + malwareScore: 1 + obfuscationScore: 2 + maliciousDomainCategories: + - Malware + maliciousUrlCategories: + - Malware + urlContainsCdnCgiPath: false + urlReportedMalicious: false + pageUrls: + - blog.test.salesforce.com/page1 + - blog.test.salesforce.com/page2 + firstPageUrl: blog.test.salesforce.com + status: active + versions: [] + additionalProperties: false + PageShieldScriptListEnvelope: + type: object + required: + - data + properties: + data: + items: + $ref: '#/components/schemas/PageShieldScriptResponse' + type: array + example: + data: + - id: 12345678901234asdfasfasdf + url: https://sfdc-test.net/on/demandware.static/Sites-SiteNemesis-Site/-/en_US//lib/jquery/ui/jquery-ui.min.js + host: sfdc-test.net + addedAt: '2022-01-01T05:20:00Z' + firstSeenAt: '2022-01-01T05:20:00Z' + lastSeenAt: '2022-01-01T05:20:00Z' + fetchedAt: '2022-01-01T05:20:00Z' + domainReportedMalicious: false + hash: 1243453456abc + cryptoMiningScore: 1 + dataflowScore: 1 + jsIntegrityScore: 1 + mageCartScore: 2 + malwareScore: 1 + obfuscationScore: 2 + maliciousDomainCategories: + - Malware + maliciousUrlCategories: + - Malware + urlContainsCdnCgiPath: false + urlReportedMalicious: false + pageUrls: + - blog.test.salesforce.com/page1 + - blog.test.salesforce.com/page2 + firstPageUrl: blog.test.salesforce.com + status: active + versions: [] + additionalProperties: false + PageShieldScriptEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/PageShieldScriptResponse' + example: + data: + id: 12345678901234asdfasfasdf + url: https://sfdc-test.net/on/demandware.static/Sites-SiteNemesis-Site/-/en_US//lib/jquery/ui/jquery-ui.min.js + host: sfdc-test.net + addedAt: '2022-01-01T05:20:00Z' + firstSeenAt: '2022-01-01T05:20:00Z' + lastSeenAt: '2022-01-01T05:20:00Z' + fetchedAt: '2022-01-01T05:20:00Z' + domainReportedMalicious: false + hash: 1243453456abc + cryptoMiningScore: 1 + dataflowScore: 1 + jsIntegrityScore: 1 + mageCartScore: 2 + malwareScore: 1 + obfuscationScore: 2 + maliciousDomainCategories: + - Malware + maliciousUrlCategories: + - Malware + urlContainsCdnCgiPath: false + urlReportedMalicious: false + pageUrls: + - blog.test.salesforce.com/page1 + - blog.test.salesforce.com/page2 + firstPageUrl: blog.test.salesforce.com + status: active + versions: [] + additionalProperties: false + Zone: + title: Zone + type: object + required: + - name + - status + - zoneId + properties: + zoneId: + maxLength: 100 + type: string + description: Identity of the zone. + example: example1-zone-Id + name: + maxLength: 100 + type: string + description: Name given to the zone. This needs to be a DNS domain name for eg example.com + example: example1.com + status: + type: string + description: Status of the zone for eg "Pending" , "Active" + enum: + - active + - pending + - initializing + - moved + - deleted + - deactivated + example: pending + description: Zone is the container for hostnames and various CDN settings/properties. Each zone is tied to a single origin. + example: + zoneId: example1-zone-Id + name: example1.com + status: pending + additionalProperties: false + ZonesEnvelope: + type: object + required: + - data + properties: + data: + items: + $ref: '#/components/schemas/Zone' + type: array + example: + data: + - zoneId: example1-zone-Id + name: example1.com + status: pending + - zoneId: example2-zone-Id + name: example2.com + status: active + additionalProperties: false + WafGroup: + required: + - mode + type: object + properties: + groupId: + maxLength: 100 + type: string + example: 372e67954025e0ba6aaa6d586b9e0b60 + action: + type: string + description: The action to apply to WAF group + example: block + enum: + - block + - challenge + - monitor + - default + mode: + type: string + description: Mode of the waf rule - on vs off + example: 'on' + enum: + - 'on' + - 'off' + description: + type: string + description: Description of the WAF Group. + pattern: ^.*$ + example: Test WAF Group to protect against SQL injection + example: + groupId: 372abe67954025e0ba6aaa6d586b9e0b + zoneId: example1-zone-Id + action: monitor + mode: true + description: SQL injection protection + additionalProperties: false + WafGroupsEnvelope: + type: object + required: + - data + properties: + data: + items: + $ref: '#/components/schemas/WafGroup' + type: array + WafGroupEnvelope: + type: object + properties: + data: + $ref: '#/components/schemas/WafGroup' + WafRule: + required: + - action + type: object + properties: + ruleId: + type: string + pattern: ^.*$ + example: 892e67954025e0ba6atefd586b9e58b3 + groupId: + maxLength: 100 + type: string + example: 372e67954025e0ba6aaa6d586b9e0b60 + action: + type: string + description: The action to apply to WAF rule + example: block + enum: + - block + - challenge + - monitor + - disable + - default + defaultAction: + type: string + description: The action to apply to WAF rule + example: block + enum: + - block + - challenge + - monitor + - disable + description: + type: string + description: Description of the WAF Group. + pattern: ^.*$ + example: Test WAF Rule to protect against SQL injection + example: + ruleId: 892e67954025e0ba6atefd586b9e58b3 + groupId: 372abe67954025e0ba6aaa6d586b9e0b + action: monitor + defaultAction: challenge + description: SQL injection protection + additionalProperties: false + WafRulesEnvelope: + type: object + required: + - data + properties: + data: + items: + $ref: '#/components/schemas/WafRule' + type: array + example: + data: + - ruleId: 892e67954025e0ba6atefd586b9e58b3 + groupId: 372abe67954025e0ba6aaa6d586b9e0b + action: monitor + defaultAction: challenge + description: SQL injection protection + additionalProperties: false + WafRuleEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/WafRule' + example: + data: + ruleId: 892e67954025e0ba6atefd586b9e58b3 + groupId: 372abe67954025e0ba6aaa6d586b9e0b + action: monitor + defaultAction: challenge + description: SQL injection protection + additionalProperties: false + SpeedSetting: + type: object + properties: + brotliCompression: + type: string + description: Brotli compression setting of a zone. + default: 'off' + example: 'off' + enum: + - 'on' + - 'off' + http2Prioritization: + type: string + description: Http2 prioritization setting for a zone. + default: 'off' + example: 'off' + enum: + - 'on' + - 'off' + webp: + type: string + description: Support for the WebP image format when using image modification for a zone. The WebP image format can be used with supported clients for added performance benefits. Setting this property to `on` will return an error when the `polish` property is set to `off`. + default: 'off' + example: 'off' + enum: + - 'on' + - 'off' + polish: + type: string + description: The level of polish (image quality) used for image modification. The value `lossless` corresponds to **Polish Level Basic** in the UI, and the value `lossy` corresponds to **Polish Level Basic+JPEG.** To disable image modification, set this property to `off`. Setting this property to `off` will prevent you from setting the `webp` property to `on`. + default: 'off' + example: 'off' + enum: + - 'off' + - lossless + - lossy + earlyHints: + type: string + description: Early Hints for a zone. + default: 'off' + example: 'off' + enum: + - 'on' + - 'off' + http3: + type: string + description: Http3 for a zone. + default: 'off' + example: 'off' + enum: + - 'on' + - 'off' + http2ToOrigin: + type: string + description: Http2 to Origin for a zone. + default: 'off' + example: 'off' + enum: + - 'on' + - 'off' + example: + brotliCompression: 'off' + additionalProperties: false + SpeedSettingsEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/SpeedSetting' + SecuritySetting: + required: + - alwaysUseHttps + type: object + properties: + hsts: + type: object + properties: + enabled: + type: boolean + description: Enable strict transport security. + example: true + includeSubdomains: + type: boolean + description: Include all subdomains for strict transport security. + example: true + maxAge: + type: number + description: Max age in seconds of the strict transport security. + example: 31536000 + preload: + type: boolean + description: Preload any URLs that are included in the response headers. + example: false + description: The security header for a zone. + example: + enabled: true + includeSubdomains: true + maxAge: 31536000 + preload: false + additionalProperties: false + securityLevel: + type: string + description: Security profile for your zone, which will automatically adjust each of the security settings. + enum: + - 'off' + - essentially_off + - low + - medium + - high + - under_attack + example: medium + tls13Enabled: + type: boolean + description: Enable Crypto TLS 1.3 feature for this zone. + example: true + wafEnabled: + type: boolean + description: Enable WAF (OWASP) protection for this zone. Not applicable for zones using WAFv2. + example: true + alwaysUseHttps: + type: boolean + description: Redirect all http requests to https. + example: true + example: + hsts: + enabled: true + includeSubdomains: true + maxAge: 31536000 + preload: false + securityLevel: medium + tls13Enabled: true + wafEnabled: true + alwaysUseHttps: true + additionalProperties: false + SecuritySettingsEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/SecuritySetting' + example: + data: + hsts: + enabled: true + includeSubdomains: true + maxAge: 31536000 + preload: false + securityLevel: medium + tls13Enabled: true + wafEnabled: true + alwaysUseHttps: true + additionalProperties: false + CachePurgeRequest: + type: object + properties: + path: + type: string + description: Path for clearing the cache. Allowed paths follow the format "/dw/shop/*/products", "/dw/image/v2/{realm}_{instance}/*", "/worker.js", "/mobify*" or "/callback*". Regular expressions and wildcards are not supported in the path. + pattern: ^.*$ + example: www.sfcc-ecdn-test5.net/dw/shop/v21_9/products + tags: + type: array + description: List of cache tags to purge. When specified, all cached content associated with these tags will be purged. + items: + type: string + pattern: ^.*$ + example: product-123 + example: + - product-123 + - category-456 + description: Request for doing a cache purge + example: + path: www.sfcc-ecdn-test5.net/dw/shop/v21_9/products + tags: + - product-123 + - category-456 + additionalProperties: false + CachePurgeResponse: + type: object + required: + - cachePurged + - details + properties: + cachePurged: + type: boolean + description: The name of the list. + example: false + details: + type: string + description: Details of errors if any. + pattern: ^.*$ + example: '1084 : Unable to purge ''''.' + description: Response from a cache purge request + example: + cachePurged: false + details: '1084 : Unable to purge ''''.' + additionalProperties: false + CachePurgeResponseEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/CachePurgeResponse' + example: + data: + cachePurged: false + details: '1084 : Unable to purge ''''.' + additionalProperties: false + OCAPICachingToggleRequest: + type: object + required: + - enableOCAPICachingPageRule + properties: + enableOCAPICachingPageRule: + type: boolean + description: True to enable API Caching Page rule, false to disable. + example: true + description: Request to enable or disable API Caching Page rule + DCVDelegationRecord: + description: eCDN automatic renewal certificate DCV delegation records. + type: object + properties: + dcvCname: + description: DNS CNAME for Domain Control Validation. + type: string + pattern: ^.*$ + example: _acme-challenge.example.com + dcvCnameValue: + description: DNS CNAME value for Domain Control Validation. + type: string + pattern: ^.*$ + example: abc123def456ghi789.acme-validation.com + example: + dcvCname: _acme-challenge.example.com + dcvCnameValue: abc123def456ghi789.acme-validation.com + additionalProperties: false + Certificate: + required: + - certificateId + - certificateType + - status + type: object + properties: + certificateId: + type: string + description: Id generated by CDN provider for the certificate. + pattern: ^.*$ + example: f90712123fb02287348dd34c0a282bb9 + hosts: + items: + type: string + pattern: ^.*$ + example: example.com + type: array + description: List of hosts the certificate applies to. + example: + - example.com + - www.example.com + expiresOn: + type: string + description: Date of expiration for the certificate. + format: date-time + example: '2025-12-31T23:59:59Z' + uploadedOn: + type: string + description: Date the certificate was uploaded. + format: date-time + example: '2024-01-01T00:00:00Z' + issuer: + type: string + description: The certificate authority that issued the certificate. + pattern: ^.*$ + example: Let's Encrypt Authority X3 + signature: + type: string + description: The type of hash used for the certificate. + pattern: ^.*$ + example: SHA256 + status: + type: string + description: Current status of the certificate. + enum: + - ACTIVE + - EXPIRED + - DELETED + - PENDING + - INITIALIZING + - PENDING_VALIDATION + - PENDING_ISSUANCE + - PENDING_DEPLOYMENT + - PENDING_DELETION + - VALIDATION_TIMED_OUT + - DEPLOYMENT_TIMED_OUT + - DELETION_TIMED_OUT + - INITIALIZING_TIMED_OUT + - PENDING_EXPIRATION + - ISSUANCE_TIMED_OUT + example: ACTIVE + minTlsVersion: + type: string + description: Minimum TLS Version only allows HTTPS connections from visitors that support the selected TLS protocol version or newer. + pattern: ^.*$ + example: '1.2' + certificateType: + type: string + description: Indicates certificate is custom cert uploaded by customer or automatic renewal certificate by eCDN. + enum: + - custom + - automatic + - custom_legacy + example: custom + certificateAuthority: + type: string + description: Indicates certificate issuer for automatic renewal certificate by eCDN. + enum: + - google + - lets_encrypt + - digicert + example: lets_encrypt + certificateValidation: + type: string + description: Indicates certificate validation type for automatic renewal certificate by eCDN. + enum: + - http + - txt + example: http + certificateVerificationTXTName: + type: string + description: eCDN automatic renewal certificate verification txt name. + pattern: ^.*$ + example: _acme-challenge.example.com + certificateVerificationTXTValue: + type: string + description: eCDN automatic renewal certificate verification txt value. + pattern: ^.*$ + example: abc123def456ghi789 + certificateVerificationStatus: + type: string + description: Current status of certificate verification. + enum: + - ACTIVE + - EXPIRED + - PENDING + - INITIALIZING + - PENDING_VALIDATION + - PENDING_ISSUANCE + - PENDING_DEPLOYMENT + example: ACTIVE + wildcardHostname: + type: boolean + description: Set to true for a wildcard custom hostname. + example: false + wildcardCertificateVerificationTXTName: + type: string + description: eCDN automatic renewal certificate verification txt name. + pattern: ^.*$ + example: _acme-challenge.wildcard.example.com + wildcardCertificateVerificationTXTValue: + type: string + description: eCDN automatic renewal certificate verification txt value. + pattern: ^.*$ + example: wildcard_abc123def456 + wildcardCertificateVerificationStatus: + type: string + description: Current status of certificate verification. + enum: + - ACTIVE + - EXPIRED + - PENDING + - INITIALIZING + - PENDING_VALIDATION + - PENDING_ISSUANCE + - PENDING_DEPLOYMENT + example: ACTIVE + customHostnameVerificationTXTName: + type: string + description: Custom Hostname verification txt name. + pattern: ^.*$ + example: _acme-challenge.custom.example.com + customHostnameVerificationTXTValue: + type: string + description: Custom Hostname verification txt value. + pattern: ^.*$ + example: custom_abc123def456 + customHostnameId: + type: string + description: Custom hostname associated with the zone + pattern: ^.*$ + example: f90712123fb02287348dd34c0a282bb9 + customHostname: + type: string + description: Custom hostname associated with the zone + pattern: ^.*$ + example: custom.example.com + customHostnameStatus: + type: string + description: Current status of custom hostname validation. + enum: + - ACTIVE + - EXPIRED + - DELETED + - PENDING + - INITIALIZING + - PENDING_VALIDATION + - PENDING_ISSUANCE + - PENDING_DEPLOYMENT + - PENDING_DELETION + - MOVED + example: ACTIVE + dcvDelegationRecords: + description: eCDN automatic renewal certificate DCV delegation records + items: + $ref: '#/components/schemas/DCVDelegationRecord' + type: array + description: The certificate information + example: + certificateId: f90712123fb02287348dd34c0a282bb9 + hosts: + - example.com + - www.example.com + expiresOn: '2025-12-31T23:59:59Z' + uploadedOn: '2024-01-01T00:00:00Z' + issuer: Let's Encrypt Authority X3 + signature: SHA256 + status: ACTIVE + minTlsVersion: '1.2' + certificateType: custom + certificateAuthority: lets_encrypt + certificateValidation: http + certificateVerificationTXTName: _acme-challenge.example.com + certificateVerificationTXTValue: abc123def456ghi789 + certificateVerificationStatus: ACTIVE + wildcardHostname: false + wildcardCertificateVerificationTXTName: _acme-challenge.wildcard.example.com + wildcardCertificateVerificationTXTValue: wildcard_abc123def456 + wildcardCertificateVerificationStatus: ACTIVE + customHostnameVerificationTXTName: _acme-challenge.custom.example.com + customHostnameVerificationTXTValue: custom_abc123def456 + customHostnameId: f90712123fb02287348dd34c0a282bb9 + customHostname: custom.example.com + customHostnameStatus: ACTIVE + dcvDelegationRecords: [] + additionalProperties: false + CertificatesEnvelope: + type: object + required: + - data + properties: + data: + items: + $ref: '#/components/schemas/Certificate' + type: array + example: + data: + - certificateId: f90712123fb02287348dd34c0a282bb9 + hosts: + - example.com + - www.example.com + expiresOn: '2025-12-31T23:59:59Z' + uploadedOn: '2024-01-01T00:00:00Z' + issuer: Let's Encrypt Authority X3 + signature: SHA256 + status: ACTIVE + minTlsVersion: '1.2' + certificateType: custom + certificateAuthority: lets_encrypt + certificateValidation: http + certificateVerificationTXTName: _acme-challenge.example.com + certificateVerificationTXTValue: abc123def456ghi789 + certificateVerificationStatus: ACTIVE + wildcardHostname: false + wildcardCertificateVerificationTXTName: _acme-challenge.wildcard.example.com + wildcardCertificateVerificationTXTValue: wildcard_abc123def456 + wildcardCertificateVerificationStatus: ACTIVE + customHostnameVerificationTXTName: _acme-challenge.custom.example.com + customHostnameVerificationTXTValue: custom_abc123def456 + customHostnameId: f90712123fb02287348dd34c0a282bb9 + customHostname: custom.example.com + customHostnameStatus: ACTIVE + dcvDelegationRecords: [] + additionalProperties: false + CertificateRequest: + required: + - hostname + type: object + properties: + hostname: + type: string + description: Hostname that certificate needs to be applied to. + pattern: ^.*$ + example: example.com + bundleMethod: + type: string + description: Bundle method of the custom certificate chain for verification. + pattern: ^.*$ + example: ubiquitous + certificateType: + type: string + description: Indicates certificate is custom or automatic certificate renewal by eCDN. Optional field, if nothing specified the default value is custom. Valid values are custom or automatic. + pattern: ^.*$ + example: custom + certificate: + type: string + description: Public key of the custom certificate. Required if the certificateType value is custom. + pattern: ^.*$ + example: |- + -----BEGIN CERTIFICATE----- + MIIDtTCCAp2gAwIBAgIJAMHAwfXZ5PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV + BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX + aWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF + MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 + ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB + CgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1 + CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB + KwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5 + 0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI + dZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2 + izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4 + 9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI + GKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV + BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF + MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2 + 2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP + Mlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG + SvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq + 2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw + YbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY= + -----END CERTIFICATE----- + privateKey: + type: string + description: Private key associated with the custom certificate. Required if the `certificateType` value is custom. + pattern: ^.*$ + example: |- + -----BEGIN RSA PRIVATE KEY----- + MIIEowIBAAKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmG + dtcGbg/1CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKn + abIRuGvBKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpid + tnKX/a+50GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+py + FxIXjbEIdZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pE + ewooaeO2izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABAoIBACbhTYXBZYKmYPCb + HBR1IBlCQA2nLGf0qRuJNJZg5iEzXows/6tc8YymZkQE7nolapWsQ+upk2y5Xdp/ + axiuprIs9JzkYK8Ox0r+dlwCG1kSW+UAbX0bQ/qUqlsTvU6muVuMP8vZYHxJ3wmb + +ufRBKztPTQ/rYWaYQcgC0RWI20HTFBMxlTAyNxYNWzX7RKFkGVVyB9RsAtmcc8g + +j4OdosbfNoJPS0HeIfNpAznDfHKdxDk2Yc1tV6RHBrC1ynyLE9+TaflIAdo2MVv + KLMLq51GqYKtgJFIlBRPQqKoyXdz3fGvXrTkf/WY9QNq0J1Vk5ERePZ54mN8iZB7 + 9lwy/AkCgYEA6FXzosxswaJ2wQLeoYc7ceaweX/SwTvxHgXzRyJIIT0eJWgx13Wo + /WA3Iziimsjf6qE+SI/8laxPp2A86VMaIt3Z3mJN/CqSVGw8LK2AQst+OwdPyDMu + iacE8lj/IFGC8mwNUAb9CzGU3JpU4PxxGFjS/eMtGeRXCWkK4NE+G08CgYEA1Kp9 + N2JrVlqUz+gAX+LPmE9OEMAS9WQSQsfCHGogIFDGGcNf7+uwBM7GAaSJIP01zcoe + VAgWdzXCv3FLhsaZoJ6RyLOLay5phbu1iaTr4UNYm5WtYTzMzqh8l1+MFFDl9xDB + vULuCIIrglM5MeS/qnSg1uMoH2oVPj9TVst/ir8CgYEAxrI7Ws9Zc4Bt70N1As+U + lySjaEVZCMkqvHJ6TCuVZFfQoE0r0whdLdRLU2PsLFP+q7qaeZQqgBaNSKeVcDYR + 9B+nY/jOmQoPewPVsp/vQTCnE/R81spu0mp0YI6cIheT1Z9zAy322svcc43JaWB7 + mEbeqyLOP4Z4qSOcmghZBSECgYACvR9Xs0DGn+wCsW4vze/2ei77MD4OQvepPIFX + dFZtlBy5ADcgE9z0cuVB6CiL8DbdK5kwY9pGNr8HUCI03iHkW6Zs+0L0YmihfEVe + PG19PSzK9CaDdhD9KFZSbLyVFmWfxOt50H7YRTTiPMgjyFpfi5j2q348yVT0tEQS + fhRqaQKBgAcWPokmJ7EbYQGeMbS7HC8eWO/RyamlnSffdCdSc7ue3zdVJxpAkQ8W + qu80pEIF6raIQfAf8MXiiZ7auFOSnHQTXUbhCpvDLKi0Mwq3G8Pl07l+2s6dQG6T + lv6XTQaMyf6n1yjzL+fzDrH3qXMxHMO/b13EePXpDMpY7HQpoLDi + -----END RSA PRIVATE KEY----- + certificateAuthority: + type: string + description: Certificate authority only for automatic certificate renewal by eCDN. Required if the `certificateType` value is automatic. Valid values are `google` or `lets_encrypt`. + pattern: ^.*$ + example: lets_encrypt + certificateValidation: + type: string + description: Certificate validation type is optional only for `certificateType` automatic, default value is `http`. Valid values are `http` or `txt`. + pattern: ^.*$ + example: http + wildcardHostname: + type: boolean + description: Set to true for a wildcard custom hostname. + example: false + description: Certificate request information + example: + hostname: example.com + bundleMethod: ubiquitous + certificateType: custom + certificate: |- + -----BEGIN CERTIFICATE----- + MIIDtTCCAp2gAwIBAgIJAMHAwfXZ5PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV + BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX + aWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF + MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 + ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB + CgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1 + CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB + KwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5 + 0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI + dZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2 + izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4 + 9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI + GKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV + BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF + MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2 + 2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP + Mlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG + SvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq + 2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw + YbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY= + -----END CERTIFICATE----- + privateKey: |- + -----BEGIN RSA PRIVATE KEY----- + MIIEowIBAAKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmG + dtcGbg/1CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKn + abIRuGvBKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpid + tnKX/a+50GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+py + FxIXjbEIdZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pE + ewooaeO2izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABAoIBACbhTYXBZYKmYPCb + HBR1IBlCQA2nLGf0qRuJNJZg5iEzXows/6tc8YymZkQE7nolapWsQ+upk2y5Xdp/ + axiuprIs9JzkYK8Ox0r+dlwCG1kSW+UAbX0bQ/qUqlsTvU6muVuMP8vZYHxJ3wmb + +ufRBKztPTQ/rYWaYQcgC0RWI20HTFBMxlTAyNxYNWzX7RKFkGVVyB9RsAtmcc8g + +j4OdosbfNoJPS0HeIfNpAznDfHKdxDk2Yc1tV6RHBrC1ynyLE9+TaflIAdo2MVv + KLMLq51GqYKtgJFIlBRPQqKoyXdz3fGvXrTkf/WY9QNq0J1Vk5ERePZ54mN8iZB7 + 9lwy/AkCgYEA6FXzosxswaJ2wQLeoYc7ceaweX/SwTvxHgXzRyJIIT0eJWgx13Wo + /WA3Iziimsjf6qE+SI/8laxPp2A86VMaIt3Z3mJN/CqSVGw8LK2AQst+OwdPyDMu + iacE8lj/IFGC8mwNUAb9CzGU3JpU4PxxGFjS/eMtGeRXCWkK4NE+G08CgYEA1Kp9 + N2JrVlqUz+gAX+LPmE9OEMAS9WQSQsfCHGogIFDGGcNf7+uwBM7GAaSJIP01zcoe + VAgWdzXCv3FLhsaZoJ6RyLOLay5phbu1iaTr4UNYm5WtYTzMzqh8l1+MFFDl9xDB + vULuCIIrglM5MeS/qnSg1uMoH2oVPj9TVst/ir8CgYEAxrI7Ws9Zc4Bt70N1As+U + lySjaEVZCMkqvHJ6TCuVZFfQoE0r0whdLdRLU2PsLFP+q7qaeZQqgBaNSKeVcDYR + 9B+nY/jOmQoPewPVsp/vQTCnE/R81spu0mp0YI6cIheT1Z9zAy322svcc43JaWB7 + mEbeqyLOP4Z4qSOcmghZBSECgYACvR9Xs0DGn+wCsW4vze/2ei77MD4OQvepPIFX + dFZtlBy5ADcgE9z0cuVB6CiL8DbdK5kwY9pGNr8HUCI03iHkW6Zs+0L0YmihfEVe + PG19PSzK9CaDdhD9KFZSbLyVFmWfxOt50H7YRTTiPMgjyFpfi5j2q348yVT0tEQS + fhRqaQKBgAcWPokmJ7EbYQGeMbS7HC8eWO/RyamlnSffdCdSc7ue3zdVJxpAkQ8W + qu80pEIF6raIQfAf8MXiiZ7auFOSnHQTXUbhCpvDLKi0Mwq3G8Pl07l+2s6dQG6T + lv6XTQaMyf6n1yjzL+fzDrH3qXMxHMO/b13EePXpDMpY7HQpoLDi + -----END RSA PRIVATE KEY----- + certificateAuthority: lets_encrypt + certificateValidation: http + wildcardHostname: false + additionalProperties: false + CertificateEnvelope: + required: + - data + type: object + properties: + data: + $ref: '#/components/schemas/Certificate' + example: + data: + certificateId: f90712123fb02287348dd34c0a282bb9 + hosts: + - example.com + - www.example.com + expiresOn: '2025-12-31T23:59:59Z' + uploadedOn: '2024-01-01T00:00:00Z' + issuer: Let's Encrypt Authority X3 + signature: SHA256 + status: ACTIVE + minTlsVersion: '1.2' + certificateType: custom + certificateAuthority: lets_encrypt + certificateValidation: http + certificateVerificationTXTName: _acme-challenge.example.com + certificateVerificationTXTValue: abc123def456ghi789 + certificateVerificationStatus: ACTIVE + wildcardHostname: false + wildcardCertificateVerificationTXTName: _acme-challenge.wildcard.example.com + wildcardCertificateVerificationTXTValue: wildcard_abc123def456 + wildcardCertificateVerificationStatus: ACTIVE + customHostnameVerificationTXTName: _acme-challenge.custom.example.com + customHostnameVerificationTXTValue: custom_abc123def456 + customHostnameId: f90712123fb02287348dd34c0a282bb9 + customHostname: custom.example.com + customHostnameStatus: ACTIVE + dcvDelegationRecords: [] + additionalProperties: false + CustomHostnameValidationResponse: + required: + - customHostname + - customHostnameId + - customHostnameStatus + - customHostnameVerificationTXTName + - customHostnameVerificationTXTValue + type: object + properties: + customHostnameId: + type: string + description: Identifier generated by the CDN provider for the custom hostname. + pattern: ^.*$ + example: a439eb1f-5e71-4544-bb29-54d18ax62277 + customHostname: + type: string + description: Name of the custom hostname + pattern: ^.*$ + example: test.example.com + customHostnameVerificationTXTName: + type: string + description: Custom hostname verification txt name. + pattern: ^.*$ + example: _acme-challenge.test.example.com + customHostnameVerificationTXTValue: + type: string + description: Custom hostname verification txt value. + pattern: ^.*$ + example: DBCtxdyQSyo9eXxys-uGVCwPFHLsc8_lu11QetQz4IA + customHostnameStatus: + type: string + description: Current status of the custom hostname. + example: ACTIVE + enum: + - PENDING + - ACTIVE + - MOVED + - DELETED + description: Custom hostname validation information. + example: + customHostnameId: a439eb1f-5e71-4544-bb29-54d18ax62277 + customHostname: test.example.com + customHostnameVerificationTXTName: _acme-challenge.test.example.com + customHostnameVerificationTXTValue: DBCtxdyQSyo9eXxys-uGVCwPFHLsc8_lu11QetQz4IA + customHostnameStatus: ACTIVE + additionalProperties: false + CustomHostnameValidationEnvelope: + type: object + properties: + data: + $ref: '#/components/schemas/CustomHostnameValidationResponse' + required: + - data + example: + data: + customHostnameId: a439eb1f-5e71-4544-bb29-54d18ax62277 + customHostname: test.example.com + customHostnameVerificationTXTName: _acme-challenge.test.example.com + customHostnameVerificationTXTValue: DBCtxdyQSyo9eXxys-uGVCwPFHLsc8_lu11QetQz4IA + customHostnameStatus: ACTIVE + additionalProperties: false + MRTRules: + required: + - enabled + - expression + - id + - lastUpdated + - mrtHostname + - ref + type: object + properties: + id: + type: string + description: The ID of the rule. + pattern: ^.*$ + example: 12345678901234asdfasfasdf + expression: + type: string + description: The expression that determines the rule's routing behavior. + pattern: ^.*$ + example: (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path1/.*" or http.request.uri.path matches "^.*/path2/.*/products/.*")) + description: + type: string + description: The description of the rule. + pattern: ^.*$ + example: Phased rollout rule for dev-customer.salesforce.com + lastUpdated: + type: string + description: Date when the rule was last updated. + format: date-time + example: '2022-01-01T05:20:00Z' + ref: + type: string + description: The ref of the rule. + pattern: ^.*$ + example: 12345678901234asdfasfasdf1234567 + enabled: + type: boolean + description: Whether or not the rule is enabled. + example: true + mrtHostname: + type: string + description: Managed runtime hostname this rule targets. + pattern: ^.*$ + example: customer-pwa-hybrid.mobify-storefront.com + description: A rule in an MRT ruleset. + example: + id: 12345678901234asdfasfasdf + expression: (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path1/.*" or http.request.uri.path matches "^.*/path2/.*/products/.*")) + description: Phased rollout rule for dev-customer.salesforce.com + lastUpdated: '2022-01-01T05:20:00Z' + ref: 12345678901234asdfasfasdf1234567 + enabled: true + mrtHostname: customer-pwa-hybrid.mobify-storefront.com + additionalProperties: false + MRTRuleset: + required: + - id + - lastUpdated + - name + - rules + type: object + properties: + id: + type: string + description: The ID of the ruleset. + pattern: ^.*$ + example: 12345678901234asdfasfasdf + name: + type: string + description: The name of the ruleset. + pattern: ^.*$ + example: MRT Rules + lastUpdated: + type: string + description: Date when the ruleset was last updated. + format: date-time + example: '2022-01-01T05:20:00Z' + rules: + items: + $ref: '#/components/schemas/MRTRules' + type: array + description: The rules defined by the ruleset. + description: An MRT ruleset. Defines a list of MRT rules that will route certain storefront requests to the managed runtime instance. + example: + id: 12345678901234asdfasfasdf + name: MRT Rules + lastUpdated: '2022-01-01T05:20:00Z' + rules: [] + additionalProperties: false + MRTRulesResponse: + required: + - ruleset + type: object + properties: + ruleset: + $ref: '#/components/schemas/MRTRuleset' + description: Response for MRT rules. MRT rules are a way to route certain storefront requests to the managed runtime instance. + example: + ruleset: + id: 12345678901234asdfasfasdf + name: MRT Rules + lastUpdated: '2022-01-01T05:20:00Z' + rules: [] + additionalProperties: false + MRTRulesResponseEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/MRTRulesResponse' + example: + data: + ruleset: + id: 12345678901234asdfasfasdf + name: MRT Rules + lastUpdated: '2022-01-01T05:20:00Z' + rules: [] + additionalProperties: false + MRTRulesPostRequest: + required: + - expressions + - mrtHostname + type: object + properties: + mrtHostname: + type: string + description: The customer's MRT instance hostname. + pattern: ^.*$ + example: customer-react-project-production.mobify-storefront.com + expressions: + items: + type: string + pattern: ^.*$ + example: (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path1/.*" or http.request.uri.path matches "^.*/path2/.*/products/.*")) + type: array + description: An array containing the expressions for each MRT rule. + example: + - (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path1/.*" or http.request.uri.path matches "^.*/path2/.*/products/.*")) + descriptions: + items: + type: string + pattern: ^.*$ + example: Phased rollout rule for dev-customer.salesforce.com + type: array + description: An array containing the descriptions for each MRT rule. The number of descriptions provided must match the number of expressions provided. Optional. + example: + - Phased rollout rule for dev-customer.salesforce.com + description: POST request for creating MRT rules. MRT rules are a way to route certain storefront requests to the managed runtime instance. + example: + mrtHostname: customer-react-project-production.mobify-storefront.com + expressions: + - (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path1/.*" or http.request.uri.path matches "^.*/path2/.*/products/.*")) + descriptions: + - Phased rollout rule for dev-customer.salesforce.com + additionalProperties: false + MRTRulesetPatchRequest: + required: + - mrtHostname + type: object + properties: + oldMrtHostname: + type: string + description: The customer's current MRT instance hostname. + pattern: ^.*$ + example: customer-react-projec-production.mobify-storefront.com + mrtHostname: + type: string + description: The customer's MRT instance hostname. + pattern: ^.*$ + example: customer-react-projec-production.mobify-storefront.com + expressions: + items: + type: string + pattern: ^.*$ + example: (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path1/.*" or http.request.uri.path matches "^.*/path2/.*/products/.*")) + type: array + description: An array containing the expressions for each MRT rule. + example: + - (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path1/.*" or http.request.uri.path matches "^.*/path2/.*/products/.*")) + descriptions: + items: + type: string + pattern: ^.*$ + example: Phased rollout rule for dev-customer.salesforce.com + type: array + description: An array containing the descriptions for each MRT rule. The number of descriptions provided must match the number of expressions provided. Optional. + example: + - Phased rollout rule for dev-customer.salesforce.com + description: PATCH request for updating the MRT environment hostname or adding MRT rules to route to an existing MRT environment. + example: + mrtHostname: customer-react-projec-production.mobify-storefront.com + expressions: + - (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path1/.*" or http.request.uri.path matches "^.*/path2/.*/products/.*")) + descriptions: + - Phased rollout rule for dev-customer.salesforce.com + additionalProperties: false + MRTRulePatchRequest: + type: object + properties: + enabled: + type: boolean + description: Whether or not the rule is enabled. + example: true + expression: + type: string + description: The expression that determines the MRT rule's routing behavior. + pattern: ^.*$ + example: (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path1/.*" or http.request.uri.path matches "^.*/path2/.*/products/.*")) + description: + type: string + description: The description of the rule. Optional. + pattern: ^.*$ + example: Phased rollout rule for dev-customer.salesforce.com + description: PATCH request for updating an MRT rule. You may use the PATCH request to update the rule's expression and description as well as disable/enable the rule. + example: + enabled: true + expression: (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path1/.*" or http.request.uri.path matches "^.*/path2/.*/products/.*")) + description: Phased rollout rule for dev-customer.salesforce.com + additionalProperties: false + LogpushOwnershipPostRequest: + required: + - destinationPath + type: object + properties: + destinationPath: + type: string + description: Uniquely identifies a resource (such as an s3 bucket) where data will be pushed. Additional configuration parameters supported by the destination may be included. You can use the special string {DATE} in the URL path to separate logs into daily subdirectories; for example s3://customer-bucket/logs/{DATE}?region=us-east-1&sse=AES256. The name of the directory will be replaced with the date in YYYYMMDD format (e.g. 20220215) when the logs are stored. + pattern: ^.*$ + example: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + description: POST request for creating new Logpush Ownership. + example: + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + additionalProperties: false + LogpushOwnershipPostResponse: + required: + - data + type: object + properties: + data: + required: + - destinationPath + - fileName + type: object + properties: + destinationPath: + type: string + description: Destination where logs will be sent (S3 bucket only). + pattern: ^.*$ + example: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + fileName: + type: string + description: File path where the ownership challenge file is written. + pattern: ^.*$ + example: site-name/20230101/ownership-challenge-d12345678.txt + description: The customer's new Logpush Ownership. + description: POST response for created new Logpush Ownership. + example: + data: + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + fileName: site-name/20230101/ownership-challenge-d12345678.txt + additionalProperties: false + LogpushResponse: + type: object + properties: + jobId: + type: integer + description: Unique ID of the job. + example: 123456 + name: + type: string + description: Logpush job name; the name cannot be changed after the job is created. + pattern: ^.*$ + example: my-logpush-job + logType: + type: string + description: Type of logs; available log types are `http_requests`, `firewall_events`, and `page_shield_events`. + example: http_requests + enum: + - http_requests + - firewall_events + - page_shield_events + filter: + type: string + description: Filter provides a way to customize which logs you want to receive. Filters are added as escaped JSON strings formatted. If the filter is not displayed, it indicates that all logs should be included. + pattern: ^.*$ + example: '{"where":{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}}' + logFields: + items: + type: string + pattern: ^.*$ + example: ClientRequestBytes + type: array + description: List of log fields. Depending on the type of log, the list of fields that you would like to see in the logs may vary. + example: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + destinationPath: + type: string + description: Uniquely identifies s3 bucket for logs. + pattern: ^.*$ + example: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + enabled: + type: boolean + description: Flag that indicates if the job is enabled or disabled. + example: false + lastComplete: + type: string + description: The last time that the log has been successfully transmitted to the destination. + format: date-time + example: '2023-01-02T00:00:00Z' + lastError: + type: string + description: The last time the job failed. If empty, the job has either never failed or has run successfully at least once since the last failure. + format: date-time + example: '2023-01-01T10:00:00Z' + errorMessage: + type: string + description: Provide details for the last failure message. If this field is empty, it indicates that the job successfully transmitted logs to the destination. + pattern: ^.*$ + example: No permissions to write to destination bucket + createdOn: + type: string + description: Job creation time. + format: date-time + example: '2023-01-01T00:00:27Z' + description: Logpush job response + example: + jobId: 123456 + name: my-logpush-job + logType: http_requests + filter: '{"where":{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}}' + logFields: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + enabled: false + lastComplete: '2023-01-02T00:00:00Z' + lastError: '2023-01-01T10:00:00Z' + errorMessage: No permissions to write to destination bucket + createdOn: '2023-01-01T00:00:27Z' + additionalProperties: false + LogpushJobsEnvelope: + type: object + required: + - data + properties: + data: + items: + $ref: '#/components/schemas/LogpushResponse' + type: array + example: + data: + - jobId: 123456 + name: my-logpush-job + logType: http_requests + filter: '{"where":{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}}' + logFields: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + enabled: false + lastComplete: '2023-01-02T00:00:00Z' + lastError: '2023-01-01T10:00:00Z' + errorMessage: No permissions to write to destination bucket + createdOn: '2023-01-01T00:00:27Z' + additionalProperties: false + LogpushCreateRequest: + required: + - destinationPath + - logFields + - logType + - name + type: object + properties: + destinationPath: + type: string + description: Uniquely identifies s3 bucket for logs. Additional configuration parameters like region can be included. The string {DATE} in the URL path to separate logs into daily subdirectories; for example `s3://customer-bucket/logs/{DATE}?region=us-east-1&sse=AES256` The name of the directory will be replaced with the date in YYYYMMDD format (e.g. 20220215) when the logs are stored. + pattern: ^.*$ + example: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + name: + type: string + description: Logpush job name; the name cannot be changed after the job is created. + pattern: ^.*$ + example: my-logpush-job + filter: + type: string + description: Filter provides a way to customize which logs you want to receive. Filters are added as escaped JSON strings formatted. Default will include all logs. + pattern: ^.*$ + example: '{"where":{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}}' + logFields: + items: + type: string + pattern: ^.*$ + example: ClientRequestBytes + type: array + description: List of log fields. Depending on the type of log, the list of fields that you would like to see in the logs may vary. + example: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + ownershipChallengeToken: + type: string + description: Ownership token to proves the ownership of the destinationPath. + pattern: ^.*$ + example: abc00000000000000000000 + logType: + type: string + description: Type of logs. Available log types are `http_requests`, `firewall_events`, and `page_shield_events`. + example: http_requests + enum: + - http_requests + - firewall_events + - page_shield_events + description: Request for create Logpush job. + example: + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + name: my-logpush-job + filter: '{"where":{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}}' + logFields: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + ownershipChallengeToken: abc00000000000000000000 + logType: http_requests + additionalProperties: false + LogpushEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/LogpushResponse' + example: + data: + jobId: 123456 + name: my-logpush-job + logType: http_requests + filter: '{"where":{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}}' + logFields: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + enabled: false + lastComplete: '2023-01-02T00:00:00Z' + lastError: '2023-01-01T10:00:00Z' + errorMessage: No permissions to write to destination bucket + createdOn: '2023-01-01T00:00:27Z' + additionalProperties: false + LogpushUpdateRequest: + type: object + properties: + enabled: + type: boolean + description: Flag that indicates if the job is enabled or disabled. + example: true + filter: + type: string + description: Provides customized selection for logs you want to receive. Filters are added as escaped, formatted JSON strings. By default, all logs are included. + pattern: ^.*$ + example: '{"where":{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}}' + logFields: + items: + type: string + pattern: ^.*$ + example: ClientRequestBytes + type: array + description: List of log fields. Depending on the log type, the list of fields that you can specify to be displayed in the log might vary. + example: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + description: Request for update Logpush job + example: + enabled: true + filter: '{"where":{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}}' + logFields: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + additionalProperties: false + WAFRulePackage: + required: + - action_mode + - description + - detection_mode + - id + - name + - sensitivity + - zone_id + type: object + properties: + id: + maxLength: 32 + type: string + example: a25a9a7e9c00afc1fb2e0245519d725b + name: + type: string + description: Name of the firewall package + pattern: ^.*$ + example: OWASP Top 10 Protection + description: + type: string + description: Summary of purpose/function of firewall package + pattern: ^.*$ + example: Protection against OWASP Top 10 vulnerabilities + detection_mode: + type: string + description: How the rules within the package are evaluated during the course of a request. When a package uses anomaly detection, each rule is given a score when triggered. If the total score of all triggered rules exceeds the sensitivity defined on the package, the action defined on the package is taken. Traditional detection decides which action to take when it is triggered by the request. If multiple rules are triggered, the action with highest protection is used. For example, a block action beats a challenge. + pattern: ^.*$ + example: traditional + zone_id: + type: string + description: Zone identifier with which this rule package is associated. + pattern: ^.*$ + example: zone_1234567890abcdef + sensitivity: + type: string + description: Sensitivity for traditional (owasp) rule package. + enum: + - low + - medium + - high + - 'off' + example: medium + action_mode: + type: string + description: The default action that is taken for rules under traditional(owasp) firewall package. + enum: + - simulate + - challenge + - block + example: block + WAFRulePackageEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/WAFRulePackage' + example: + data: + id: a25a9a7e9c00afc1fb2e0245519d725b + name: OWASP Top 10 Protection + description: Protection against OWASP Top 10 vulnerabilities + detection_mode: traditional + zone_id: zone_1234567890abcdef + sensitivity: medium + action_mode: block + additionalProperties: false + WafPackagePatchRequest: + required: + - action_mode + - sensitivity + type: object + properties: + sensitivity: + type: string + description: Sensitivity for traditional (owasp) rule package. + enum: + - low + - medium + - high + - 'off' + example: medium + action_mode: + type: string + description: The default action that is taken for rules under traditional(owasp) firewall package. + enum: + - simulate + - challenge + - block + example: block + example: + sensitivity: medium + action_mode: block + additionalProperties: false + CustomRule: + required: + - actions + - description + - enabled + - expression + - lastUpdated + - ruleId + type: object + properties: + ruleId: + type: string + description: The ID of the custom rule. + pattern: ^.*$ + example: 2c0fc9fa937b11eaa1b71c4d701ab86e + description: + type: string + description: The description of the custom rule. + pattern: ^.*$ + example: Block traffic for malformed URL requests. + expression: + type: string + description: The expression that determines the custom rule's behavior. + pattern: ^.*$ + example: (http.request.uri.path matches \"^/path1/.*\") + actions: + items: + type: string + pattern: ^.*$ + example: block + type: array + description: The action(s) applied by the custom rule. + example: + - block + lastUpdated: + type: string + description: Date when the custom rule was last updated. + format: date-time + example: '2022-01-01T05:20:00Z' + enabled: + type: boolean + description: Whether or not the custom rule is enabled. + example: true + description: A custom rule. + CustomRulesEnvelope: + type: object + required: + - data + properties: + data: + items: + $ref: '#/components/schemas/CustomRule' + type: array + example: + data: + - ruleId: 2c0fc9fa937b11eaa1b71c4d701ab86e + description: Block traffic for malformed URL requests. + expression: (http.request.uri.path matches "^/path1/.*") + actions: + - block + lastUpdated: '2022-01-01T05:20:00Z' + enabled: true + - ruleId: ffffe61cf25e4ec49c34b029ff3060f7 + description: Rate limit form traffic + expression: http.request.uri.path eq "/form" + actions: + - block + lastUpdated: '2022-12-14T21:25:22.329194Z' + enabled: false + additionalProperties: false + RulePosition: + type: object + properties: + before: + type: string + description: Insert the current rule before this ruleId. + pattern: ^.*$ + example: 2c0fc9fa937b11eaa1b71c4d701ab86e + after: + type: string + description: Insert the current rule after this ruleId. + pattern: ^.*$ + example: 2c0fc9fa937b11eaa1b71c4d701ab86e + description: Used to specify the position of a rule. + CustomRulesPostRequest: + type: object + required: + - actions + - description + - expression + properties: + description: + type: string + description: A description of the custom rule. + pattern: ^.*$ + example: Block traffic for malformed URL requests + expression: + type: string + description: The expression that determines the custom rule's behavior. + pattern: ^.*$ + example: (http.request.uri.path matches \"^/path1/.*\") + actions: + items: + type: string + pattern: ^.*$ + example: block + type: array + description: The action(s) applied by the custom rule. + example: + - block + enabled: + type: boolean + description: Whether or not the custom rule is enabled. + example: true + position: + $ref: '#/components/schemas/RulePosition' + description: Create a custom rule. + CustomRuleEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/CustomRule' + example: + data: + ruleId: 2c0fc9fa937b11eaa1b71c4d701ab86e + description: Block traffic for malformed URL requests. + expression: (http.request.uri.path matches "^/path1/.*") + actions: + - block + lastUpdated: '2022-01-01T05:20:00Z' + enabled: true + additionalProperties: false + CustomRulesPatchOrderRequest: + type: object + required: + - ruleIds + properties: + ruleIds: + items: + type: string + pattern: ^.*$ + example: ffffe61cf25e4ec49c34b029ff3060f7 + type: array + description: An array of ruleIds representing the new order of custom rules. + example: + - ffffe61cf25e4ec49c34b029ff3060f7 + - 2c0fc9fa937b11eaa1b71c4d701ab86e + description: Update the order of all existing custom rules. + CustomRulesPatchRequest: + type: object + properties: + description: + type: string + description: A description of the custom rule. + pattern: ^.*$ + example: Block traffic for malformed URL requests + expression: + type: string + description: The expression that determines the custom rule's behavior. + pattern: ^.*$ + example: (http.request.uri.path matches \"^/path1/.*\") + actions: + items: + type: string + pattern: ^.*$ + example: block + type: array + description: The action(s) applied by the custom rule. + example: + - block + enabled: + type: boolean + description: Whether or not the custom rule is enabled. + example: true + position: + $ref: '#/components/schemas/RulePosition' + description: Update a custom rule. + RateLimitingRule: + required: + - action + - characteristics + - description + - enabled + - expression + - lastUpdated + - period + - requestsPerPeriod + - ruleId + - mitigationTimeout + type: object + properties: + ruleId: + type: string + description: The ID of the rate limiting rule. + pattern: ^.*$ + example: 2c0fc9fa937b11eaa1b71c4d701ab86e + description: + type: string + description: The description of the rate limiting rule. + pattern: ^.*$ + example: Rate limit /path1. + expression: + type: string + description: The expression that defines when to evaluate the rate limiting rule. + pattern: ^.*$ + example: (http.request.uri.path matches "^/path1/.*") + characteristics: + items: + type: string + pattern: ^.*$ + example: cf.unique_visitor_id + type: array + description: Set of parameters defining how to group requests when tracking the request rate. + example: + - cf.unique_visitor_id + action: + type: string + description: The action applied by the rate limiting rule. Valid actions are "block", "managed_challenge", "js_challenge", "legacy_captcha", and "log". + pattern: ^.*$ + example: block + period: + type: integer + description: The period of time to consider when evaluating the request rate (in seconds). Valid values are 10, 60, 120, 300, and 600. + example: 60 + requestsPerPeriod: + type: integer + description: The limit for the number of requests in the specified period of time. + example: 50 + mitigationTimeout: + type: integer + description: After the rate is reached, the rate limiting rule applies the rule action to further requests for the period of time defined in this field (in seconds). When set to 0, the rule throttles requests over the maximum configured rate. When greater than 0, the action is presented for the selected duration after the configured rate is exceeded. Valid values are 0, 60, 120, 300, 600, 3600, and 86400. + example: 600 + countingExpression: + type: string + description: The expression that defines what kind of requests we want to rate limit. + pattern: ^.*$ + example: (http.request.uri.path matches "^/path1/.*" and http.response.code eq 400) + lastUpdated: + type: string + description: Date when the rate limiting rule was last updated. + format: date-time + example: '2022-01-01T05:20:00Z' + enabled: + type: boolean + description: Whether or not the rate limiting rule is enabled. + example: true + description: A rate limiting rule. + RateLimitingRulesEnvelope: + type: object + required: + - data + properties: + data: + items: + $ref: '#/components/schemas/RateLimitingRule' + type: array + RateLimitingRulesPostRequest: + required: + - action + - characteristics + - description + - expression + - period + - requestsPerPeriod + - mitigationTimeout + type: object + properties: + description: + type: string + description: The description of the rate limiting rule. + pattern: ^.*$ + example: Rate limit /path1. + expression: + type: string + description: The expression that defines when to evaluate the rate limiting rule. + pattern: ^.*$ + example: (http.request.uri.path matches "^/path1/.*") + characteristics: + items: + type: string + pattern: ^.*$ + example: cf.unique_visitor_id + type: array + description: Set of parameters defining how to group requests when tracking the request rate. + example: + - cf.unique_visitor_id + action: + type: string + description: The action applied by the rate limiting rule. Valid actions are "block", "managed_challenge", "js_challenge", "legacy_captcha", and "log". + pattern: ^.*$ + example: block + period: + type: integer + description: The period of time to consider when evaluating the request rate (in seconds). Valid values are 10, 60, 120, 300, and 600. + example: 60 + requestsPerPeriod: + type: integer + description: The limit for the number of requests in the specified period of time. + example: 50 + mitigationTimeout: + type: integer + description: After the rate is reached, the rate limiting rule applies the rule action to further requests for the period of time defined in this field (in seconds). When set to 0, the rule throttles requests over the maximum configured rate. When greater than 0, the action is presented for the selected duration after the configured rate is exceeded. Valid values are 0, 60, 120, 300, 600, 3600, and 86400. + example: 600 + countingExpression: + type: string + description: The expression that defines what kind of requests we want to rate limit. + pattern: ^.*$ + example: (http.request.uri.path matches "^/path1/.*" and http.response.code eq 400) + enabled: + type: boolean + description: Whether or not the rate limiting rule is enabled. + example: true + position: + $ref: '#/components/schemas/RulePosition' + description: Create a rate limiting rule. + RateLimitingRuleEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/RateLimitingRule' + RateLimitingRulesPatchRequest: + type: object + properties: + description: + type: string + description: The description of the rate limiting rule. + pattern: ^.*$ + example: Rate limit /path1. + expression: + type: string + description: The expression that defines when to evaluate the rate limiting rule. + pattern: ^.*$ + example: (http.request.uri.path matches "^/path1/.*") + characteristics: + items: + type: string + pattern: ^.*$ + example: cf.unique_visitor_id + type: array + description: Set of parameters defining how to group requests when tracking the request rate. + example: + - cf.unique_visitor_id + action: + type: string + description: The action applied by the rate limiting rule. Valid actions are "block", "managed_challenge", "js_challenge", "legacy_captcha", and "log". + pattern: ^.*$ + example: block + period: + type: integer + description: The period of time to consider when evaluating the request rate (in seconds). Valid values are 10, 60, 120, 300, and 600. + example: 60 + requestsPerPeriod: + type: integer + description: The limit for the number of requests in the specified period of time. + example: 50 + mitigationTimeout: + type: integer + description: After the rate is reached, the rate limiting rule applies the rule action to further requests for the period of time defined in this field (in seconds). When set to 0, the rule throttles requests over the maximum configured rate. When greater than 0, the action is presented for the selected duration after the configured rate is exceeded. Valid values are 0, 60, 120, 300, 600, 3600, and 86400. + example: 600 + countingExpression: + type: string + description: The expression that defines what kind of requests we want to rate limit. + pattern: ^.*$ + example: (http.request.uri.path matches "^/path1/.*" and http.response.code eq 400) + enabled: + type: boolean + description: Whether or not the rate limiting rule is enabled. + example: true + position: + $ref: '#/components/schemas/RulePosition' + description: Update a rate limiting rule. + WAFManagedRuleset: + required: + - action + - enabled + - name + - rulesetId + type: object + properties: + name: + type: string + description: The name of the WAF managed ruleset. + pattern: ^.*$ + example: OWASP Core Ruleset + rulesetId: + type: string + description: The ID of the WAF managed ruleset. + pattern: ^.*$ + example: 4814384a9e5d4991b9815dcfc25d2f1f + action: + type: string + description: The action applied by the WAF managed ruleset. + pattern: ^.*$ + example: default + anomalyScore: + type: string + description: The anomaly score threshold of the WAF managed ruleset. Only applicable for the OWASP Core Ruleset. + pattern: ^.*$ + example: low + anomalyScoreThreshold: + type: integer + description: The numerical value of the anomaly score threshold of the WAF managed ruleset. Only applicable for the OWASP Core Ruleset. + example: 60 + paranoiaLevel: + type: integer + description: The paranoia level of the WAF managed ruleset. Higher paranoia levels activate more aggressive rules. Only applicable for the OWASP Core Ruleset. + example: 1 + enabled: + type: boolean + description: Whether or not the WAF managed ruleset is enabled. + example: true + description: A WAF managed ruleset. + example: + name: OWASP Core Ruleset + rulesetId: 4814384a9e5d4991b9815dcfc25d2f1f + action: default + anomalyScore: low + anomalyScoreThreshold: 60 + paranoiaLevel: 1 + enabled: true + additionalProperties: false + WAFManagedRulesetsEnvelope: + type: object + required: + - data + properties: + data: + type: array + items: + $ref: '#/components/schemas/WAFManagedRuleset' + example: + data: + - name: OWASP Core Ruleset + rulesetId: 4814384a9e5d4991b9815dcfc25d2f1f + action: default + anomalyScore: low + anomalyScoreThreshold: 60 + paranoiaLevel: 1 + enabled: true + additionalProperties: false + WAFManagedRulesetRequest: + type: object + properties: + action: + type: string + description: The action applied by the WAF managed ruleset. + pattern: ^.*$ + example: default + anomalyScore: + type: string + description: The anomaly score threshold of the WAF managed ruleset. Only applicable for the OWASP Core Ruleset. + pattern: ^.*$ + example: low + paranoiaLevel: + type: integer + description: The paranoia level of the WAF managed ruleset. Higher paranoia levels activate more aggressive rules. Only applicable for the OWASP Core Ruleset. + example: 1 + enabled: + type: boolean + description: Whether or not the WAF managed ruleset is enabled. + example: true + description: A WAF managed ruleset request body. + example: + action: default + anomalyScore: low + paranoiaLevel: 1 + enabled: true + additionalProperties: false + WAFManagedRulesetEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/WAFManagedRuleset' + example: + data: + name: OWASP Core Ruleset + rulesetId: 4814384a9e5d4991b9815dcfc25d2f1f + action: default + anomalyScore: low + anomalyScoreThreshold: 60 + paranoiaLevel: 1 + enabled: true + additionalProperties: false + WAFManagedRule: + required: + - action + - categories + - description + - enabled + - lastUpdated + - ruleId + type: object + properties: + ruleId: + type: string + description: The ID of the WAF managed rule. + pattern: ^.*$ + example: 5de7edfa648c4d6891dc3e7f84534ffa + action: + type: string + description: The action applied by the WAF managed rule. + pattern: ^.*$ + example: block + score: + type: integer + description: The score of the WAF managed rule. Only applicable for the OWASP Managed Ruleset. + example: 5 + categories: + items: + type: string + pattern: ^.*$ + example: broken-access-control + type: array + description: A list of categories describing the function of the WAF managed rule. + example: + - broken-access-control + - wordpress + description: + type: string + description: The description of the WAF managed rule. + pattern: ^.*$ + example: Wordpress - Broken Access Control + lastUpdated: + type: string + description: Date when the WAF managed rule was last updated. + format: date-time + example: '2024-01-01T05:20:00Z' + enabled: + type: boolean + description: Whether or not the WAF managed rule is enabled. + example: true + description: A WAF managed rule. + example: + ruleId: 5de7edfa648c4d6891dc3e7f84534ffa + action: block + score: 5 + categories: + - broken-access-control + - wordpress + description: Wordpress - Broken Access Control + lastUpdated: '2024-01-01T05:20:00Z' + enabled: true + additionalProperties: false + WAFManagedRulesEnvelope: + type: object + required: + - data + properties: + data: + items: + $ref: '#/components/schemas/WAFManagedRule' + type: array + example: + data: + - ruleId: 5de7edfa648c4d6891dc3e7f84534ffa + action: block + score: 5 + categories: + - broken-access-control + - wordpress + description: Wordpress - Broken Access Control + lastUpdated: '2024-01-01T05:20:00Z' + enabled: true + additionalProperties: false + WAFManagedRuleRequest: + type: object + properties: + action: + type: string + description: The action applied by the WAF managed rule. + pattern: ^.*$ + example: block + enabled: + type: boolean + description: Whether or not the WAF managed rule is enabled. + example: true + description: A PATCH request for updating a WAF managed rule. + example: + action: block + enabled: true + additionalProperties: false + WAFManagedRuleEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/WAFManagedRule' + example: + data: + ruleId: 5de7edfa648c4d6891dc3e7f84534ffa + action: block + score: 5 + categories: + - broken-access-control + - wordpress + description: Wordpress - Broken Access Control + lastUpdated: '2024-01-01T05:20:00Z' + enabled: true + additionalProperties: false + OriginHeaderModification: + required: + - headerName + - headerValue + - lastUpdated + type: object + properties: + headerName: + type: string + description: The name of the header forwarded to the origin. + pattern: ^.*$ + example: x-sfdc-access-control + headerValue: + type: string + description: The masked value of the header forwarded to the origin. + pattern: ^.*$ + example: '****************789' + lastUpdated: + type: string + description: Date when the rule was last updated. + format: date-time + example: '2022-01-01T05:20:00Z' + description: An origin header modification rule. + OriginHeaderModificationEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/OriginHeaderModification' + OriginHeaderModificationPutRequest: + required: + - headerValue + type: object + properties: + headerValue: + type: string + description: The value of the header forwarded to the origin. + pattern: ^.*$ + example: '123456789' + headerName: + type: string + description: The name of the header forwarded to the origin. Cannot be modified for the MRT origin. + pattern: ^.*$ + example: x-sfdc-access-control + description: Put request for creating/updating the origin header modification. + CipherSuitesResponse: + required: + - cipherSuiteType + - ciphers + type: object + properties: + ciphers: + items: + type: string + pattern: ^.*$ + example: ECDHE-ECDSA-AES128-GCM-SHA256 + type: array + description: List of zone level ciphers in the suite. + example: + - ECDHE-ECDSA-AES128-GCM-SHA256 + - ECDHE-RSA-AES128-GCM-SHA256 + cipherSuiteType: + type: string + description: Classification of the ciphers in the suite. + example: Modern + enum: + - Compatible + - Modern + - Custom + - Legacy + description: Cipher suites information. + example: + cipherSuiteType: Modern + additionalProperties: false + CipherSuitesEnvelope: + type: object + required: + - data + properties: + data: + $ref: '#/components/schemas/CipherSuitesResponse' + example: + data: + cipherSuiteType: Modern + additionalProperties: false + CipherSuitesRequest: + required: + - cipherSuiteType + type: object + properties: + ciphers: + items: + type: string + pattern: ^.*$ + example: ECDHE-ECDSA-AES128-GCM-SHA256 + type: array + description: List of zone level ciphers in the suite. + example: + - ECDHE-ECDSA-AES128-GCM-SHA256 + - ECDHE-RSA-AES128-GCM-SHA256 + cipherSuiteType: + type: string + description: Classification of all ciphers in the suite. + example: Modern + enum: + - Compatible + - Modern + - Custom + - Legacy + description: Cipher suites information. + example: + cipherSuiteType: Modern + additionalProperties: false + securitySchemes: + AmOAuth2: + type: oauth2 + description: AccountManager OAuth 2.0 bearer token Authentication. + flows: + clientCredentials: + tokenUrl: https://account.demandware.com/dwsso/oauth2/access_token + scopes: + sfcc.cdn-zones: CDN API Scope READONLY + sfcc.cdn-zones.rw: CDN API Scope + authorizationCode: + authorizationUrl: https://account.demandware.com/dwsso/oauth2/authorize + tokenUrl: https://account.demandware.com/dwsso/oauth2/access_token + scopes: + sfcc.cdn-zones: CDN API Scope READONLY + sfcc.cdn-zones.rw: CDN API Scope + parameters: + organizationId: + description: An identifier for the organization the request is being made by + name: organizationId + in: path + required: true + example: f_ecom_zzxy_prd + schema: + $ref: '#/components/schemas/OrganizationId' + mtlsCertificateId: + name: mtlsCertificateId + in: path + required: true + schema: + type: string + pattern: ^.*$ + example: 465a48f6-3d98-4c15-9312-211984ee8629 + webhookId: + name: webhookId + in: path + required: true + schema: + type: string + pattern: ^.*$ + example: f90712123fb02287348dd34c0a282bb9 + zoneId: + name: zoneId + in: path + required: true + schema: + type: string + pattern: ^.*$ + example: f90712123fb02287348dd34c0a282bb9 + policyId: + name: policyId + in: path + required: true + schema: + type: string + pattern: ^.*$ + example: f90712123fb02287348dd34c0a282bb9 + direction: + name: direction + in: query + description: The direction used to sort returned scripts. + required: false + schema: + type: string + enum: + - asc + - desc + example: asc + excludeCdnCgi: + name: excludeCdnCgi + in: query + description: When true, excludes scripts existing in a /cdn-cgi path from the returned scripts. Default is true. + required: false + schema: + type: boolean + example: true + excludeDuplicates: + name: excludeDuplicates + in: query + description: When true, excludes duplicate scripts. Default is false. + required: false + schema: + type: boolean + example: false + excludeUrls: + name: excludeUrls + in: query + description: Excludes scripts with a URL that contains one of the URL-encoded URLs separated by commas. + required: false + schema: + type: string + pattern: ^.*$ + example: https://example.com/script1.js,https://example.com/script2.js + hosts: + name: hosts + in: query + description: Includes scripts that match one or more URL-encoded hostnames separated by commas. Wildcards are supported at the beginning and end of each hostname. + required: false + schema: + type: string + pattern: ^.*$ + example: '*.example.com,test.example.com' + orderBy: + name: orderBy + in: query + description: The field used to sort returned scripts. + required: false + schema: + type: string + enum: + - first_seen_at + - last_seen_at + example: last_seen_at + pageUrl: + name: pageUrl + in: query + description: Includes scripts that match one or more page URLs (separated by commas) where they were last detected. Wildcards are supported at the beginning and end of each page URL. + required: false + schema: + type: string + pattern: ^.*$ + example: https://example.com/page1,https://example.com/page2 + prioritizeMalicious: + name: prioritizeMalicious + in: query + description: When true, lists malicious scripts first in the returned scripts. + required: false + schema: + type: boolean + example: true + status: + name: status + in: query + description: Filters the returned scripts using a comma-separated list of script statuses. Accepted values are 'active', 'infrequent', and 'inactive'. Default is 'active'. + required: false + schema: + type: string + pattern: ^.*$ + example: active,infrequent + urls: + name: urls + in: query + description: Includes scripts with a URL that contains one or more URL-encoded URLs separated by commas. + required: false + schema: + type: string + pattern: ^.*$ + example: https://example.com/script1.js,https://example.com/script2.js + scriptId: + name: scriptId + in: path + required: true + schema: + type: string + pattern: ^.*$ + example: f90712123fb02287348dd34c0a282bb9 + groupIdPath: + name: groupId + in: path + description: WAF Group that contains the WAF rules. + example: f90712123fb02287348dd34c0a282bb9 + required: true + schema: + type: string + pattern: ^.*$ + example: f90712123fb02287348dd34c0a282bb9 + groupIdQuery: + name: groupId + in: query + description: WAF Group that contains the WAF rules. + example: f90712123fb02287348dd34c0a282bb9 + required: false + schema: + type: string + pattern: ^.*$ + example: f90712123fb02287348dd34c0a282bb9 + ruleId: + name: ruleId + in: path + required: true + schema: + type: string + pattern: ^.*$ + example: ffffe61cf25e4ec49c34b029ff3060f7 + certificateId: + name: certificateId + in: path + required: true + schema: + type: string + pattern: ^.*$ + example: f90712123fb02287348dd34c0a282bb9 + customHostnameId: + name: customHostnameId + in: path + required: true + schema: + type: string + pattern: ^.*$ + example: f90712123fb02287348dd34c0a282bb9 + rulesetId: + name: rulesetId + in: path + required: true + schema: + type: string + pattern: ^.*$ + example: f90712123fb02287348dd34c0a282bb9 + jobId: + name: jobId + in: path + required: true + schema: + type: string + pattern: ^.*$ + example: f90712123fb02287348dd34c0a282bb9 + type: + name: type + in: path + description: The type of origin header modification. Only the `mrt` type is supported. + required: true + schema: + type: string + pattern: ^.*$ + example: mrt + examples: + StorefrontZoneCreateRequestBodyExample: + value: + domainName: cc-merchant.com + StorefrontZoneCreateResponse: + value: + data: + zoneId: 023e105f4ecef8ad9ca31a8372d0c353 + zoneName: stg-zzzz-cc-merchant-com.cc-ecdn.net + createdOn: '2022-01-01T05:20:00.12345Z' + status: active + BadRequest: + value: + type: https://api.commercecloud.salesforce.com/documentation/error/v1/errors/bad-request + title: Bad Request + detail: Request body contains 1 or more attributes that contains errors. + Unauthorized: + value: + type: https://api.commercecloud.salesforce.com/documentation/error/v1/errors/unauthorized + title: UnAuthorized Access + detail: The authorization token passed is no longer valid + Forbidden: + value: + type: https://api.commercecloud.salesforce.com/documentation/error/v1/errors/forbidden-access + title: Forbidden + detail: Access to requested resource is forbidden. + NotFound: + value: + type: https://api.commercecloud.salesforce.com/documentation/error/v1/errors/resource-not-found + title: Not Found + detail: Requested resource was not found + InternalServerError: + value: + type: https://api.commercecloud.salesforce.com/documentation/error/v1/errors/internal-server + title: Internal Server Error + detail: An internal server error occured. Please contact support. + MtlsCodeUploadGetCertificatesResponse: + value: + data: + - mtlsCertificateId: 465a48f6-3d98-4c15-9312-211984ee8629 + expiresOn: '2022-01-12T04:15:57Z' + issuer: DigiCert + signature: SHA256WithRSA + uploadedOn: '2020-01-12T04:15:57Z' + ca: true + serialNumber: '432217133297895665180570788458463042229861757760' + mtlsCertificateName: mtls_cert_name + mtlsAssociatedCodeUploadHostname: mtls.cert.salesforce.com + - mtlsCertificateId: 465a48f6-3d98-4c15-9312-211984ee8630 + expiresOn: '2022-01-12T04:15:57Z' + issuer: DigiCert + signature: SHA256WithRSA + uploadedOn: '2020-01-12T04:15:57Z' + ca: true + serialNumber: '432217133297895665180570788458463042229861757761' + mtlsCertificateName: mtls_cert_name + mtlsAssociatedCodeUploadHostname: mtls.cert.salesforce.com + MtlsCodeUploadPostCertificateRequestBodyExample: + value: + name: mtls_cert_name + certificate: |- + -----BEGIN CERTIFICATE----- + MIIDtTCCAp2gAwIBAgIJAMHAwfXZ5PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV + BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX + aWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF + MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 + ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB + CgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1 + CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB + KwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5 + 0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI + dZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2 + izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4 + 9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI + GKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV + BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF + MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2 + 2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP + Mlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG + SvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq + 2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw + YbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY= + -----END CERTIFICATE----- + privateKey: |- + -----BEGIN RSA PRIVATE KEY----- + MIIEowIBAAKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmG + dtcGbg/1CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKn + abIRuGvBKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpid + tnKX/a+50GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+py + FxIXjbEIdZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pE + ewooaeO2izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABAoIBACbhTYXBZYKmYPCb + HBR1IBlCQA2nLGf0qRuJNJZg5iEzXows/6tc8YymZkQE7nolapWsQ+upk2y5Xdp/ + axiuprIs9JzkYK8Ox0r+dlwCG1kSW+UAbX0bQ/qUqlsTvU6muVuMP8vZYHxJ3wmb + +ufRBKztPTQ/rYWaYQcgC0RWI20HTFBMxlTAyNxYNWzX7RKFkGVVyB9RsAtmcc8g + +j4OdosbfNoJPS0HeIfNpAznDfHKdxDk2Yc1tV6RHBrC1ynyLE9+TaflIAdo2MVv + KLMLq51GqYKtgJFIlBRPQqKoyXdz3fGvXrTkf/WY9QNq0J1Vk5ERePZ54mN8iZB7 + 9lwy/AkCgYEA6FXzosxswaJ2wQLeoYc7ceaweX/SwTvxHgXzRyJIIT0eJWgx13Wo + /WA3Iziimsjf6qE+SI/8laxPp2A86VMaIt3Z3mJN/CqSVGw8LK2AQst+OwdPyDMu + iacE8lj/IFGC8mwNUAb9CzGU3JpU4PxxGFjS/eMtGeRXCWkK4NE+G08CgYEA1Kp9 + N2JrVlqUz+gAX+LPmE9OEMAS9WQSQsfCHGogIFDGGcNf7+uwBM7GAaSJIP01zcoe + VAgWdzXCv3FLhsaZoJ6RyLOLay5phbu1iaTr4UNYm5WtYTzMzqh8l1+MFFDl9xDB + vULuCIIrglM5MeS/qnSg1uMoH2oVPj9TVst/ir8CgYEAxrI7Ws9Zc4Bt70N1As+U + lySjaEVZCMkqvHJ6TCuVZFfQoE0r0whdLdRLU2PsLFP+q7qaeZQqgBaNSKeVcDYR + 9B+nY/jOmQoPewPVsp/vQTCnE/R81spu0mp0YI6cIheT1Z9zAy322svcc43JaWB7 + mEbeqyLOP4Z4qSOcmghZBSECgYACvR9Xs0DGn+wCsW4vze/2ei77MD4OQvepPIFX + dFZtlBy5ADcgE9z0cuVB6CiL8DbdK5kwY9pGNr8HUCI03iHkW6Zs+0L0YmihfEVe + PG19PSzK9CaDdhD9KFZSbLyVFmWfxOt50H7YRTTiPMgjyFpfi5j2q348yVT0tEQS + fhRqaQKBgAcWPokmJ7EbYQGeMbS7HC8eWO/RyamlnSffdCdSc7ue3zdVJxpAkQ8W + qu80pEIF6raIQfAf8MXiiZ7auFOSnHQTXUbhCpvDLKi0Mwq3G8Pl07l+2s6dQG6T + lv6XTQaMyf6n1yjzL+fzDrH3qXMxHMO/b13EePXpDMpY7HQpoLDi + -----END RSA PRIVATE KEY----- + MtlsCodeUploadGetCertificateResponse: + value: + data: + mtlsCertificateId: 465a48f6-3d98-4c15-9312-211984ee8629 + expiresOn: '2022-01-12T04:15:57Z' + issuer: DigiCert + signature: SHA256WithRSA + uploadedOn: '2020-01-12T04:15:57Z' + ca: true + serialNumber: '432217133297895665180570788458463042229861757760' + mtlsCertificateName: mtls_cert_name + mtlsAssociatedCodeUploadHostname: mtls.cert.salesforce.com + PageShieldNotificationWebhookListResponse: + value: + data: + - id: webhook_1234567890abcdef + name: Security Alert Webhook + webhookUrl: https://example.com/webhook/security + type: security_alert + createdAt: '2023-01-01T00:00:00Z' + lastSuccess: '2023-01-01T12:00:00Z' + lastFailure: '2023-01-01T18:00:00Z' + zones: + - zone_1234567890abcdef + PageShieldNotificationWebhookRequest: + value: + webhookUrl: https://example.com/webhook/security + secret: webhook_secret_123 + zones: + - zone_1234567890abcdef + PageShieldNotificationWebhookResponse: + value: + data: + id: webhook_1234567890abcdef + name: Security Alert Webhook + webhookUrl: https://example.com/webhook/security + type: security_alert + createdAt: '2023-01-01T00:00:00Z' + lastSuccess: '2023-01-01T12:00:00Z' + lastFailure: '2023-01-01T18:00:00Z' + zones: + - zone_1234567890abcdef + PageShieldPoliciesGetResponse: + value: + data: + - action: log + description: example page shield policy 1 + enabled: true + expression: (http.request.full_uri contains "/Checkout-Begin" and http.host eq "www.example.com") + value: script-src salesforce.com *.salesforce.com https://www.example.com/on/demandware.static/Sites-RefArch-Site/-/en_US/v1738096133818/js/checkout.js 'unsafe-inline' + id: 4805ab87bb867579757a4564ba46ebca + - action: log + description: example page shield policy 2 + enabled: true + expression: ends_with(http.request.uri.path, "/test1") + value: script-src 'none' + id: 7650c87c9c2846c296ea4564ba46ebca + PageShieldPolicyRequestBodyExample: + value: + action: log + description: example page shield policy + enabled: true + expression: ends_with(http.request.uri.path, "/test1") + value: script-src 'none' + PageShieldPolicyGetResponse: + value: + data: + action: log + description: example page shield policy + enabled: true + expression: ends_with(http.request.uri.path, "/test1") + value: script-src 'none' + id: 7650c87c9c2846c296ea4564ba46ebca + PageShieldPolicyPutRequestBodyExample: + value: + action: allow + enabled: true + PageShieldPolicyPutResponse: + value: + data: + action: allow + description: example page shield policy + enabled: true + expression: ends_with(http.request.uri.path, "/test1") + value: script-src 'none' + id: 7650c87c9c2846c296ea4564ba46ebca + PageShieldScriptListResponse: + value: + data: + - id: 12345678901234asdfasfasdf + url: https://sfdc-test.net/on/demandware.static/Sites-SiteNemesis-Site/-/en_US//lib/jquery/ui/jquery-ui.min.js + host: sfdc-test.net + addedAt: '2022-01-01T05:20:00Z' + firstSeenAt: '2022-01-01T05:20:00Z' + lastSeenAt: '2022-01-01T05:20:00Z' + fetchedAt: '2022-01-01T05:20:00Z' + domainReportedMalicious: false + hash: 1243453456abc + cryptoMiningScore: 1 + dataflowScore: 1 + jsIntegrityScore: 1 + mageCartScore: 2 + malwareScore: 1 + obfuscationScore: 2 + maliciousDomainCategories: + - Malware + maliciousUrlCategories: + - Malware + urlContainsCdnCgiPath: false + urlReportedMalicious: false + pageUrls: + - blog.test.salesforce.com/page1 + - blog.test.salesforce.com/page2 + firstPageUrl: blog.test.salesforce.com + status: active + versions: [] + PageShieldScriptResponse: + value: + data: + id: 12345678901234asdfasfasdf + url: https://sfdc-test.net/on/demandware.static/Sites-SiteNemesis-Site/-/en_US//lib/jquery/ui/jquery-ui.min.js + host: sfdc-test.net + addedAt: '2022-01-01T05:20:00Z' + firstSeenAt: '2022-01-01T05:20:00Z' + lastSeenAt: '2022-01-01T05:20:00Z' + fetchedAt: '2022-01-01T05:20:00Z' + domainReportedMalicious: false + hash: 1243453456abc + cryptoMiningScore: 1 + dataflowScore: 1 + jsIntegrityScore: 1 + mageCartScore: 2 + malwareScore: 1 + obfuscationScore: 2 + maliciousDomainCategories: + - Malware + maliciousUrlCategories: + - Malware + urlContainsCdnCgiPath: false + urlReportedMalicious: false + pageUrls: + - blog.test.salesforce.com/page1 + - blog.test.salesforce.com/page2 + firstPageUrl: blog.test.salesforce.com + status: active + versions: [] + ZonesGetResponse: + value: + data: + - zoneId: e4288c0a1f80fa5490b598d74c69bde4 + name: sfcc-cdn.net + status: pending + WafGroupsGetResponse: + value: + data: + - groupId: f90712123fb02287348dd34c0a282bb9 + mode: 'on' + description: 'This WAF Group contains a number of rules that have been created to deal with specific attack types. ' + - groupId: da9d75b083345c63f48e6fde5f617a8b + mode: 'on' + description: This WAF Group contains rules to deal with known malicious traffic or patch flaws in specific web applications. + WafGroupPutRequestBodyExample: + value: + action: monitor + mode: 'on' + WafGroupPutResponse: + value: + data: + groupId: f90712123fb02287348dd34c0a282bb9 + mode: 'on' + description: 'This WAF Group contains a number of rules that have been created to deal with specific attack types. ' + WafRulesGetResponse: + value: + data: + - ruleId: '100001' + groupId: f90712123fb02287348dd34c0a282bb9 + action: monitor + defaultAction: challenge + description: Anomaly:Header:User-Agent - Missing + - ruleId: '100002' + groupId: f90712123fb02287348dd34c0a282bb9 + action: monitor + defaultAction: challenge + description: DoS - IE6 Binary POST + - ruleId: 100002A + groupId: f90712123fb02287348dd34c0a282bb9 + action: monitor + defaultAction: challenge + description: DoS - CtrlFunc Botnet + WafRuleGetResponse: + value: + data: + ruleId: '100001' + groupId: f90712123fb02287348dd34c0a282bb9 + action: monitor + defaultAction: challenge + description: Anomaly:Header:User-Agent - Missing + WafRulePutRequestBodyExample: + value: + action: monitor + WafRulePutResponse: + value: + data: + ruleId: '100001' + groupId: f90712123fb02287348dd34c0a282bb9 + action: monitor + defaultAction: challenge + description: 'Anomaly:Header:User-Agent - Missing ' + SpeedSettingsResponse: + value: + data: + brotliCompression: 'off' + http2Prioritization: 'off' + webp: 'off' + polish: 'off' + earlyHints: 'off' + http3: 'off' + http2ToOrigin: 'off' + SpeedSettingsPatchRequestBodyExample: + value: + brotliCompression: 'off' + http2Prioritization: 'off' + SecuritySettingsResponse: + value: + data: + hsts: + enabled: false + includeSubdomains: false + maxAge: 200 + preload: false + securityLevel: medium + tls13Enabled: false + alwaysUseHttps: true + SecuritySettingsUpdateRequestBodyExample: + value: + hsts: + enabled: false + preload: true + securityLevel: high + tls13Enabled: true + alwaysUseHttps: true + CachePurgeRequest: + value: + path: www.sfcc-ecdn-test5.net/dw/shop/v21_9/products + tags: + - product-123 + - category-456 + CachePurgeResponse: + value: + data: + cachePurged: true + details: Cache purged successfully + CachingToggleRequest: + value: + enableOCAPICachingPageRule: true + CachingToggleResponse: + value: + data: + enableOCAPICachingPageRule: true + CertificatesGetResponse1: + value: + data: + - certificateId: 14b72e2c-db8e-40ec-9f89-d80ca431a36e + status: PENDING_VALIDATION + minTlsVersion: '1.2' + certificateType: automatic + certificateAuthority: google + certificateValidation: txt + certificateVerificationTXTName: _acme-challenge.test.example.com + certificateVerificationTXTValue: DBCtxdyQSyo9eXxys-uGVCwPFHLsc8_lu11QetQz4IA + certificateVerificationStatus: PENDING + customHostnameId: 6c8beb36-a679-4eca-a09a-e3d6aca12787 + customHostname: test.example.com + customHostnameStatus: ACTIVE + - certificateId: 16b3f671-de15-4ba8-8c02-84ba011b7751 + hosts: + - shop.example.com + expiresOn: '2024-05-27T22:58:10Z' + uploadedOn: '2024-02-27T22:58:11Z' + issuer: LetsEncrypt + signature: SHA256WithRSA + status: ACTIVE + minTlsVersion: '1.2' + certificateType: automatic + certificateAuthority: lets_encrypt + certificateValidation: http + customHostnameId: dd625c6d-8553-4d14-abc2-6d747866c8d9 + customHostname: shop.example.com + customHostnameStatus: ACTIVE + - certificateId: f135013c-2bf7-4225-b043-84cf35a93e12 + hosts: + - '*.example.com' + expiresOn: '2024-04-09T20:36:39Z' + uploadedOn: '2024-03-19T22:32:41Z' + issuer: LetsEncrypt + signature: SHA256WithRSA + status: ACTIVE + minTlsVersion: '1.2' + certificateType: custom + customHostnameId: 6567aee6-bdbe-4cb1-9f4b-73209c5e867a + customHostname: www.example.com + customHostnameStatus: ACTIVE + CertificatesGetResponse2: + value: + data: + - certificateId: dc95610a-9a20-4e24-b6d6-232df5fc32d1 + hosts: + - shop.example.com + expiresOn: '2024-05-14T23:00:45Z' + uploadedOn: '2024-03-19T21:28:36Z' + issuer: LetsEncrypt + signature: SHA256WithRSA + status: ACTIVE + certificateType: custom_legacy + - certificateId: 3a2a71c6-c00f-41c4-86dd-d6dc434851d5 + hosts: + - www.example.com + expiresOn: '2024-04-15T17:07:59Z' + uploadedOn: '2024-03-19T21:28:36Z' + issuer: LetsEncrypt + signature: SHA256WithRSA + status: ACTIVE + certificateType: custom_legacy + CertificatePostRequestBodyExample: + value: + hostname: www.salesforce.com + certificate: |- + -----BEGIN CERTIFICATE----- + MIIDtTCCAp2gAwIBAgIJAMHAwfXZ5PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV + BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX + aWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF + MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 + ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB + CgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1 + CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB + KwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5 + 0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI + dZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2 + izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4 + 9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI + GKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV + BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF + MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2 + 2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP + Mlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG + SvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq + 2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw + YbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY= + -----END CERTIFICATE----- + privateKey: |- + -----BEGIN RSA PRIVATE KEY----- + MIIEowIBAAKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmG + dtcGbg/1CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKn + abIRuGvBKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpid + tnKX/a+50GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+py + FxIXjbEIdZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pE + ewooaeO2izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABAoIBACbhTYXBZYKmYPCb + HBR1IBlCQA2nLGf0qRuJNJZg5iEzXows/6tc8YymZkQE7nolapWsQ+upk2y5Xdp/ + axiuprIs9JzkYK8Ox0r+dlwCG1kSW+UAbX0bQ/qUqlsTvU6muVuMP8vZYHxJ3wmb + +ufRBKztPTQ/rYWaYQcgC0RWI20HTFBMxlTAyNxYNWzX7RKFkGVVyB9RsAtmcc8g + +j4OdosbfNoJPS0HeIfNpAznDfHKdxDk2Yc1tV6RHBrC1ynyLE9+TaflIAdo2MVv + KLMLq51GqYKtgJFIlBRPQqKoyXdz3fGvXrTkf/WY9QNq0J1Vk5ERePZ54mN8iZB7 + 9lwy/AkCgYEA6FXzosxswaJ2wQLeoYc7ceaweX/SwTvxHgXzRyJIIT0eJWgx13Wo + /WA3Iziimsjf6qE+SI/8laxPp2A86VMaIt3Z3mJN/CqSVGw8LK2AQst+OwdPyDMu + iacE8lj/IFGC8mwNUAb9CzGU3JpU4PxxGFjS/eMtGeRXCWkK4NE+G08CgYEA1Kp9 + N2JrVlqUz+gAX+LPmE9OEMAS9WQSQsfCHGogIFDGGcNf7+uwBM7GAaSJIP01zcoe + VAgWdzXCv3FLhsaZoJ6RyLOLay5phbu1iaTr4UNYm5WtYTzMzqh8l1+MFFDl9xDB + vULuCIIrglM5MeS/qnSg1uMoH2oVPj9TVst/ir8CgYEAxrI7Ws9Zc4Bt70N1As+U + lySjaEVZCMkqvHJ6TCuVZFfQoE0r0whdLdRLU2PsLFP+q7qaeZQqgBaNSKeVcDYR + 9B+nY/jOmQoPewPVsp/vQTCnE/R81spu0mp0YI6cIheT1Z9zAy322svcc43JaWB7 + mEbeqyLOP4Z4qSOcmghZBSECgYACvR9Xs0DGn+wCsW4vze/2ei77MD4OQvepPIFX + dFZtlBy5ADcgE9z0cuVB6CiL8DbdK5kwY9pGNr8HUCI03iHkW6Zs+0L0YmihfEVe + PG19PSzK9CaDdhD9KFZSbLyVFmWfxOt50H7YRTTiPMgjyFpfi5j2q348yVT0tEQS + fhRqaQKBgAcWPokmJ7EbYQGeMbS7HC8eWO/RyamlnSffdCdSc7ue3zdVJxpAkQ8W + qu80pEIF6raIQfAf8MXiiZ7auFOSnHQTXUbhCpvDLKi0Mwq3G8Pl07l+2s6dQG6T + lv6XTQaMyf6n1yjzL+fzDrH3qXMxHMO/b13EePXpDMpY7HQpoLDi + -----END RSA PRIVATE KEY----- + CertificatePostResponse1: + value: + data: + certificateId: 730a1be4-22d7-11eb-aff1-0242ac120002 + status: ACTIVE + hosts: + - salesforce.com + expiresOn: '2022-01-12T04:15:57Z' + uploadedOn: '2020-01-12T04:15:57Z' + issuer: DigiCert + signature: SHA256WithRSA + certificateType: custom + customHostnameVerificationTXTName: _salesforce.com + customHostnameVerificationTXTValue: 4c9c3f4f-2e91-4c5d-a902-f12f9c285b9e + customHostnameId: 465a48f6-3d98-4c15-9312-211984ee8629 + customHostname: test.salesforce.com + customHostnameStatus: ACTIVE + CertificatePostResponse2: + value: + data: + certificateId: 730a1be4-22d7-11eb-aff1-0242ac120002 + hosts: + - salesforce.com + expiresOn: '2022-01-12T04:15:57Z' + uploadedOn: '2020-01-12T04:15:57Z' + status: PENDING + certificateType: automatic + certificateAuthority: google + certificateValidation: txt + certificateVerificationTXTName: _acme-challenge.test.example.com + certificateVerificationTXTValue: SH5Yet8S5dBwPXcRcCjXdf9FXMBVnQjihQ8oN8LoMv0 + certificateVerificationStatus: PENDING + customHostnameVerificationTXTName: _salesforce.com + customHostnameVerificationTXTValue: 4c9c3f4f-2e91-4c5d-a902-f12f9c285b9e + customHostnameId: 465a48f6-3d98-4c15-9312-211984ee8629 + customHostname: test.salesforce.com + customHostnameStatus: ACTIVE + Conflict: + value: + type: https://api.commercecloud.salesforce.com/documentation/error/v1/errors/conflicted + title: Resource Conflict + detail: The request made for the resource is not valid. + CertificateUpdateRequestBodyExample: + value: + hostname: www.salesforce.com + certificate: |- + -----BEGIN CERTIFICATE----- + MIIDtTCCAp2gAwIBAgIJAMHAwfXZ5PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV + BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX + aWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF + MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 + ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB + CgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1 + CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB + KwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5 + 0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI + dZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2 + izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4 + 9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBTLbE49rWf288N6sJA5BRb6FJI + GKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV + BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF + MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2 + 2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP + Mlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG + SvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq + 2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw + YbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY= + -----END CERTIFICATE----- + privateKey: |- + -----BEGIN RSA PRIVATE KEY----- + MIIEowIBAAKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmG + dtcGbg/1CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKn + abIRuGvBKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpid + tnKX/a+50GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+py + FxIXjbEIdZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pE + ewooaeO2izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABAoIBACbhTYXBZYKmYPCb + HBR1IBlCQA2nLGf0qRuJNJZg5iEzXows/6tc8YymZkQE7nolapWsQ+upk2y5Xdp/ + axiuprIs9JzkYK8Ox0r+dlwCG1kSW+UAbX0bQ/qUqlsTvU6muVuMP8vZYHxJ3wmb + +ufRBKztPTQ/rYWaYQcgC0RWI20HTFBMxlTAyNxYNWzX7RKFkGVVyB9RsAtmcc8g + +j4OdosbfNoJPS0HeIfNpAznDfHKdxDk2Yc1tV6RHBrC1ynyLE9+TaflIAdo2MVv + KLMLq51GqYKtgJFIlBRPQqKoyXdz3fGvXrTkf/WY9QNq0J1Vk5ERePZ54mN8iZB7 + 9lwy/AkCgYEA6FXzosxswaJ2wQLeoYc7ceaweX/SwTvxHgXzRyJIIT0eJWgx13Wo + /WA3Iziimsjf6qE+SI/8laxPp2A86VMaIt3Z3mJN/CqSVGw8LK2AQst+OwdPyDMu + iacE8lj/IFGC8mwNUAb9CzGU3JpU4PxxGFjS/eMtGeRXCWkK4NE+G08CgYEA1Kp9 + N2JrVlqUz+gAX+LPmE9OEMAS9WQSQsfCHGogIFDGGcNf7+uwBM7GAaSJIP01zcoe + VAgWdzXCv3FLhsaZoJ6RyLOLay5phbu1iaTr4UNYm5WtYTzMzqh8l1+MFFDl9xDB + vULuCIIrglM5MeS/qnSg1uMoH2oVPj9TVst/ir8CgYEAxrI7Ws9Zc4Bt70N1As+U + lySjaEVZCMkqvHJ6TCuVZFfQoE0r0whdLdRLU2PsLFP+q7qaeZQqgBaNSKeVcDYR + 9B+nY/jOmQoPewPVsp/vQTCnE/R81spu0mp0YI6cIheT1Z9zAy322svcc43JaWB7 + mEbeqyLOP4Z4qSOcmghZBSECgYACvR9Xs0DGn+wCsW4vze/2ei77MD4OQvepPIFX + dFZtlBy5ADcgE9z0cuVB6CiL8DbdK5kwY9pGNr8HUCI03iHkW6Zs+0L0YmihfEVe + PG19PSzK9CaDdhD9KFZSbLyVFmWfxOt50H7YRTTiPMgjyFpfi5j2q348yVT0tEQS + fhRqaQKBgAcWPokmJ7EbYQGeMbS7HC8eWO/RyamlnSffdCdSc7ue3zdVJxpAkQ8W + qu80pEIF6raIQfAf8MXiiZ7auFOSnHQTXUbhCpvDLKi0Mwq3G8Pl07l+2s6dQG6T + lv6XTQaMyf6n1yjzL+fzDrH3qXMxHMO/b13EePXpDMpY7HQpoLDi + -----END RSA PRIVATE KEY----- + CertificateUpdateResponse1: + value: + data: + certificateId: 730a1be4-22d7-11eb-aff1-0242ac120002 + status: ACTIVE + hosts: + - salesforce.com + expiresOn: '2022-01-12T04:15:57Z' + uploadedOn: '2020-01-12T04:15:57Z' + customHostnameVerificationTXTName: _salesforce.com + customHostnameVerificationTXTValue: 4c9c3f4f-2e91-4c5d-a902-f12f9c285b9e + customHostnameId: 465a48f6-3d98-4c15-9312-211984ee8629 + customHostname: test.salesforce.com + customHostnameStatus: ACTIVE + certificateType: custom + CertificateUpdateResponse2: + value: + data: + certificateId: 730a1be4-22d7-11eb-aff1-0242ac120002 + hosts: + - salesforce.com + expiresOn: '2022-01-12T04:15:57Z' + uploadedOn: '2020-01-12T04:15:57Z' + status: PENDING + certificateType: automatic + certificateAuthority: google + certificateValidation: txt + certificateVerificationTXTName: _acme-challenge.test.example.com + certificateVerificationTXTValue: SH5Yet8S5dBwPXcRcCjXdf9FXMBVnQjihQ8oN8LoMv0 + certificateVerificationStatus: PENDING + customHostnameVerificationTXTName: _salesforce.com + customHostnameVerificationTXTValue: 4c9c3f4f-2e91-4c5d-a902-f12f9c285b9e + customHostnameId: 465a48f6-3d98-4c15-9312-211984ee8629 + customHostname: test.salesforce.com + customHostnameStatus: ACTIVE + CustomHostnamesPatchResponse: + value: + data: + customHostnameId: 465a48f6-3d98-4c15-9312-211984ee8629 + customHostname: test.salesforce.com + customHostnameVerificationTXTName: _salesforce.com + customHostnameVerificationTXTValue: 4c9c3f4f-2e91-4c5d-a902-f12f9c285b9e + customHostnameStatus: ACTIVE + MrtRulesGetResponse: + value: + data: + ruleset: + id: 12345678901234asdfasfasdf1234567 + name: MRT Rules + lastUpdated: '2022-09-27T18:32:34.675182Z' + rules: + - id: 12345678901234asdfasfasdf1234567 + expression: (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "/on/path1/.*" or http.request.uri.path matches "/on/path2/.*" or http.request.uri.path matches ".*routeDetails=true" or http.request.uri.path eq "/path3.txt" )) + description: Phased rollout rule for dev-customer.salesforce.com + lastUpdated: '2022-09-15T21:14:42.372459Z' + ref: 12345678901234asdfasfasdf1234567 + enabled: true + mrtHostname: customer.mobify-storefront.com + - id: 12345678901234asdfasfasdf1234567 + expression: (http.host in {"test-customer.salesforce.com" "test2-customer.salesforce.com"} and not ( http.request.uri.path matches "^/path4/.*" or http.request.uri.path matches "^.*/path5/.*/products/.*")) + description: Phased rollout rule for test-customer.salesforce.com + lastUpdated: '2022-09-15T21:14:42.372459Z' + ref: 12345678901234asdfasfasdf1233333 + enabled: true + mrtHostname: customer.mobify-storefront.com + - id: 12345678901234asdfasfasdf1234567 + expression: (http.host eq "prd-customer.salesforce.com" and not ( http.request.uri.path matches "^/path4/.*" or http.request.uri.path matches "^.*/path5/.*/products/.*")) + description: Phased rollout rule for prd-customer.salesforce.com + lastUpdated: '2022-09-15T21:14:42.372459Z' + ref: 98745678901234asdfasfasdf1234567 + enabled: true + mrtHostname: customer.mobify-storefront.com + MrtRulesPostRequestSingleHostnameBodyExample: + value: + mrtHostname: customer.mobify-storefront.com + expressions: + - (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "/on/path1/.*" or http.request.uri.path matches "/on/path2/.*" or http.request.uri.path matches ".*routeDetails=true" or http.request.uri.path eq "/path3.txt" )) + descriptions: + - Phased rollout rule for dev-customer.salesforce.com + MrtRulesPostRequestMultipleHostnamesBodyExample: + value: + mrtHostname: customer.mobify-storefront.com + expressions: + - (http.host in {"test-customer.salesforce.com" "test2-customer.salesforce.com"} and not ( http.request.uri.path matches "^/path4/.*" or http.request.uri.path matches "^.*/path5/.*/products/.*")) + descriptions: + - Phased rollout rule for test-customer.salesforce.com and test2-customer.salesforce.com + MrtRulesPostResponseSingleHostname: + value: + data: + ruleset: + id: 12345678901234asdfasfasdf1234567 + name: MRT Rules + lastUpdated: '2022-09-27T18:32:34.675182Z' + rules: + - id: 12345678901234asdfasfasdf1234567 + expression: (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "/on/path1/.*" or http.request.uri.path matches "/on/path2/.*" or http.request.uri.path matches ".*routeDetails=true" or http.request.uri.path eq "/path3.txt" )) + description: Phased rollout rule for dev-customer.salesforce.com + lastUpdated: '2022-09-15T21:14:42.372459Z' + ref: 12345678901234asdfasfasdf1234567 + enabled: true + mrtHostname: customer.mobify-storefront.com + MrtRulesPostResponseMultipleHostnames: + value: + data: + ruleset: + id: 12345678901234asdfasfasdf1234567 + name: MRT Rules + lastUpdated: '2022-09-27T18:32:34.675182Z' + rules: + - id: 12345678901234asdfasfasdf1234567 + expression: (http.host in {"test-customer.salesforce.com" "test2-customer.salesforce.com"} and not ( http.request.uri.path matches "^/path4/.*" or http.request.uri.path matches "^.*/path5/.*/products/.*")) + description: Phased rollout rule for test-customer.salesforce.com and test2-customer.salesforce.com + lastUpdated: '2022-09-15T21:14:42.372459Z' + ref: 12345678901234asdfasfasdf1234567 + enabled: true + mrtHostname: customer.mobify-storefront.com + MrtRulesetPatchRequestUpdateHostnameBodyExample: + value: + oldMrtHostname: old-hostname.mobify-storefront.com + mrtHostname: new-hostname.mobify-storefront.com + MrtRulesetPatchRequestAddRulesBodyExample: + value: + mrtHostname: customer.mobify-storefront.com + expressions: + - (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "/on/path1/.*" or http.request.uri.path matches "/on/path2/.*" or http.request.uri.path matches ".*routeDetails=true" or http.request.uri.path eq "/path3.txt" )) + - (http.host in {"test-customer.salesforce.com" "test2-customer.salesforce.com"} and not ( http.request.uri.path matches "^/path4/.*" or http.request.uri.path matches "^.*/path5/.*/products/.*")) + descriptions: + - Phased rollout rule for dev-customer.salesforce.com + MrtRulesetPatchResponseUpdateHostname: + value: + data: + ruleset: + id: 12345678901234asdfasfasdf1234567 + name: MRT Rules + lastUpdated: '2022-09-27T18:32:34.675182Z' + rules: + - id: 12345678901234asdfasfasdf1234567 + expression: (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "/on/path1/.*" or http.request.uri.path matches "/on/path2/.*" or http.request.uri.path matches ".*routeDetails=true" or http.request.uri.path eq "/path3.txt" )) + description: Phased rollout rule for dev-customer.salesforce.com + lastUpdated: '2022-09-15T21:14:42.372459Z' + ref: 12345678901234asdfasfasdf1234567 + enabled: true + mrtHostname: new-hostname.mobify-storefront.com + - id: 12345678901234asdfasfasdf1234568 + expression: (http.host in {"test-customer.salesforce.com" "test2-customer.salesforce.com"} and not ( http.request.uri.path matches "^/path4/.*" or http.request.uri.path matches "^.*/path5/.*/products/.*")) + description: Phased rollout rule for test-customer.salesforce.com and test2-customer.salesforce.com + lastUpdated: '2022-09-15T21:14:42.372459Z' + ref: 12345678901234asdfasfasdf1234568 + enabled: true + mrtHostname: new-hostname.mobify-storefront.com + MrtRulesetPatchResponseAddRules: + value: + data: + ruleset: + id: 12345678901234asdfasfasdf1234567 + name: MRT Rules + lastUpdated: '2022-09-27T18:32:34.675182Z' + rules: + - id: 12345678901234asdfasfasdf1234567 + expression: (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "/on/path1/.*" or http.request.uri.path matches "/on/path2/.*" or http.request.uri.path matches ".*routeDetails=true" or http.request.uri.path eq "/path3.txt" )) + description: Phased rollout rule for dev-customer.salesforce.com + lastUpdated: '2022-09-15T21:14:42.372459Z' + ref: 12345678901234asdfasfasdf1234567 + enabled: true + mrtHostname: customer.mobify-storefront.com + - id: 12345678901234asdfasfasdf1234568 + expression: (http.host in {"test-customer.salesforce.com" "test2-customer.salesforce.com"} and not ( http.request.uri.path matches "^/path4/.*" or http.request.uri.path matches "^.*/path5/.*/products/.*")) + description: Phased rollout rule for test-customer.salesforce.com and test2-customer.salesforce.com + lastUpdated: '2022-09-15T21:14:42.372459Z' + ref: 12345678901234asdfasfasdf1234568 + enabled: true + mrtHostname: customer.mobify-storefront.com + MrtRulePatchRequestBodyExample: + value: + enabled: true + expression: (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path4/.*" or http.request.uri.path matches "^.*/path5/.*/products/.*")) + description: Phased rollout rule for dev-customer.salesforce.com + MrtRulePatchResponse: + value: + data: + ruleset: + id: 12345678901234asdfasfasdf1234567 + name: MRT Rules + lastUpdated: '2022-09-15T21:14:42.372459Z' + rules: + - id: 12345678901234asdfasfasdf1234567 + expression: (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path4/.*" or http.request.uri.path matches "^.*/path5/.*/products/.*")) + description: Phased rollout rule for dev-customer.salesforce.com + lastUpdated: '2022-09-27T18:32:34.675182Z' + ref: 12345678901234asdfasfasdf1234567 + enabled: true + mrtHostname: customer.mobify-storefront.com + LogpushOwnershipPostRequestBodyExample: + value: + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + LogpushOwnershipPostResponse: + value: + data: + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + fileName: site-name/20230101/ownership-challenge-f1234567.txt + LogpushGetListJob: + value: + data: + - jobId: 123456 + name: example1-job-name + logType: http_requests + logFields: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + lastComplete: '2023-03-14T02:09:32Z' + createdOn: '2023-01-01T00:00:27Z' + - jobId: 123457 + name: example2-job-name + logType: firewall_events + logFields: + - RuleID + - ClientRequestUserAgent + - ClientRequestPath + filter: '{"where":{"and":[{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}, {"key":"EdgeResponseStatus","operator":"in","value":[502, 503, 504, 520, 521, 522, 522, 523, 524, 525, 526, 530]}]}}' + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + lastComplete: '2023-03-22T02:09:32Z' + createdOn: '2023-01-03T00:00:27Z' + - jobId: 123458 + name: example3-job-name + logType: page_shield_events + logFields: + - Action + - CSPDirective + - Host + - PageURL + - PolicyID + - ResourceType + - Timestamp + - URL + - URLHost + destinationPath: s3://customer-bucket/site-name/page-shield-events/{DATE}?region=us-east-1&sse=AES256 + lastComplete: '2025-01-02T02:09:32Z' + createdOn: '2025-01-01T00:00:27Z' + LogpushCreateRequestBodyExample1: + value: + name: example-job-name + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + ownershipChallengeToken: abc00000000000000000000 + logFields: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + logType: http_requests + LogpushCreateRequestBodyExample2: + value: + name: example-job-name-with-filter + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + ownershipChallengeToken: abc00000000000000000000 + logFields: + - ClientRequestBytes + - ClientRequestPath + - ClientRequestHost + - ClientRequestMethod + - EdgeResponseStatus + filter: '{"where":{"and":[{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}, {"key":"EdgeResponseStatus","operator":"in","value":[502, 503, 504, 520, 521, 522, 522, 523, 524, 525, 526, 530]}]}}' + logType: http_requests + LogpushCreateRequestBodyExample3: + value: + name: example-job-name + destinationPath: s3://customer-bucket/site-name/page-shield-events/{DATE}?region=us-east-1&sse=AES256 + ownershipChallengeToken: abc00000000000000000000 + logFields: + - Action + - CSPDirective + - Host + - PageURL + - PolicyID + - ResourceType + - Timestamp + - URL + - URLHost + logType: page_shield_events + LogpushCreateResponse1: + value: + data: + jobId: 123456 + name: example-job-name + logType: http_requests + logFields: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + enabled: false + createdOn: '2023-01-01T00:00:27Z' + LogpushCreateResponse2: + value: + data: + jobId: 123456 + name: example-job-name-with-filter + logType: http_requests + logFields: + - ClientRequestBytes + - ClientRequestPath + - ClientRequestHost + - ClientRequestMethod + - EdgeResponseStatus + filter: '{"where":{"and":[{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}, {"key":"EdgeResponseStatus","operator":"in","value":[502, 503, 504, 520, 521, 522, 522, 523, 524, 525, 526, 530]}]}}' + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + enabled: false + createdOn: '2023-01-01T00:00:27Z' + LogpushCreateResponse3: + value: + data: + jobId: 123458 + name: example-job-name + logType: page_shield_events + logFields: + - Action + - CSPDirective + - Host + - PageURL + - PolicyID + - ResourceType + - Timestamp + - URL + - URLHost + destinationPath: s3://customer-bucket/site-name/page-shield-events/{DATE}?region=us-east-1&sse=AES256 + enabled: true + createdOn: '2025-01-01T00:00:27Z' + LogpushGetJobById1: + value: + data: + jobId: 123456 + name: example-job-name + logType: http_requests + logFields: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + lastComplete: '2023-03-14T02:09:32Z' + createdOn: '2023-01-01T00:00:27Z' + LogpushGetJobById2: + value: + data: + jobId: 123456 + name: example-job-name + logType: http_requests + logFields: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + lastComplete: '2023-03-14T02:09:32Z' + lastError: '2023-03-16T02:00:00Z' + errorMessage: No permissions to write to destination bucket + createdOn: '2023-01-01T00:00:27Z' + LogpushGetJobById3: + value: + data: + jobId: 123456 + name: example-job-name + logType: http_requests + logFields: + - ClientRequestBytes + - ClientRequestPath + - ClientRequestHost + - ClientRequestMethod + - EdgeResponseStatus + filter: '{"where":{"and":[{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}, {"key":"EdgeResponseStatus","operator":"in","value":[502, 503, 504, 520, 521, 522, 522, 523, 524, 525, 526, 530]}]}}' + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + lastComplete: '2023-03-14T02:09:32Z' + createdOn: '2023-01-01T00:00:27Z' + LogpushUpdateRequestBodyExample: + value: + enabled: true + filter: '{"where":{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}}' + logFields: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + LogpushUpdateResponse: + value: + data: + jobId: 123456 + name: example-job-name + enabled: true + logType: http_requests + logFields: + - ClientRequestBytes + - ClientRequestHost + - ClientRequestMethod + destinationPath: s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + lastComplete: '2023-03-14T02:09:32Z' + lastError: '2023-01-01T00:00:27Z' + errorMessage: '' + WafPackagesGetExample: + value: + data: + id: c504870194831cd12c3fc0284f294abb + name: OWASP ModSecurity Core Rule Set + description: OWASP Core Ruleset (2013) provides protection against common attack categories, including SQL Injection and Cross-Site Scripting. + zone_id: 56702a674281951f541f9f304f7431f0 + detection_mode: anomaly + sensitivity: low + action_mode: simulate + WafPackagesPatchRequestBodyExample: + value: + sensitivity: low + action_mode: simulate + CustomRulesResponse: + value: + data: + - ruleId: ffffe61cf25e4ec49c34b029ff3060f7 + description: Block traffic for malformed URL requests + expression: (http.request.uri.path matches "^/path1/.*") + actions: + - block + lastUpdated: '2022-12-14T21:25:22.329194Z' + enabled: false + - ruleId: 2c0fc9fa937b11eaa1b71c4d701ab86e + description: Skip user agent + expression: (http.user_agent contains "Client") + actions: + - skip_custom_rules, skip_waf + lastUpdated: '2022-12-14T21:30:34.263795Z' + enabled: true + CustomRulesPostRequestBodyExample: + value: + description: Block traffic for malformed URL requests + expression: (http.request.uri.path matches "^/path1/.*") + actions: + - block + enabled: false + position: + before: 2c0fc9fa937b11eaa1b71c4d701ab86e + CustomRuleResponse: + value: + data: + ruleId: ffffe61cf25e4ec49c34b029ff3060f7 + description: Block traffic for malformed URL requests + expression: (http.request.uri.path matches "^/path1/.*") + actions: + - block + lastUpdated: '2022-12-14T21:25:22.329194Z' + enabled: false + CustomRulesPatchOrderRequest: + value: + ruleIds: + - ffffe61cf25e4ec49c34b029ff3060f7 + - 2c0fc9fa937b11eaa1b71c4d701ab86e + CustomRulesPatchRequest: + value: + description: Updated description for the custom rule + expression: (http.request.uri.path matches "^/updated-path/.*") + actions: + - block + RateLimitingRulesResponse: + value: + data: + - ruleId: ffffe61cf25e4ec49c34b029ff3060f7 + description: Rate limit /path1 + expression: http.request.uri.path matches "^/path1/.*" + characteristics: + - cf.unique_visitor_id + action: block + period: 60 + requestsPerPeriod: 50 + mitigationTimeout: 600 + countingExpression: http.request.uri.path matches "^/path1/.*" and http.response.code eq 400 + enabled: false + lastUpdated: '2022-12-14T21:25:22.329194Z' + - ruleId: 2c0fc9fa937b11eaa1b71c4d701ab86e + description: Rate limit AS number 12345 + expression: ip.src.asnum eq 12345 + characteristics: + - ip.src + action: managed_challenge + period: 600 + requestsPerPeriod: 1000 + mitigationTimeout: 0 + enabled: true + lastUpdated: '2022-12-14T21:47:24.323223Z' + RateLimitingRulesPostRequestBodyExample: + value: + description: Rate limit /path1 + expression: http.request.uri.path matches "^/path1/.*" + characteristics: + - cf.unique_visitor_id + action: block + period: 60 + requestsPerPeriod: 50 + mitigationTimeout: 600 + countingExpression: http.request.uri.path matches "^/path1/.*" and http.response.code eq 400 + enabled: false + position: + before: 2c0fc9fa937b11eaa1b71c4d701ab86e + RateLimitingRuleResponse: + value: + data: + ruleId: ffffe61cf25e4ec49c34b029ff3060f7 + description: Rate limit /path1 + expression: http.request.uri.path matches "^/path1/.*" + characteristics: + - cf.unique_visitor_id + action: block + period: 60 + requestsPerPeriod: 50 + mitigationTimeout: 600 + countingExpression: http.request.uri.path matches "^/path1/.*" and http.response.code eq 400 + enabled: false + lastUpdated: '2022-12-14T21:25:22.329194Z' + RateLimitingRulesPatchRequest: + value: + description: Updated rate limiting rule description + expression: http.request.uri.path matches "^/updated-path/.*" + characteristics: + - cf.unique_visitor_id + action: block + period: 120 + requestsPerPeriod: 100 + mitigationTimeout: 1200 + countingExpression: http.request.uri.path matches "^/updated-path/.*" and http.response.code eq 400 + enabled: true + WAFManagedRulesetsResponse: + value: + data: + - name: Managed Ruleset + rulesetId: efb7b8c949ac4650a09736fc376e9aee + action: default + enabled: true + - name: OWASP Core Ruleset + rulesetId: 4814384a9e5d4991b9815dcfc25d2f1f + action: log + anomalyScoreThreshold: 25 + anomalyScore: high + paranoiaLevel: 1 + enabled: true + - name: Leaked Crednetials Check Ruleset + rulesetId: c2e184081120413c86c3ab7e14069605 + action: block + enabled: true + WAFManagedRulesetsUpdateRequestBodyExample: + value: + action: js_challenge + enabled: true + WAFManagedRulesetsUpdateResponse: + value: + data: + name: Managed Ruleset + rulesetId: efb7b8c949ac4650a09736fc376e9aee + action: js_challenge + enabled: true + WAFManagedRulesResponse: + value: + data: + - ruleId: 8ac8bc2a661e475d940980f9317f28e1 + action: block + score: 5 + categories: + - application-multi + - attack-generic + - capec-1000 + - capec-210 + - capec-220 + - capec-272 + - capec-274 + - language-multi + - paranoia-level-1 + - pci-12-1 + - platform-multi + description: '911100: Method is not allowed by policy' + lastUpdated: '2024-08-19T17:26:58.593021Z' + enabled: false + - ruleId: 53065ac9bd9449f3895f1865467a0e6a + action: block + score: 5 + categories: + - application-multi + - attack-reputation-scanner + - capec-1000 + - capec-118 + - capec-224 + - capec-310 + - capec-541 + - language-multi + - paranoia-level-1 + - pci-6-5-10 + - platform-multi + description: '913100: Found User-Agent associated with security scanner' + lastUpdated: '2024-08-19T17:26:58.593021Z' + enabled: true + WAFManagedRulesUpdateRequestBodyExample: + value: + action: log + enabled: true + WAFManagedRulesUpdateResponse: + value: + data: + ruleId: 53065ac9bd9449f3895f1865467a0e6a + action: log + score: 5 + categories: + - application-multi + - attack-reputation-scanner + - capec-1000 + - capec-118 + - capec-224 + - capec-310 + - capec-541 + - language-multi + - paranoia-level-1 + - pci-6-5-10 + - platform-multi + description: '913100: Found User-Agent associated with security scanner' + lastUpdated: '2024-08-19T17:26:58.593021Z' + enabled: true + MrtGetResponse: + value: + data: + headerName: x-sfdc-access-control + headerValue: '********789' + lastUpdated: '2024-04-27T18:32:34.675182Z' + MrtPutRequestBodyExample: + value: + headerValue: '123456789' + MrtPutUpdateResponse: + value: + data: + headerName: x-sfdc-access-control + headerValue: '********789' + lastUpdated: '2024-04-27T18:32:34.675182Z' + MrtPutCreateResponse: + value: + data: + headerName: x-sfdc-access-control + headerValue: '********789' + lastUpdated: '2024-04-27T18:32:34.675182Z' + CipherSettingsGetResponse: + value: + data: + ciphers: + - ECDHE-ECDSA-AES128-GCM-SHA256 + - ECDHE-RSA-AES128-GCM-SHA256 + cipherSuiteType: Custom + CipherSettingsPatchRequestBodyExample: + value: + ciphers: + - ECDHE-ECDSA-AES128-GCM-SHA256 + cipherSuiteType: Custom + CipherSettingsPatchResponse: + value: + data: + ciphers: + - ECDHE-ECDSA-AES128-GCM-SHA256 + cipherSuiteType: Custom diff --git a/packages/b2c-tooling-sdk/src/clients/cdn-zones.generated.ts b/packages/b2c-tooling-sdk/src/clients/cdn-zones.generated.ts new file mode 100644 index 00000000..dedba5eb --- /dev/null +++ b/packages/b2c-tooling-sdk/src/clients/cdn-zones.generated.ts @@ -0,0 +1,8331 @@ +/** + * This file was auto-generated by openapi-typescript. + * Do not make direct changes to the file. + */ + +export interface paths { + "/organizations/{organizationId}/storefront-zones": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create a new storefront zone. + * @description Create a new storefront zone for the organization. Use this endpoint to set up a new CDN zone with specific configurations for storefront applications. + */ + post: operations["createStorefrontZone"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/mtls/code-upload-certificates": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Return all the mTLS certificates for the account. + * @description Retrieve all mTLS certificates for the account. These certificates are used for secure code upload operations and client authentication. + */ + get: operations["getCodeUploadCertificates"]; + put?: never; + /** + * Set up two-factor mTLS certificates for the account and associate the staging zone code upload hostname. + * @description Create a new mTLS certificate for code upload operations. This certificate enables secure client authentication for code deployment processes. + */ + post: operations["createCodeUploadCertificate"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/mtls/code-upload-certificates/{mtlsCertificateId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Return the mTLS certificate for the given account's mTLS certificate ID. + * @description Retrieve a specific mTLS certificate by its ID. This endpoint provides detailed information about the certificate's configuration, status, and associated hostname. + */ + get: operations["getCodeUploadCertificate"]; + put?: never; + post?: never; + /** + * Remove an mTLS certificate and associated hostname. + * @description Permanently delete an mTLS certificate and its associated hostname from the account. This operation cannot be undone. + */ + delete: operations["deleteCodeUploadCertificate"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/page-shield/notifications": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get page shield notification webhooks. + * @description See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + */ + get: operations["getPageShieldNotification"]; + put?: never; + /** + * Setup page shield notification webhook. + * @description See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + */ + post: operations["postPageShieldNotification"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/page-shield/notifications/{webhookId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Delete page shield notification webhook. + * @description See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + */ + delete: operations["deletePageShieldNotification"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/page-shield/policies": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List page shield policies. + * @description See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + */ + get: operations["getPageShieldPolicies"]; + put?: never; + /** + * Create page shield policy. + * @description See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + */ + post: operations["createPageShieldPolicy"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/page-shield/policies/{policyId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get page shield policy by policy ID. + * @description See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + */ + get: operations["getPageShieldPolicy"]; + /** + * Update page shield policy by policy ID. + * @description See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + */ + put: operations["updatePageShieldPolicy"]; + post?: never; + /** + * Delete page shield policy. + * @description See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + */ + delete: operations["deletePageShieldPolicy"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/page-shield/scripts": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve a list of scripts detected by page shield for a specific zone. + * @description See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + */ + get: operations["getPageShieldScripts"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/page-shield/scripts/{scriptId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Fetch a script detected by Page Shield by script ID. + * @description See [eCDN PCI 4.0 Compliance Tools](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-pci-4-compliance.html). + */ + get: operations["getPageShieldScript"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/info": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve zone information. + * @description Retrieve information about all zones for the organization. This endpoint provides an overview of all CDN zones, including their status, configuration, and basic details. + */ + get: operations["getZonesInfo"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/waf/groups": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve all WAF groups accessible to the caller. + * @description Retrieve all Web Application Firewall (WAF) groups accessible to the caller. This endpoint provides information about WAF groups and their configurations for the specified zone. Not applicable for zones using WAFv2. For zones created after the 24.5 release, use the endpoints for WAF managed rulesets. + */ + get: operations["getWafGroups"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/waf/groups/{groupId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** + * Update the action or mode of a specific WAF group. + * @description Update the action or mode of a specific Web Application Firewall (WAF) group. Use this endpoint to modify the security settings and behavior of a WAF group. Not applicable for zones using WAFv2. For any zones created after the 24.5 release, use the endpoints for WAF managed rulesets. + */ + put: operations["updateWafGroup"]; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/waf/rules": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve WAF rules for the WAF group specified by the caller. + * @description Retrieve WAF rules for the WAF group specified by the caller. This endpoint provides information about the security rules configured for a specific WAF group. Not applicable for zones using WAFv2. For any zones created after the 24.5 release, use the endpoints for WAF managed rulesets. + */ + get: operations["getWafRules"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/waf/rules/{ruleId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve details of a specific WAF rule. + * @description Retrieve details of a specific WAF rule by its ID. This endpoint provides comprehensive information about the rule's configuration and settings. Not applicable for zones using WAFv2. For any zones created after the 24.5 release, use the endpoints for WAF managed rulesets. + */ + get: operations["getWafRule"]; + /** + * Update the action of a specific WAF rule. + * @description Update the action of a specific WAF rule. Use this endpoint to modify the security behavior and response actions of a WAF rule. Not applicable for zones using WAFv2. For any zones created after the 24.5 release, use the endpoints for WAF managed rulesets. + */ + put: operations["updateWafRule"]; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/speed-settings": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve the speed settings for a zone. + * @description Retrieve speed settings for the specified zone. This endpoint provides information about performance optimizations. + */ + get: operations["getSpeedSettings"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Update the speed settings for a zone. + * @description Update speed settings for the specified zone. Use this endpoint to modify performance optimizations. + */ + patch: operations["updateSpeedSettings"]; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/security-settings": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve the security settings for a zone. + * @description Retrieve security settings for the specified zone. This endpoint provides information about security configurations and protection settings. + */ + get: operations["getSecuritySettings"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Update the security settings for a zone. + * @description Update security settings for the specified zone. Use this endpoint to modify security configurations and protection settings. + */ + patch: operations["updateSecuritySettings"]; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/cachepurge": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Purge the cache for the host specified in the request body. + * @description Purge cache for the specified zone. Use this endpoint to clear cached content and force fresh content to be fetched from origin servers. Unlike storefronts, SCAPI only uses server-side web tier caching, and eCDN edge caching is not at all applicable to SCAPI. + */ + post: operations["cachePurge"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/ocapicachingpagerule": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Enable or disable the OCAPI Caching page rule. + * @description Use this endpoint to toggle the caching behavior for caching requests. + */ + patch: operations["toggleOcapiCachingPageRule"]; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/certificates": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List certificates for a zone. + * @description For information on automatic certificates, see [eCDN Automatic Certificates](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-automatic-certs.html). + */ + get: operations["getCertificates"]; + put?: never; + /** + * Add certificate for a zone. + * @description For information on automatic certificates, see [eCDN Automatic Certificates](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-automatic-certs.html). + */ + post: operations["addCertificateForZone"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/certificates/{certificateId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Delete a custom hostname and the certificate associated with it. Note that a valid certificate is necessary for a site to remain operational. DELETING A CERTIFICATE THAT IS IN USE CAN RESULT IN DOWNTIME. + * @description This operation removes both the custom hostname configuration and the associated SSL certificate. + */ + delete: operations["deleteCertificate"]; + options?: never; + head?: never; + /** + * Update the certificate for a given certificateId for a particular zone. + * @description For information on automatic certificates, see [eCDN Automatic Certificates](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-automatic-certs.html). + */ + patch: operations["updateCertificate"]; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/certificates/custom-hostnames/{customHostnameId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Trigger the validation of a custom hostname. + * @description This endpoint initiates the DNS validation process for custom hostnames associated with the zone. + */ + patch: operations["validateCustomHostname"]; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/mrtrules": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get all MRT rules. + * @description See [eCDN Rules for Hybrid Implementations](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/ecdn-rules-for-phased-headless-rollout.html). + */ + get: operations["getMrtRules"]; + put?: never; + /** + * Create MRT rules to route to a new MRT environment. + * @description See [eCDN Rules for Hybrid Implementations](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/ecdn-rules-for-phased-headless-rollout.html). + */ + post: operations["createMrtRules"]; + delete?: never; + options?: never; + head?: never; + /** + * Update the MRT environment hostname or add MRT rules to route to an existing MRT environment. + * @description See [eCDN Rules for Hybrid Implementations](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/ecdn-rules-for-phased-headless-rollout.html). + */ + patch: operations["updateMrtRuleset"]; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/mrtrules/{rulesetId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Delete the MRT ruleset and all rules within the ruleset. + * @description See [eCDN Rules for Hybrid Implementations](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/ecdn-rules-for-phased-headless-rollout.html). + */ + delete: operations["deleteMrtRuleset"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/mrtrules/{rulesetId}/rules/{ruleId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + /** + * Delete an MRT rule. + * @description See [eCDN Rules for Hybrid Implementations](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/ecdn-rules-for-phased-headless-rollout.html). + */ + delete: operations["deleteMrtRule"]; + options?: never; + head?: never; + /** + * Update an MRT rule. + * @description See [eCDN Rules for Hybrid Implementations](https://developer.salesforce.com/docs/commerce/pwa-kit-managed-runtime/guide/ecdn-rules-for-phased-headless-rollout.html). + */ + patch: operations["updateMrtRule"]; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/logpush/ownership": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + /** + * Create Logpush ownership token file. + * @description See [eCDN Logpush](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-logpush.html). + */ + post: operations["createLogpushOwnership"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/logpush/jobs": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * List Logpush job. + * @description See [eCDN Logpush](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-logpush.html). + */ + get: operations["listLogpushJob"]; + put?: never; + /** + * Create Logpush job. + * @description See [eCDN Logpush](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-logpush.html). + */ + post: operations["createLogpushJob"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/logpush/jobs/{jobId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get Logpush job details. + * @description See [eCDN Logpush](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-logpush.html). + */ + get: operations["getLogpushJob"]; + /** + * Update Logpush job. + * @description See [eCDN Logpush](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-logpush.html). + */ + put: operations["updateLogpushJob"]; + post?: never; + /** + * Delete Logpush job by job ID. + * @description See [eCDN Logpush](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-logpush.html). + */ + delete: operations["deleteLogpushJob"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/firewall/waf/packages/owasp": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get a OWASP ModSecurity Core Rule Set. + * @description Retrieve OWASP WAF package information for the specified zone. This endpoint provides details about the OWASP security rules and configurations. + */ + get: operations["getOwaspWafPackage"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Patch a OWASP ModSecurity Core Rule Set. + * @description Update OWASP WAF package settings for the specified zone. Use this endpoint to modify OWASP security rule configurations. + */ + patch: operations["patchOwaspWafPackage"]; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/firewall-custom/rules": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve existing custom rules. + * @description Retrieve existing custom rules. See [eCDN Custom Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-custom-rules.html). + */ + get: operations["getCustomRules"]; + put?: never; + /** + * Create a custom rule. + * @description See [eCDN Custom Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-custom-rules.html). + */ + post: operations["createCustomRule"]; + delete?: never; + options?: never; + head?: never; + /** + * Update the order of all existing custom rules. + * @description See [eCDN Custom Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-custom-rules.html). + */ + patch: operations["updateOrderOfCustomRules"]; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/firewall-custom/rules/{ruleId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve a specific custom rule. + * @description See [eCDN Custom Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-custom-rules.html). + */ + get: operations["getCustomRule"]; + put?: never; + post?: never; + /** + * Delete a specific custom rule. + * @description See [eCDN Custom Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-custom-rules.html). + */ + delete: operations["deleteCustomRule"]; + options?: never; + head?: never; + /** + * Update a specific custom rule. + * @description See [eCDN Custom Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-custom-rules.html). + */ + patch: operations["updateCustomRule"]; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/rate-limiting/rules": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve existing rate limiting rules. + * @description See [eCDN Rate Limiting Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-rate-limiting-rules.html). + */ + get: operations["getRateLimitingRules"]; + put?: never; + /** + * Create a rate limiting rule. + * @description See [eCDN Rate Limiting Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-rate-limiting-rules.html). + */ + post: operations["createRateLimitingRule"]; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/rate-limiting/rules/{ruleId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve a specific rate limiting rule. + * @description See [eCDN Rate Limiting Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-rate-limiting-rules.html). + */ + get: operations["getRateLimitingRule"]; + put?: never; + post?: never; + /** + * Delete a specific rate limiting rule. + * @description See [eCDN Rate Limiting Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-rate-limiting-rules.html). + */ + delete: operations["deleteRateLimitingRule"]; + options?: never; + head?: never; + /** + * Update a specific rate limiting rule. + * @description See [eCDN Rate Limiting Rules](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-rate-limiting-rules.html). + */ + patch: operations["updateRateLimitingRule"]; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/firewall-managed/rulesets": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve WAFv2 managed rulesets. + * @description See [eCDN WAFv2](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-wafv2.html). + */ + get: operations["getWafManagedRulesets"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/firewall-managed/rulesets/{rulesetId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Update WAFv2 managed ruleset. + * @description See [eCDN WAFv2](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-wafv2.html). + */ + patch: operations["updateWafManagedRuleset"]; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/firewall-managed/rulesets/{rulesetId}/rules": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Retrieve all rules in the specified WAFv2 managed ruleset. + * @description See [eCDN WAFv2](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-wafv2.html). + */ + get: operations["getWafManagedRulesInRuleset"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/firewall-managed/rulesets/{rulesetId}/rules/{ruleId}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Update a WAF managed rule in the specified WAFv2 managed ruleset. + * @description See [eCDN WAFv2](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-wafv2.html). + */ + patch: operations["updateWafManagedRuleInRuleset"]; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/firewall-managed/migration": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + get?: never; + /** + * Migrate a zone to WAFv2. Only applicable for existing zones using WAFv1. + * @description See [eCDN WAFv2](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-wafv2.html). + */ + put: operations["migrateZoneToWafV2"]; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/origin-header-modification/{type}": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get the origin header modification associated with a zone. Only the `mrt` type is supported. + * @description Retrieve origin header modification settings for the specified zone. This endpoint provides information about how headers are modified when forwarding requests to origin servers. + */ + get: operations["getOriginHeaderModification"]; + /** + * Upsert an origin header modification. Only the `mrt` type is supported. + * @description Create or update origin header modification settings for the specified zone. Use this endpoint to configure how headers are modified when forwarding requests to origin servers. + */ + put: operations["upsertOriginHeaderModification"]; + post?: never; + /** + * Delete the origin header modification associated with a zone. Only the `mrt` type is supported. + * @description Delete origin header modification settings for the specified zone. This endpoint removes header modification configurations. + */ + delete: operations["deleteOriginHeaderModification"]; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/organizations/{organizationId}/zones/{zoneId}/settings/ciphers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** + * Get cipher suites settings by zoneId. + * @description Retrieve cipher suite settings for the specified zone. This endpoint provides information about supported encryption algorithms and security protocols. See [eCDN Supported Cipher Suites](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-cipher-suite-types.html). + */ + get: operations["getCipherSuites"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + /** + * Update cipher suite settings for the zone. + * @description Update cipher suite settings for the specified zone. Use this endpoint to modify supported encryption algorithms and security protocols. See [eCDN Supported Cipher Suites](https://developer.salesforce.com/docs/commerce/commerce-api/guide/cdn-zones-cipher-suite-types.html). + */ + patch: operations["updateCipherSuites"]; + trace?: never; + }; +} +export type webhooks = Record; +export interface components { + schemas: { + ApiStandardsErrorResponse: { + /** + * @description A short, human-readable summary of the problem + * type. It will not change from occurrence to occurrence of the + * problem, except for purposes of localization + * @example You do not have enough credit + */ + title: string; + /** + * @description A URI reference [RFC3986] that identifies the + * problem type. This specification encourages that, when + * dereferenced, it provide human-readable documentation for the + * problem type (e.g., using HTML [W3C.REC-html5-20141028]). When + * this member is not present, its value is assumed to be + * "about:blank". It accepts relative URIs; this means + * that they must be resolved relative to the document's base URI, as + * per [RFC3986], Section 5. + * @example NotEnoughMoney + */ + type: string; + /** + * @description A human-readable explanation specific to this occurrence of the problem. + * @example Your current balance is 30, but that costs 50 + */ + detail: string; + /** + * @description A URI reference that identifies the specific + * occurrence of the problem. It may or may not yield further + * information if dereferenced. It accepts relative URIs; this means + * that they must be resolved relative to the document's base URI, as + * per [RFC3986], Section 5. + * @example /account/12345/msgs/abc + */ + instance?: string; + }; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + OrganizationId: string; + /** @description The storefront zone information to be created. */ + StorefrontZoneCreateRequest: { + /** + * @description Domain name for the site. + * @example cc-merchant.com + */ + domainName: string; + }; + /** @description The response of create zone, includes zone and zone properties. */ + StorefrontZoneCreateResponse: { + /** + * @description The zone id tag. + * @example 023e105f4ecef8ad9ca31a8372d0c353 + */ + zoneId: string; + /** + * @description The domain name for the zone. + * @example stg-zzzz-cc-merchant-com.cc-ecdn.net + */ + zoneName: string; + /** + * @description current status of the zone + * @example active + * @enum {string} + */ + status: "active" | "pending" | "initializing" | "moved" | "deleted" | "deactivated"; + /** + * Format: date-time + * @description Date and time of zone creation. + * @example 2014-01-01T05:20:00.12345Z + */ + createdOn: string; + }; + /** + * @example { + * "data": { + * "zoneId": "023e105f4ecef8ad9ca31a8372d0c353", + * "zoneName": "stg-zzzz-cc-merchant-com.cc-ecdn.net", + * "status": "active", + * "createdOn": "2014-01-01T05:20:00.12345Z" + * } + * } + */ + StorefrontZoneCreateEnvelope: { + data: components["schemas"]["StorefrontZoneCreateResponse"]; + }; + /** @description mTLS certificate information. */ + MtlsCertificateResponse: { + /** + * @description ID generated by the CDN provider for the certificate. + * @example 465a48f6-3d98-4c15-9312-211984ee8629 + */ + mtlsCertificateId?: string; + /** + * Format: date-time + * @description Expiration date for the mTLS certificate. + * @example 2022-01-12T04:15:57Z + */ + expiresOn?: string; + /** + * @description The certificate authority that issued the mTLS certificate. + * @example DigiCert + */ + issuer?: string; + /** + * @description The type of hash used for the mTLS certificate. + * @example SHA256WithRSA + */ + signature?: string; + /** + * Format: date-time + * @description Date the mTLS certificate was uploaded. + * @example 2020-01-12T04:15:57Z + */ + uploadedOn?: string; + /** + * @description Indicates whether the mTLS certificate is a CA or leaf certificate. + * @example true + */ + ca?: boolean; + /** + * @description The mTLS certificate serial number. + * @example 432217133297895665180570788458463042229861757760 + */ + serialNumber?: string; + /** + * @description Optional name for the mTLS certificate used for ease of understanding. + * @example mtls_cert_name + */ + mtlsCertificateName?: string; + /** + * @description Hostname associated with this mTLS certificate. + * @example mtls.cert.salesforce.com + */ + mtlsAssociatedCodeUploadHostname?: string; + }; + /** + * @example { + * "data": [ + * { + * "mtlsCertificateId": "465a48f6-3d98-4c15-9312-211984ee8629", + * "expiresOn": "2022-01-12T04:15:57Z", + * "issuer": "DigiCert", + * "signature": "SHA256WithRSA", + * "uploadedOn": "2020-01-12T04:15:57Z", + * "ca": true, + * "serialNumber": "432217133297895665180570788458463042229861757760", + * "mtlsCertificateName": "mtls_cert_name", + * "mtlsAssociatedCodeUploadHostname": "mtls.cert.salesforce.com" + * } + * ] + * } + */ + MtlsCertificatesResponseEnvelope: { + data: components["schemas"]["MtlsCertificateResponse"][]; + }; + /** + * @description mTLS certificate request information. + * @example { + * "certificate": "-----BEGIN CERTIFICATE-----\nMIIDtTCCAp2gAwIBAgIJAMHAwfXZ5PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX\naWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF\nMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50\nZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1\nCGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB\nKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5\n0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI\ndZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2\nizNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4\n9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI\nGKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV\nBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF\nMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2\n2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP\nMlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG\nSvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq\n2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw\nYbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY=\n-----END CERTIFICATE-----", + * "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmG\ndtcGbg/1CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKn\nabIRuGvBKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpid\ntnKX/a+50GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+py\nFxIXjbEIdZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pE\newooaeO2izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABAoIBACbhTYXBZYKmYPCb\nHBR1IBlCQA2nLGf0qRuJNJZg5iEzXows/6tc8YymZkQE7nolapWsQ+upk2y5Xdp/\naxiuprIs9JzkYK8Ox0r+dlwCG1kSW+UAbX0bQ/qUqlsTvU6muVuMP8vZYHxJ3wmb\n+ufRBKztPTQ/rYWaYQcgC0RWI20HTFBMxlTAyNxYNWzX7RKFkGVVyB9RsAtmcc8g\n+j4OdosbfNoJPS0HeIfNpAznDfHKdxDk2Yc1tV6RHBrC1ynyLE9+TaflIAdo2MVv\nKLMLq51GqYKtgJFIlBRPQqKoyXdz3fGvXrTkf/WY9QNq0J1Vk5ERePZ54mN8iZB7\n9lwy/AkCgYEA6FXzosxswaJ2wQLeoYc7ceaweX/SwTvxHgXzRyJIIT0eJWgx13Wo\n/WA3Iziimsjf6qE+SI/8laxPp2A86VMaIt3Z3mJN/CqSVGw8LK2AQst+OwdPyDMu\niacE8lj/IFGC8mwNUAb9CzGU3JpU4PxxGFjS/eMtGeRXCWkK4NE+G08CgYEA1Kp9\nN2JrVlqUz+gAX+LPmE9OEMAS9WQSQsfCHGogIFDGGcNf7+uwBM7GAaSJIP01zcoe\nVAgWdzXCv3FLhsaZoJ6RyLOLay5phbu1iaTr4UNYm5WtYTzMzqh8l1+MFFDl9xDB\nvULuCIIrglM5MeS/qnSg1uMoH2oVPj9TVst/ir8CgYEAxrI7Ws9Zc4Bt70N1As+U\nlySjaEVZCMkqvHJ6TCuVZFfQoE0r0whdLdRLU2PsLFP+q7qaeZQqgBaNSKeVcDYR\n9B+nY/jOmQoPewPVsp/vQTCnE/R81spu0mp0YI6cIheT1Z9zAy322svcc43JaWB7\nmEbeqyLOP4Z4qSOcmghZBSECgYACvR9Xs0DGn+wCsW4vze/2ei77MD4OQvepPIFX\ndFZtlBy5ADcgE9z0cuVB6CiL8DbdK5kwY9pGNr8HUCI03iHkW6Zs+0L0YmihfEVe\nPG19PSzK9CaDdhD9KFZSbLyVFmWfxOt50H7YRTTiPMgjyFpfi5j2q348yVT0tEQS\nfhRqaQKBgAcWPokmJ7EbYQGeMbS7HC8eWO/RyamlnSffdCdSc7ue3zdVJxpAkQ8W\nqu80pEIF6raIQfAf8MXiiZ7auFOSnHQTXUbhCpvDLKi0Mwq3G8Pl07l+2s6dQG6T\nlv6XTQaMyf6n1yjzL+fzDrH3qXMxHMO/b13EePXpDMpY7HQpoLDi\n-----END RSA PRIVATE KEY-----", + * "name": "mtls_cert_name" + * } + */ + MtlsCertificateRequest: { + /** + * @description Public key for the CA certificate in mTLS. + * @example -----BEGIN CERTIFICATE----- + * MIIDtTCCAp2gAwIBAgIJAMHAwfXZ5PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV + * BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX + * aWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF + * MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 + * ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB + * CgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1 + * CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB + * KwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5 + * 0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI + * dZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2 + * izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4 + * 9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI + * GKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV + * BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF + * MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2 + * 2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP + * Mlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG + * SvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq + * 2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw + * YbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY= + * -----END CERTIFICATE----- + */ + certificate: string; + /** + * @description Private key of the CA certificate in mTLS. + * @example -----BEGIN RSA PRIVATE KEY----- + * MIIEowIBAAKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmG + * dtcGbg/1CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKn + * abIRuGvBKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpid + * tnKX/a+50GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+py + * FxIXjbEIdZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pE + * ewooaeO2izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABAoIBACbhTYXBZYKmYPCb + * HBR1IBlCQA2nLGf0qRuJNJZg5iEzXows/6tc8YymZkQE7nolapWsQ+upk2y5Xdp/ + * axiuprIs9JzkYK8Ox0r+dlwCG1kSW+UAbX0bQ/qUqlsTvU6muVuMP8vZYHxJ3wmb + * +ufRBKztPTQ/rYWaYQcgC0RWI20HTFBMxlTAyNxYNWzX7RKFkGVVyB9RsAtmcc8g + * +j4OdosbfNoJPS0HeIfNpAznDfHKdxDk2Yc1tV6RHBrC1ynyLE9+TaflIAdo2MVv + * KLMLq51GqYKtgJFIlBRPQqKoyXdz3fGvXrTkf/WY9QNq0J1Vk5ERePZ54mN8iZB7 + * 9lwy/AkCgYEA6FXzosxswaJ2wQLeoYc7ceaweX/SwTvxHgXzRyJIIT0eJWgx13Wo + * /WA3Iziimsjf6qE+SI/8laxPp2A86VMaIt3Z3mJN/CqSVGw8LK2AQst+OwdPyDMu + * iacE8lj/IFGC8mwNUAb9CzGU3JpU4PxxGFjS/eMtGeRXCWkK4NE+G08CgYEA1Kp9 + * N2JrVlqUz+gAX+LPmE9OEMAS9WQSQsfCHGogIFDGGcNf7+uwBM7GAaSJIP01zcoe + * VAgWdzXCv3FLhsaZoJ6RyLOLay5phbu1iaTr4UNYm5WtYTzMzqh8l1+MFFDl9xDB + * vULuCIIrglM5MeS/qnSg1uMoH2oVPj9TVst/ir8CgYEAxrI7Ws9Zc4Bt70N1As+U + * lySjaEVZCMkqvHJ6TCuVZFfQoE0r0whdLdRLU2PsLFP+q7qaeZQqgBaNSKeVcDYR + * 9B+nY/jOmQoPewPVsp/vQTCnE/R81spu0mp0YI6cIheT1Z9zAy322svcc43JaWB7 + * mEbeqyLOP4Z4qSOcmghZBSECgYACvR9Xs0DGn+wCsW4vze/2ei77MD4OQvepPIFX + * dFZtlBy5ADcgE9z0cuVB6CiL8DbdK5kwY9pGNr8HUCI03iHkW6Zs+0L0YmihfEVe + * PG19PSzK9CaDdhD9KFZSbLyVFmWfxOt50H7YRTTiPMgjyFpfi5j2q348yVT0tEQS + * fhRqaQKBgAcWPokmJ7EbYQGeMbS7HC8eWO/RyamlnSffdCdSc7ue3zdVJxpAkQ8W + * qu80pEIF6raIQfAf8MXiiZ7auFOSnHQTXUbhCpvDLKi0Mwq3G8Pl07l+2s6dQG6T + * lv6XTQaMyf6n1yjzL+fzDrH3qXMxHMO/b13EePXpDMpY7HQpoLDi + * -----END RSA PRIVATE KEY----- + */ + privateKey: string; + /** + * @description Certificate name used for ease of understanding. + * @example mtls_cert_name + */ + name: string; + }; + /** + * @example { + * "data": { + * "mtlsCertificateId": "465a48f6-3d98-4c15-9312-211984ee8629", + * "expiresOn": "2022-01-12T04:15:57Z", + * "issuer": "DigiCert", + * "signature": "SHA256WithRSA", + * "uploadedOn": "2020-01-12T04:15:57Z", + * "ca": true, + * "serialNumber": "432217133297895665180570788458463042229861757760", + * "mtlsCertificateName": "mtls_cert_name", + * "mtlsAssociatedCodeUploadHostname": "mtls.cert.salesforce.com" + * } + * } + */ + MtlsCertificateResponseEnvelope: { + data: components["schemas"]["MtlsCertificateResponse"]; + }; + /** + * @description Page shield notification for the webhook response. + * @example { + * "id": "webhook_1234567890abcdef", + * "name": "Security Alert Webhook", + * "webhookUrl": "https://example.com/webhook/security", + * "type": "security_alert", + * "createdAt": "2023-01-01T00:00:00Z", + * "lastSuccess": "2023-01-01T12:00:00Z", + * "lastFailure": "2023-01-01T18:00:00Z", + * "zones": [ + * "zone_1234567890abcdef" + * ] + * } + */ + PageShieldNotificationWebhookResponse: { + /** + * @description Webhook ID. + * @example webhook_1234567890abcdef + */ + id: string; + /** + * @description Webhook name. + * @example Security Alert Webhook + */ + name: string; + /** + * @description Webhook URL. + * @example https://example.com/webhook/security + */ + webhookUrl: string; + /** + * @description Webhook type. + * @example security_alert + */ + type: string; + /** + * Format: date-time + * @description Timestamp of webhook creation. + * @example 2023-01-01T00:00:00Z + */ + createdAt: string; + /** + * Format: date-time + * @description Timestamp of the last successful notification. + * @example 2023-01-01T12:00:00Z + */ + lastSuccess?: string; + /** + * Format: date-time + * @description Timestamp of the last failed notification. + * @example 2023-01-01T18:00:00Z + */ + lastFailure?: string; + /** @description Zone IDs on which to filter notifications alerts. */ + zones?: string[]; + }; + /** + * @example { + * "data": [ + * { + * "id": "webhook_1234567890abcdef", + * "name": "Security Alert Webhook", + * "webhookUrl": "https://example.com/webhook/security", + * "type": "security_alert", + * "createdAt": "2023-01-01T00:00:00Z", + * "lastSuccess": "2023-01-01T12:00:00Z", + * "lastFailure": "2023-01-01T18:00:00Z", + * "zones": [ + * "zone_1234567890abcdef" + * ] + * } + * ] + * } + */ + PageShieldNotificationWebhookListEnvelope: { + data: components["schemas"]["PageShieldNotificationWebhookResponse"][]; + }; + /** + * @description Page shield notification for the webhook request. + * @example { + * "webhookUrl": "https://example.com/webhook/security", + * "secret": "webhook_secret_123", + * "zones": [ + * "zone_1234567890abcdef" + * ] + * } + */ + PageShieldNotificationWebhookRequest: { + /** + * @description Webhook URL. + * @example https://example.com/webhook/security + */ + webhookUrl: string; + /** + * @description Webhook optional secret. + * @example webhook_secret_123 + */ + secret?: string; + /** @description Zone names on which to filter notifications alerts. */ + zones?: string[]; + }; + /** + * @example { + * "data": { + * "id": "webhook_1234567890abcdef", + * "name": "Security Alert Webhook", + * "webhookUrl": "https://example.com/webhook/security", + * "type": "security_alert", + * "createdAt": "2023-01-01T00:00:00Z", + * "lastSuccess": "2023-01-01T12:00:00Z", + * "lastFailure": "2023-01-01T18:00:00Z", + * "zones": [ + * "zone_1234567890abcdef" + * ] + * } + * } + */ + PageShieldNotificationWebhookEnvelope: { + data: components["schemas"]["PageShieldNotificationWebhookResponse"]; + }; + /** + * @description Page shield policy response. + * @example { + * "action": "allow", + * "description": "Allow scripts from trusted CDN sources", + * "enabled": true, + * "expression": "http.request.uri.path contains \"/trusted-cdn/\"", + * "value": "script-src", + * "id": "policy_1234567890abcdef" + * } + */ + PageShieldPolicyResponse: { + /** + * @description Action taken when expression matches allow or log. + * @example allow + * @enum {string} + */ + action?: "allow" | "log"; + /** + * @description Description for the policy. + * @example Allow scripts from trusted CDN sources + */ + description?: string; + /** + * @description Enable/disable the policy. + * @example true + */ + enabled?: boolean; + /** + * @description Expression of the policy. + * @example http.request.uri.path contains "/trusted-cdn/" + */ + expression?: string; + /** + * @description Policy to be applied. + * @example script-src + */ + value?: string; + /** + * @description Policy ID + * @example policy_1234567890abcdef + */ + id?: string; + }; + /** + * @example { + * "data": [ + * { + * "action": "allow", + * "description": "Allow scripts from trusted CDN sources", + * "enabled": true, + * "expression": "http.request.uri.path contains \"/trusted-cdn/\"", + * "value": "script-src", + * "id": "policy_1234567890abcdef" + * } + * ] + * } + */ + PageShieldPoliciesListEnvelope: { + data: components["schemas"]["PageShieldPolicyResponse"][]; + }; + /** + * @description Page shield policy request object. + * @example { + * "action": "allow", + * "description": "Allow scripts from trusted CDN sources", + * "enabled": true, + * "expression": "http.request.uri.path contains \"/trusted-cdn/\"", + * "value": "script-src" + * } + */ + PageShieldPolicyRequest: { + /** + * @description Action taken when expression matches allow or log. + * @example allow + * @enum {string} + */ + action?: "allow" | "log"; + /** + * @description Description for the policy. + * @example Allow scripts from trusted CDN sources + */ + description?: string; + /** + * @description Enable/disable the policy. + * @example true + */ + enabled?: boolean; + /** + * @description Expression of the policy. + * @example http.request.uri.path contains "/trusted-cdn/" + */ + expression?: string; + /** + * @description Policy to be applied. + * @example script-src + */ + value?: string; + }; + /** + * @example { + * "data": { + * "action": "allow", + * "description": "Allow scripts from trusted CDN sources", + * "enabled": true, + * "expression": "http.request.uri.path contains \"/trusted-cdn/\"", + * "value": "script-src", + * "id": "policy_1234567890abcdef" + * } + * } + */ + PageShieldPoliciesEnvelope: { + data: components["schemas"]["PageShieldPolicyResponse"]; + }; + /** + * @description Version details for the JavaScript script. + * @example { + * "hash": "1243453456abc", + * "jsIntegrityScore": 1, + * "obfuscationScore": 2, + * "dataflowScore": 1, + * "malwareScore": 1, + * "cryptoMiningScore": 1, + * "mageCartScore": 2, + * "fetchedAt": "2023-01-01T00:00:00Z", + * "isMaliciousCode": false + * } + */ + PageShieldScriptVersion: { + /** + * @description The computed hash of the analyzed script. + * @example 1243453456abc + */ + hash?: string; + /** + * @description The integrity score of the JavaScript content. + * @example 1 + */ + jsIntegrityScore?: number; + /** + * @description The obfuscation score of the JavaScript content. + * @example 2 + */ + obfuscationScore?: number; + /** + * @description The dataflow score of the JavaScript content. + * @example 1 + */ + dataflowScore?: number; + /** + * @description The malware score of the JavaScript content. + * @example 1 + */ + malwareScore?: number; + /** + * @description The crypto mining score of the JavaScript content. + * @example 1 + */ + cryptoMiningScore?: number; + /** + * @description The Magecart score of the JavaScript content. + * @example 2 + */ + mageCartScore?: number; + /** + * Format: date-time + * @description The timestamp of when the script was last fetched. + * @example 2023-01-01T00:00:00Z + */ + fetchedAt?: string; + /** + * @description Indicates whether the script has been reported as malicious. + * @example false + */ + isMaliciousCode: boolean; + }; + /** + * @description Response of Page Shield script object. + * @example { + * "id": "12345678901234asdfasfasdf", + * "url": "https://sfdc-test.net/on/demandware.static/Sites-SiteNemesis-Site/-/en_US//lib/jquery/ui/jquery-ui.min.js", + * "host": "sfdc-test.net", + * "addedAt": "2022-01-01T05:20:00Z", + * "firstSeenAt": "2022-01-01T05:20:00Z", + * "lastSeenAt": "2022-01-01T05:20:00Z", + * "fetchedAt": "2022-01-01T05:20:00Z", + * "domainReportedMalicious": false, + * "hash": "1243453456abc", + * "cryptoMiningScore": 1, + * "dataflowScore": 1, + * "jsIntegrityScore": 1, + * "mageCartScore": 2, + * "malwareScore": 1, + * "obfuscationScore": 2, + * "maliciousDomainCategories": [ + * "Malware" + * ], + * "maliciousUrlCategories": [ + * "Malware" + * ], + * "urlContainsCdnCgiPath": false, + * "urlReportedMalicious": false, + * "pageUrls": [ + * "blog.test.salesforce.com/page1", + * "blog.test.salesforce.com/page2" + * ], + * "firstPageUrl": "blog.test.salesforce.com", + * "status": "active", + * "versions": [] + * } + */ + PageShieldScriptResponse: { + /** + * @description Page Shield script ID. + * @example 12345678901234asdfasfasdf + */ + id?: string; + /** + * @description Page Shield script URL. + * @example https://sfdc-test.net/on/demandware.static/Sites-SiteNemesis-Site/-/en_US//lib/jquery/ui/jquery-ui.min.js + */ + url?: string; + /** + * @description Hostname where the script was detected by Page Shield. + * @example sfdc-test.net + */ + host?: string; + /** + * Format: date-time + * @description Date the script was added to Page Shield. + * @example 2022-01-01T05:20:00Z + */ + addedAt?: string; + /** + * Format: date-time + * @description Date the script was detected by Page Shield. + * @example 2022-01-01T05:20:00Z + */ + firstSeenAt?: string; + /** + * Format: date-time + * @description Date the script was recently detected by Page Shield. + * @example 2022-01-01T05:20:00Z + */ + lastSeenAt?: string; + /** + * Format: date-time + * @description The timestamp when the script was last fetched. + * @example 2022-01-01T05:20:00Z + */ + fetchedAt?: string; + /** + * @description Reported domain is malicious. + * @example false + */ + domainReportedMalicious?: boolean; + /** + * @description The computed hash of the analyzed script. + * @example 1243453456abc + */ + hash?: string; + /** + * @description The crypto mining score of the JavaScript content. + * @example 1 + */ + cryptoMiningScore?: number; + /** + * @description The dataflow score of the JavaScript content. + * @example 1 + */ + dataflowScore?: number; + /** + * @description The integrity score of the JavaScript content. + * @example 1 + */ + jsIntegrityScore?: number; + /** + * @description The Magecart score of the JavaScript content. + * @example 2 + */ + mageCartScore?: number; + /** + * @description The malware score of the JavaScript content. + * @example 1 + */ + malwareScore?: number; + /** + * @description The obfuscation score of the JavaScript content. + * @example 2 + */ + obfuscationScore?: number; + /** + * @description Malicious domain category. + * @example [ + * "Malware" + * ] + */ + maliciousDomainCategories?: string[]; + /** + * @description Malicious URL category. + * @example [ + * "Malware" + * ] + */ + maliciousUrlCategories?: string[]; + /** + * @description URL contains CDN CGI path. + * @example false + */ + urlContainsCdnCgiPath?: boolean; + /** + * @description Reported URL is malicious. + * @example false + */ + urlReportedMalicious?: boolean; + /** + * @description Page URLs + * @example [ + * "blog.test.salesforce.com/page1", + * "blog.test.salesforce.com/page2" + * ] + */ + pageUrls?: string[]; + /** + * @description First page URL for the JavaScript. + * @example blog.test.salesforce.com + */ + firstPageUrl?: string; + /** + * @description The current status of the script. Possible values are active, inactive, or infrequent. + * @example active + */ + status?: string; + /** @description List of script versions. */ + versions?: components["schemas"]["PageShieldScriptVersion"][]; + }; + /** + * @example { + * "data": [ + * { + * "id": "12345678901234asdfasfasdf", + * "url": "https://sfdc-test.net/on/demandware.static/Sites-SiteNemesis-Site/-/en_US//lib/jquery/ui/jquery-ui.min.js", + * "host": "sfdc-test.net", + * "addedAt": "2022-01-01T05:20:00Z", + * "firstSeenAt": "2022-01-01T05:20:00Z", + * "lastSeenAt": "2022-01-01T05:20:00Z", + * "fetchedAt": "2022-01-01T05:20:00Z", + * "domainReportedMalicious": false, + * "hash": "1243453456abc", + * "cryptoMiningScore": 1, + * "dataflowScore": 1, + * "jsIntegrityScore": 1, + * "mageCartScore": 2, + * "malwareScore": 1, + * "obfuscationScore": 2, + * "maliciousDomainCategories": [ + * "Malware" + * ], + * "maliciousUrlCategories": [ + * "Malware" + * ], + * "urlContainsCdnCgiPath": false, + * "urlReportedMalicious": false, + * "pageUrls": [ + * "blog.test.salesforce.com/page1", + * "blog.test.salesforce.com/page2" + * ], + * "firstPageUrl": "blog.test.salesforce.com", + * "status": "active", + * "versions": [] + * } + * ] + * } + */ + PageShieldScriptListEnvelope: { + data: components["schemas"]["PageShieldScriptResponse"][]; + }; + /** + * @example { + * "data": { + * "id": "12345678901234asdfasfasdf", + * "url": "https://sfdc-test.net/on/demandware.static/Sites-SiteNemesis-Site/-/en_US//lib/jquery/ui/jquery-ui.min.js", + * "host": "sfdc-test.net", + * "addedAt": "2022-01-01T05:20:00Z", + * "firstSeenAt": "2022-01-01T05:20:00Z", + * "lastSeenAt": "2022-01-01T05:20:00Z", + * "fetchedAt": "2022-01-01T05:20:00Z", + * "domainReportedMalicious": false, + * "hash": "1243453456abc", + * "cryptoMiningScore": 1, + * "dataflowScore": 1, + * "jsIntegrityScore": 1, + * "mageCartScore": 2, + * "malwareScore": 1, + * "obfuscationScore": 2, + * "maliciousDomainCategories": [ + * "Malware" + * ], + * "maliciousUrlCategories": [ + * "Malware" + * ], + * "urlContainsCdnCgiPath": false, + * "urlReportedMalicious": false, + * "pageUrls": [ + * "blog.test.salesforce.com/page1", + * "blog.test.salesforce.com/page2" + * ], + * "firstPageUrl": "blog.test.salesforce.com", + * "status": "active", + * "versions": [] + * } + * } + */ + PageShieldScriptEnvelope: { + data: components["schemas"]["PageShieldScriptResponse"]; + }; + /** + * Zone + * @description Zone is the container for hostnames and various CDN settings/properties. Each zone is tied to a single origin. + * @example { + * "zoneId": "example1-zone-Id", + * "name": "example1.com", + * "status": "pending" + * } + */ + Zone: { + /** + * @description Identity of the zone. + * @example example1-zone-Id + */ + zoneId: string; + /** + * @description Name given to the zone. This needs to be a DNS domain name for eg example.com + * @example example1.com + */ + name: string; + /** + * @description Status of the zone for eg "Pending" , "Active" + * @example pending + * @enum {string} + */ + status: "active" | "pending" | "initializing" | "moved" | "deleted" | "deactivated"; + }; + /** + * @example { + * "data": [ + * { + * "zoneId": "example1-zone-Id", + * "name": "example1.com", + * "status": "pending" + * }, + * { + * "zoneId": "example2-zone-Id", + * "name": "example2.com", + * "status": "active" + * } + * ] + * } + */ + ZonesEnvelope: { + data: components["schemas"]["Zone"][]; + }; + /** + * @example { + * "groupId": "372abe67954025e0ba6aaa6d586b9e0b", + * "zoneId": "example1-zone-Id", + * "action": "monitor", + * "mode": true, + * "description": "SQL injection protection" + * } + */ + WafGroup: { + /** @example 372e67954025e0ba6aaa6d586b9e0b60 */ + groupId?: string; + /** + * @description The action to apply to WAF group + * @example block + * @enum {string} + */ + action?: "block" | "challenge" | "monitor" | "default"; + /** + * @description Mode of the waf rule - on vs off + * @example on + * @enum {string} + */ + mode: "on" | "off"; + /** + * @description Description of the WAF Group. + * @example Test WAF Group to protect against SQL injection + */ + description?: string; + }; + WafGroupsEnvelope: { + data: components["schemas"]["WafGroup"][]; + }; + WafGroupEnvelope: { + data?: components["schemas"]["WafGroup"]; + }; + /** + * @example { + * "ruleId": "892e67954025e0ba6atefd586b9e58b3", + * "groupId": "372abe67954025e0ba6aaa6d586b9e0b", + * "action": "monitor", + * "defaultAction": "challenge", + * "description": "SQL injection protection" + * } + */ + WafRule: { + /** @example 892e67954025e0ba6atefd586b9e58b3 */ + ruleId?: string; + /** @example 372e67954025e0ba6aaa6d586b9e0b60 */ + groupId?: string; + /** + * @description The action to apply to WAF rule + * @example block + * @enum {string} + */ + action: "block" | "challenge" | "monitor" | "disable" | "default"; + /** + * @description The action to apply to WAF rule + * @example block + * @enum {string} + */ + defaultAction?: "block" | "challenge" | "monitor" | "disable"; + /** + * @description Description of the WAF Group. + * @example Test WAF Rule to protect against SQL injection + */ + description?: string; + }; + /** + * @example { + * "data": [ + * { + * "ruleId": "892e67954025e0ba6atefd586b9e58b3", + * "groupId": "372abe67954025e0ba6aaa6d586b9e0b", + * "action": "monitor", + * "defaultAction": "challenge", + * "description": "SQL injection protection" + * } + * ] + * } + */ + WafRulesEnvelope: { + data: components["schemas"]["WafRule"][]; + }; + /** + * @example { + * "data": { + * "ruleId": "892e67954025e0ba6atefd586b9e58b3", + * "groupId": "372abe67954025e0ba6aaa6d586b9e0b", + * "action": "monitor", + * "defaultAction": "challenge", + * "description": "SQL injection protection" + * } + * } + */ + WafRuleEnvelope: { + data: components["schemas"]["WafRule"]; + }; + /** + * @example { + * "brotliCompression": "off" + * } + */ + SpeedSetting: { + /** + * @description Brotli compression setting of a zone. + * @default off + * @example off + * @enum {string} + */ + brotliCompression: "on" | "off"; + /** + * @description Http2 prioritization setting for a zone. + * @default off + * @example off + * @enum {string} + */ + http2Prioritization: "on" | "off"; + /** + * @description Support for the WebP image format when using image modification for a zone. The WebP image format can be used with supported clients for added performance benefits. Setting this property to `on` will return an error when the `polish` property is set to `off`. + * @default off + * @example off + * @enum {string} + */ + webp: "on" | "off"; + /** + * @description The level of polish (image quality) used for image modification. The value `lossless` corresponds to **Polish Level Basic** in the UI, and the value `lossy` corresponds to **Polish Level Basic+JPEG.** To disable image modification, set this property to `off`. Setting this property to `off` will prevent you from setting the `webp` property to `on`. + * @default off + * @example off + * @enum {string} + */ + polish: "off" | "lossless" | "lossy"; + /** + * @description Early Hints for a zone. + * @default off + * @example off + * @enum {string} + */ + earlyHints: "on" | "off"; + /** + * @description Http3 for a zone. + * @default off + * @example off + * @enum {string} + */ + http3: "on" | "off"; + /** + * @description Http2 to Origin for a zone. + * @default off + * @example off + * @enum {string} + */ + http2ToOrigin: "on" | "off"; + }; + SpeedSettingsEnvelope: { + data: components["schemas"]["SpeedSetting"]; + }; + /** + * @example { + * "hsts": { + * "enabled": true, + * "includeSubdomains": true, + * "maxAge": 31536000, + * "preload": false + * }, + * "securityLevel": "medium", + * "tls13Enabled": true, + * "wafEnabled": true, + * "alwaysUseHttps": true + * } + */ + SecuritySetting: { + /** + * @description The security header for a zone. + * @example { + * "enabled": true, + * "includeSubdomains": true, + * "maxAge": 31536000, + * "preload": false + * } + */ + hsts?: { + /** + * @description Enable strict transport security. + * @example true + */ + enabled?: boolean; + /** + * @description Include all subdomains for strict transport security. + * @example true + */ + includeSubdomains?: boolean; + /** + * @description Max age in seconds of the strict transport security. + * @example 31536000 + */ + maxAge?: number; + /** + * @description Preload any URLs that are included in the response headers. + * @example false + */ + preload?: boolean; + }; + /** + * @description Security profile for your zone, which will automatically adjust each of the security settings. + * @example medium + * @enum {string} + */ + securityLevel?: "off" | "essentially_off" | "low" | "medium" | "high" | "under_attack"; + /** + * @description Enable Crypto TLS 1.3 feature for this zone. + * @example true + */ + tls13Enabled?: boolean; + /** + * @description Enable WAF (OWASP) protection for this zone. Not applicable for zones using WAFv2. + * @example true + */ + wafEnabled?: boolean; + /** + * @description Redirect all http requests to https. + * @example true + */ + alwaysUseHttps: boolean; + }; + /** + * @example { + * "data": { + * "hsts": { + * "enabled": true, + * "includeSubdomains": true, + * "maxAge": 31536000, + * "preload": false + * }, + * "securityLevel": "medium", + * "tls13Enabled": true, + * "wafEnabled": true, + * "alwaysUseHttps": true + * } + * } + */ + SecuritySettingsEnvelope: { + data: components["schemas"]["SecuritySetting"]; + }; + /** + * @description Request for doing a cache purge + * @example { + * "path": "www.sfcc-ecdn-test5.net/dw/shop/v21_9/products", + * "tags": [ + * "product-123", + * "category-456" + * ] + * } + */ + CachePurgeRequest: { + /** + * @description Path for clearing the cache. Allowed paths follow the format "/dw/shop/*\/products", "/dw/image/v2/{realm}_{instance}/*", "/worker.js", "/mobify*" or "/callback*". Regular expressions and wildcards are not supported in the path. + * @example www.sfcc-ecdn-test5.net/dw/shop/v21_9/products + */ + path?: string; + /** + * @description List of cache tags to purge. When specified, all cached content associated with these tags will be purged. + * @example [ + * "product-123", + * "category-456" + * ] + */ + tags?: string[]; + }; + /** + * @description Response from a cache purge request + * @example { + * "cachePurged": false, + * "details": "1084 : Unable to purge ''." + * } + */ + CachePurgeResponse: { + /** + * @description The name of the list. + * @example false + */ + cachePurged: boolean; + /** + * @description Details of errors if any. + * @example 1084 : Unable to purge ''. + */ + details: string; + }; + /** + * @example { + * "data": { + * "cachePurged": false, + * "details": "1084 : Unable to purge ''." + * } + * } + */ + CachePurgeResponseEnvelope: { + data: components["schemas"]["CachePurgeResponse"]; + }; + /** @description Request to enable or disable API Caching Page rule */ + OCAPICachingToggleRequest: { + /** + * @description True to enable API Caching Page rule, false to disable. + * @example true + */ + enableOCAPICachingPageRule: boolean; + }; + /** + * @description eCDN automatic renewal certificate DCV delegation records. + * @example { + * "dcvCname": "_acme-challenge.example.com", + * "dcvCnameValue": "abc123def456ghi789.acme-validation.com" + * } + */ + DCVDelegationRecord: { + /** + * @description DNS CNAME for Domain Control Validation. + * @example _acme-challenge.example.com + */ + dcvCname?: string; + /** + * @description DNS CNAME value for Domain Control Validation. + * @example abc123def456ghi789.acme-validation.com + */ + dcvCnameValue?: string; + }; + /** + * @description The certificate information + * @example { + * "certificateId": "f90712123fb02287348dd34c0a282bb9", + * "hosts": [ + * "example.com", + * "www.example.com" + * ], + * "expiresOn": "2025-12-31T23:59:59Z", + * "uploadedOn": "2024-01-01T00:00:00Z", + * "issuer": "Let's Encrypt Authority X3", + * "signature": "SHA256", + * "status": "ACTIVE", + * "minTlsVersion": "1.2", + * "certificateType": "custom", + * "certificateAuthority": "lets_encrypt", + * "certificateValidation": "http", + * "certificateVerificationTXTName": "_acme-challenge.example.com", + * "certificateVerificationTXTValue": "abc123def456ghi789", + * "certificateVerificationStatus": "ACTIVE", + * "wildcardHostname": false, + * "wildcardCertificateVerificationTXTName": "_acme-challenge.wildcard.example.com", + * "wildcardCertificateVerificationTXTValue": "wildcard_abc123def456", + * "wildcardCertificateVerificationStatus": "ACTIVE", + * "customHostnameVerificationTXTName": "_acme-challenge.custom.example.com", + * "customHostnameVerificationTXTValue": "custom_abc123def456", + * "customHostnameId": "f90712123fb02287348dd34c0a282bb9", + * "customHostname": "custom.example.com", + * "customHostnameStatus": "ACTIVE", + * "dcvDelegationRecords": [] + * } + */ + Certificate: { + /** + * @description Id generated by CDN provider for the certificate. + * @example f90712123fb02287348dd34c0a282bb9 + */ + certificateId: string; + /** + * @description List of hosts the certificate applies to. + * @example [ + * "example.com", + * "www.example.com" + * ] + */ + hosts?: string[]; + /** + * Format: date-time + * @description Date of expiration for the certificate. + * @example 2025-12-31T23:59:59Z + */ + expiresOn?: string; + /** + * Format: date-time + * @description Date the certificate was uploaded. + * @example 2024-01-01T00:00:00Z + */ + uploadedOn?: string; + /** + * @description The certificate authority that issued the certificate. + * @example Let's Encrypt Authority X3 + */ + issuer?: string; + /** + * @description The type of hash used for the certificate. + * @example SHA256 + */ + signature?: string; + /** + * @description Current status of the certificate. + * @example ACTIVE + * @enum {string} + */ + status: "ACTIVE" | "EXPIRED" | "DELETED" | "PENDING" | "INITIALIZING" | "PENDING_VALIDATION" | "PENDING_ISSUANCE" | "PENDING_DEPLOYMENT" | "PENDING_DELETION" | "VALIDATION_TIMED_OUT" | "DEPLOYMENT_TIMED_OUT" | "DELETION_TIMED_OUT" | "INITIALIZING_TIMED_OUT" | "PENDING_EXPIRATION" | "ISSUANCE_TIMED_OUT"; + /** + * @description Minimum TLS Version only allows HTTPS connections from visitors that support the selected TLS protocol version or newer. + * @example 1.2 + */ + minTlsVersion?: string; + /** + * @description Indicates certificate is custom cert uploaded by customer or automatic renewal certificate by eCDN. + * @example custom + * @enum {string} + */ + certificateType: "custom" | "automatic" | "custom_legacy"; + /** + * @description Indicates certificate issuer for automatic renewal certificate by eCDN. + * @example lets_encrypt + * @enum {string} + */ + certificateAuthority?: "google" | "lets_encrypt" | "digicert"; + /** + * @description Indicates certificate validation type for automatic renewal certificate by eCDN. + * @example http + * @enum {string} + */ + certificateValidation?: "http" | "txt"; + /** + * @description eCDN automatic renewal certificate verification txt name. + * @example _acme-challenge.example.com + */ + certificateVerificationTXTName?: string; + /** + * @description eCDN automatic renewal certificate verification txt value. + * @example abc123def456ghi789 + */ + certificateVerificationTXTValue?: string; + /** + * @description Current status of certificate verification. + * @example ACTIVE + * @enum {string} + */ + certificateVerificationStatus?: "ACTIVE" | "EXPIRED" | "PENDING" | "INITIALIZING" | "PENDING_VALIDATION" | "PENDING_ISSUANCE" | "PENDING_DEPLOYMENT"; + /** + * @description Set to true for a wildcard custom hostname. + * @example false + */ + wildcardHostname?: boolean; + /** + * @description eCDN automatic renewal certificate verification txt name. + * @example _acme-challenge.wildcard.example.com + */ + wildcardCertificateVerificationTXTName?: string; + /** + * @description eCDN automatic renewal certificate verification txt value. + * @example wildcard_abc123def456 + */ + wildcardCertificateVerificationTXTValue?: string; + /** + * @description Current status of certificate verification. + * @example ACTIVE + * @enum {string} + */ + wildcardCertificateVerificationStatus?: "ACTIVE" | "EXPIRED" | "PENDING" | "INITIALIZING" | "PENDING_VALIDATION" | "PENDING_ISSUANCE" | "PENDING_DEPLOYMENT"; + /** + * @description Custom Hostname verification txt name. + * @example _acme-challenge.custom.example.com + */ + customHostnameVerificationTXTName?: string; + /** + * @description Custom Hostname verification txt value. + * @example custom_abc123def456 + */ + customHostnameVerificationTXTValue?: string; + /** + * @description Custom hostname associated with the zone + * @example f90712123fb02287348dd34c0a282bb9 + */ + customHostnameId?: string; + /** + * @description Custom hostname associated with the zone + * @example custom.example.com + */ + customHostname?: string; + /** + * @description Current status of custom hostname validation. + * @example ACTIVE + * @enum {string} + */ + customHostnameStatus?: "ACTIVE" | "EXPIRED" | "DELETED" | "PENDING" | "INITIALIZING" | "PENDING_VALIDATION" | "PENDING_ISSUANCE" | "PENDING_DEPLOYMENT" | "PENDING_DELETION" | "MOVED"; + /** @description eCDN automatic renewal certificate DCV delegation records */ + dcvDelegationRecords?: components["schemas"]["DCVDelegationRecord"][]; + }; + /** + * @example { + * "data": [ + * { + * "certificateId": "f90712123fb02287348dd34c0a282bb9", + * "hosts": [ + * "example.com", + * "www.example.com" + * ], + * "expiresOn": "2025-12-31T23:59:59Z", + * "uploadedOn": "2024-01-01T00:00:00Z", + * "issuer": "Let's Encrypt Authority X3", + * "signature": "SHA256", + * "status": "ACTIVE", + * "minTlsVersion": "1.2", + * "certificateType": "custom", + * "certificateAuthority": "lets_encrypt", + * "certificateValidation": "http", + * "certificateVerificationTXTName": "_acme-challenge.example.com", + * "certificateVerificationTXTValue": "abc123def456ghi789", + * "certificateVerificationStatus": "ACTIVE", + * "wildcardHostname": false, + * "wildcardCertificateVerificationTXTName": "_acme-challenge.wildcard.example.com", + * "wildcardCertificateVerificationTXTValue": "wildcard_abc123def456", + * "wildcardCertificateVerificationStatus": "ACTIVE", + * "customHostnameVerificationTXTName": "_acme-challenge.custom.example.com", + * "customHostnameVerificationTXTValue": "custom_abc123def456", + * "customHostnameId": "f90712123fb02287348dd34c0a282bb9", + * "customHostname": "custom.example.com", + * "customHostnameStatus": "ACTIVE", + * "dcvDelegationRecords": [] + * } + * ] + * } + */ + CertificatesEnvelope: { + data: components["schemas"]["Certificate"][]; + }; + /** + * @description Certificate request information + * @example { + * "hostname": "example.com", + * "bundleMethod": "ubiquitous", + * "certificateType": "custom", + * "certificate": "-----BEGIN CERTIFICATE-----\nMIIDtTCCAp2gAwIBAgIJAMHAwfXZ5PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX\naWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF\nMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50\nZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1\nCGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB\nKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5\n0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI\ndZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2\nizNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4\n9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI\nGKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV\nBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF\nMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2\n2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP\nMlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG\nSvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq\n2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw\nYbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY=\n-----END CERTIFICATE-----", + * "privateKey": "-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmG\ndtcGbg/1CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKn\nabIRuGvBKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpid\ntnKX/a+50GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+py\nFxIXjbEIdZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pE\newooaeO2izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABAoIBACbhTYXBZYKmYPCb\nHBR1IBlCQA2nLGf0qRuJNJZg5iEzXows/6tc8YymZkQE7nolapWsQ+upk2y5Xdp/\naxiuprIs9JzkYK8Ox0r+dlwCG1kSW+UAbX0bQ/qUqlsTvU6muVuMP8vZYHxJ3wmb\n+ufRBKztPTQ/rYWaYQcgC0RWI20HTFBMxlTAyNxYNWzX7RKFkGVVyB9RsAtmcc8g\n+j4OdosbfNoJPS0HeIfNpAznDfHKdxDk2Yc1tV6RHBrC1ynyLE9+TaflIAdo2MVv\nKLMLq51GqYKtgJFIlBRPQqKoyXdz3fGvXrTkf/WY9QNq0J1Vk5ERePZ54mN8iZB7\n9lwy/AkCgYEA6FXzosxswaJ2wQLeoYc7ceaweX/SwTvxHgXzRyJIIT0eJWgx13Wo\n/WA3Iziimsjf6qE+SI/8laxPp2A86VMaIt3Z3mJN/CqSVGw8LK2AQst+OwdPyDMu\niacE8lj/IFGC8mwNUAb9CzGU3JpU4PxxGFjS/eMtGeRXCWkK4NE+G08CgYEA1Kp9\nN2JrVlqUz+gAX+LPmE9OEMAS9WQSQsfCHGogIFDGGcNf7+uwBM7GAaSJIP01zcoe\nVAgWdzXCv3FLhsaZoJ6RyLOLay5phbu1iaTr4UNYm5WtYTzMzqh8l1+MFFDl9xDB\nvULuCIIrglM5MeS/qnSg1uMoH2oVPj9TVst/ir8CgYEAxrI7Ws9Zc4Bt70N1As+U\nlySjaEVZCMkqvHJ6TCuVZFfQoE0r0whdLdRLU2PsLFP+q7qaeZQqgBaNSKeVcDYR\n9B+nY/jOmQoPewPVsp/vQTCnE/R81spu0mp0YI6cIheT1Z9zAy322svcc43JaWB7\nmEbeqyLOP4Z4qSOcmghZBSECgYACvR9Xs0DGn+wCsW4vze/2ei77MD4OQvepPIFX\ndFZtlBy5ADcgE9z0cuVB6CiL8DbdK5kwY9pGNr8HUCI03iHkW6Zs+0L0YmihfEVe\nPG19PSzK9CaDdhD9KFZSbLyVFmWfxOt50H7YRTTiPMgjyFpfi5j2q348yVT0tEQS\nfhRqaQKBgAcWPokmJ7EbYQGeMbS7HC8eWO/RyamlnSffdCdSc7ue3zdVJxpAkQ8W\nqu80pEIF6raIQfAf8MXiiZ7auFOSnHQTXUbhCpvDLKi0Mwq3G8Pl07l+2s6dQG6T\nlv6XTQaMyf6n1yjzL+fzDrH3qXMxHMO/b13EePXpDMpY7HQpoLDi\n-----END RSA PRIVATE KEY-----", + * "certificateAuthority": "lets_encrypt", + * "certificateValidation": "http", + * "wildcardHostname": false + * } + */ + CertificateRequest: { + /** + * @description Hostname that certificate needs to be applied to. + * @example example.com + */ + hostname: string; + /** + * @description Bundle method of the custom certificate chain for verification. + * @example ubiquitous + */ + bundleMethod?: string; + /** + * @description Indicates certificate is custom or automatic certificate renewal by eCDN. Optional field, if nothing specified the default value is custom. Valid values are custom or automatic. + * @example custom + */ + certificateType?: string; + /** + * @description Public key of the custom certificate. Required if the certificateType value is custom. + * @example -----BEGIN CERTIFICATE----- + * MIIDtTCCAp2gAwIBAgIJAMHAwfXZ5PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV + * BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX + * aWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF + * MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 + * ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB + * CgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1 + * CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB + * KwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5 + * 0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI + * dZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2 + * izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4 + * 9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI + * GKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV + * BAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF + * MAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2 + * 2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP + * Mlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG + * SvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq + * 2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw + * YbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY= + * -----END CERTIFICATE----- + */ + certificate?: string; + /** + * @description Private key associated with the custom certificate. Required if the `certificateType` value is custom. + * @example -----BEGIN RSA PRIVATE KEY----- + * MIIEowIBAAKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmG + * dtcGbg/1CGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKn + * abIRuGvBKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpid + * tnKX/a+50GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+py + * FxIXjbEIdZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pE + * ewooaeO2izNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABAoIBACbhTYXBZYKmYPCb + * HBR1IBlCQA2nLGf0qRuJNJZg5iEzXows/6tc8YymZkQE7nolapWsQ+upk2y5Xdp/ + * axiuprIs9JzkYK8Ox0r+dlwCG1kSW+UAbX0bQ/qUqlsTvU6muVuMP8vZYHxJ3wmb + * +ufRBKztPTQ/rYWaYQcgC0RWI20HTFBMxlTAyNxYNWzX7RKFkGVVyB9RsAtmcc8g + * +j4OdosbfNoJPS0HeIfNpAznDfHKdxDk2Yc1tV6RHBrC1ynyLE9+TaflIAdo2MVv + * KLMLq51GqYKtgJFIlBRPQqKoyXdz3fGvXrTkf/WY9QNq0J1Vk5ERePZ54mN8iZB7 + * 9lwy/AkCgYEA6FXzosxswaJ2wQLeoYc7ceaweX/SwTvxHgXzRyJIIT0eJWgx13Wo + * /WA3Iziimsjf6qE+SI/8laxPp2A86VMaIt3Z3mJN/CqSVGw8LK2AQst+OwdPyDMu + * iacE8lj/IFGC8mwNUAb9CzGU3JpU4PxxGFjS/eMtGeRXCWkK4NE+G08CgYEA1Kp9 + * N2JrVlqUz+gAX+LPmE9OEMAS9WQSQsfCHGogIFDGGcNf7+uwBM7GAaSJIP01zcoe + * VAgWdzXCv3FLhsaZoJ6RyLOLay5phbu1iaTr4UNYm5WtYTzMzqh8l1+MFFDl9xDB + * vULuCIIrglM5MeS/qnSg1uMoH2oVPj9TVst/ir8CgYEAxrI7Ws9Zc4Bt70N1As+U + * lySjaEVZCMkqvHJ6TCuVZFfQoE0r0whdLdRLU2PsLFP+q7qaeZQqgBaNSKeVcDYR + * 9B+nY/jOmQoPewPVsp/vQTCnE/R81spu0mp0YI6cIheT1Z9zAy322svcc43JaWB7 + * mEbeqyLOP4Z4qSOcmghZBSECgYACvR9Xs0DGn+wCsW4vze/2ei77MD4OQvepPIFX + * dFZtlBy5ADcgE9z0cuVB6CiL8DbdK5kwY9pGNr8HUCI03iHkW6Zs+0L0YmihfEVe + * PG19PSzK9CaDdhD9KFZSbLyVFmWfxOt50H7YRTTiPMgjyFpfi5j2q348yVT0tEQS + * fhRqaQKBgAcWPokmJ7EbYQGeMbS7HC8eWO/RyamlnSffdCdSc7ue3zdVJxpAkQ8W + * qu80pEIF6raIQfAf8MXiiZ7auFOSnHQTXUbhCpvDLKi0Mwq3G8Pl07l+2s6dQG6T + * lv6XTQaMyf6n1yjzL+fzDrH3qXMxHMO/b13EePXpDMpY7HQpoLDi + * -----END RSA PRIVATE KEY----- + */ + privateKey?: string; + /** + * @description Certificate authority only for automatic certificate renewal by eCDN. Required if the `certificateType` value is automatic. Valid values are `google` or `lets_encrypt`. + * @example lets_encrypt + */ + certificateAuthority?: string; + /** + * @description Certificate validation type is optional only for `certificateType` automatic, default value is `http`. Valid values are `http` or `txt`. + * @example http + */ + certificateValidation?: string; + /** + * @description Set to true for a wildcard custom hostname. + * @example false + */ + wildcardHostname?: boolean; + }; + /** + * @example { + * "data": { + * "certificateId": "f90712123fb02287348dd34c0a282bb9", + * "hosts": [ + * "example.com", + * "www.example.com" + * ], + * "expiresOn": "2025-12-31T23:59:59Z", + * "uploadedOn": "2024-01-01T00:00:00Z", + * "issuer": "Let's Encrypt Authority X3", + * "signature": "SHA256", + * "status": "ACTIVE", + * "minTlsVersion": "1.2", + * "certificateType": "custom", + * "certificateAuthority": "lets_encrypt", + * "certificateValidation": "http", + * "certificateVerificationTXTName": "_acme-challenge.example.com", + * "certificateVerificationTXTValue": "abc123def456ghi789", + * "certificateVerificationStatus": "ACTIVE", + * "wildcardHostname": false, + * "wildcardCertificateVerificationTXTName": "_acme-challenge.wildcard.example.com", + * "wildcardCertificateVerificationTXTValue": "wildcard_abc123def456", + * "wildcardCertificateVerificationStatus": "ACTIVE", + * "customHostnameVerificationTXTName": "_acme-challenge.custom.example.com", + * "customHostnameVerificationTXTValue": "custom_abc123def456", + * "customHostnameId": "f90712123fb02287348dd34c0a282bb9", + * "customHostname": "custom.example.com", + * "customHostnameStatus": "ACTIVE", + * "dcvDelegationRecords": [] + * } + * } + */ + CertificateEnvelope: { + data: components["schemas"]["Certificate"]; + }; + /** + * @description Custom hostname validation information. + * @example { + * "customHostnameId": "a439eb1f-5e71-4544-bb29-54d18ax62277", + * "customHostname": "test.example.com", + * "customHostnameVerificationTXTName": "_acme-challenge.test.example.com", + * "customHostnameVerificationTXTValue": "DBCtxdyQSyo9eXxys-uGVCwPFHLsc8_lu11QetQz4IA", + * "customHostnameStatus": "ACTIVE" + * } + */ + CustomHostnameValidationResponse: { + /** + * @description Identifier generated by the CDN provider for the custom hostname. + * @example a439eb1f-5e71-4544-bb29-54d18ax62277 + */ + customHostnameId: string; + /** + * @description Name of the custom hostname + * @example test.example.com + */ + customHostname: string; + /** + * @description Custom hostname verification txt name. + * @example _acme-challenge.test.example.com + */ + customHostnameVerificationTXTName: string; + /** + * @description Custom hostname verification txt value. + * @example DBCtxdyQSyo9eXxys-uGVCwPFHLsc8_lu11QetQz4IA + */ + customHostnameVerificationTXTValue: string; + /** + * @description Current status of the custom hostname. + * @example ACTIVE + * @enum {string} + */ + customHostnameStatus: "PENDING" | "ACTIVE" | "MOVED" | "DELETED"; + }; + /** + * @example { + * "data": { + * "customHostnameId": "a439eb1f-5e71-4544-bb29-54d18ax62277", + * "customHostname": "test.example.com", + * "customHostnameVerificationTXTName": "_acme-challenge.test.example.com", + * "customHostnameVerificationTXTValue": "DBCtxdyQSyo9eXxys-uGVCwPFHLsc8_lu11QetQz4IA", + * "customHostnameStatus": "ACTIVE" + * } + * } + */ + CustomHostnameValidationEnvelope: { + data: components["schemas"]["CustomHostnameValidationResponse"]; + }; + /** + * @description A rule in an MRT ruleset. + * @example { + * "id": "12345678901234asdfasfasdf", + * "expression": "(http.host eq \"dev-customer.salesforce.com\" and not ( http.request.uri.path matches \"^/path1/.*\" or http.request.uri.path matches \"^.*\/path2/.*\/products/.*\"))", + * "description": "Phased rollout rule for dev-customer.salesforce.com", + * "lastUpdated": "2022-01-01T05:20:00Z", + * "ref": "12345678901234asdfasfasdf1234567", + * "enabled": true, + * "mrtHostname": "customer-pwa-hybrid.mobify-storefront.com" + * } + */ + MRTRules: { + /** + * @description The ID of the rule. + * @example 12345678901234asdfasfasdf + */ + id: string; + /** + * @description The expression that determines the rule's routing behavior. + * @example (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path1/.*" or http.request.uri.path matches "^.*\/path2/.*\/products/.*")) + */ + expression: string; + /** + * @description The description of the rule. + * @example Phased rollout rule for dev-customer.salesforce.com + */ + description?: string; + /** + * Format: date-time + * @description Date when the rule was last updated. + * @example 2022-01-01T05:20:00Z + */ + lastUpdated: string; + /** + * @description The ref of the rule. + * @example 12345678901234asdfasfasdf1234567 + */ + ref: string; + /** + * @description Whether or not the rule is enabled. + * @example true + */ + enabled: boolean; + /** + * @description Managed runtime hostname this rule targets. + * @example customer-pwa-hybrid.mobify-storefront.com + */ + mrtHostname: string; + }; + /** + * @description An MRT ruleset. Defines a list of MRT rules that will route certain storefront requests to the managed runtime instance. + * @example { + * "id": "12345678901234asdfasfasdf", + * "name": "MRT Rules", + * "lastUpdated": "2022-01-01T05:20:00Z", + * "rules": [] + * } + */ + MRTRuleset: { + /** + * @description The ID of the ruleset. + * @example 12345678901234asdfasfasdf + */ + id: string; + /** + * @description The name of the ruleset. + * @example MRT Rules + */ + name: string; + /** + * Format: date-time + * @description Date when the ruleset was last updated. + * @example 2022-01-01T05:20:00Z + */ + lastUpdated: string; + /** @description The rules defined by the ruleset. */ + rules: components["schemas"]["MRTRules"][]; + }; + /** + * @description Response for MRT rules. MRT rules are a way to route certain storefront requests to the managed runtime instance. + * @example { + * "ruleset": { + * "id": "12345678901234asdfasfasdf", + * "name": "MRT Rules", + * "lastUpdated": "2022-01-01T05:20:00Z", + * "rules": [] + * } + * } + */ + MRTRulesResponse: { + ruleset: components["schemas"]["MRTRuleset"]; + }; + /** + * @example { + * "data": { + * "ruleset": { + * "id": "12345678901234asdfasfasdf", + * "name": "MRT Rules", + * "lastUpdated": "2022-01-01T05:20:00Z", + * "rules": [] + * } + * } + * } + */ + MRTRulesResponseEnvelope: { + data: components["schemas"]["MRTRulesResponse"]; + }; + /** + * @description POST request for creating MRT rules. MRT rules are a way to route certain storefront requests to the managed runtime instance. + * @example { + * "mrtHostname": "customer-react-project-production.mobify-storefront.com", + * "expressions": [ + * "(http.host eq \"dev-customer.salesforce.com\" and not ( http.request.uri.path matches \"^/path1/.*\" or http.request.uri.path matches \"^.*\/path2/.*\/products/.*\"))" + * ], + * "descriptions": [ + * "Phased rollout rule for dev-customer.salesforce.com" + * ] + * } + */ + MRTRulesPostRequest: { + /** + * @description The customer's MRT instance hostname. + * @example customer-react-project-production.mobify-storefront.com + */ + mrtHostname: string; + /** + * @description An array containing the expressions for each MRT rule. + * @example [ + * "(http.host eq \"dev-customer.salesforce.com\" and not ( http.request.uri.path matches \"^/path1/.*\" or http.request.uri.path matches \"^.*\/path2/.*\/products/.*\"))" + * ] + */ + expressions: string[]; + /** + * @description An array containing the descriptions for each MRT rule. The number of descriptions provided must match the number of expressions provided. Optional. + * @example [ + * "Phased rollout rule for dev-customer.salesforce.com" + * ] + */ + descriptions?: string[]; + }; + /** + * @description PATCH request for updating the MRT environment hostname or adding MRT rules to route to an existing MRT environment. + * @example { + * "mrtHostname": "customer-react-projec-production.mobify-storefront.com", + * "expressions": [ + * "(http.host eq \"dev-customer.salesforce.com\" and not ( http.request.uri.path matches \"^/path1/.*\" or http.request.uri.path matches \"^.*\/path2/.*\/products/.*\"))" + * ], + * "descriptions": [ + * "Phased rollout rule for dev-customer.salesforce.com" + * ] + * } + */ + MRTRulesetPatchRequest: { + /** + * @description The customer's current MRT instance hostname. + * @example customer-react-projec-production.mobify-storefront.com + */ + oldMrtHostname?: string; + /** + * @description The customer's MRT instance hostname. + * @example customer-react-projec-production.mobify-storefront.com + */ + mrtHostname: string; + /** + * @description An array containing the expressions for each MRT rule. + * @example [ + * "(http.host eq \"dev-customer.salesforce.com\" and not ( http.request.uri.path matches \"^/path1/.*\" or http.request.uri.path matches \"^.*\/path2/.*\/products/.*\"))" + * ] + */ + expressions?: string[]; + /** + * @description An array containing the descriptions for each MRT rule. The number of descriptions provided must match the number of expressions provided. Optional. + * @example [ + * "Phased rollout rule for dev-customer.salesforce.com" + * ] + */ + descriptions?: string[]; + }; + /** + * @description PATCH request for updating an MRT rule. You may use the PATCH request to update the rule's expression and description as well as disable/enable the rule. + * @example { + * "enabled": true, + * "expression": "(http.host eq \"dev-customer.salesforce.com\" and not ( http.request.uri.path matches \"^/path1/.*\" or http.request.uri.path matches \"^.*\/path2/.*\/products/.*\"))", + * "description": "Phased rollout rule for dev-customer.salesforce.com" + * } + */ + MRTRulePatchRequest: { + /** + * @description Whether or not the rule is enabled. + * @example true + */ + enabled?: boolean; + /** + * @description The expression that determines the MRT rule's routing behavior. + * @example (http.host eq "dev-customer.salesforce.com" and not ( http.request.uri.path matches "^/path1/.*" or http.request.uri.path matches "^.*\/path2/.*\/products/.*")) + */ + expression?: string; + /** + * @description The description of the rule. Optional. + * @example Phased rollout rule for dev-customer.salesforce.com + */ + description?: string; + }; + /** + * @description POST request for creating new Logpush Ownership. + * @example { + * "destinationPath": "s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256" + * } + */ + LogpushOwnershipPostRequest: { + /** + * @description Uniquely identifies a resource (such as an s3 bucket) where data will be pushed. Additional configuration parameters supported by the destination may be included. You can use the special string {DATE} in the URL path to separate logs into daily subdirectories; for example s3://customer-bucket/logs/{DATE}?region=us-east-1&sse=AES256. The name of the directory will be replaced with the date in YYYYMMDD format (e.g. 20220215) when the logs are stored. + * @example s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + */ + destinationPath: string; + }; + /** + * @description POST response for created new Logpush Ownership. + * @example { + * "data": { + * "destinationPath": "s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256", + * "fileName": "site-name/20230101/ownership-challenge-d12345678.txt" + * } + * } + */ + LogpushOwnershipPostResponse: { + /** @description The customer's new Logpush Ownership. */ + data: { + /** + * @description Destination where logs will be sent (S3 bucket only). + * @example s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + */ + destinationPath: string; + /** + * @description File path where the ownership challenge file is written. + * @example site-name/20230101/ownership-challenge-d12345678.txt + */ + fileName: string; + }; + }; + /** + * @description Logpush job response + * @example { + * "jobId": 123456, + * "name": "my-logpush-job", + * "logType": "http_requests", + * "filter": "{\"where\":{\"key\":\"ClientRequestPath\",\"operator\":\"contains\",\"value\":\"/example-path\"}}", + * "logFields": [ + * "ClientRequestBytes", + * "ClientRequestHost", + * "ClientRequestMethod" + * ], + * "destinationPath": "s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256", + * "enabled": false, + * "lastComplete": "2023-01-02T00:00:00Z", + * "lastError": "2023-01-01T10:00:00Z", + * "errorMessage": "No permissions to write to destination bucket", + * "createdOn": "2023-01-01T00:00:27Z" + * } + */ + LogpushResponse: { + /** + * @description Unique ID of the job. + * @example 123456 + */ + jobId?: number; + /** + * @description Logpush job name; the name cannot be changed after the job is created. + * @example my-logpush-job + */ + name?: string; + /** + * @description Type of logs; available log types are `http_requests`, `firewall_events`, and `page_shield_events`. + * @example http_requests + * @enum {string} + */ + logType?: "http_requests" | "firewall_events" | "page_shield_events"; + /** + * @description Filter provides a way to customize which logs you want to receive. Filters are added as escaped JSON strings formatted. If the filter is not displayed, it indicates that all logs should be included. + * @example {"where":{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}} + */ + filter?: string; + /** + * @description List of log fields. Depending on the type of log, the list of fields that you would like to see in the logs may vary. + * @example [ + * "ClientRequestBytes", + * "ClientRequestHost", + * "ClientRequestMethod" + * ] + */ + logFields?: string[]; + /** + * @description Uniquely identifies s3 bucket for logs. + * @example s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + */ + destinationPath?: string; + /** + * @description Flag that indicates if the job is enabled or disabled. + * @example false + */ + enabled?: boolean; + /** + * Format: date-time + * @description The last time that the log has been successfully transmitted to the destination. + * @example 2023-01-02T00:00:00Z + */ + lastComplete?: string; + /** + * Format: date-time + * @description The last time the job failed. If empty, the job has either never failed or has run successfully at least once since the last failure. + * @example 2023-01-01T10:00:00Z + */ + lastError?: string; + /** + * @description Provide details for the last failure message. If this field is empty, it indicates that the job successfully transmitted logs to the destination. + * @example No permissions to write to destination bucket + */ + errorMessage?: string; + /** + * Format: date-time + * @description Job creation time. + * @example 2023-01-01T00:00:27Z + */ + createdOn?: string; + }; + /** + * @example { + * "data": [ + * { + * "jobId": 123456, + * "name": "my-logpush-job", + * "logType": "http_requests", + * "filter": "{\"where\":{\"key\":\"ClientRequestPath\",\"operator\":\"contains\",\"value\":\"/example-path\"}}", + * "logFields": [ + * "ClientRequestBytes", + * "ClientRequestHost", + * "ClientRequestMethod" + * ], + * "destinationPath": "s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256", + * "enabled": false, + * "lastComplete": "2023-01-02T00:00:00Z", + * "lastError": "2023-01-01T10:00:00Z", + * "errorMessage": "No permissions to write to destination bucket", + * "createdOn": "2023-01-01T00:00:27Z" + * } + * ] + * } + */ + LogpushJobsEnvelope: { + data: components["schemas"]["LogpushResponse"][]; + }; + /** + * @description Request for create Logpush job. + * @example { + * "destinationPath": "s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256", + * "name": "my-logpush-job", + * "filter": "{\"where\":{\"key\":\"ClientRequestPath\",\"operator\":\"contains\",\"value\":\"/example-path\"}}", + * "logFields": [ + * "ClientRequestBytes", + * "ClientRequestHost", + * "ClientRequestMethod" + * ], + * "ownershipChallengeToken": "abc00000000000000000000", + * "logType": "http_requests" + * } + */ + LogpushCreateRequest: { + /** + * @description Uniquely identifies s3 bucket for logs. Additional configuration parameters like region can be included. The string {DATE} in the URL path to separate logs into daily subdirectories; for example `s3://customer-bucket/logs/{DATE}?region=us-east-1&sse=AES256` The name of the directory will be replaced with the date in YYYYMMDD format (e.g. 20220215) when the logs are stored. + * @example s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256 + */ + destinationPath: string; + /** + * @description Logpush job name; the name cannot be changed after the job is created. + * @example my-logpush-job + */ + name: string; + /** + * @description Filter provides a way to customize which logs you want to receive. Filters are added as escaped JSON strings formatted. Default will include all logs. + * @example {"where":{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}} + */ + filter?: string; + /** + * @description List of log fields. Depending on the type of log, the list of fields that you would like to see in the logs may vary. + * @example [ + * "ClientRequestBytes", + * "ClientRequestHost", + * "ClientRequestMethod" + * ] + */ + logFields: string[]; + /** + * @description Ownership token to proves the ownership of the destinationPath. + * @example abc00000000000000000000 + */ + ownershipChallengeToken?: string; + /** + * @description Type of logs. Available log types are `http_requests`, `firewall_events`, and `page_shield_events`. + * @example http_requests + * @enum {string} + */ + logType: "http_requests" | "firewall_events" | "page_shield_events"; + }; + /** + * @example { + * "data": { + * "jobId": 123456, + * "name": "my-logpush-job", + * "logType": "http_requests", + * "filter": "{\"where\":{\"key\":\"ClientRequestPath\",\"operator\":\"contains\",\"value\":\"/example-path\"}}", + * "logFields": [ + * "ClientRequestBytes", + * "ClientRequestHost", + * "ClientRequestMethod" + * ], + * "destinationPath": "s3://customer-bucket/site-name/{DATE}?region=us-east-1&sse=AES256", + * "enabled": false, + * "lastComplete": "2023-01-02T00:00:00Z", + * "lastError": "2023-01-01T10:00:00Z", + * "errorMessage": "No permissions to write to destination bucket", + * "createdOn": "2023-01-01T00:00:27Z" + * } + * } + */ + LogpushEnvelope: { + data: components["schemas"]["LogpushResponse"]; + }; + /** + * @description Request for update Logpush job + * @example { + * "enabled": true, + * "filter": "{\"where\":{\"key\":\"ClientRequestPath\",\"operator\":\"contains\",\"value\":\"/example-path\"}}", + * "logFields": [ + * "ClientRequestBytes", + * "ClientRequestHost", + * "ClientRequestMethod" + * ] + * } + */ + LogpushUpdateRequest: { + /** + * @description Flag that indicates if the job is enabled or disabled. + * @example true + */ + enabled?: boolean; + /** + * @description Provides customized selection for logs you want to receive. Filters are added as escaped, formatted JSON strings. By default, all logs are included. + * @example {"where":{"key":"ClientRequestPath","operator":"contains","value":"/example-path"}} + */ + filter?: string; + /** + * @description List of log fields. Depending on the log type, the list of fields that you can specify to be displayed in the log might vary. + * @example [ + * "ClientRequestBytes", + * "ClientRequestHost", + * "ClientRequestMethod" + * ] + */ + logFields?: string[]; + }; + WAFRulePackage: { + /** @example a25a9a7e9c00afc1fb2e0245519d725b */ + id: string; + /** + * @description Name of the firewall package + * @example OWASP Top 10 Protection + */ + name: string; + /** + * @description Summary of purpose/function of firewall package + * @example Protection against OWASP Top 10 vulnerabilities + */ + description: string; + /** + * @description How the rules within the package are evaluated during the course of a request. When a package uses anomaly detection, each rule is given a score when triggered. If the total score of all triggered rules exceeds the sensitivity defined on the package, the action defined on the package is taken. Traditional detection decides which action to take when it is triggered by the request. If multiple rules are triggered, the action with highest protection is used. For example, a block action beats a challenge. + * @example traditional + */ + detection_mode: string; + /** + * @description Zone identifier with which this rule package is associated. + * @example zone_1234567890abcdef + */ + zone_id: string; + /** + * @description Sensitivity for traditional (owasp) rule package. + * @example medium + * @enum {string} + */ + sensitivity: "low" | "medium" | "high" | "off"; + /** + * @description The default action that is taken for rules under traditional(owasp) firewall package. + * @example block + * @enum {string} + */ + action_mode: "simulate" | "challenge" | "block"; + }; + /** + * @example { + * "data": { + * "id": "a25a9a7e9c00afc1fb2e0245519d725b", + * "name": "OWASP Top 10 Protection", + * "description": "Protection against OWASP Top 10 vulnerabilities", + * "detection_mode": "traditional", + * "zone_id": "zone_1234567890abcdef", + * "sensitivity": "medium", + * "action_mode": "block" + * } + * } + */ + WAFRulePackageEnvelope: { + data: components["schemas"]["WAFRulePackage"]; + }; + /** + * @example { + * "sensitivity": "medium", + * "action_mode": "block" + * } + */ + WafPackagePatchRequest: { + /** + * @description Sensitivity for traditional (owasp) rule package. + * @example medium + * @enum {string} + */ + sensitivity: "low" | "medium" | "high" | "off"; + /** + * @description The default action that is taken for rules under traditional(owasp) firewall package. + * @example block + * @enum {string} + */ + action_mode: "simulate" | "challenge" | "block"; + }; + /** @description A custom rule. */ + CustomRule: { + /** + * @description The ID of the custom rule. + * @example 2c0fc9fa937b11eaa1b71c4d701ab86e + */ + ruleId: string; + /** + * @description The description of the custom rule. + * @example Block traffic for malformed URL requests. + */ + description: string; + /** + * @description The expression that determines the custom rule's behavior. + * @example (http.request.uri.path matches \"^/path1/.*\") + */ + expression: string; + /** + * @description The action(s) applied by the custom rule. + * @example [ + * "block" + * ] + */ + actions: string[]; + /** + * Format: date-time + * @description Date when the custom rule was last updated. + * @example 2022-01-01T05:20:00Z + */ + lastUpdated: string; + /** + * @description Whether or not the custom rule is enabled. + * @example true + */ + enabled: boolean; + }; + /** + * @example { + * "data": [ + * { + * "ruleId": "2c0fc9fa937b11eaa1b71c4d701ab86e", + * "description": "Block traffic for malformed URL requests.", + * "expression": "(http.request.uri.path matches \"^/path1/.*\")", + * "actions": [ + * "block" + * ], + * "lastUpdated": "2022-01-01T05:20:00Z", + * "enabled": true + * }, + * { + * "ruleId": "ffffe61cf25e4ec49c34b029ff3060f7", + * "description": "Rate limit form traffic", + * "expression": "http.request.uri.path eq \"/form\"", + * "actions": [ + * "block" + * ], + * "lastUpdated": "2022-12-14T21:25:22.329194Z", + * "enabled": false + * } + * ] + * } + */ + CustomRulesEnvelope: { + data: components["schemas"]["CustomRule"][]; + }; + /** @description Used to specify the position of a rule. */ + RulePosition: { + /** + * @description Insert the current rule before this ruleId. + * @example 2c0fc9fa937b11eaa1b71c4d701ab86e + */ + before?: string; + /** + * @description Insert the current rule after this ruleId. + * @example 2c0fc9fa937b11eaa1b71c4d701ab86e + */ + after?: string; + }; + /** @description Create a custom rule. */ + CustomRulesPostRequest: { + /** + * @description A description of the custom rule. + * @example Block traffic for malformed URL requests + */ + description: string; + /** + * @description The expression that determines the custom rule's behavior. + * @example (http.request.uri.path matches \"^/path1/.*\") + */ + expression: string; + /** + * @description The action(s) applied by the custom rule. + * @example [ + * "block" + * ] + */ + actions: string[]; + /** + * @description Whether or not the custom rule is enabled. + * @example true + */ + enabled?: boolean; + position?: components["schemas"]["RulePosition"]; + }; + /** + * @example { + * "data": { + * "ruleId": "2c0fc9fa937b11eaa1b71c4d701ab86e", + * "description": "Block traffic for malformed URL requests.", + * "expression": "(http.request.uri.path matches \"^/path1/.*\")", + * "actions": [ + * "block" + * ], + * "lastUpdated": "2022-01-01T05:20:00Z", + * "enabled": true + * } + * } + */ + CustomRuleEnvelope: { + data: components["schemas"]["CustomRule"]; + }; + /** @description Update the order of all existing custom rules. */ + CustomRulesPatchOrderRequest: { + /** + * @description An array of ruleIds representing the new order of custom rules. + * @example [ + * "ffffe61cf25e4ec49c34b029ff3060f7", + * "2c0fc9fa937b11eaa1b71c4d701ab86e" + * ] + */ + ruleIds: string[]; + }; + /** @description Update a custom rule. */ + CustomRulesPatchRequest: { + /** + * @description A description of the custom rule. + * @example Block traffic for malformed URL requests + */ + description?: string; + /** + * @description The expression that determines the custom rule's behavior. + * @example (http.request.uri.path matches \"^/path1/.*\") + */ + expression?: string; + /** + * @description The action(s) applied by the custom rule. + * @example [ + * "block" + * ] + */ + actions?: string[]; + /** + * @description Whether or not the custom rule is enabled. + * @example true + */ + enabled?: boolean; + position?: components["schemas"]["RulePosition"]; + }; + /** @description A rate limiting rule. */ + RateLimitingRule: { + /** + * @description The ID of the rate limiting rule. + * @example 2c0fc9fa937b11eaa1b71c4d701ab86e + */ + ruleId: string; + /** + * @description The description of the rate limiting rule. + * @example Rate limit /path1. + */ + description: string; + /** + * @description The expression that defines when to evaluate the rate limiting rule. + * @example (http.request.uri.path matches "^/path1/.*") + */ + expression: string; + /** + * @description Set of parameters defining how to group requests when tracking the request rate. + * @example [ + * "cf.unique_visitor_id" + * ] + */ + characteristics: string[]; + /** + * @description The action applied by the rate limiting rule. Valid actions are "block", "managed_challenge", "js_challenge", "legacy_captcha", and "log". + * @example block + */ + action: string; + /** + * @description The period of time to consider when evaluating the request rate (in seconds). Valid values are 10, 60, 120, 300, and 600. + * @example 60 + */ + period: number; + /** + * @description The limit for the number of requests in the specified period of time. + * @example 50 + */ + requestsPerPeriod: number; + /** + * @description After the rate is reached, the rate limiting rule applies the rule action to further requests for the period of time defined in this field (in seconds). When set to 0, the rule throttles requests over the maximum configured rate. When greater than 0, the action is presented for the selected duration after the configured rate is exceeded. Valid values are 0, 60, 120, 300, 600, 3600, and 86400. + * @example 600 + */ + mitigationTimeout: number; + /** + * @description The expression that defines what kind of requests we want to rate limit. + * @example (http.request.uri.path matches "^/path1/.*" and http.response.code eq 400) + */ + countingExpression?: string; + /** + * Format: date-time + * @description Date when the rate limiting rule was last updated. + * @example 2022-01-01T05:20:00Z + */ + lastUpdated: string; + /** + * @description Whether or not the rate limiting rule is enabled. + * @example true + */ + enabled: boolean; + }; + RateLimitingRulesEnvelope: { + data: components["schemas"]["RateLimitingRule"][]; + }; + /** @description Create a rate limiting rule. */ + RateLimitingRulesPostRequest: { + /** + * @description The description of the rate limiting rule. + * @example Rate limit /path1. + */ + description: string; + /** + * @description The expression that defines when to evaluate the rate limiting rule. + * @example (http.request.uri.path matches "^/path1/.*") + */ + expression: string; + /** + * @description Set of parameters defining how to group requests when tracking the request rate. + * @example [ + * "cf.unique_visitor_id" + * ] + */ + characteristics: string[]; + /** + * @description The action applied by the rate limiting rule. Valid actions are "block", "managed_challenge", "js_challenge", "legacy_captcha", and "log". + * @example block + */ + action: string; + /** + * @description The period of time to consider when evaluating the request rate (in seconds). Valid values are 10, 60, 120, 300, and 600. + * @example 60 + */ + period: number; + /** + * @description The limit for the number of requests in the specified period of time. + * @example 50 + */ + requestsPerPeriod: number; + /** + * @description After the rate is reached, the rate limiting rule applies the rule action to further requests for the period of time defined in this field (in seconds). When set to 0, the rule throttles requests over the maximum configured rate. When greater than 0, the action is presented for the selected duration after the configured rate is exceeded. Valid values are 0, 60, 120, 300, 600, 3600, and 86400. + * @example 600 + */ + mitigationTimeout: number; + /** + * @description The expression that defines what kind of requests we want to rate limit. + * @example (http.request.uri.path matches "^/path1/.*" and http.response.code eq 400) + */ + countingExpression?: string; + /** + * @description Whether or not the rate limiting rule is enabled. + * @example true + */ + enabled?: boolean; + position?: components["schemas"]["RulePosition"]; + }; + RateLimitingRuleEnvelope: { + data: components["schemas"]["RateLimitingRule"]; + }; + /** @description Update a rate limiting rule. */ + RateLimitingRulesPatchRequest: { + /** + * @description The description of the rate limiting rule. + * @example Rate limit /path1. + */ + description?: string; + /** + * @description The expression that defines when to evaluate the rate limiting rule. + * @example (http.request.uri.path matches "^/path1/.*") + */ + expression?: string; + /** + * @description Set of parameters defining how to group requests when tracking the request rate. + * @example [ + * "cf.unique_visitor_id" + * ] + */ + characteristics?: string[]; + /** + * @description The action applied by the rate limiting rule. Valid actions are "block", "managed_challenge", "js_challenge", "legacy_captcha", and "log". + * @example block + */ + action?: string; + /** + * @description The period of time to consider when evaluating the request rate (in seconds). Valid values are 10, 60, 120, 300, and 600. + * @example 60 + */ + period?: number; + /** + * @description The limit for the number of requests in the specified period of time. + * @example 50 + */ + requestsPerPeriod?: number; + /** + * @description After the rate is reached, the rate limiting rule applies the rule action to further requests for the period of time defined in this field (in seconds). When set to 0, the rule throttles requests over the maximum configured rate. When greater than 0, the action is presented for the selected duration after the configured rate is exceeded. Valid values are 0, 60, 120, 300, 600, 3600, and 86400. + * @example 600 + */ + mitigationTimeout?: number; + /** + * @description The expression that defines what kind of requests we want to rate limit. + * @example (http.request.uri.path matches "^/path1/.*" and http.response.code eq 400) + */ + countingExpression?: string; + /** + * @description Whether or not the rate limiting rule is enabled. + * @example true + */ + enabled?: boolean; + position?: components["schemas"]["RulePosition"]; + }; + /** + * @description A WAF managed ruleset. + * @example { + * "name": "OWASP Core Ruleset", + * "rulesetId": "4814384a9e5d4991b9815dcfc25d2f1f", + * "action": "default", + * "anomalyScore": "low", + * "anomalyScoreThreshold": 60, + * "paranoiaLevel": 1, + * "enabled": true + * } + */ + WAFManagedRuleset: { + /** + * @description The name of the WAF managed ruleset. + * @example OWASP Core Ruleset + */ + name: string; + /** + * @description The ID of the WAF managed ruleset. + * @example 4814384a9e5d4991b9815dcfc25d2f1f + */ + rulesetId: string; + /** + * @description The action applied by the WAF managed ruleset. + * @example default + */ + action: string; + /** + * @description The anomaly score threshold of the WAF managed ruleset. Only applicable for the OWASP Core Ruleset. + * @example low + */ + anomalyScore?: string; + /** + * @description The numerical value of the anomaly score threshold of the WAF managed ruleset. Only applicable for the OWASP Core Ruleset. + * @example 60 + */ + anomalyScoreThreshold?: number; + /** + * @description The paranoia level of the WAF managed ruleset. Higher paranoia levels activate more aggressive rules. Only applicable for the OWASP Core Ruleset. + * @example 1 + */ + paranoiaLevel?: number; + /** + * @description Whether or not the WAF managed ruleset is enabled. + * @example true + */ + enabled: boolean; + }; + /** + * @example { + * "data": [ + * { + * "name": "OWASP Core Ruleset", + * "rulesetId": "4814384a9e5d4991b9815dcfc25d2f1f", + * "action": "default", + * "anomalyScore": "low", + * "anomalyScoreThreshold": 60, + * "paranoiaLevel": 1, + * "enabled": true + * } + * ] + * } + */ + WAFManagedRulesetsEnvelope: { + data: components["schemas"]["WAFManagedRuleset"][]; + }; + /** + * @description A WAF managed ruleset request body. + * @example { + * "action": "default", + * "anomalyScore": "low", + * "paranoiaLevel": 1, + * "enabled": true + * } + */ + WAFManagedRulesetRequest: { + /** + * @description The action applied by the WAF managed ruleset. + * @example default + */ + action?: string; + /** + * @description The anomaly score threshold of the WAF managed ruleset. Only applicable for the OWASP Core Ruleset. + * @example low + */ + anomalyScore?: string; + /** + * @description The paranoia level of the WAF managed ruleset. Higher paranoia levels activate more aggressive rules. Only applicable for the OWASP Core Ruleset. + * @example 1 + */ + paranoiaLevel?: number; + /** + * @description Whether or not the WAF managed ruleset is enabled. + * @example true + */ + enabled?: boolean; + }; + /** + * @example { + * "data": { + * "name": "OWASP Core Ruleset", + * "rulesetId": "4814384a9e5d4991b9815dcfc25d2f1f", + * "action": "default", + * "anomalyScore": "low", + * "anomalyScoreThreshold": 60, + * "paranoiaLevel": 1, + * "enabled": true + * } + * } + */ + WAFManagedRulesetEnvelope: { + data: components["schemas"]["WAFManagedRuleset"]; + }; + /** + * @description A WAF managed rule. + * @example { + * "ruleId": "5de7edfa648c4d6891dc3e7f84534ffa", + * "action": "block", + * "score": 5, + * "categories": [ + * "broken-access-control", + * "wordpress" + * ], + * "description": "Wordpress - Broken Access Control", + * "lastUpdated": "2024-01-01T05:20:00Z", + * "enabled": true + * } + */ + WAFManagedRule: { + /** + * @description The ID of the WAF managed rule. + * @example 5de7edfa648c4d6891dc3e7f84534ffa + */ + ruleId: string; + /** + * @description The action applied by the WAF managed rule. + * @example block + */ + action: string; + /** + * @description The score of the WAF managed rule. Only applicable for the OWASP Managed Ruleset. + * @example 5 + */ + score?: number; + /** + * @description A list of categories describing the function of the WAF managed rule. + * @example [ + * "broken-access-control", + * "wordpress" + * ] + */ + categories: string[]; + /** + * @description The description of the WAF managed rule. + * @example Wordpress - Broken Access Control + */ + description: string; + /** + * Format: date-time + * @description Date when the WAF managed rule was last updated. + * @example 2024-01-01T05:20:00Z + */ + lastUpdated: string; + /** + * @description Whether or not the WAF managed rule is enabled. + * @example true + */ + enabled: boolean; + }; + /** + * @example { + * "data": [ + * { + * "ruleId": "5de7edfa648c4d6891dc3e7f84534ffa", + * "action": "block", + * "score": 5, + * "categories": [ + * "broken-access-control", + * "wordpress" + * ], + * "description": "Wordpress - Broken Access Control", + * "lastUpdated": "2024-01-01T05:20:00Z", + * "enabled": true + * } + * ] + * } + */ + WAFManagedRulesEnvelope: { + data: components["schemas"]["WAFManagedRule"][]; + }; + /** + * @description A PATCH request for updating a WAF managed rule. + * @example { + * "action": "block", + * "enabled": true + * } + */ + WAFManagedRuleRequest: { + /** + * @description The action applied by the WAF managed rule. + * @example block + */ + action?: string; + /** + * @description Whether or not the WAF managed rule is enabled. + * @example true + */ + enabled?: boolean; + }; + /** + * @example { + * "data": { + * "ruleId": "5de7edfa648c4d6891dc3e7f84534ffa", + * "action": "block", + * "score": 5, + * "categories": [ + * "broken-access-control", + * "wordpress" + * ], + * "description": "Wordpress - Broken Access Control", + * "lastUpdated": "2024-01-01T05:20:00Z", + * "enabled": true + * } + * } + */ + WAFManagedRuleEnvelope: { + data: components["schemas"]["WAFManagedRule"]; + }; + /** @description An origin header modification rule. */ + OriginHeaderModification: { + /** + * @description The name of the header forwarded to the origin. + * @example x-sfdc-access-control + */ + headerName: string; + /** + * @description The masked value of the header forwarded to the origin. + * @example ****************789 + */ + headerValue: string; + /** + * Format: date-time + * @description Date when the rule was last updated. + * @example 2022-01-01T05:20:00Z + */ + lastUpdated: string; + }; + OriginHeaderModificationEnvelope: { + data: components["schemas"]["OriginHeaderModification"]; + }; + /** @description Put request for creating/updating the origin header modification. */ + OriginHeaderModificationPutRequest: { + /** + * @description The value of the header forwarded to the origin. + * @example 123456789 + */ + headerValue: string; + /** + * @description The name of the header forwarded to the origin. Cannot be modified for the MRT origin. + * @example x-sfdc-access-control + */ + headerName?: string; + }; + /** + * @description Cipher suites information. + * @example { + * "cipherSuiteType": "Modern" + * } + */ + CipherSuitesResponse: { + /** + * @description List of zone level ciphers in the suite. + * @example [ + * "ECDHE-ECDSA-AES128-GCM-SHA256", + * "ECDHE-RSA-AES128-GCM-SHA256" + * ] + */ + ciphers: string[]; + /** + * @description Classification of the ciphers in the suite. + * @example Modern + * @enum {string} + */ + cipherSuiteType: "Compatible" | "Modern" | "Custom" | "Legacy"; + }; + /** + * @example { + * "data": { + * "cipherSuiteType": "Modern" + * } + * } + */ + CipherSuitesEnvelope: { + data: components["schemas"]["CipherSuitesResponse"]; + }; + /** + * @description Cipher suites information. + * @example { + * "cipherSuiteType": "Modern" + * } + */ + CipherSuitesRequest: { + /** + * @description List of zone level ciphers in the suite. + * @example [ + * "ECDHE-ECDSA-AES128-GCM-SHA256", + * "ECDHE-RSA-AES128-GCM-SHA256" + * ] + */ + ciphers?: string[]; + /** + * @description Classification of all ciphers in the suite. + * @example Modern + * @enum {string} + */ + cipherSuiteType: "Compatible" | "Modern" | "Custom" | "Legacy"; + }; + }; + responses: never; + parameters: { + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["schemas"]["OrganizationId"]; + mtlsCertificateId: string; + webhookId: string; + zoneId: string; + policyId: string; + /** @description The direction used to sort returned scripts. */ + direction: "asc" | "desc"; + /** @description When true, excludes scripts existing in a /cdn-cgi path from the returned scripts. Default is true. */ + excludeCdnCgi: boolean; + /** @description When true, excludes duplicate scripts. Default is false. */ + excludeDuplicates: boolean; + /** @description Excludes scripts with a URL that contains one of the URL-encoded URLs separated by commas. */ + excludeUrls: string; + /** @description Includes scripts that match one or more URL-encoded hostnames separated by commas. Wildcards are supported at the beginning and end of each hostname. */ + hosts: string; + /** @description The field used to sort returned scripts. */ + orderBy: "first_seen_at" | "last_seen_at"; + /** @description Includes scripts that match one or more page URLs (separated by commas) where they were last detected. Wildcards are supported at the beginning and end of each page URL. */ + pageUrl: string; + /** @description When true, lists malicious scripts first in the returned scripts. */ + prioritizeMalicious: boolean; + /** @description Filters the returned scripts using a comma-separated list of script statuses. Accepted values are 'active', 'infrequent', and 'inactive'. Default is 'active'. */ + status: string; + /** @description Includes scripts with a URL that contains one or more URL-encoded URLs separated by commas. */ + urls: string; + scriptId: string; + /** + * @description WAF Group that contains the WAF rules. + * @example f90712123fb02287348dd34c0a282bb9 + */ + groupIdPath: string; + /** + * @description WAF Group that contains the WAF rules. + * @example f90712123fb02287348dd34c0a282bb9 + */ + groupIdQuery: string; + ruleId: string; + certificateId: string; + customHostnameId: string; + rulesetId: string; + jobId: string; + /** @description The type of origin header modification. Only the `mrt` type is supported. */ + type: string; + }; + requestBodies: never; + headers: never; + pathItems: never; +} +export type $defs = Record; +export interface operations { + createStorefrontZone: { + parameters: { + query?: never; + header?: never; + path: { + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["StorefrontZoneCreateRequest"]; + }; + }; + responses: { + /** @description Successfully created new storefront zone. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["StorefrontZoneCreateEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getCodeUploadCertificates: { + parameters: { + query?: never; + header?: never; + path: { + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully retrieved details of the mTLS certificates requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MtlsCertificatesResponseEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + createCodeUploadCertificate: { + parameters: { + query?: never; + header?: never; + path: { + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["MtlsCertificateRequest"]; + }; + }; + responses: { + /** @description Returns information about the uploaded mTLS certificate. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MtlsCertificateResponseEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getCodeUploadCertificate: { + parameters: { + query?: never; + header?: never; + path: { + mtlsCertificateId: components["parameters"]["mtlsCertificateId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully retrieved mTLS certificate information from the mTLS certificate ID requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MtlsCertificateResponseEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + deleteCodeUploadCertificate: { + parameters: { + query?: never; + header?: never; + path: { + mtlsCertificateId: components["parameters"]["mtlsCertificateId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully deleted the mTLS certificate from the account. */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getPageShieldNotification: { + parameters: { + query?: never; + header?: never; + path: { + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully retrieved notification webhooks. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PageShieldNotificationWebhookListEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + postPageShieldNotification: { + parameters: { + query?: never; + header?: never; + path: { + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["PageShieldNotificationWebhookRequest"]; + }; + }; + responses: { + /** @description Successfully added notification webhook. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PageShieldNotificationWebhookEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + deletePageShieldNotification: { + parameters: { + query?: never; + header?: never; + path: { + webhookId: components["parameters"]["webhookId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully deleted notification webhook. */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getPageShieldPolicies: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List current page shield policies. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PageShieldPoliciesListEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + createPageShieldPolicy: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["PageShieldPolicyRequest"]; + }; + }; + responses: { + /** @description Successfully created page shield policy. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PageShieldPoliciesEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getPageShieldPolicy: { + parameters: { + query?: never; + header?: never; + path: { + policyId: components["parameters"]["policyId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully retrieved the details of the page shield policy. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PageShieldPoliciesEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updatePageShieldPolicy: { + parameters: { + query?: never; + header?: never; + path: { + policyId: components["parameters"]["policyId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["PageShieldPolicyRequest"]; + }; + }; + responses: { + /** @description Successfully updated the page shield policy. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PageShieldPoliciesEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + deletePageShieldPolicy: { + parameters: { + query?: never; + header?: never; + path: { + policyId: components["parameters"]["policyId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully deleted the page shield policy. */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getPageShieldScripts: { + parameters: { + query?: { + /** @description The direction used to sort returned scripts. */ + direction?: components["parameters"]["direction"]; + /** @description When true, excludes scripts existing in a /cdn-cgi path from the returned scripts. Default is true. */ + excludeCdnCgi?: components["parameters"]["excludeCdnCgi"]; + /** @description When true, excludes duplicate scripts. Default is false. */ + excludeDuplicates?: components["parameters"]["excludeDuplicates"]; + /** @description Excludes scripts with a URL that contains one of the URL-encoded URLs separated by commas. */ + excludeUrls?: components["parameters"]["excludeUrls"]; + /** @description Includes scripts that match one or more URL-encoded hostnames separated by commas. Wildcards are supported at the beginning and end of each hostname. */ + hosts?: components["parameters"]["hosts"]; + /** @description The field used to sort returned scripts. */ + orderBy?: components["parameters"]["orderBy"]; + /** @description Includes scripts that match one or more page URLs (separated by commas) where they were last detected. Wildcards are supported at the beginning and end of each page URL. */ + pageUrl?: components["parameters"]["pageUrl"]; + /** @description When true, lists malicious scripts first in the returned scripts. */ + prioritizeMalicious?: components["parameters"]["prioritizeMalicious"]; + /** @description Filters the returned scripts using a comma-separated list of script statuses. Accepted values are 'active', 'infrequent', and 'inactive'. Default is 'active'. */ + status?: components["parameters"]["status"]; + /** @description Includes scripts with a URL that contains one or more URL-encoded URLs separated by commas. */ + urls?: components["parameters"]["urls"]; + /** @description Maximum records to retrieve per request, not to exceed 200. Defaults to 200. */ + limit?: number; + /** @description Used to retrieve the results based on a particular resource offset. */ + offset?: number; + }; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description List current page shield scripts. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PageShieldScriptListEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getPageShieldScript: { + parameters: { + query?: never; + header?: never; + path: { + scriptId: components["parameters"]["scriptId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description A script detected by Page Shield by script ID. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["PageShieldScriptEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getZonesInfo: { + parameters: { + query?: { + /** @description Maximum records to retrieve per request, not to exceed 50. Defaults to 25. */ + limit?: number; + /** @description Used to retrieve the results based on a particular resource offset. */ + offset?: number; + }; + header?: never; + path: { + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully retrieved zone information requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["ZonesEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getWafGroups: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully retrieved details of WAF groups to which the caller has access. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WafGroupsEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateWafGroup: { + parameters: { + query?: never; + header?: never; + path: { + /** + * @description WAF Group that contains the WAF rules. + * @example f90712123fb02287348dd34c0a282bb9 + */ + groupId: components["parameters"]["groupIdPath"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["WafGroup"]; + }; + }; + responses: { + /** @description Successfully updated the WAF group specified by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WafGroupEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getWafRules: { + parameters: { + query?: { + /** + * @description WAF Group that contains the WAF rules. + * @example f90712123fb02287348dd34c0a282bb9 + */ + groupId?: components["parameters"]["groupIdQuery"]; + }; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully retrieved the WAF rules requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WafRulesEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getWafRule: { + parameters: { + query?: never; + header?: never; + path: { + ruleId: components["parameters"]["ruleId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully retrieved details of the WAF rule requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WafRuleEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateWafRule: { + parameters: { + query?: never; + header?: never; + path: { + ruleId: components["parameters"]["ruleId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["WafRule"]; + }; + }; + responses: { + /** @description Successfully updated the WAF rule specified by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WafRuleEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getSpeedSettings: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully returned the speed settings requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SpeedSettingsEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateSpeedSettings: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["SpeedSetting"]; + }; + }; + responses: { + /** @description Successfully updated the speed settings requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SpeedSettingsEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getSecuritySettings: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully returned security settings for zone. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SecuritySettingsEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateSecuritySettings: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["SecuritySetting"]; + }; + }; + responses: { + /** @description Successfully updated the security settings. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["SecuritySettingsEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + cachePurge: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CachePurgeRequest"]; + }; + }; + responses: { + /** @description Successfully returned the complete operationId statuses for the rule list operations that the server processed. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CachePurgeResponseEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + toggleOcapiCachingPageRule: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["OCAPICachingToggleRequest"]; + }; + }; + responses: { + /** @description Successfully returned the current state of the Caching page rule. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["OCAPICachingToggleRequest"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getCertificates: { + parameters: { + query?: { + /** @description Maximum records to retrieve per request, not to exceed 50. Defaults to 25. */ + limit?: number; + /** @description Used to retrieve the results based on a particular resource offset. */ + offset?: number; + }; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully retrieved the list of certificates for the specified zone. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CertificatesEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + addCertificateForZone: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CertificateRequest"]; + }; + }; + responses: { + /** @description Returned information about the added certificate. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CertificateEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The request sent by the caller has conflicts. */ + 409: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + deleteCertificate: { + parameters: { + query?: never; + header?: never; + path: { + certificateId: components["parameters"]["certificateId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully deleted the custom hostname and the certificate associated with it. */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateCertificate: { + parameters: { + query?: never; + header?: never; + path: { + certificateId: components["parameters"]["certificateId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CertificateRequest"]; + }; + }; + responses: { + /** @description Successfully updated the certificate requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CertificateEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + validateCustomHostname: { + parameters: { + query?: never; + header?: never; + path: { + customHostnameId: components["parameters"]["customHostnameId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully triggered the custom hostname validation process. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CustomHostnameValidationEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getMrtRules: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully retrieved all MRT rules. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MRTRulesResponseEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + createMrtRules: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["MRTRulesPostRequest"]; + }; + }; + responses: { + /** @description Created MRT rules to route to a new MRT environment. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MRTRulesResponseEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateMrtRuleset: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["MRTRulesetPatchRequest"]; + }; + }; + responses: { + /** @description Updated the MRT environment hostname or added MRT rules to route to an existing MRT environment. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MRTRulesResponseEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + deleteMrtRuleset: { + parameters: { + query?: never; + header?: never; + path: { + rulesetId: components["parameters"]["rulesetId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Deleted the MRT ruleset and all rules within the ruleset. */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + deleteMrtRule: { + parameters: { + query?: never; + header?: never; + path: { + ruleId: components["parameters"]["ruleId"]; + rulesetId: components["parameters"]["rulesetId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Deleted an MRT rule. */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateMrtRule: { + parameters: { + query?: never; + header?: never; + path: { + ruleId: components["parameters"]["ruleId"]; + rulesetId: components["parameters"]["rulesetId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["MRTRulePatchRequest"]; + }; + }; + responses: { + /** @description Successfully updated the MRT rule. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["MRTRulesResponseEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + createLogpushOwnership: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["LogpushOwnershipPostRequest"]; + }; + }; + responses: { + /** @description Created a new Logpush Ownership token. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["LogpushOwnershipPostResponse"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + listLogpushJob: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returned all jobs with details for the zone. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["LogpushJobsEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + createLogpushJob: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["LogpushCreateRequest"]; + }; + }; + responses: { + /** @description Successfully created the Logpush job and returned the job details. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["LogpushEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to therequested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getLogpushJob: { + parameters: { + query?: never; + header?: never; + path: { + jobId: components["parameters"]["jobId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Returned job details for the specified Logpush job ID. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["LogpushEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateLogpushJob: { + parameters: { + query?: never; + header?: never; + path: { + jobId: components["parameters"]["jobId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["LogpushUpdateRequest"]; + }; + }; + responses: { + /** @description Successfully enabled or disabled the Logpush job and returned job details. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["LogpushEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + deleteLogpushJob: { + parameters: { + query?: never; + header?: never; + path: { + jobId: components["parameters"]["jobId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Deleted the Logpush job for the specified job ID. */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getOwaspWafPackage: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully retrieved the OWASP ModSecurity Core Rule Set. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WAFRulePackageEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + patchOwaspWafPackage: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["WafPackagePatchRequest"]; + }; + }; + responses: { + /** @description Successfully patched the OWASP ModSecurity Core Rule Set. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WAFRulePackageEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getCustomRules: { + parameters: { + query?: { + /** @description Maximum records to retrieve per request, not to exceed 50. Defaults to 25. */ + limit?: number; + /** @description Used to retrieve the results based on a particular resource offset. */ + offset?: number; + }; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully returned the list of custom rules requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CustomRulesEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + createCustomRule: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CustomRulesPostRequest"]; + }; + }; + responses: { + /** @description Successfully created the custom rule requested by the caller. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CustomRuleEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateOrderOfCustomRules: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CustomRulesPatchOrderRequest"]; + }; + }; + responses: { + /** @description Successfully updated the order of existing custom rules as requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CustomRulesEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getCustomRule: { + parameters: { + query?: never; + header?: never; + path: { + ruleId: components["parameters"]["ruleId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully returned the custom rule requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CustomRuleEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + deleteCustomRule: { + parameters: { + query?: never; + header?: never; + path: { + ruleId: components["parameters"]["ruleId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully deleted the custom rule requested by the caller. */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateCustomRule: { + parameters: { + query?: never; + header?: never; + path: { + ruleId: components["parameters"]["ruleId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CustomRulesPatchRequest"]; + }; + }; + responses: { + /** @description Successfully updated the custom rule requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CustomRuleEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getRateLimitingRules: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully returned the list of rate limiting rules requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["RateLimitingRulesEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + createRateLimitingRule: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["RateLimitingRulesPostRequest"]; + }; + }; + responses: { + /** @description Successfully created the rate limiting rule requested by the caller. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["RateLimitingRuleEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getRateLimitingRule: { + parameters: { + query?: never; + header?: never; + path: { + ruleId: components["parameters"]["ruleId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully returned the rate limiting rule requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["RateLimitingRuleEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + deleteRateLimitingRule: { + parameters: { + query?: never; + header?: never; + path: { + ruleId: components["parameters"]["ruleId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully deleted the rate limiting rule requested by the caller. */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateRateLimitingRule: { + parameters: { + query?: never; + header?: never; + path: { + ruleId: components["parameters"]["ruleId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["RateLimitingRulesPatchRequest"]; + }; + }; + responses: { + /** @description Successfully updated the rate limiting rule requested by the caller. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["RateLimitingRuleEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getWafManagedRulesets: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully returned the list of WAFv2 managed rulesets. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WAFManagedRulesetsEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateWafManagedRuleset: { + parameters: { + query?: never; + header?: never; + path: { + rulesetId: components["parameters"]["rulesetId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["WAFManagedRulesetRequest"]; + }; + }; + responses: { + /** @description Successfully updated the WAFv2 managed rulesets. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WAFManagedRulesetEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getWafManagedRulesInRuleset: { + parameters: { + query?: never; + header?: never; + path: { + rulesetId: components["parameters"]["rulesetId"]; + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully returned the rules in the WAFv2 managed ruleset. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WAFManagedRulesEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateWafManagedRuleInRuleset: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + rulesetId: components["parameters"]["rulesetId"]; + ruleId: components["parameters"]["ruleId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["WAFManagedRuleRequest"]; + }; + }; + responses: { + /** @description Successfully updated the WAF managed rule in the specified WAFv2 managed ruleset. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WAFManagedRuleEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + migrateZoneToWafV2: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully migrated the zone to WAFv2 and returned the WAF managed rulesets. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WAFManagedRulesetsEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getOriginHeaderModification: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** @description The type of origin header modification. Only the `mrt` type is supported. */ + type: components["parameters"]["type"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully returned the origin header modification associated with a zone. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["OriginHeaderModificationEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + upsertOriginHeaderModification: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** @description The type of origin header modification. Only the `mrt` type is supported. */ + type: components["parameters"]["type"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["OriginHeaderModificationPutRequest"]; + }; + }; + responses: { + /** @description Successfully upserted the origin header modification. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["OriginHeaderModificationEnvelope"]; + }; + }; + /** @description Successfully created the origin header modification. */ + 201: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["OriginHeaderModificationEnvelope"]; + }; + }; + /** @description The request sent by the caller is not valid. */ + 400: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + deleteOriginHeaderModification: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** @description The type of origin header modification. Only the `mrt` type is supported. */ + type: components["parameters"]["type"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Successfully deleted the origin header modification associated with a zone. */ + 204: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + getCipherSuites: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody?: never; + responses: { + /** @description Retrieves current zone level cipher settings. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CipherSuitesEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; + updateCipherSuites: { + parameters: { + query?: never; + header?: never; + path: { + zoneId: components["parameters"]["zoneId"]; + /** + * @description An identifier for the organization the request is being made by + * @example f_ecom_zzxy_prd + */ + organizationId: components["parameters"]["organizationId"]; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["CipherSuitesRequest"]; + }; + }; + responses: { + /** @description Updates current zone level cipher settings. */ + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["CipherSuitesEnvelope"]; + }; + }; + /** @description The caller is not authorized to access the requested resource. */ + 401: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The caller does not have access to the requested resource. */ + 403: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description The resource requested by the caller was not found. */ + 404: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + /** @description An error occurred on the server side. */ + 500: { + headers: { + [name: string]: unknown; + }; + content: { + "application/problem+json": components["schemas"]["ApiStandardsErrorResponse"]; + }; + }; + }; + }; +} diff --git a/packages/b2c-tooling-sdk/src/clients/cdn-zones.ts b/packages/b2c-tooling-sdk/src/clients/cdn-zones.ts new file mode 100644 index 00000000..bc7712b5 --- /dev/null +++ b/packages/b2c-tooling-sdk/src/clients/cdn-zones.ts @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +/** + * CDN Zones API client for B2C Commerce. + * + * Provides a fully typed client for CDN Zones API operations using + * openapi-fetch with OAuth authentication middleware. Used for managing + * eCDN configurations including zones, certificates, WAF, rate limiting, + * cache purge, and other CDN settings. + * + * @module clients/cdn-zones + */ +import createClient, {type Client} from 'openapi-fetch'; +import type {AuthStrategy} from '../auth/types.js'; +import {OAuthStrategy} from '../auth/oauth.js'; +import type {paths, components} from './cdn-zones.generated.js'; +import {createAuthMiddleware, createLoggingMiddleware} from './middleware.js'; +import {globalMiddlewareRegistry, type MiddlewareRegistry} from './middleware-registry.js'; +import {toOrganizationId, toTenantId, buildTenantScope} from './custom-apis.js'; + +/** + * Re-export generated types for external use. + */ +export type {paths, components}; + +/** + * Re-export organization/tenant utilities for convenience. + */ +export {toOrganizationId, toTenantId, buildTenantScope}; + +/** + * The typed CDN Zones client - this is the openapi-fetch Client with full type safety. + * + * @see {@link createCdnZonesClient} for instantiation + */ +export type CdnZonesClient = Client; + +/** + * Helper type to extract response data from an operation. + */ +export type CdnZonesResponse = T extends {content: {'application/json': infer R}} ? R : never; + +/** + * Standard CDN Zones error response structure. + */ +export type CdnZonesError = components['schemas']['ApiStandardsErrorResponse']; + +/** + * Zone information from the zones/info endpoint. + */ +export type Zone = components['schemas']['Zone']; + +/** + * Zone list envelope. + */ +export type ZonesEnvelope = components['schemas']['ZonesEnvelope']; + +/** + * Certificate information. + */ +export type Certificate = components['schemas']['Certificate']; + +/** + * Security settings. + */ +export type SecuritySetting = components['schemas']['SecuritySetting']; + +/** + * Speed settings. + */ +export type SpeedSetting = components['schemas']['SpeedSetting']; + +/** Default OAuth scopes required for CDN Zones (read-only) */ +export const CDN_ZONES_READ_SCOPES = ['sfcc.cdn-zones']; + +/** OAuth scopes required for CDN Zones (read-write) */ +export const CDN_ZONES_RW_SCOPES = ['sfcc.cdn-zones.rw']; + +/** + * Configuration for creating a CDN Zones client. + */ +export interface CdnZonesClientConfig { + /** + * The short code for the SCAPI instance. + * This is typically a 4-8 character alphanumeric code. + * @example "kv7kzm78" + */ + shortCode: string; + + /** + * The tenant ID (with or without f_ecom_ prefix). + * Used to build the organizationId path parameter and tenant-specific OAuth scope. + * @example "zzxy_prd" or "f_ecom_zzxy_prd" + */ + tenantId: string; + + /** + * Optional scope override. If not provided, defaults to domain scope + * (sfcc.cdn-zones) plus tenant-specific scope (SALESFORCE_COMMERCE_API:{tenant}). + */ + scopes?: string[]; + + /** + * Middleware registry to use for this client. + * If not specified, uses the global middleware registry. + */ + middlewareRegistry?: MiddlewareRegistry; +} + +/** + * Options for creating a CDN Zones client. + */ +export interface CdnZonesClientOptions { + /** + * If true, request read-write scopes (sfcc.cdn-zones.rw). + * If false or not specified, request read-only scopes (sfcc.cdn-zones). + */ + readWrite?: boolean; +} + +/** + * Creates a typed CDN Zones API client. + * + * Returns the openapi-fetch client directly, with authentication + * handled via middleware. This gives full access to all openapi-fetch + * features with type-safe paths, parameters, and responses. + * + * The client automatically handles OAuth scope requirements: + * - Domain scope: `sfcc.cdn-zones` (read) or `sfcc.cdn-zones.rw` (read-write) + * - Tenant scope: `SALESFORCE_COMMERCE_API:{tenantId}` + * + * @param config - CDN Zones client configuration including shortCode and tenantId + * @param auth - Authentication strategy (typically OAuth) + * @param options - Optional settings like readWrite scope + * @returns Typed openapi-fetch client + * + * @example + * // Create CDN Zones client for read-only operations + * const oauthStrategy = new OAuthStrategy({ + * clientId: 'your-client-id', + * clientSecret: 'your-client-secret', + * }); + * + * const client = createCdnZonesClient( + * { shortCode: 'kv7kzm78', tenantId: 'zzxy_prd' }, + * oauthStrategy + * ); + * + * // List all zones + * const { data, error } = await client.GET('/organizations/{organizationId}/zones/info', { + * params: { + * path: { organizationId: toOrganizationId('zzxy_prd') } + * } + * }); + * + * @example + * // Create CDN Zones client for read-write operations (e.g., cache purge) + * const rwClient = createCdnZonesClient( + * { shortCode: 'kv7kzm78', tenantId: 'zzxy_prd' }, + * oauthStrategy, + * { readWrite: true } + * ); + * + * // Purge cache + * const { data } = await rwClient.POST('/organizations/{organizationId}/zones/{zoneId}/cachepurge', { + * params: { + * path: { organizationId: toOrganizationId('zzxy_prd'), zoneId: 'zone-id' } + * }, + * body: { path: ['/some/path'] } + * }); + */ +export function createCdnZonesClient( + config: CdnZonesClientConfig, + auth: AuthStrategy, + options?: CdnZonesClientOptions, +): CdnZonesClient { + const registry = config.middlewareRegistry ?? globalMiddlewareRegistry; + + const client = createClient({ + baseUrl: `https://${config.shortCode}.api.commercecloud.salesforce.com/cdn/zones/v1`, + }); + + // Build required scopes: domain scope + tenant-specific scope + const domainScopes = options?.readWrite ? CDN_ZONES_RW_SCOPES : CDN_ZONES_READ_SCOPES; + const requiredScopes = config.scopes ?? [...domainScopes, buildTenantScope(config.tenantId)]; + + // If OAuth strategy, add required scopes; otherwise use as-is + const scopedAuth = auth instanceof OAuthStrategy ? auth.withAdditionalScopes(requiredScopes) : auth; + + // Core middleware: auth first + client.use(createAuthMiddleware(scopedAuth)); + + // Plugin middleware from registry + for (const middleware of registry.getMiddleware('cdn-zones')) { + client.use(middleware); + } + + // Logging middleware last (sees complete request with all modifications) + client.use(createLoggingMiddleware('CDN-ZONES')); + + return client; +} diff --git a/packages/b2c-tooling-sdk/src/clients/index.ts b/packages/b2c-tooling-sdk/src/clients/index.ts index be069af3..9abca497 100644 --- a/packages/b2c-tooling-sdk/src/clients/index.ts +++ b/packages/b2c-tooling-sdk/src/clients/index.ts @@ -196,6 +196,22 @@ export type { components as ScapiSchemasComponents, } from './scapi-schemas.js'; +export {createCdnZonesClient, CDN_ZONES_READ_SCOPES, CDN_ZONES_RW_SCOPES} from './cdn-zones.js'; +export type { + CdnZonesClient, + CdnZonesClientConfig, + CdnZonesClientOptions, + CdnZonesError, + CdnZonesResponse, + Zone, + ZonesEnvelope, + Certificate, + SecuritySetting, + SpeedSetting, + paths as CdnZonesPaths, + components as CdnZonesComponents, +} from './cdn-zones.js'; + export {createMrtB2CClient, DEFAULT_MRT_B2C_ORIGIN} from './mrt-b2c.js'; export type { MrtB2CClient, diff --git a/packages/b2c-tooling-sdk/src/clients/middleware-registry.ts b/packages/b2c-tooling-sdk/src/clients/middleware-registry.ts index 8b979454..9d22231b 100644 --- a/packages/b2c-tooling-sdk/src/clients/middleware-registry.ts +++ b/packages/b2c-tooling-sdk/src/clients/middleware-registry.ts @@ -44,7 +44,16 @@ import type {Middleware} from 'openapi-fetch'; /** * Types of HTTP clients that can receive middleware. */ -export type HttpClientType = 'ocapi' | 'slas' | 'ods' | 'mrt' | 'mrt-b2c' | 'custom-apis' | 'scapi-schemas' | 'webdav'; +export type HttpClientType = + | 'ocapi' + | 'slas' + | 'ods' + | 'mrt' + | 'mrt-b2c' + | 'custom-apis' + | 'scapi-schemas' + | 'cdn-zones' + | 'webdav'; /** * Middleware interface compatible with openapi-fetch. diff --git a/packages/b2c-tooling-sdk/src/index.ts b/packages/b2c-tooling-sdk/src/index.ts index 4970ef19..4db29443 100644 --- a/packages/b2c-tooling-sdk/src/index.ts +++ b/packages/b2c-tooling-sdk/src/index.ts @@ -71,6 +71,7 @@ export { createSlasClient, createOdsClient, createCustomApisClient, + createCdnZonesClient, toOrganizationId, toTenantId, buildTenantScope, @@ -78,6 +79,8 @@ export { ORGANIZATION_ID_PREFIX, SCAPI_TENANT_SCOPE_PREFIX, CUSTOM_APIS_DEFAULT_SCOPES, + CDN_ZONES_READ_SCOPES, + CDN_ZONES_RW_SCOPES, } from './clients/index.js'; export type { PropfindEntry, @@ -105,6 +108,15 @@ export type { CustomApisResponse, CustomApisPaths, CustomApisComponents, + CdnZonesClient, + CdnZonesClientConfig, + CdnZonesClientOptions, + CdnZonesError, + CdnZonesResponse, + Zone, + ZonesEnvelope, + CdnZonesPaths, + CdnZonesComponents, } from './clients/index.js'; // Context Layer - Platform diff --git a/packages/b2c-tooling-sdk/test/clients/cdn-zones.test.ts b/packages/b2c-tooling-sdk/test/clients/cdn-zones.test.ts new file mode 100644 index 00000000..220f9fc2 --- /dev/null +++ b/packages/b2c-tooling-sdk/test/clients/cdn-zones.test.ts @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2025, Salesforce, Inc. + * SPDX-License-Identifier: Apache-2 + * For full license text, see the license.txt file in the repo root or http://www.apache.org/licenses/LICENSE-2.0 + */ +import {expect} from 'chai'; +import {http, HttpResponse} from 'msw'; +import {setupServer} from 'msw/node'; +import { + createCdnZonesClient, + CDN_ZONES_READ_SCOPES, + CDN_ZONES_RW_SCOPES, + toOrganizationId, +} from '@salesforce/b2c-tooling-sdk/clients'; +import {MockAuthStrategy} from '../helpers/mock-auth.js'; + +const SHORT_CODE = 'kv7kzm78'; +const TENANT_ID = 'zzxy_prd'; +const ORG_ID = toOrganizationId(TENANT_ID); +const BASE_URL = `https://${SHORT_CODE}.api.commercecloud.salesforce.com/cdn/zones/v1`; + +describe('clients/cdn-zones', () => { + describe('createCdnZonesClient', () => { + const server = setupServer(); + + before(() => { + server.listen({onUnhandledRequest: 'error'}); + }); + + afterEach(() => { + server.resetHandlers(); + }); + + after(() => { + server.close(); + }); + + it('creates a client with the correct base URL and applies auth middleware', async () => { + server.use( + http.get(`${BASE_URL}/organizations/:organizationId/zones/info`, ({request}) => { + expect(request.headers.get('Authorization')).to.equal('Bearer test-token'); + return HttpResponse.json({ + data: [], + }); + }), + ); + + const auth = new MockAuthStrategy(); + const client = createCdnZonesClient({shortCode: SHORT_CODE, tenantId: TENANT_ID}, auth); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/info', { + params: {path: {organizationId: ORG_ID}}, + }); + + expect(error).to.be.undefined; + expect(data?.data).to.deep.equal([]); + }); + + it('lists zones with zone data', async () => { + server.use( + http.get(`${BASE_URL}/organizations/:organizationId/zones/info`, () => { + return HttpResponse.json({ + data: [ + { + zoneId: 'zone-abc123', + name: 'my-storefront', + status: 'active', + }, + { + zoneId: 'zone-def456', + name: 'another-zone', + status: 'pending', + }, + ], + }); + }), + ); + + const auth = new MockAuthStrategy(); + const client = createCdnZonesClient({shortCode: SHORT_CODE, tenantId: TENANT_ID}, auth); + + const {data} = await client.GET('/organizations/{organizationId}/zones/info', { + params: {path: {organizationId: ORG_ID}}, + }); + + expect(data?.data).to.have.length(2); + expect(data?.data?.[0]?.name).to.equal('my-storefront'); + expect(data?.data?.[0]?.status).to.equal('active'); + expect(data?.data?.[1]?.zoneId).to.equal('zone-def456'); + }); + + it('fetches security settings for a zone', async () => { + const zoneId = 'zone-abc123'; + + server.use( + http.get(`${BASE_URL}/organizations/:organizationId/zones/:zoneId/security-settings`, ({params}) => { + expect(params.organizationId).to.equal(ORG_ID); + expect(params.zoneId).to.equal(zoneId); + + return HttpResponse.json({ + data: { + securityLevel: 'medium', + alwaysUseHttps: true, + tls13Enabled: true, + wafEnabled: false, + hsts: { + enabled: true, + includeSubdomains: true, + maxAge: 31536000, + preload: false, + }, + }, + }); + }), + ); + + const auth = new MockAuthStrategy(); + const client = createCdnZonesClient({shortCode: SHORT_CODE, tenantId: TENANT_ID}, auth); + + const {data} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/security-settings', { + params: { + path: {organizationId: ORG_ID, zoneId}, + }, + }); + + expect(data?.data?.securityLevel).to.equal('medium'); + expect(data?.data?.alwaysUseHttps).to.be.true; + expect(data?.data?.tls13Enabled).to.be.true; + }); + + it('performs cache purge with POST request', async () => { + const zoneId = 'zone-abc123'; + let capturedBody: unknown; + + server.use( + http.post(`${BASE_URL}/organizations/:organizationId/zones/:zoneId/cachepurge`, async ({request}) => { + capturedBody = await request.json(); + return HttpResponse.json({ + data: { + cachePurged: true, + details: 'Purge completed successfully', + }, + }); + }), + ); + + const auth = new MockAuthStrategy(); + const client = createCdnZonesClient({shortCode: SHORT_CODE, tenantId: TENANT_ID}, auth, {readWrite: true}); + + const {data} = await client.POST('/organizations/{organizationId}/zones/{zoneId}/cachepurge', { + params: { + path: {organizationId: ORG_ID, zoneId}, + }, + body: { + path: 'www.example.com/dw/shop/v21_9/products', + }, + }); + + expect(data?.data?.cachePurged).to.be.true; + expect(capturedBody).to.deep.include({ + path: 'www.example.com/dw/shop/v21_9/products', + }); + }); + + it('updates security settings with PATCH request', async () => { + const zoneId = 'zone-abc123'; + let capturedBody: unknown; + + server.use( + http.patch(`${BASE_URL}/organizations/:organizationId/zones/:zoneId/security-settings`, async ({request}) => { + capturedBody = await request.json(); + return HttpResponse.json({ + data: { + securityLevel: 'high', + alwaysUseHttps: true, + tls13Enabled: true, + wafEnabled: true, + }, + }); + }), + ); + + const auth = new MockAuthStrategy(); + const client = createCdnZonesClient({shortCode: SHORT_CODE, tenantId: TENANT_ID}, auth, {readWrite: true}); + + const {data} = await client.PATCH('/organizations/{organizationId}/zones/{zoneId}/security-settings', { + params: { + path: {organizationId: ORG_ID, zoneId}, + }, + body: { + securityLevel: 'high', + alwaysUseHttps: true, + }, + }); + + expect(data?.data?.securityLevel).to.equal('high'); + expect(capturedBody).to.deep.include({securityLevel: 'high'}); + }); + + it('deletes a certificate with DELETE request', async () => { + const zoneId = 'zone-abc123'; + const certificateId = 'cert-xyz789'; + + server.use( + http.delete( + `${BASE_URL}/organizations/:organizationId/zones/:zoneId/certificates/:certificateId`, + ({params}) => { + expect(params.certificateId).to.equal(certificateId); + return new HttpResponse(null, {status: 204}); + }, + ), + ); + + const auth = new MockAuthStrategy(); + const client = createCdnZonesClient({shortCode: SHORT_CODE, tenantId: TENANT_ID}, auth, {readWrite: true}); + + const {error, response} = await client.DELETE( + '/organizations/{organizationId}/zones/{zoneId}/certificates/{certificateId}', + { + params: { + path: {organizationId: ORG_ID, zoneId, certificateId}, + }, + }, + ); + + expect(error).to.be.undefined; + expect(response.status).to.equal(204); + }); + + it('handles 404 errors', async () => { + server.use( + http.get(`${BASE_URL}/organizations/:organizationId/zones/:zoneId/security-settings`, () => { + return HttpResponse.json( + { + title: 'Not Found', + type: 'https://api.commercecloud.salesforce.com/documentation/error/v1/errors/not-found', + detail: 'Zone not found', + }, + {status: 404}, + ); + }), + ); + + const auth = new MockAuthStrategy(); + const client = createCdnZonesClient({shortCode: SHORT_CODE, tenantId: TENANT_ID}, auth); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/{zoneId}/security-settings', { + params: { + path: {organizationId: ORG_ID, zoneId: 'nonexistent-zone'}, + }, + }); + + expect(data).to.be.undefined; + expect(error).to.have.property('title', 'Not Found'); + expect(error).to.have.property('detail', 'Zone not found'); + }); + + it('handles 500 server errors', async () => { + server.use( + http.get(`${BASE_URL}/organizations/:organizationId/zones/info`, () => { + return HttpResponse.json( + { + title: 'Internal Server Error', + type: 'https://api.commercecloud.salesforce.com/documentation/error/v1/errors/internal-error', + detail: 'An unexpected error occurred', + }, + {status: 500}, + ); + }), + ); + + const auth = new MockAuthStrategy(); + const client = createCdnZonesClient({shortCode: SHORT_CODE, tenantId: TENANT_ID}, auth); + + const {data, error} = await client.GET('/organizations/{organizationId}/zones/info', { + params: {path: {organizationId: ORG_ID}}, + }); + + expect(data).to.be.undefined; + expect(error).to.have.property('title', 'Internal Server Error'); + }); + }); + + describe('CDN_ZONES_READ_SCOPES', () => { + it('includes the correct read scope', () => { + expect(CDN_ZONES_READ_SCOPES).to.deep.equal(['sfcc.cdn-zones']); + }); + }); + + describe('CDN_ZONES_RW_SCOPES', () => { + it('includes the correct read-write scope', () => { + expect(CDN_ZONES_RW_SCOPES).to.deep.equal(['sfcc.cdn-zones.rw']); + }); + }); + + describe('toOrganizationId', () => { + it('converts tenant ID to organization ID with prefix', () => { + expect(toOrganizationId('zzxy_prd')).to.equal('f_ecom_zzxy_prd'); + }); + + it('returns already-prefixed IDs unchanged', () => { + expect(toOrganizationId('f_ecom_zzxy_prd')).to.equal('f_ecom_zzxy_prd'); + }); + }); +}); diff --git a/plugins/b2c-cli/skills/b2c-ecdn/SKILL.md b/plugins/b2c-cli/skills/b2c-ecdn/SKILL.md new file mode 100644 index 00000000..c2f9e0b3 --- /dev/null +++ b/plugins/b2c-cli/skills/b2c-ecdn/SKILL.md @@ -0,0 +1,249 @@ +--- +name: b2c-ecdn +description: Using the b2c CLI for eCDN (embedded Content Delivery Network) management +--- + +# B2C eCDN Skill + +Use the `b2c` CLI plugin to manage eCDN (embedded Content Delivery Network) zones, certificates, security settings, and more. + +## Prerequisites + +- OAuth credentials with `sfcc.cdn-zones` scope (read operations) +- OAuth credentials with `sfcc.cdn-zones.rw` scope (write operations) +- Tenant ID for your B2C Commerce organization + +## Examples + +### List CDN Zones + +```bash +# list all CDN zones for a tenant +b2c ecdn zones list --tenant-id zzxy_prd + +# list with JSON output +b2c ecdn zones list --tenant-id zzxy_prd --json +``` + +### Create a Storefront Zone + +```bash +# create a new storefront zone +b2c ecdn zones create --tenant-id zzxy_prd --storefront-hostname www.example.com --origin-hostname origin.example.com +``` + +### Purge Cache + +```bash +# purge cache for specific paths +b2c ecdn cache purge --tenant-id zzxy_prd --zone my-zone --path /products --path /categories + +# purge by cache tags +b2c ecdn cache purge --tenant-id zzxy_prd --zone my-zone --tag product-123 --tag category-456 + +# purge everything +b2c ecdn cache purge --tenant-id zzxy_prd --zone my-zone --purge-everything +``` + +### Manage Certificates + +```bash +# list certificates for a zone +b2c ecdn certificates list --tenant-id zzxy_prd --zone my-zone + +# add a new certificate +b2c ecdn certificates add --tenant-id zzxy_prd --zone my-zone --hostname www.example.com --certificate-file ./cert.pem --private-key-file ./key.pem + +# get certificate details +b2c ecdn certificates get --tenant-id zzxy_prd --zone my-zone --certificate-id abc123 + +# validate a custom hostname +b2c ecdn certificates validate --tenant-id zzxy_prd --zone my-zone --certificate-id abc123 +``` + +### Security Settings + +```bash +# get security settings +b2c ecdn security get --tenant-id zzxy_prd --zone my-zone + +# update security settings +b2c ecdn security update --tenant-id zzxy_prd --zone my-zone --ssl-mode full --min-tls-version 1.2 --always-use-https +``` + +### Speed Settings + +```bash +# get speed optimization settings +b2c ecdn speed get --tenant-id zzxy_prd --zone my-zone + +# update speed settings +b2c ecdn speed update --tenant-id zzxy_prd --zone my-zone --browser-cache-ttl 14400 --auto-minify-html --auto-minify-css +``` + +### WAF (Web Application Firewall) + +```bash +# list WAF v1 groups +b2c ecdn waf groups list --tenant-id zzxy_prd --zone my-zone + +# update WAF v1 group mode +b2c ecdn waf groups update --tenant-id zzxy_prd --zone my-zone --group-id abc123 --mode on + +# list WAF v1 rules in a group +b2c ecdn waf rules list --tenant-id zzxy_prd --zone my-zone --group-id abc123 + +# list WAF v2 rulesets +b2c ecdn waf rulesets list --tenant-id zzxy_prd --zone my-zone + +# update WAF v2 ruleset +b2c ecdn waf rulesets update --tenant-id zzxy_prd --zone my-zone --ruleset-id abc123 --action block + +# migrate zone to WAF v2 +b2c ecdn waf migrate --tenant-id zzxy_prd --zone my-zone +``` + +### Firewall Rules + +```bash +# list custom firewall rules +b2c ecdn firewall list --tenant-id zzxy_prd --zone my-zone + +# create a firewall rule +b2c ecdn firewall create --tenant-id zzxy_prd --zone my-zone --description "Block bad bots" --action block --filter '(cf.client.bot)' + +# update a firewall rule +b2c ecdn firewall update --tenant-id zzxy_prd --zone my-zone --rule-id abc123 --action challenge + +# reorder firewall rules +b2c ecdn firewall reorder --tenant-id zzxy_prd --zone my-zone --rule-ids id1,id2,id3 +``` + +### Rate Limiting + +```bash +# list rate limiting rules +b2c ecdn rate-limit list --tenant-id zzxy_prd --zone my-zone + +# create a rate limiting rule +b2c ecdn rate-limit create --tenant-id zzxy_prd --zone my-zone --description "API rate limit" --threshold 100 --period 60 --action block --match-url '/api/*' + +# delete a rate limiting rule +b2c ecdn rate-limit delete --tenant-id zzxy_prd --zone my-zone --rule-id abc123 +``` + +### Logpush + +```bash +# create ownership challenge for S3 destination +b2c ecdn logpush ownership --tenant-id zzxy_prd --zone my-zone --destination-path 's3://my-bucket/logs?region=us-east-1' + +# list logpush jobs +b2c ecdn logpush jobs list --tenant-id zzxy_prd --zone my-zone + +# create a logpush job +b2c ecdn logpush jobs create --tenant-id zzxy_prd --zone my-zone --name "HTTP logs" --destination-path 's3://my-bucket/logs?region=us-east-1' --log-type http_requests + +# update a logpush job (enable/disable) +b2c ecdn logpush jobs update --tenant-id zzxy_prd --zone my-zone --job-id 123456 --enabled + +# delete a logpush job +b2c ecdn logpush jobs delete --tenant-id zzxy_prd --zone my-zone --job-id 123456 +``` + +### Page Shield + +```bash +# list Page Shield notification webhooks (organization level) +b2c ecdn page-shield notifications list --tenant-id zzxy_prd + +# create a notification webhook +b2c ecdn page-shield notifications create --tenant-id zzxy_prd --url https://example.com/webhook --secret my-secret --zones zone1,zone2 + +# list Page Shield policies (zone level) +b2c ecdn page-shield policies list --tenant-id zzxy_prd --zone my-zone + +# create a CSP policy +b2c ecdn page-shield policies create --tenant-id zzxy_prd --zone my-zone --action allow --value script-src + +# list detected scripts +b2c ecdn page-shield scripts list --tenant-id zzxy_prd --zone my-zone +``` + +### MRT Rules + +```bash +# get MRT ruleset for a zone +b2c ecdn mrt-rules get --tenant-id zzxy_prd --zone my-zone + +# create MRT rules to route to a Managed Runtime environment +b2c ecdn mrt-rules create --tenant-id zzxy_prd --zone my-zone --mrt-hostname customer-pwa.mobify-storefront.com --expressions '(http.host eq "example.com")' + +# update MRT ruleset hostname +b2c ecdn mrt-rules update --tenant-id zzxy_prd --zone my-zone --mrt-hostname new-customer-pwa.mobify-storefront.com + +# delete MRT ruleset +b2c ecdn mrt-rules delete --tenant-id zzxy_prd --zone my-zone +``` + +### mTLS Certificates + +```bash +# list mTLS certificates (organization level) +b2c ecdn mtls list --tenant-id zzxy_prd + +# create mTLS certificate for code upload authentication +b2c ecdn mtls create --tenant-id zzxy_prd --name "Build Server" --ca-certificate-file ./ca.pem --leaf-certificate-file ./leaf.pem + +# get mTLS certificate details +b2c ecdn mtls get --tenant-id zzxy_prd --certificate-id abc123 + +# delete mTLS certificate +b2c ecdn mtls delete --tenant-id zzxy_prd --certificate-id abc123 +``` + +### Cipher Suites + +```bash +# get cipher suites configuration +b2c ecdn cipher-suites get --tenant-id zzxy_prd --zone my-zone + +# update to Modern cipher suite +b2c ecdn cipher-suites update --tenant-id zzxy_prd --zone my-zone --suite-type Modern + +# update to Custom cipher suite with specific ciphers +b2c ecdn cipher-suites update --tenant-id zzxy_prd --zone my-zone --suite-type Custom --ciphers "ECDHE-ECDSA-AES128-GCM-SHA256,ECDHE-RSA-AES128-GCM-SHA256" +``` + +### Origin Headers + +```bash +# get origin header modification +b2c ecdn origin-headers get --tenant-id zzxy_prd --zone my-zone + +# set origin header modification (for MRT) +b2c ecdn origin-headers set --tenant-id zzxy_prd --zone my-zone --header-value my-secret-value + +# delete origin header modification +b2c ecdn origin-headers delete --tenant-id zzxy_prd --zone my-zone +``` + +## Configuration + +The tenant ID can be set via environment variable: +- `SFCC_TENANT_ID`: B2C Commerce tenant ID + +The `--zone` flag accepts either: +- Zone ID (32-character hex string) +- Zone name (human-readable, case-insensitive lookup) + +### OAuth Scopes + +| Operation | Required Scope | +|-----------|---------------| +| Read operations | `sfcc.cdn-zones` | +| Write operations | `sfcc.cdn-zones.rw` | + +### More Commands + +See `b2c ecdn --help` for a full list of available commands and options in the `ecdn` topic.