@zackbart/connecta 0.30.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +6 -3
  3. package/bin/version.mjs +1 -1
  4. package/dist/call-recovery.js +25 -0
  5. package/dist/config-schema.d.ts +14 -7
  6. package/dist/config-schema.js +29 -10
  7. package/dist/connectors/guarded-fetch.d.ts +9 -1
  8. package/dist/connectors/guarded-fetch.js +14 -2
  9. package/dist/errors.d.ts +2 -0
  10. package/dist/invocation.js +32 -0
  11. package/dist/operator-ui/generated.js +2 -2
  12. package/dist/operator-ui/view.d.ts +9 -0
  13. package/dist/operator-ui/view.js +11 -0
  14. package/dist/program-writes.js +2 -47
  15. package/dist/provider.d.ts +7 -5
  16. package/dist/provider.js +3 -4
  17. package/dist/providers/_shared/rest/dispatch.js +41 -0
  18. package/dist/providers/_shared/rest/operation-index.d.ts +133 -0
  19. package/dist/providers/_shared/rest/operation-index.js +527 -0
  20. package/dist/providers/_shared/rest/tools.d.ts +141 -0
  21. package/dist/providers/_shared/rest/tools.js +569 -0
  22. package/dist/providers/_shared/rest/value-safety.d.ts +151 -0
  23. package/dist/providers/_shared/rest/value-safety.js +580 -0
  24. package/dist/providers/cloudflare/graphql.js +385 -0
  25. package/dist/providers/cloudflare/index.d.ts +47 -51
  26. package/dist/providers/cloudflare/index.js +188 -1997
  27. package/dist/providers/cloudflare/openapi.generated.js +3347 -0
  28. package/dist/providers/cloudflare/rest.d.ts +37 -0
  29. package/dist/providers/cloudflare/rest.js +1056 -0
  30. package/dist/providers/cloudflare/skill.generated.js +7 -4
  31. package/dist/providers/cloudflare/value-safety.js +1247 -0
  32. package/dist/providers/notion/index.d.ts +35 -31
  33. package/dist/providers/notion/index.js +60 -1499
  34. package/dist/providers/notion/openapi.generated.js +75 -0
  35. package/dist/providers/notion/rest.d.ts +24 -0
  36. package/dist/providers/notion/rest.js +1067 -0
  37. package/dist/providers/notion/skill.generated.js +5 -4
  38. package/dist/providers/notion/value-safety.js +31 -0
  39. package/dist/providers/stripe/index.d.ts +26 -20
  40. package/dist/providers/stripe/index.js +103 -130
  41. package/dist/providers/stripe/openapi.generated.js +649 -0
  42. package/dist/providers/stripe/rest.d.ts +14 -0
  43. package/dist/providers/stripe/rest.js +395 -0
  44. package/dist/providers/stripe/skill.generated.js +7 -5
  45. package/dist/providers/stripe/value-safety.js +705 -0
  46. package/dist/providers/vercel/index.d.ts +31 -22
  47. package/dist/providers/vercel/index.js +96 -853
  48. package/dist/providers/vercel/openapi.generated.js +456 -0
  49. package/dist/providers/vercel/rest.d.ts +20 -0
  50. package/dist/providers/vercel/rest.js +1002 -0
  51. package/dist/providers/vercel/skill.generated.js +4 -5
  52. package/dist/providers/vercel/value-safety.js +328 -0
  53. package/dist/version.d.ts +1 -1
  54. package/dist/version.js +1 -1
  55. package/dist/write-outcome.js +47 -0
  56. package/documentation/README.md +1 -0
  57. package/documentation/architecture.md +120 -8
  58. package/documentation/integrating.md +16 -5
  59. package/documentation/meta-tools.md +9 -2
  60. package/documentation/provider-auth-migration.md +307 -0
  61. package/documentation/provider-migration-0.29.md +17 -5
  62. package/examples/worker/README.md +2 -2
  63. package/package.json +3 -2
  64. package/templates/node/README.md +2 -2
  65. package/templates/node/package.json +1 -1
  66. package/dist/providers/vercel/mcp-ownership.js +0 -212
@@ -0,0 +1,1247 @@
1
+ // Cloudflare's reviewed value-safety table (#801), on the shared mechanism in
2
+ // `../_shared/rest/value-safety.ts`: every operation the detector flags in
3
+ // the pinned spec (`value-safety.candidates.json`) has one verdict here, and
4
+ // `value-safety.node.test.ts` runs the shared harness over it.
5
+ //
6
+ // - `refuse`: the operation exists to mint, rotate, or hand back a credential
7
+ // (or move money through a payment secret); nothing is sent.
8
+ // - `redact`: the operation is useful, and these field paths carry a
9
+ // credential or stored secret; they are replaced before the result is
10
+ // returned, on every method. A path ending in `#url` keeps only the URL's
11
+ // scheme and host.
12
+ // - `safe`: no credential value comes back; `keep` names credential-named
13
+ // fields reviewed as metadata, which the key-name heuristic leaves alone.
14
+ //
15
+ // Paths are dot paths into the data a tool returns (Cloudflare's `result`,
16
+ // or the whole body when it is not an envelope); lists are traversed
17
+ // implicitly and `*` matches every key of an object.
18
+ import { redact as reviewed, refuse, safe as reviewedSafe, } from "../_shared/rest/value-safety.js";
19
+ const MINT = "Connecta does not create, rotate, or return credentials; an operator manages this credential in the Cloudflare dashboard.";
20
+ const API_TOKENS = "Connecta does not create, roll, edit, or delete API tokens; an operator manages tokens in the Cloudflare dashboard.";
21
+ const PAYMENT = "This starts a payment and returns its client secret; billing changes belong in the Cloudflare dashboard.";
22
+ const BEARER = "This returns a URL or upload token that grants access without Cloudflare authentication; Connecta does not hand those out. Upload through cloudflare_api_upload.";
23
+ const ACTS = "This GET acts rather than reads (it completes a connection or an unsubscribe), so it is not a read.";
24
+ const INTERNAL = "An internal Cloudflare test route; it is not part of the supported API.";
25
+ const CAPTURE = "A URL scan's captured session (cookies, request and response headers, response bodies, DOM) can carry credentials, so Connecta does not return it. Read scan verdicts with GET /accounts/{account_id}/urlscanner/v2/search.";
26
+ const METADATA = "Returns names, ids, status, and timestamps; no credential value.";
27
+ const REVOKES = "Revokes or deletes; returns no credential value.";
28
+ const CALLER_SUPPLIED = "The caller supplies the secret; the response returns only its name and metadata.";
29
+ /** The reason a bare `redact(...)` verdict states: the reviewed paths are the finding. */
30
+ const CARRIES = "These fields carry a credential or a stored secret value; they are redacted, the rest returned.";
31
+ const redact = (...paths) => reviewed(CARRIES, paths);
32
+ const safe = (reason, ...keep) => reviewedSafe(reason, keep);
33
+ const ACCESS_APP = reviewed("Access applications carry SaaS and SCIM client secrets, passwords, and bearer tokens.", [
34
+ "saas_app.client_secret",
35
+ "scim_config.authentication.client_secret",
36
+ "scim_config.authentication.password",
37
+ "scim_config.authentication.token",
38
+ ], [
39
+ "cors_headers.allowed_headers",
40
+ "read_service_tokens_from_header",
41
+ "saas_app.custom_claims",
42
+ ...["exclude", "include", "require"].flatMap((rule) => ["any_valid_service_token", "linked_app_token", "service_token"].map((name) => `policies.${rule}.${name}`)),
43
+ ]);
44
+ const ACCESS_RULES = safe("Access rules name service tokens by id; no token value.", "exclude.any_valid_service_token", "exclude.linked_app_token", "exclude.service_token", "include.any_valid_service_token", "include.linked_app_token", "include.service_token", "require.any_valid_service_token", "require.linked_app_token", "require.service_token", "is_default.any_valid_service_token", "is_default.linked_app_token", "is_default.service_token");
45
+ const IDENTITY_PROVIDER = reviewed("Identity providers carry OAuth client secrets and SCIM secrets.", ["config.client_secret", "scim_config.secret"], ["config.prompt", "config.attributes", "config.claims"]);
46
+ /**
47
+ * Environment variable values are redacted wherever they appear, names and
48
+ * types kept. Cloudflare returns plain-text variables in the clear, and
49
+ * operators routinely put API keys in them (a Stripe key in a Pages
50
+ * variable); the value stays readable in the dashboard.
51
+ */
52
+ const PAGES_PROJECT = reviewed("Pages projects and deployments embed environment variable values.", [
53
+ "env_vars.*.value",
54
+ "canonical_deployment.env_vars.*.value",
55
+ "latest_deployment.env_vars.*.value",
56
+ "deployment_configs.preview.env_vars.*.value",
57
+ "deployment_configs.production.env_vars.*.value",
58
+ ], [
59
+ "build_config.web_analytics_token",
60
+ "canonical_deployment.build_config.web_analytics_token",
61
+ "latest_deployment.build_config.web_analytics_token",
62
+ "deployment_configs.preview.ai_bindings",
63
+ "deployment_configs.preview.hyperdrive_bindings",
64
+ "deployment_configs.preview.vectorize_bindings",
65
+ "deployment_configs.production.ai_bindings",
66
+ "deployment_configs.production.hyperdrive_bindings",
67
+ "deployment_configs.production.vectorize_bindings",
68
+ ]);
69
+ const LIVE_INPUT = reviewed("Live inputs carry RTMPS stream keys, SRT passphrases, and a WebRTC URL that is itself the credential.", ["rtmps.streamKey", "rtmpsPlayback.streamKey", "srt.passphrase", "srtPlayback.passphrase", "webRTC.url#url"], ["rtmps.url", "rtmpsPlayback.url", "srt.url", "srtPlayback.url", "webRTCPlayback.url"]);
70
+ const WORKER_SECRET = redact("text", "key_base64", "key_jwk", "*.text", "*.key_base64", "*.key_jwk");
71
+ /**
72
+ * Worker bindings: plain-text and JSON binding values are redacted (the same
73
+ * judgment as environment variables: they are often credentials in
74
+ * practice); names, types, and resource ids are kept.
75
+ */
76
+ const WORKER_BINDINGS = redact("bindings.text", "bindings.json");
77
+ const WORKER_VERSION = redact("assets.jwt", "bindings.text", "bindings.json", "env.*.text", "env.*.json");
78
+ const ZARAZ = redact("variables.*.value", "debugKey", "*.variables.*.value", "*.debugKey", "*.config.variables.*.value", "*.config.debugKey");
79
+ const TSIG = redact("secret");
80
+ /**
81
+ * Rulesets: a transform rule's static header value is sent to the origin or
82
+ * the visitor and can be a credential (`Authorization: Bearer …`); its name,
83
+ * operation, and expression stay. Cache-key cookie and header lists, logged
84
+ * cookie fields, and exposed-credential expressions name fields, not values.
85
+ */
86
+ const RULESET = reviewed("Transform rules set header values, which can be credentials sent to an origin; the rest is rule configuration.", ["rules.action_parameters.headers.*.value"], [
87
+ "rules.exposed_credential_check",
88
+ "rules.action_parameters.cache_key.custom_key.cookie",
89
+ "rules.action_parameters.cache_key.custom_key.header",
90
+ "rules.action_parameters.cookie_fields",
91
+ "rules.action_parameters.vary.headers",
92
+ ]);
93
+ /** A webhook destination URL can carry a bearer secret in its path (a Slack or Discord hook); only its origin comes back. */
94
+ const WEBHOOK_DESTINATION = reviewed("Notification webhook destinations: a URL path can be the bearer secret (a Slack or Discord hook), and the signing secret is write-only.", ["secret", "origin:url"]);
95
+ const KIT_WEBHOOK = reviewed("RealtimeKit webhook destinations: a URL path can be the bearer secret, so only the origin comes back.", ["origin:data.url"]);
96
+ const POSTURE_WEBHOOK = reviewed("Data security webhooks: header values and a destination URL whose path can be a bearer secret.", ["headers", "origin:destination_url"]);
97
+ const HYPERDRIVE = reviewed("Hyperdrive origins carry the database password and an Access client secret (write-only; redacted if ever returned).", ["origin.password", "origin.access_client_secret"]);
98
+ /** RealtimeKit recording storage: third-party storage credentials (write-only; redacted if ever returned). */
99
+ const KIT_STORAGE_REASON = "Recording storage configurations carry third-party storage access keys, secrets, SFTP passwords, and private keys.";
100
+ const storageCredentials = (...prefixes) => prefixes.flatMap((prefix) => ["access_key", "secret", "password", "private_key"].map((name) => `${prefix}.${name}`));
101
+ const KIT_MEETING_STORAGE = reviewed(KIT_STORAGE_REASON, storageCredentials("data.recording_config.storage_config"));
102
+ const KIT_RECORDING_STORAGE = reviewed(KIT_STORAGE_REASON, storageCredentials("data.storage_config"));
103
+ const BINDING_VALUES = reviewed("Worker bindings: plain-text, JSON, and key-material values are often credentials; names, types, and resource ids stay.", ["text", "json", "key_base64", "key_jwk"]);
104
+ const WORKER = reviewed("Workers carry the bindings new previews get, keyed by name; plain-text and JSON values are often credentials.", ["previews_base_config.env.*.text", "previews_base_config.env.*.json"]);
105
+ const MOQ_TOKENS = reviewed("MoQ relay token issuers carry signing secrets; token ids and allowed operations are metadata.", ["issuers.cloudflare_tokens.secret"], ["issuers.cloudflare_tokens.jti", "issuers.cloudflare_tokens.operations"]);
106
+ const KV_DATA = "Workers KV is application data storage, not a secret store (Workers Secrets and the Secrets Store hold secrets, and their values are write-only); returning what the caller stored is the operation's purpose.";
107
+ const DLP_FLAG = "`secret` is a boolean marking a DLP dataset or entry as sensitive, not a secret.";
108
+ const CERTIFICATE = "Certificates and their metadata; `signature` names the signature algorithm and is withheld by the field review.";
109
+ const OBSERVABILITY = "Saved query filters and telemetry values from the caller's own Workers; no Cloudflare credential (a secret an application logged is out of scope).";
110
+ const COUNTS = "Request token counts, quotas, and costs; no credential.";
111
+ const CURSOR = "A pagination cursor.";
112
+ const ANSWERS_ID = "Answers the destination's id; no secret.";
113
+ const TRACE = "Worker settings; trace propagation names a policy, not a token.";
114
+ const TRACE_POLICY = (paths = []) => safe(TRACE, ...paths);
115
+ const LIVESTREAM = redact("data.stream_key", "data.livestream.stream_key", "data.livestreams.stream_key");
116
+ /** Container environment values redacted, names kept; authorized keys are public SSH keys. */
117
+ const CONTAINER_APP = reviewed("Container applications embed environment variable values.", [
118
+ "configuration.environment_variables.value",
119
+ "current_configuration.environment_variables.value",
120
+ "target_configuration.environment_variables.value",
121
+ ], [
122
+ "next_page_token",
123
+ "page_token",
124
+ "configuration.authorized_keys",
125
+ "current_configuration.authorized_keys",
126
+ "target_configuration.authorized_keys",
127
+ ]);
128
+ /** Workers Builds environment values redacted, names kept. */
129
+ const BUILD_ENV = redact("*.value", "build_trigger_metadata.environment_variables.*.value", "builds.*.build_trigger_metadata.environment_variables.*.value", "previews_base_config.environment_variables.*.value", "production_settings.environment_variables.*.value", "settings.environment_variables.*.value");
130
+ /** A BGP session's MD5 key authenticates the session. */
131
+ const BGP = (...paths) => redact(...paths.map((path) => `${path}.bgp.md5_key`));
132
+ const ROOT_BGP = redact("bgp.md5_key");
133
+ /** Probe and health-check headers often carry authorization. */
134
+ const HEALTH_HEADERS = redact("http_config.header");
135
+ const DESCRIBED_ONLY = "The spec mentions credentials in this field's description; the value is metadata, names, or counts.";
136
+ const A = "/accounts/{account_id}";
137
+ const Z = "/zones/{zone_id}";
138
+ const OPERATIONS = {
139
+ // Access
140
+ [`GET ${A}/access/apps`]: ACCESS_APP,
141
+ [`POST ${A}/access/apps`]: ACCESS_APP,
142
+ [`GET ${A}/access/apps/{app_id}`]: ACCESS_APP,
143
+ [`PUT ${A}/access/apps/{app_id}`]: ACCESS_APP,
144
+ [`GET ${Z}/access/apps`]: ACCESS_APP,
145
+ [`POST ${Z}/access/apps`]: ACCESS_APP,
146
+ [`GET ${Z}/access/apps/{app_id}`]: ACCESS_APP,
147
+ [`PUT ${Z}/access/apps/{app_id}`]: ACCESS_APP,
148
+ [`GET ${A}/access/apps/{app_id}/policies`]: ACCESS_RULES,
149
+ [`POST ${A}/access/apps/{app_id}/policies`]: ACCESS_RULES,
150
+ [`GET ${A}/access/apps/{app_id}/policies/{policy_id}`]: ACCESS_RULES,
151
+ [`PUT ${A}/access/apps/{app_id}/policies/{policy_id}`]: ACCESS_RULES,
152
+ [`PUT ${A}/access/apps/{app_id}/policies/{policy_id}/make_reusable`]: ACCESS_RULES,
153
+ [`GET ${A}/access/groups`]: ACCESS_RULES,
154
+ [`POST ${A}/access/groups`]: ACCESS_RULES,
155
+ [`GET ${A}/access/groups/{group_id}`]: ACCESS_RULES,
156
+ [`PUT ${A}/access/groups/{group_id}`]: ACCESS_RULES,
157
+ [`GET ${A}/access/policies`]: ACCESS_RULES,
158
+ [`POST ${A}/access/policies`]: ACCESS_RULES,
159
+ [`GET ${A}/access/policies/{policy_id}`]: ACCESS_RULES,
160
+ [`PUT ${A}/access/policies/{policy_id}`]: ACCESS_RULES,
161
+ [`GET ${Z}/access/apps/{app_id}/policies`]: ACCESS_RULES,
162
+ [`POST ${Z}/access/apps/{app_id}/policies`]: ACCESS_RULES,
163
+ [`GET ${Z}/access/apps/{app_id}/policies/{policy_id}`]: ACCESS_RULES,
164
+ [`PUT ${Z}/access/apps/{app_id}/policies/{policy_id}`]: ACCESS_RULES,
165
+ [`GET ${Z}/access/groups`]: ACCESS_RULES,
166
+ [`POST ${Z}/access/groups`]: ACCESS_RULES,
167
+ [`GET ${Z}/access/groups/{group_id}`]: ACCESS_RULES,
168
+ [`PUT ${Z}/access/groups/{group_id}`]: ACCESS_RULES,
169
+ [`GET ${A}/access/identity_providers`]: IDENTITY_PROVIDER,
170
+ [`POST ${A}/access/identity_providers`]: IDENTITY_PROVIDER,
171
+ [`GET ${A}/access/identity_providers/{identity_provider_id}`]: IDENTITY_PROVIDER,
172
+ [`PUT ${A}/access/identity_providers/{identity_provider_id}`]: IDENTITY_PROVIDER,
173
+ [`GET ${Z}/access/identity_providers`]: IDENTITY_PROVIDER,
174
+ [`POST ${Z}/access/identity_providers`]: IDENTITY_PROVIDER,
175
+ [`GET ${Z}/access/identity_providers/{identity_provider_id}`]: IDENTITY_PROVIDER,
176
+ [`PUT ${Z}/access/identity_providers/{identity_provider_id}`]: IDENTITY_PROVIDER,
177
+ [`POST ${A}/access/apps/{app_id}/revoke_tokens`]: safe(REVOKES),
178
+ [`POST ${Z}/access/apps/{app_id}/revoke_tokens`]: safe(REVOKES),
179
+ [`POST ${A}/access/organizations/revoke_user`]: safe(REVOKES),
180
+ [`POST ${Z}/access/organizations/revoke_user`]: safe(REVOKES),
181
+ [`POST ${A}/access/keys/rotate`]: safe("Rotates Cloudflare-held signing keys; returns the key configuration, no key."),
182
+ [`POST ${A}/access/saml_certificates/{saml_cert_set_id}/rotate`]: safe("Rotates a Cloudflare-held SAML certificate; returns the public certificate."),
183
+ [`GET ${A}/access/service_tokens`]: safe(METADATA),
184
+ [`POST ${A}/access/service_tokens`]: refuse(MINT),
185
+ [`GET ${A}/access/service_tokens/{service_token_id}`]: safe(METADATA),
186
+ [`PUT ${A}/access/service_tokens/{service_token_id}`]: safe(METADATA),
187
+ [`DELETE ${A}/access/service_tokens/{service_token_id}`]: safe(REVOKES),
188
+ [`POST ${A}/access/service_tokens/{service_token_id}/refresh`]: safe("Extends the token's expiry; returns no secret."),
189
+ [`POST ${A}/access/service_tokens/{service_token_id}/rotate`]: refuse(MINT),
190
+ [`GET ${Z}/access/service_tokens`]: safe(METADATA),
191
+ [`POST ${Z}/access/service_tokens`]: refuse(MINT),
192
+ [`GET ${Z}/access/service_tokens/{service_token_id}`]: safe(METADATA),
193
+ [`PUT ${Z}/access/service_tokens/{service_token_id}`]: safe(METADATA),
194
+ [`DELETE ${Z}/access/service_tokens/{service_token_id}`]: safe(REVOKES),
195
+ // Addressing
196
+ ...Object.fromEntries([
197
+ `GET ${A}/addressing/prefixes`,
198
+ `POST ${A}/addressing/prefixes`,
199
+ `GET ${A}/addressing/prefixes/{prefix_id}`,
200
+ `PATCH ${A}/addressing/prefixes/{prefix_id}`,
201
+ `POST ${A}/addressing/prefixes/{prefix_id}/validate`,
202
+ ].map((key) => [
203
+ key,
204
+ safe("The ownership token is published in DNS to prove ownership.", "ownership_validation_token"),
205
+ ])),
206
+ // AI Gateway, AI Search
207
+ [`POST ${A}/ai-gateway/billing/topup`]: refuse(PAYMENT),
208
+ ...Object.fromEntries([
209
+ `GET ${A}/ai-gateway/gateways`,
210
+ `POST ${A}/ai-gateway/gateways`,
211
+ `GET ${A}/ai-gateway/gateways/{id}`,
212
+ `PUT ${A}/ai-gateway/gateways/{id}`,
213
+ `DELETE ${A}/ai-gateway/gateways/{id}`,
214
+ ].map((key) => [key, redact("otel.authorization", "otel.headers", "stripe.authorization")])),
215
+ // Custom providers carry auth headers as a JSON-encoded string or an object.
216
+ ...Object.fromEntries([
217
+ `GET ${A}/ai-gateway/custom-providers`,
218
+ `POST ${A}/ai-gateway/custom-providers`,
219
+ `GET ${A}/ai-gateway/custom-providers/{id}`,
220
+ `PATCH ${A}/ai-gateway/custom-providers/{id}`,
221
+ `DELETE ${A}/ai-gateway/custom-providers/{id}`,
222
+ ].map((key) => [key, redact("headers")])),
223
+ [`PUT ${A}/ai-gateway/gateways/{gateway_id}/provider_configs/{id}`]: safe("The caller supplies the provider key; the response returns a masked preview."),
224
+ [`GET ${A}/ai-search/tokens`]: safe(METADATA),
225
+ [`POST ${A}/ai-search/tokens`]: refuse(MINT),
226
+ [`GET ${A}/ai-search/tokens/{id}`]: safe(METADATA),
227
+ [`PUT ${A}/ai-search/tokens/{id}`]: safe(METADATA),
228
+ [`DELETE ${A}/ai-search/tokens/{id}`]: safe(REVOKES),
229
+ // Alerting
230
+ [`POST ${A}/alerting/v3/destinations/pagerduty/connect`]: refuse(MINT),
231
+ [`GET ${A}/alerting/v3/destinations/pagerduty/connect/{token_id}`]: refuse(ACTS),
232
+ [`GET ${A}/alerting/v3/policies/{policy_id}/email/unsubscribe`]: refuse(ACTS),
233
+ // Artifacts
234
+ [`POST ${A}/artifacts/namespaces/{namespace}/repos`]: redact("token"),
235
+ [`POST ${A}/artifacts/namespaces/{namespace}/repos/{name}/fork`]: redact("token"),
236
+ [`POST ${A}/artifacts/namespaces/{namespace}/repos/{name}/import`]: redact("token"),
237
+ [`GET ${A}/artifacts/namespaces/{namespace}/repos/{name}/tokens`]: safe(METADATA),
238
+ [`POST ${A}/artifacts/namespaces/{namespace}/tokens`]: refuse(MINT),
239
+ [`DELETE ${A}/artifacts/namespaces/{namespace}/tokens/{id}`]: safe(REVOKES),
240
+ // R2 Data Catalog
241
+ [`POST ${A}/basin-catalog/{bucket_name}/credential`]: safe(CALLER_SUPPLIED),
242
+ [`GET ${A}/basin-catalog/{bucket_name}/credential/status`]: safe(METADATA),
243
+ [`GET ${A}/basin-catalog/{bucket_name}/namespaces`]: safe("A pagination cursor.", "next_page_token"),
244
+ [`GET ${A}/basin-catalog/{bucket_name}/namespaces/{namespace}/tables`]: safe("A pagination cursor.", "next_page_token"),
245
+ [`GET ${A}/basin-catalog/{bucket_name}/namespaces/{namespace}/tables/{table_name}/maintenance-runs`]: safe("A pagination cursor.", "next_page_token"),
246
+ // Billing
247
+ [`POST ${A}/billing/profile/payment-method`]: refuse(PAYMENT),
248
+ [`POST ${A}/client-secret`]: refuse(PAYMENT),
249
+ [`POST ${A}/pay-bad-debt`]: refuse(PAYMENT),
250
+ [`POST ${A}/pay-invoice`]: refuse(PAYMENT),
251
+ // Workers Builds
252
+ [`GET ${A}/builds/tokens`]: safe(METADATA),
253
+ [`POST ${A}/builds/tokens`]: refuse(MINT),
254
+ [`DELETE ${A}/builds/tokens/{build_token_uuid}`]: safe(REVOKES),
255
+ [`GET ${A}/builds/workers/{script_name}/deploy_hooks`]: redact("deploy_hook_uuid"),
256
+ [`POST ${A}/builds/workers/{script_name}/deploy_hooks`]: refuse(BEARER),
257
+ [`GET ${A}/builds/workers/{script_name}/deploy_hooks/{deploy_hook_uuid}`]: redact("deploy_hook_uuid"),
258
+ [`PUT ${A}/builds/workers/{script_name}/deploy_hooks/{deploy_hook_uuid}`]: redact("deploy_hook_uuid"),
259
+ [`DELETE ${A}/builds/workers/{script_name}/deploy_hooks/{deploy_hook_uuid}`]: safe(REVOKES),
260
+ [`POST /workers/builds/deploy_hooks/{deploy_hook_uuid}`]: safe("Triggers a build with a hook id the caller already holds; returns no credential."),
261
+ // Calls, Turnstile
262
+ [`POST ${A}/calls/apps`]: redact("secret"),
263
+ [`GET ${A}/calls/turn_keys`]: safe(METADATA),
264
+ [`POST ${A}/calls/turn_keys`]: refuse(MINT),
265
+ [`GET ${A}/calls/turn_keys/{key_id}`]: safe(METADATA),
266
+ [`PUT ${A}/calls/turn_keys/{key_id}`]: safe(METADATA),
267
+ [`DELETE ${A}/calls/turn_keys/{key_id}`]: safe(REVOKES),
268
+ [`POST ${A}/challenges/widgets`]: redact("secret"),
269
+ [`GET ${A}/challenges/widgets/{sitekey}`]: redact("secret"),
270
+ [`PUT ${A}/challenges/widgets/{sitekey}`]: redact("secret"),
271
+ [`DELETE ${A}/challenges/widgets/{sitekey}`]: redact("secret"),
272
+ [`POST ${A}/challenges/widgets/{sitekey}/rotate_secret`]: refuse(MINT),
273
+ // Tunnels
274
+ [`POST ${A}/cfd_tunnel/{tunnel_id}/management`]: refuse(MINT),
275
+ [`GET ${A}/cfd_tunnel/{tunnel_id}/token`]: refuse("A tunnel token lets anyone run this tunnel; Connecta does not return it. Read the tunnel itself instead."),
276
+ [`GET ${A}/warp_connector/{tunnel_id}/token`]: refuse("A Mesh node token lets anyone run this connector; Connecta does not return it."),
277
+ // Cloudforce One
278
+ [`GET ${A}/cloudforce-one/v2/credential-monitor/domains`]: safe(METADATA),
279
+ [`POST ${A}/cloudforce-one/v2/credential-monitor/domains`]: safe(METADATA),
280
+ [`DELETE ${A}/cloudforce-one/v2/credential-monitor/domains/{id}`]: safe(REVOKES),
281
+ [`GET ${A}/cloudforce-one/v2/credential-monitor/matches`]: safe("Matches name the domain and username, not a password."),
282
+ [`GET ${A}/cloudforce-one/v2/requests/{project_type}/quota`]: safe("A request quota, not a token."),
283
+ // Containers
284
+ [`GET ${A}/containers/applications`]: CONTAINER_APP,
285
+ [`GET ${A}/containers/applications/{application_id}/instances-v2`]: safe("A pagination cursor.", "next_page_token", "page_token"),
286
+ [`POST ${A}/containers/registries/{domain}/credentials`]: refuse(MINT),
287
+ // Custom pages
288
+ [`POST ${A}/custom_pages/preview_tokens`]: refuse(MINT),
289
+ [`POST ${Z}/custom_pages/preview_tokens`]: refuse(MINT),
290
+ // D1, DLP, Email Security
291
+ [`POST ${A}/d1/database/{database_id}/export`]: redact("result.signed_url#url", "signed_url#url"),
292
+ [`POST ${A}/d1/database/{database_id}/import`]: redact("upload_url#url"),
293
+ [`POST ${A}/dlp/datasets`]: reviewed(CARRIES, ["secret"], ["dataset.secret"]),
294
+ [`POST ${A}/dlp/datasets/{dataset_id}/upload`]: redact("secret"),
295
+ [`GET ${A}/dlp/email/account_mapping`]: redact("addin_identifier_token"),
296
+ [`POST ${A}/dlp/email/account_mapping`]: redact("addin_identifier_token"),
297
+ ...Object.fromEntries([
298
+ `GET ${A}/email-security/settings/domains`,
299
+ `POST ${A}/email-security/settings/domains`,
300
+ `GET ${A}/email-security/settings/domains/{domain_id}`,
301
+ `PUT ${A}/email-security/settings/domains/{domain_id}`,
302
+ `PATCH ${A}/email-security/settings/domains/{domain_id}`,
303
+ ].map((key) => [key, safe("authorization is the domain's authorization status.", "authorization")])),
304
+ [`POST ${A}/email-security/settings/domains/batch`]: safe("authorization is each domain's authorization status.", "patches.authorization", "posts.authorization", "puts.authorization"),
305
+ [`POST ${A}/gateway/audit_ssh_settings/rotate_seed`]: safe("Returns the new seed's id and public key."),
306
+ // Hyperdrive
307
+ [`POST ${A}/hyperdrive/integrationsOperations/planetScale/createDatabaseSignature`]: refuse(MINT),
308
+ // Images
309
+ [`GET ${A}/images/v1/keys`]: redact("keys.value"),
310
+ [`PUT ${A}/images/v1/keys/{signing_key_name}`]: refuse(MINT),
311
+ [`DELETE ${A}/images/v1/keys/{signing_key_name}`]: redact("keys.value"),
312
+ [`GET ${A}/images/v2`]: safe("A pagination cursor.", "continuation_token"),
313
+ [`POST ${A}/images/v2/direct_upload`]: refuse(BEARER),
314
+ // Load Balancing monitors: probe headers often carry authorization.
315
+ ...Object.fromEntries([
316
+ `GET ${A}/load_balancers/monitors`,
317
+ `POST ${A}/load_balancers/monitors`,
318
+ `GET ${A}/load_balancers/monitors/{monitor_id}`,
319
+ `PUT ${A}/load_balancers/monitors/{monitor_id}`,
320
+ `PATCH ${A}/load_balancers/monitors/{monitor_id}`,
321
+ `GET /user/load_balancers/monitors`,
322
+ `POST /user/load_balancers/monitors`,
323
+ `GET /user/load_balancers/monitors/{monitor_id}`,
324
+ `PUT /user/load_balancers/monitors/{monitor_id}`,
325
+ `PATCH /user/load_balancers/monitors/{monitor_id}`,
326
+ ].map((key) => [key, redact("header")])),
327
+ // Logpush destinations carry credentials in their query string.
328
+ ...Object.fromEntries([
329
+ `GET ${A}/logpush/jobs`,
330
+ `POST ${A}/logpush/jobs`,
331
+ `GET ${A}/logpush/jobs/{job_id}`,
332
+ `PUT ${A}/logpush/jobs/{job_id}`,
333
+ `GET ${Z}/logpush/jobs`,
334
+ `POST ${Z}/logpush/jobs`,
335
+ `GET ${Z}/logpush/jobs/{job_id}`,
336
+ `PUT ${Z}/logpush/jobs/{job_id}`,
337
+ ].map((key) => [key, redact("destination_conf#url")])),
338
+ // Magic WAN
339
+ [`POST ${A}/magic/ipsec_tunnels/psk`]: reviewed("Applied pre-shared keys authenticate IPsec tunnels.", ["successfully_applied_psks.*.psk"], ["unapplied_psks"]),
340
+ [`POST ${A}/magic/ipsec_tunnels/{ipsec_tunnel_id}/psk_generate`]: refuse(MINT),
341
+ [`POST ${A}/mnm/vpc-flows/token`]: refuse(MINT),
342
+ [`POST ${A}/managed-defense/vulnerability-discovery/repos`]: redact("upload.token"),
343
+ // MoQ
344
+ [`POST ${A}/moq/relays`]: MOQ_TOKENS,
345
+ [`GET ${A}/moq/relays/{relay_id}/tokens`]: MOQ_TOKENS,
346
+ [`POST ${A}/moq/relays/{relay_id}/tokens`]: refuse(MINT),
347
+ [`DELETE ${A}/moq/relays/{relay_id}/tokens/{jti}`]: safe(REVOKES),
348
+ // OAuth clients
349
+ [`POST ${A}/oauth_clients`]: refuse(MINT),
350
+ [`POST ${A}/oauth_clients/{oauth_client_id}/rotate_secret`]: refuse(MINT),
351
+ [`DELETE ${A}/oauth_clients/{oauth_client_id}/rotate_secret`]: safe(REVOKES),
352
+ // Pages
353
+ [`GET ${A}/pages/projects`]: PAGES_PROJECT,
354
+ [`POST ${A}/pages/projects`]: PAGES_PROJECT,
355
+ [`GET ${A}/pages/projects/{project_name}`]: PAGES_PROJECT,
356
+ [`PATCH ${A}/pages/projects/{project_name}`]: PAGES_PROJECT,
357
+ [`GET ${A}/pages/projects/{project_name}/deployments`]: PAGES_PROJECT,
358
+ [`POST ${A}/pages/projects/{project_name}/deployments`]: PAGES_PROJECT,
359
+ [`GET ${A}/pages/projects/{project_name}/deployments/{deployment_id}`]: PAGES_PROJECT,
360
+ [`POST ${A}/pages/projects/{project_name}/deployments/{deployment_id}/retry`]: PAGES_PROJECT,
361
+ [`POST ${A}/pages/projects/{project_name}/deployments/{deployment_id}/rollback`]: PAGES_PROJECT,
362
+ [`POST ${A}/pages/projects/{project_name}/source`]: PAGES_PROJECT,
363
+ [`DELETE ${A}/pages/projects/{project_name}/source`]: PAGES_PROJECT,
364
+ [`GET ${A}/pages/projects/{project_name}/upload-token`]: refuse(BEARER),
365
+ // Pipelines, R2
366
+ [`POST ${A}/pipelines/v1/sinks`]: redact("config.credentials", "config.token"),
367
+ [`GET ${A}/r2/buckets/{bucket_name}/jobs`]: safe("A pagination cursor.", "nextContinuationToken"),
368
+ [`POST ${A}/r2/temp-access-credentials`]: refuse(MINT),
369
+ // RealtimeKit (bare `data` bodies)
370
+ [`GET ${A}/realtime/kit/{app_id}/livestreams`]: LIVESTREAM,
371
+ [`GET ${A}/realtime/kit/{app_id}/livestreams/{livestream_id}`]: LIVESTREAM,
372
+ [`GET ${A}/realtime/kit/{app_id}/livestreams/{livestream_id}/active-livestream-session`]: LIVESTREAM,
373
+ [`GET ${A}/realtime/kit/{app_id}/meetings/{meeting_id}/active-livestream`]: LIVESTREAM,
374
+ [`GET ${A}/realtime/kit/{app_id}/meetings/{meeting_id}/livestream`]: LIVESTREAM,
375
+ [`POST ${A}/realtime/kit/{app_id}/meetings/{meeting_id}/livestreams`]: LIVESTREAM,
376
+ [`POST ${A}/realtime/kit/{app_id}/meetings/{meeting_id}/participants`]: refuse(MINT),
377
+ [`PUT ${A}/realtime/kit/{app_id}/meetings/{meeting_id}/participants/{participant_id}`]: redact("data.token"),
378
+ [`PATCH ${A}/realtime/kit/{app_id}/meetings/{meeting_id}/participants/{participant_id}`]: redact("data.token"),
379
+ [`POST ${A}/realtime/kit/{app_id}/meetings/{meeting_id}/participants/{participant_id}/token`]: refuse(MINT),
380
+ // Web Analytics
381
+ ...Object.fromEntries([
382
+ `POST ${A}/rum/site_info`,
383
+ `GET ${A}/rum/site_info/list`,
384
+ `GET ${A}/rum/site_info/{site_id}`,
385
+ `PUT ${A}/rum/site_info/{site_id}`,
386
+ ].map((key) => [key, safe("The site token is a public beacon id embedded in pages.", "site_token")])),
387
+ [`GET ${A}/scim/v2/ServiceProviderConfig`]: safe("Describes SCIM features; no credential.", "changePassword"),
388
+ // Secondary DNS
389
+ [`GET ${A}/secondary_dns/tsigs`]: TSIG,
390
+ [`POST ${A}/secondary_dns/tsigs`]: TSIG,
391
+ [`GET ${A}/secondary_dns/tsigs/{tsig_id}`]: TSIG,
392
+ [`PUT ${A}/secondary_dns/tsigs/{tsig_id}`]: TSIG,
393
+ [`DELETE ${A}/secondary_dns/tsigs/{tsig_id}`]: safe(REVOKES),
394
+ // Secrets Store: values are write-only.
395
+ ...Object.fromEntries([
396
+ `GET ${A}/secrets_store/stores`,
397
+ `POST ${A}/secrets_store/stores`,
398
+ `GET ${A}/secrets_store/stores/{store_id}`,
399
+ `GET ${A}/secrets_store/stores/{store_id}/secrets`,
400
+ `POST ${A}/secrets_store/stores/{store_id}/secrets`,
401
+ `GET ${A}/secrets_store/stores/{store_id}/secrets/{secret_id}`,
402
+ `PATCH ${A}/secrets_store/stores/{store_id}/secrets/{secret_id}`,
403
+ `POST ${A}/secrets_store/stores/{store_id}/secrets/{secret_id}/duplicate`,
404
+ ].map((key) => [key, safe(CALLER_SUPPLIED)])),
405
+ [`GET ${A}/secrets_store/quota`]: safe("A usage count of secrets.", "secrets"),
406
+ [`DELETE ${A}/secrets_store/stores/{store_id}`]: safe(REVOKES),
407
+ [`DELETE ${A}/secrets_store/stores/{store_id}/secrets`]: safe(REVOKES),
408
+ [`DELETE ${A}/secrets_store/stores/{store_id}/secrets/{secret_id}`]: safe(REVOKES),
409
+ // Stream
410
+ [`POST ${A}/stream/direct_upload`]: refuse(BEARER),
411
+ [`GET ${A}/stream/keys`]: safe(METADATA),
412
+ [`POST ${A}/stream/keys`]: refuse(MINT),
413
+ [`DELETE ${A}/stream/keys/{identifier}`]: safe(REVOKES),
414
+ [`GET ${A}/stream/live_inputs`]: LIVE_INPUT,
415
+ [`POST ${A}/stream/live_inputs`]: LIVE_INPUT,
416
+ [`GET ${A}/stream/live_inputs/{live_input_identifier}`]: LIVE_INPUT,
417
+ [`PUT ${A}/stream/live_inputs/{live_input_identifier}`]: LIVE_INPUT,
418
+ [`POST ${A}/stream/live_inputs/{live_input_identifier}/disable`]: LIVE_INPUT,
419
+ [`POST ${A}/stream/live_inputs/{live_input_identifier}/enable`]: LIVE_INPUT,
420
+ [`POST ${A}/stream/live_inputs/{live_input_identifier}/rotate_keys`]: refuse(MINT),
421
+ [`GET ${A}/stream/live_inputs/{live_input_identifier}/outputs`]: redact("streamKey", "url#url"),
422
+ [`POST ${A}/stream/live_inputs/{live_input_identifier}/outputs`]: redact("streamKey", "url#url"),
423
+ [`PUT ${A}/stream/live_inputs/{live_input_identifier}/outputs/{output_identifier}`]: redact("streamKey", "url#url"),
424
+ [`GET ${A}/stream/webhook`]: redact("secret"),
425
+ [`PUT ${A}/stream/webhook`]: redact("secret"),
426
+ [`POST ${A}/stream/{identifier}/token`]: refuse(BEARER),
427
+ // API tokens
428
+ [`GET ${A}/tokens`]: safe(METADATA),
429
+ [`POST ${A}/tokens`]: refuse(API_TOKENS),
430
+ [`GET ${A}/tokens/permission_groups`]: safe(METADATA),
431
+ [`GET ${A}/tokens/verify`]: safe(METADATA),
432
+ [`GET ${A}/tokens/{token_id}`]: safe(METADATA),
433
+ [`PUT ${A}/tokens/{token_id}`]: refuse(API_TOKENS),
434
+ [`DELETE ${A}/tokens/{token_id}`]: refuse(API_TOKENS),
435
+ [`PUT ${A}/tokens/{token_id}/value`]: refuse(API_TOKENS),
436
+ [`GET /user/tokens`]: safe(METADATA),
437
+ [`POST /user/tokens`]: refuse(API_TOKENS),
438
+ [`GET /user/tokens/permission_groups`]: safe(METADATA),
439
+ [`GET /user/tokens/verify`]: safe(METADATA),
440
+ [`GET /user/tokens/{token_id}`]: safe(METADATA),
441
+ [`PUT /user/tokens/{token_id}`]: refuse(API_TOKENS),
442
+ [`DELETE /user/tokens/{token_id}`]: refuse(API_TOKENS),
443
+ [`PUT /user/tokens/{token_id}/value`]: refuse(API_TOKENS),
444
+ // Vulnerability scanner: credential values are write-only.
445
+ ...Object.fromEntries([
446
+ `GET ${A}/vuln_scanner/credential_sets`,
447
+ `POST ${A}/vuln_scanner/credential_sets`,
448
+ `GET ${A}/vuln_scanner/credential_sets/{credential_set_id}`,
449
+ `PUT ${A}/vuln_scanner/credential_sets/{credential_set_id}`,
450
+ `PATCH ${A}/vuln_scanner/credential_sets/{credential_set_id}`,
451
+ `GET ${A}/vuln_scanner/credential_sets/{credential_set_id}/credentials`,
452
+ `POST ${A}/vuln_scanner/credential_sets/{credential_set_id}/credentials`,
453
+ `GET ${A}/vuln_scanner/credential_sets/{credential_set_id}/credentials/{credential_id}`,
454
+ `PUT ${A}/vuln_scanner/credential_sets/{credential_set_id}/credentials/{credential_id}`,
455
+ `PATCH ${A}/vuln_scanner/credential_sets/{credential_set_id}/credentials/{credential_id}`,
456
+ ].map((key) => [key, safe(CALLER_SUPPLIED)])),
457
+ [`DELETE ${A}/vuln_scanner/credential_sets/{credential_set_id}`]: safe(REVOKES),
458
+ [`DELETE ${A}/vuln_scanner/credential_sets/{credential_set_id}/credentials/{credential_id}`]: safe(REVOKES),
459
+ // Workers
460
+ [`POST ${A}/workers/assets/upload`]: refuse(BEARER),
461
+ [`POST ${A}/workers/scripts/{script_name}/assets-upload-session`]: refuse(BEARER),
462
+ [`POST ${A}/workers/dispatch/namespaces/{dispatch_namespace}/scripts/{script_name}/assets-upload-session`]: refuse(BEARER),
463
+ [`GET ${A}/workers/scripts/{script_name}/secrets`]: WORKER_SECRET,
464
+ [`PUT ${A}/workers/scripts/{script_name}/secrets`]: WORKER_SECRET,
465
+ [`PATCH ${A}/workers/scripts/{script_name}/secrets-bulk`]: WORKER_SECRET,
466
+ [`GET ${A}/workers/scripts/{script_name}/secrets/{secret_name}`]: WORKER_SECRET,
467
+ [`DELETE ${A}/workers/scripts/{script_name}/secrets/{secret_name}`]: safe(REVOKES),
468
+ [`GET ${A}/workers/dispatch/namespaces/{dispatch_namespace}/scripts/{script_name}/secrets`]: WORKER_SECRET,
469
+ [`PUT ${A}/workers/dispatch/namespaces/{dispatch_namespace}/scripts/{script_name}/secrets`]: WORKER_SECRET,
470
+ [`PATCH ${A}/workers/dispatch/namespaces/{dispatch_namespace}/scripts/{script_name}/secrets-bulk`]: WORKER_SECRET,
471
+ [`GET ${A}/workers/dispatch/namespaces/{dispatch_namespace}/scripts/{script_name}/secrets/{secret_name}`]: WORKER_SECRET,
472
+ [`DELETE ${A}/workers/dispatch/namespaces/{dispatch_namespace}/scripts/{script_name}/secrets/{secret_name}`]: safe(REVOKES),
473
+ [`GET ${A}/workers/workers/{worker_id}/previews/{preview_id}/deployments`]: WORKER_VERSION,
474
+ [`POST ${A}/workers/workers/{worker_id}/previews/{preview_id}/deployments`]: WORKER_VERSION,
475
+ [`PATCH ${A}/workers/workers/{worker_id}/previews/{preview_id}/deployments/latest`]: WORKER_VERSION,
476
+ [`GET ${A}/workers/workers/{worker_id}/previews/{preview_id}/deployments/{deployment_id}`]: WORKER_VERSION,
477
+ [`GET ${A}/workers/workers/{worker_id}/versions`]: WORKER_VERSION,
478
+ [`POST ${A}/workers/workers/{worker_id}/versions`]: WORKER_VERSION,
479
+ [`GET ${A}/workers/workers/{worker_id}/versions/latest`]: WORKER_VERSION,
480
+ [`PATCH ${A}/workers/workers/{worker_id}/versions/latest`]: WORKER_VERSION,
481
+ [`GET ${A}/workers/workers/{worker_id}/versions/{version_id}`]: WORKER_VERSION,
482
+ [`GET ${A}/workflows/{workflow_name}/instances/{instance_id}/subscribe/token`]: refuse(MINT),
483
+ // Unscoped
484
+ [`GET /organizations`]: safe("A pagination cursor.", "next_page_token"),
485
+ [`GET /organizations/{organization_id}/accounts`]: safe("A pagination cursor.", "next_page_token"),
486
+ [`GET /organizations/{organization_id}/members`]: safe("A pagination cursor.", "next_page_token"),
487
+ [`GET /radar/leaked_credential_checks/summary/{dimension}`]: safe("Aggregate internet statistics."),
488
+ [`GET /radar/leaked_credential_checks/timeseries_groups/{dimension}`]: safe("Aggregate internet statistics."),
489
+ [`GET /signed-url`]: refuse(INTERNAL),
490
+ // Zones
491
+ [`GET ${Z}/leaked-credential-checks`]: safe(METADATA, "enabled"),
492
+ [`POST ${Z}/leaked-credential-checks`]: safe(METADATA, "enabled"),
493
+ ...Object.fromEntries([
494
+ `GET ${Z}/leaked-credential-checks/detections`,
495
+ `POST ${Z}/leaked-credential-checks/detections`,
496
+ `GET ${Z}/leaked-credential-checks/detections/{detection_id}`,
497
+ `PUT ${Z}/leaked-credential-checks/detections/{detection_id}`,
498
+ ].map((key) => [key, safe("password is an expression locating the field, not a password.", "password")])),
499
+ [`DELETE ${Z}/leaked-credential-checks/detections/{detection_id}`]: safe(REVOKES),
500
+ [`GET ${Z}/origin_tls_client_auth`]: redact("private_key"),
501
+ [`POST ${Z}/origin_tls_client_auth`]: redact("private_key"),
502
+ [`PUT ${Z}/origin_tls_client_auth/hostnames`]: redact("private_key"),
503
+ [`GET ${Z}/origin_tls_client_auth/{certificate_id}`]: redact("private_key"),
504
+ [`DELETE ${Z}/origin_tls_client_auth/{certificate_id}`]: redact("private_key"),
505
+ ...Object.fromEntries([
506
+ `GET ${Z}/pagerules`,
507
+ `POST ${Z}/pagerules`,
508
+ `GET ${Z}/pagerules/{pagerule_id}`,
509
+ `PUT ${Z}/pagerules/{pagerule_id}`,
510
+ `PATCH ${Z}/pagerules/{pagerule_id}`,
511
+ ].map((key) => [
512
+ key,
513
+ safe("cookie and header list cache-key names.", "actions.value.cookie", "actions.value.header"),
514
+ ])),
515
+ ...Object.fromEntries([`GET ${Z}/settings/zaraz/config`, `PUT ${Z}/settings/zaraz/config`, `GET ${Z}/settings/zaraz/default`].map((key) => [key, ZARAZ])),
516
+ [`GET ${Z}/settings/zaraz/export`]: ZARAZ,
517
+ [`GET ${Z}/settings/zaraz/history/configs`]: ZARAZ,
518
+ [`GET ${Z}/token_validation/config`]: safe("credentials are public JWKS keys.", "credentials"),
519
+ [`POST ${Z}/token_validation/config`]: safe("credentials are public JWKS keys.", "credentials"),
520
+ [`GET ${Z}/token_validation/config/{config_id}`]: safe("credentials are public JWKS keys.", "credentials"),
521
+ [`PATCH ${Z}/token_validation/config/{config_id}`]: safe(METADATA),
522
+ [`DELETE ${Z}/token_validation/config/{config_id}`]: safe(REVOKES),
523
+ [`PUT ${Z}/token_validation/config/{config_id}/credentials`]: safe("Public JWKS keys.", "keys"),
524
+ [`PATCH ${Z}/token_validation/config/{config_id}/credentials`]: safe("Public JWKS keys.", "keys"),
525
+ [`GET ${Z}/token_validation/rules`]: safe(METADATA),
526
+ [`POST ${Z}/token_validation/rules`]: safe(METADATA),
527
+ [`POST ${Z}/token_validation/rules/bulk`]: safe(METADATA),
528
+ [`PATCH ${Z}/token_validation/rules/bulk`]: safe(METADATA),
529
+ [`POST ${Z}/token_validation/rules/preview`]: safe(METADATA),
530
+ [`GET ${Z}/token_validation/rules/{rule_id}`]: safe(METADATA),
531
+ [`PATCH ${Z}/token_validation/rules/{rule_id}`]: safe(METADATA),
532
+ [`DELETE ${Z}/token_validation/rules/{rule_id}`]: safe(REVOKES),
533
+ // Round 2: candidates surfaced by plurals, headers, environment variables,
534
+ // credential descriptions, and x-sensitive.
535
+ [`POST ${A}/bulk/subscriptions`]: refuse(PAYMENT),
536
+ [`POST ${A}/devices/override_codes`]: refuse(MINT),
537
+ ...Object.fromEntries([
538
+ `GET ${A}/builds/builds`,
539
+ `GET ${A}/builds/builds/latest`,
540
+ `GET ${A}/builds/builds/{build_uuid}`,
541
+ `POST ${A}/builds/triggers/{trigger_uuid}/builds`,
542
+ `GET ${A}/builds/triggers/{trigger_uuid}/environment_variables`,
543
+ `PATCH ${A}/builds/triggers/{trigger_uuid}/environment_variables`,
544
+ `POST ${A}/builds/workers`,
545
+ `GET ${A}/builds/workers/{external_script_id}/builds`,
546
+ `GET ${A}/builds/workers/{script_tag}`,
547
+ `PATCH ${A}/builds/workers/{script_tag}`,
548
+ `POST ${A}/builds/workers/{script_tag}/migrate_to_previews`,
549
+ `GET ${A}/builds/workers/{script_tag}/previews/{preview_id}`,
550
+ `PATCH ${A}/builds/workers/{script_tag}/previews/{preview_id}`,
551
+ `GET ${A}/builds/workers/{script_tag}/previews/{preview_id}/builds`,
552
+ `POST ${A}/builds/workers/{script_tag}/previews/{preview_id}/builds`,
553
+ ].map((key) => [key, BUILD_ENV])),
554
+ ...Object.fromEntries([
555
+ `POST ${A}/containers/applications`,
556
+ `GET ${A}/containers/applications/{application_id}`,
557
+ `PATCH ${A}/containers/applications/{application_id}`,
558
+ `POST ${A}/containers/applications/{application_id}/rollouts`,
559
+ `GET ${A}/containers/applications/{application_id}/versions`,
560
+ ].map((key) => [key, CONTAINER_APP])),
561
+ [`GET ${A}/containers/registries`]: safe("A registry's public key.", "public_key"),
562
+ [`POST ${A}/containers/registries`]: safe("A registry's public key.", "public_key"),
563
+ ...Object.fromEntries([`GET ${A}/cni/cnis`, `POST ${A}/cni/cnis`, `GET ${A}/cni/cnis/{cni}`, `PUT ${A}/cni/cnis/{cni}`].map((key) => [
564
+ key,
565
+ redact("bgp.md5_key", "items.bgp.md5_key"),
566
+ ])),
567
+ [`GET ${A}/magic/cf_interconnects`]: BGP("interconnects"),
568
+ [`PUT ${A}/magic/cf_interconnects`]: BGP("modified_interconnects"),
569
+ [`GET ${A}/magic/cf_interconnects/{cf_interconnect_id}`]: BGP("interconnect"),
570
+ [`PUT ${A}/magic/cf_interconnects/{cf_interconnect_id}`]: BGP("modified_interconnect"),
571
+ [`GET ${A}/magic/gre_tunnels`]: BGP("gre_tunnels"),
572
+ [`POST ${A}/magic/gre_tunnels`]: ROOT_BGP,
573
+ [`PUT ${A}/magic/gre_tunnels`]: BGP("modified_gre_tunnels"),
574
+ [`GET ${A}/magic/gre_tunnels/{gre_tunnel_id}`]: BGP("gre_tunnel"),
575
+ [`PUT ${A}/magic/gre_tunnels/{gre_tunnel_id}`]: BGP("modified_gre_tunnel"),
576
+ [`DELETE ${A}/magic/gre_tunnels/{gre_tunnel_id}`]: BGP("deleted_gre_tunnel"),
577
+ [`GET ${A}/magic/ipsec_tunnels`]: BGP("ipsec_tunnels"),
578
+ [`POST ${A}/magic/ipsec_tunnels`]: ROOT_BGP,
579
+ [`PUT ${A}/magic/ipsec_tunnels`]: BGP("modified_ipsec_tunnels"),
580
+ [`GET ${A}/magic/ipsec_tunnels/{ipsec_tunnel_id}`]: BGP("ipsec_tunnel"),
581
+ [`PUT ${A}/magic/ipsec_tunnels/{ipsec_tunnel_id}`]: BGP("modified_ipsec_tunnel"),
582
+ [`DELETE ${A}/magic/ipsec_tunnels/{ipsec_tunnel_id}`]: BGP("deleted_ipsec_tunnel"),
583
+ ...Object.fromEntries([
584
+ `GET ${A}/data-security/posture/webhooks`,
585
+ `POST ${A}/data-security/posture/webhooks`,
586
+ `GET ${A}/data-security/posture/webhooks/{webhook_id}`,
587
+ `PUT ${A}/data-security/posture/webhooks/{webhook_id}`,
588
+ ].map((key) => [key, POSTURE_WEBHOOK])),
589
+ ...Object.fromEntries([
590
+ `GET ${A}/gateway/rules`,
591
+ `POST ${A}/gateway/rules`,
592
+ `PATCH ${A}/gateway/rules`,
593
+ `GET ${A}/gateway/rules/tenant`,
594
+ `GET ${A}/gateway/rules/{rule_id}`,
595
+ `PUT ${A}/gateway/rules/{rule_id}`,
596
+ `PATCH ${A}/gateway/rules/{rule_id}`,
597
+ `POST ${A}/gateway/rules/{rule_id}/reset_expiration`,
598
+ ].map((key) => [
599
+ key,
600
+ reviewed("Gateway rules that add or set headers can carry credential header values.", ["rule_settings.add_headers", "rule_settings.set_headers"], ["rule_settings.delete_headers"]),
601
+ ])),
602
+ [`GET ${A}/logpush/datasets/{dataset_id}/jobs`]: redact("destination_conf#url"),
603
+ [`GET ${Z}/logpush/datasets/{dataset_id}/jobs`]: redact("destination_conf#url"),
604
+ [`GET ${A}/workers/observability/destinations`]: redact("configuration.headers", "configuration.destination_conf#url"),
605
+ [`GET ${A}/workers/observability/issues/{issueId}/occurrences`]: redact("request.headers"),
606
+ [`GET ${A}/workers/scripts/{script_name}/settings`]: WORKER_BINDINGS,
607
+ [`PATCH ${A}/workers/scripts/{script_name}/settings`]: WORKER_BINDINGS,
608
+ [`GET ${A}/workers/dispatch/namespaces/{dispatch_namespace}/scripts/{script_name}/settings`]: WORKER_BINDINGS,
609
+ [`PATCH ${A}/workers/dispatch/namespaces/{dispatch_namespace}/scripts/{script_name}/settings`]: WORKER_BINDINGS,
610
+ [`POST ${A}/workers/scripts/{script_name}/versions`]: redact("resources.bindings.text", "resources.bindings.json"),
611
+ [`GET ${A}/workers/scripts/{script_name}/versions/{version_id}`]: redact("resources.bindings.text", "resources.bindings.json"),
612
+ ...Object.fromEntries([
613
+ `GET ${Z}/custom_hostnames`,
614
+ `POST ${Z}/custom_hostnames`,
615
+ `GET ${Z}/custom_hostnames/{custom_hostname_id}`,
616
+ `PATCH ${Z}/custom_hostnames/{custom_hostname_id}`,
617
+ `PUT ${Z}/custom_hostnames/{custom_hostname_id}/certificate_pack/{certificate_pack_id}/certificates/{certificate_id}`,
618
+ ].map((key) => [key, redact("ssl.custom_key")])),
619
+ [`GET ${Z}/dnssec/zsk`]: reviewed("The zone signing key's private key and key-encryption key sign the zone.", ["SigningKey.privkey", "SigningKey.kek"], ["SigningKey.pubkey"]),
620
+ ...Object.fromEntries([
621
+ `GET ${Z}/healthchecks`,
622
+ `POST ${Z}/healthchecks`,
623
+ `POST ${Z}/healthchecks/preview`,
624
+ `GET ${Z}/healthchecks/preview/{healthcheck_id}`,
625
+ `GET ${Z}/healthchecks/{healthcheck_id}`,
626
+ `PUT ${Z}/healthchecks/{healthcheck_id}`,
627
+ `PATCH ${Z}/healthchecks/{healthcheck_id}`,
628
+ `GET ${Z}/smart_shield/healthchecks`,
629
+ `POST ${Z}/smart_shield/healthchecks`,
630
+ `GET ${Z}/smart_shield/healthchecks/{healthcheck_id}`,
631
+ `PUT ${Z}/smart_shield/healthchecks/{healthcheck_id}`,
632
+ `PATCH ${Z}/smart_shield/healthchecks/{healthcheck_id}`,
633
+ ].map((key) => [key, HEALTH_HEADERS])),
634
+ [`PUT ${Z}/settings/zaraz/history`]: ZARAZ,
635
+ // URL Scanner captures the scanned session: cookies, request and response
636
+ // headers (Authorization among them), raw response bodies, and the DOM.
637
+ // No reviewed projection exists, so these are refused; scan verdicts are in
638
+ // the search results and the screenshot is an image.
639
+ [`GET ${A}/urlscanner/v2/result/{scan_id}`]: refuse(CAPTURE),
640
+ [`GET ${A}/urlscanner/v2/har/{scan_id}`]: refuse(CAPTURE),
641
+ [`GET ${A}/urlscanner/v2/dom/{scan_id}`]: refuse(CAPTURE),
642
+ [`GET ${A}/urlscanner/v2/responses/{response_id}`]: refuse(CAPTURE),
643
+ // Reviewed safe: the flagged field is metadata, a header name list, a count, or third-party data the operation exists to return.
644
+ ...Object.fromEntries([
645
+ [`GET ${A}/access/ai-controls/mcp/portals`, "servers.auth_config_summary"],
646
+ [`POST ${A}/access/ai-controls/mcp/portals`, "servers.auth_config_summary"],
647
+ [`GET ${A}/access/ai-controls/mcp/portals/{id}`, "servers.auth_config_summary"],
648
+ [`PUT ${A}/access/ai-controls/mcp/portals/{id}`, "servers.auth_config_summary"],
649
+ [`GET ${A}/access/ai-controls/mcp/servers`, "auth_config_summary"],
650
+ [`POST ${A}/access/ai-controls/mcp/servers`, "auth_config_summary"],
651
+ [`GET ${A}/access/ai-controls/mcp/servers/{id}`, "auth_config_summary"],
652
+ [`PUT ${A}/access/ai-controls/mcp/servers/{id}`, "auth_config_summary"],
653
+ [`DELETE ${A}/access/ai-controls/mcp/servers/{id}`, "auth_config_summary"],
654
+ [`GET ${A}/access/users/{user_id}/last_seen_identity`, "passkeys"],
655
+ [`GET ${A}/ai-search/namespaces/{name}/instances`, "source_params.web_crawler.parse_options.include_headers"],
656
+ [`POST ${A}/ai-search/namespaces/{name}/instances`, "source_params.web_crawler.parse_options.include_headers"],
657
+ [
658
+ `GET ${A}/ai-search/namespaces/{name}/instances/{id}`,
659
+ "source_params.web_crawler.parse_options.include_headers",
660
+ ],
661
+ [
662
+ `PUT ${A}/ai-search/namespaces/{name}/instances/{id}`,
663
+ "source_params.web_crawler.parse_options.include_headers",
664
+ ],
665
+ [
666
+ `DELETE ${A}/ai-search/namespaces/{name}/instances/{id}`,
667
+ "source_params.web_crawler.parse_options.include_headers",
668
+ ],
669
+ [`POST ${A}/ai/tomarkdown`, "tokens"],
670
+ [`GET ${A}/basin-catalog/{bucket_name}/maintenance-configs`, ""],
671
+ [`GET ${A}/billable/usage/billable-metrics`, "DimensionKeys"],
672
+ [`POST ${A}/browser-rendering/accessibilityTree`, "meta.headers", "meta.redirectChain.headers"],
673
+ [`POST ${A}/browser-rendering/content`, "meta.headers", "meta.redirectChain.headers"],
674
+ [`POST ${A}/browser-rendering/json`, "meta.headers", "meta.redirectChain.headers"],
675
+ [`POST ${A}/browser-rendering/links`, "meta.headers", "meta.redirectChain.headers"],
676
+ [`POST ${A}/browser-rendering/markdown`, "meta.headers", "meta.redirectChain.headers"],
677
+ [`POST ${A}/browser-rendering/scrape`, "meta.headers", "meta.redirectChain.headers"],
678
+ [`POST ${A}/browser-rendering/snapshot`, "meta.headers", "meta.redirectChain.headers"],
679
+ [
680
+ `GET ${A}/cfd_tunnel/{tunnel_id}/configurations`,
681
+ "config.originRequest.httpHostHeader",
682
+ "config.ingress.originRequest.httpHostHeader",
683
+ ],
684
+ [
685
+ `PUT ${A}/cfd_tunnel/{tunnel_id}/configurations`,
686
+ "config.originRequest.httpHostHeader",
687
+ "config.ingress.originRequest.httpHostHeader",
688
+ ],
689
+ [`GET ${A}/cloudforce-one/rules/structured/schema`, "headers"],
690
+ [`GET ${A}/custom_pages`, "required_tokens"],
691
+ [`GET ${A}/custom_pages/{identifier}`, "required_tokens"],
692
+ [`PUT ${A}/custom_pages/{identifier}`, "required_tokens"],
693
+ [`GET ${Z}/custom_pages`, "required_tokens"],
694
+ [`GET ${Z}/custom_pages/{identifier}`, "required_tokens"],
695
+ [`PUT ${Z}/custom_pages/{identifier}`, "required_tokens"],
696
+ [`GET ${A}/data-security/posture/content`, "integration.credentials_expiry", "integration.last_hydrated"],
697
+ [`GET ${A}/data-security/posture/findings`, "integration.credentials_expiry", "integration.last_hydrated"],
698
+ [
699
+ `POST ${A}/data-security/posture/findings/ignore`,
700
+ "integration.credentials_expiry",
701
+ "integration.last_hydrated",
702
+ ],
703
+ [
704
+ `POST ${A}/data-security/posture/findings/unignore`,
705
+ "integration.credentials_expiry",
706
+ "integration.last_hydrated",
707
+ ],
708
+ [
709
+ `GET ${A}/data-security/posture/findings/{finding_id}`,
710
+ "integration.credentials_expiry",
711
+ "integration.last_hydrated",
712
+ ],
713
+ [
714
+ `POST ${A}/data-security/posture/findings/{finding_id}/reset_finding_severity`,
715
+ "integration.credentials_expiry",
716
+ "integration.last_hydrated",
717
+ ],
718
+ [
719
+ `POST ${A}/data-security/posture/findings/{finding_id}/tune_finding_severity`,
720
+ "integration.credentials_expiry",
721
+ "integration.last_hydrated",
722
+ ],
723
+ [`GET ${A}/data-security/posture/remediations/jobs`, "triggered_by_user"],
724
+ [`POST ${A}/data-security/posture/remediations/jobs`, "created.triggered_by_user"],
725
+ [`GET ${A}/email-security/investigate/{investigate_id}/detections`, "headers"],
726
+ [`GET ${A}/images/v2/metadata/keys`, "keys"],
727
+ [`GET ${A}/logs/audit`, "actor.context"],
728
+ [`GET ${A}/logs/audit/{id}/history`, "actor.context"],
729
+ [`GET ${A}/logs/list`, "keys"],
730
+ [
731
+ `GET ${A}/one/applications/{application_id}/auth-methods`,
732
+ "instructions",
733
+ "payload_example",
734
+ "payload_schema",
735
+ ],
736
+ [`POST ${A}/one/integrations`, "credentials_expiry", "authorization_link"],
737
+ [`GET ${A}/one/integrations/{id}`, "credentials_expiry", "authorization_link"],
738
+ [`PATCH ${A}/one/integrations/{id}`, "credentials_expiry", "authorization_link"],
739
+ [`POST ${A}/one/integrations/{id}/pause`, "credentials_expiry", "authorization_link"],
740
+ [`POST ${A}/one/integrations/{id}/resume`, "credentials_expiry", "authorization_link"],
741
+ [`GET ${A}/r2/buckets/{bucket_name}/cors`, "rules.allowed.headers", "rules.exposeHeaders"],
742
+ [`POST ${A}/realtime/kit/{app_id}/presets`, "data.ui.design_tokens"],
743
+ [`GET ${A}/realtime/kit/{app_id}/presets/{preset_id}`, "data.ui.design_tokens"],
744
+ [`PUT ${A}/realtime/kit/{app_id}/presets/{preset_id}`, "data.ui.design_tokens"],
745
+ [`PATCH ${A}/realtime/kit/{app_id}/presets/{preset_id}`, "data.ui.design_tokens"],
746
+ [`DELETE ${A}/realtime/kit/{app_id}/presets/{preset_id}`, "data.ui.design_tokens"],
747
+ [`GET ${A}/slurper/jobs`, "source.keys"],
748
+ [`GET ${A}/slurper/jobs/{job_id}`, "source.keys"],
749
+ [`PUT ${A}/storage/kv/namespaces/{namespace_id}/bulk`, "unsuccessful_keys"],
750
+ [`POST ${A}/storage/kv/namespaces/{namespace_id}/bulk/delete`, "unsuccessful_keys"],
751
+ [`GET /organizations/{organization_id}/logs/audit`, "actor.context"],
752
+ [`GET /organizations/{organization_id}/logs/audit/{id}/history`, "actor.context"],
753
+ [`POST /subscriptions/{subscription_id}/consume`, "records.headers"],
754
+ [`GET ${Z}/managed_headers`, "managed_request_headers", "managed_response_headers"],
755
+ [`PATCH ${Z}/managed_headers`, "managed_request_headers", "managed_response_headers"],
756
+ ].map(([key, ...paths]) => [key, safe(DESCRIBED_ONLY, ...paths.filter(Boolean))])),
757
+ ...Object.fromEntries([
758
+ `GET ${A}/load_balancers/pools`,
759
+ `POST ${A}/load_balancers/pools`,
760
+ `PATCH ${A}/load_balancers/pools`,
761
+ `GET ${A}/load_balancers/pools/{pool_id}`,
762
+ `PUT ${A}/load_balancers/pools/{pool_id}`,
763
+ `PATCH ${A}/load_balancers/pools/{pool_id}`,
764
+ `GET /user/load_balancers/pools`,
765
+ `POST /user/load_balancers/pools`,
766
+ `PATCH /user/load_balancers/pools`,
767
+ `GET /user/load_balancers/pools/{pool_id}`,
768
+ `PUT /user/load_balancers/pools/{pool_id}`,
769
+ `PATCH /user/load_balancers/pools/{pool_id}`,
770
+ ].map((key) => [key, safe("An origin's header map is limited to Host.", "origins.header")])),
771
+ ...Object.fromEntries([
772
+ `GET ${A}/load_balancers`,
773
+ `POST ${A}/load_balancers`,
774
+ `GET ${A}/load_balancers/{load_balancer_id}`,
775
+ `PUT ${A}/load_balancers/{load_balancer_id}`,
776
+ `PATCH ${A}/load_balancers/{load_balancer_id}`,
777
+ `GET ${Z}/load_balancers`,
778
+ `POST ${Z}/load_balancers`,
779
+ `GET ${Z}/load_balancers/{load_balancer_id}`,
780
+ `PUT ${Z}/load_balancers/{load_balancer_id}`,
781
+ `PATCH ${Z}/load_balancers/{load_balancer_id}`,
782
+ ].map((key) => [
783
+ key,
784
+ safe("Session affinity names the headers to hash, not their values.", "session_affinity_attributes.headers", "rules.overrides.session_affinity_attributes.headers"),
785
+ ])),
786
+ ...Object.fromEntries([
787
+ `GET ${A}/rulesets/phases/{ruleset_phase}/entrypoint`,
788
+ `GET ${A}/rulesets/phases/{ruleset_phase}/entrypoint/versions/{ruleset_version}`,
789
+ `GET ${A}/rulesets/{ruleset_id}`,
790
+ `GET ${A}/rulesets/{ruleset_id}/versions/{ruleset_version}`,
791
+ `GET ${A}/rulesets/{ruleset_id}/versions/{ruleset_version}/by_tag/{rule_tag}`,
792
+ `GET ${Z}/rulesets/phases/{ruleset_phase}/entrypoint`,
793
+ `GET ${Z}/rulesets/phases/{ruleset_phase}/entrypoint/versions/{ruleset_version}`,
794
+ `GET ${Z}/rulesets/{ruleset_id}`,
795
+ `GET ${Z}/rulesets/{ruleset_id}/versions/{ruleset_version}`,
796
+ `GET ${Z}/rulesets/{ruleset_id}/versions/{ruleset_version}/by_tag/{rule_tag}`,
797
+ `POST ${A}/rulesets`,
798
+ `PUT ${A}/rulesets/phases/{ruleset_phase}/entrypoint`,
799
+ `PUT ${A}/rulesets/{ruleset_id}`,
800
+ `POST ${A}/rulesets/{ruleset_id}/rules`,
801
+ `PATCH ${A}/rulesets/{ruleset_id}/rules/{rule_id}`,
802
+ `DELETE ${A}/rulesets/{ruleset_id}/rules/{rule_id}`,
803
+ `POST ${Z}/rulesets`,
804
+ `PUT ${Z}/rulesets/phases/{ruleset_phase}/entrypoint`,
805
+ `PUT ${Z}/rulesets/{ruleset_id}`,
806
+ `POST ${Z}/rulesets/{ruleset_id}/rules`,
807
+ `PATCH ${Z}/rulesets/{ruleset_id}/rules/{rule_id}`,
808
+ `DELETE ${Z}/rulesets/{ruleset_id}/rules/{rule_id}`,
809
+ ].map((key) => [key, RULESET])),
810
+ ...Object.fromEntries([
811
+ `GET ${Z}/custom_certificates`,
812
+ `POST ${Z}/custom_certificates`,
813
+ `PUT ${Z}/custom_certificates/prioritize`,
814
+ `GET ${Z}/custom_certificates/{custom_certificate_id}`,
815
+ `PATCH ${Z}/custom_certificates/{custom_certificate_id}`,
816
+ `GET ${Z}/ssl/certificate_packs`,
817
+ `POST ${Z}/ssl/certificate_packs/order`,
818
+ `GET ${Z}/ssl/certificate_packs/{certificate_pack_id}`,
819
+ `PATCH ${Z}/ssl/certificate_packs/{certificate_pack_id}`,
820
+ ].map((key) => [
821
+ key,
822
+ safe(DESCRIBED_ONLY, "geo_restrictions", "policy_restrictions", "certificates.geo_restrictions"),
823
+ ])),
824
+ // Round 3 (#801): candidates the consolidated detector surfaced (the union
825
+ // of the two former detectors, with transfer, claim, invite, key, signing,
826
+ // and webhook families).
827
+ [`GET ${A}/abuse-reports/submitted/{report_id}`]: safe("An abuse report; the authorization statement is the reporter's text."),
828
+ [`GET ${A}/access/keys`]: safe("Signing key rotation settings; no key."),
829
+ [`PUT ${A}/access/keys`]: safe("Signing key rotation settings; no key."),
830
+ ...Object.fromEntries([
831
+ `GET ${A}/access/organizations`,
832
+ `POST ${A}/access/organizations`,
833
+ `PUT ${A}/access/organizations`,
834
+ `GET ${A}/access/organizations/doh`,
835
+ `PUT ${A}/access/organizations/doh`,
836
+ `GET ${Z}/access/organizations`,
837
+ `POST ${Z}/access/organizations`,
838
+ `PUT ${Z}/access/organizations`,
839
+ ].map((key) => [key, safe("Organization session and service-token policies; durations and flags, no token.")])),
840
+ ...Object.fromEntries([
841
+ `GET ${A}/ai-gateway/custom-providers/costs`,
842
+ `POST ${A}/ai-gateway/custom-providers/costs`,
843
+ `GET ${A}/ai-gateway/custom-providers/costs/{id}`,
844
+ `PATCH ${A}/ai-gateway/custom-providers/costs/{id}`,
845
+ `DELETE ${A}/ai-gateway/custom-providers/costs/{id}`,
846
+ ].map((key) => [key, safe("Per-token model pricing; no credential.")])),
847
+ ...Object.fromEntries([
848
+ `GET ${A}/ai-gateway/gateways/{gateway_id}/datasets`,
849
+ `POST ${A}/ai-gateway/gateways/{gateway_id}/datasets`,
850
+ `GET ${A}/ai-gateway/gateways/{gateway_id}/datasets/{id}`,
851
+ `PUT ${A}/ai-gateway/gateways/{gateway_id}/datasets/{id}`,
852
+ `DELETE ${A}/ai-gateway/gateways/{gateway_id}/datasets/{id}`,
853
+ ].map((key) => [key, safe("Dataset filters match log fields (model, cost, tokens).", "filters.value")])),
854
+ ...Object.fromEntries([
855
+ `GET ${A}/ai-gateway/gateways/{gateway_id}/evaluations`,
856
+ `POST ${A}/ai-gateway/gateways/{gateway_id}/evaluations`,
857
+ `GET ${A}/ai-gateway/gateways/{gateway_id}/evaluations/{id}`,
858
+ `DELETE ${A}/ai-gateway/gateways/{gateway_id}/evaluations/{id}`,
859
+ ].map((key) => [key, safe("Evaluation datasets filter log fields.", "datasets.filters.value")])),
860
+ [`GET ${A}/ai-gateway/gateways/{gateway_id}/logs`]: safe("Gateway logs with token counts; no credential."),
861
+ [`GET ${A}/ai-gateway/gateways/{gateway_id}/logs/{id}`]: safe("A gateway log with token counts; no credential."),
862
+ ...Object.fromEntries([
863
+ `GET ${A}/ai-gateway/gateways/{gateway_id}/provider_configs`,
864
+ `POST ${A}/ai-gateway/gateways/{gateway_id}/provider_configs`,
865
+ `GET ${A}/ai-gateway/gateways/{gateway_id}/provider_configs/{id}`,
866
+ `DELETE ${A}/ai-gateway/gateways/{gateway_id}/provider_configs/{id}`,
867
+ ].map((key) => [key, safe("The caller supplies the provider key; the response returns a masked preview.")])),
868
+ [`POST ${A}/ai/run/{model_name}`]: safe("Model output and token usage counts; no credential."),
869
+ [`GET ${A}/alerting/v3/destinations/webhooks`]: WEBHOOK_DESTINATION,
870
+ [`POST ${A}/alerting/v3/destinations/webhooks`]: safe(ANSWERS_ID),
871
+ [`GET ${A}/alerting/v3/destinations/webhooks/{webhook_id}`]: WEBHOOK_DESTINATION,
872
+ [`PUT ${A}/alerting/v3/destinations/webhooks/{webhook_id}`]: safe(ANSWERS_ID),
873
+ [`DELETE ${A}/alerting/v3/destinations/webhooks/{webhook_id}`]: safe(REVOKES),
874
+ [`GET ${A}/billable/usage`]: safe(COUNTS),
875
+ [`POST ${A}/billable/usage`]: safe(COUNTS),
876
+ [`GET /organizations/{organization_id}/billable/usage`]: safe(COUNTS),
877
+ ...Object.fromEntries([
878
+ `POST ${A}/cloudforce-one/requests`,
879
+ `POST ${A}/cloudforce-one/requests/new`,
880
+ `GET ${A}/cloudforce-one/requests/priority/quota`,
881
+ `GET ${A}/cloudforce-one/requests/priority/{priority_id}`,
882
+ `PUT ${A}/cloudforce-one/requests/priority/{priority_id}`,
883
+ `GET ${A}/cloudforce-one/requests/{request_id}`,
884
+ `PUT ${A}/cloudforce-one/requests/{request_id}`,
885
+ `POST ${A}/cloudforce-one/v2/requests/{project_type}`,
886
+ `GET ${A}/cloudforce-one/v2/requests/{project_type}/{request_id}`,
887
+ `PUT ${A}/cloudforce-one/v2/requests/{project_type}/{request_id}`,
888
+ ].map((key) => [key, safe(COUNTS, "tokens")])),
889
+ ...Object.fromEntries([
890
+ `GET ${A}/cloudforce-one/requests/priority/quota`,
891
+ `GET ${A}/cloudforce-one/requests/quota`,
892
+ `GET ${A}/cloudforce-one/v2/requests/{project_type}/constants`,
893
+ `GET ${A}/cloudforce-one/v2/requests/{project_type}/types`,
894
+ ].map((key) => [key, safe(COUNTS)])),
895
+ ...Object.fromEntries([
896
+ [`GET ${A}/cloudforce-one/rules`, "rules.meta.value"],
897
+ [`POST ${A}/cloudforce-one/rules`, "meta.value"],
898
+ [`GET ${A}/cloudforce-one/rules/approvals/{id}`, "approval.current_rule.meta.value"],
899
+ [`GET ${A}/cloudforce-one/rules/search`, "results.meta.value"],
900
+ [`GET ${A}/cloudforce-one/rules/structured`, "rules.meta.value"],
901
+ [`POST ${A}/cloudforce-one/rules/structured`, "meta.value"],
902
+ [`PUT ${A}/cloudforce-one/rules/structured/approvals/{id}`, "approval.current_rule.meta.value"],
903
+ [`GET ${A}/cloudforce-one/rules/structured/{id}`, "meta.value"],
904
+ [`PUT ${A}/cloudforce-one/rules/structured/{id}`, "meta.value"],
905
+ [`GET ${A}/cloudforce-one/rules/{id}`, "meta.value"],
906
+ [`PUT ${A}/cloudforce-one/rules/{id}`, "meta.value"],
907
+ ].map(([key, path]) => [key, safe("Detection rule metadata (key, type, value); no credential.", path)])),
908
+ [`GET ${A}/cloudforce-one/v2/threat-signals/search`]: safe("Searches threat intelligence articles; no credential."),
909
+ [`GET ${A}/cni/interconnects/{icon}/loa`]: safe("A Letter of Authorization for a cross-connect; no credential."),
910
+ [`POST ${A}/data-security/posture/webhooks/evaluate`]: safe("Answers a delivery test's status and message."),
911
+ [`POST ${A}/data-security/posture/webhooks/jobs`]: safe("Answers created and failed job ids."),
912
+ [`DELETE ${A}/data-security/posture/webhooks/{webhook_id}`]: safe(REVOKES),
913
+ [`POST ${A}/data-security/posture/webhooks/{webhook_id}/evaluate`]: safe("Answers a delivery test's status and message."),
914
+ [`GET ${A}/devices/physical-devices`]: safe(CURSOR),
915
+ [`GET ${A}/devices/registrations`]: safe(CURSOR),
916
+ [`DELETE ${A}/devices/registrations`]: safe(CURSOR),
917
+ [`GET ${A}/r2/buckets`]: safe(CURSOR),
918
+ [`GET ${A}/registrar-sandbox/extensions`]: safe(CURSOR),
919
+ [`GET ${A}/registrar/extensions`]: safe(CURSOR),
920
+ ...Object.fromEntries([
921
+ `GET ${A}/devices/posture`,
922
+ `POST ${A}/devices/posture`,
923
+ `GET ${A}/devices/posture/{rule_id}`,
924
+ `PUT ${A}/devices/posture/{rule_id}`,
925
+ ].map((key) => [key, safe("Device posture rules; check_private_key is a boolean.")])),
926
+ ...Object.fromEntries([
927
+ `GET ${A}/dlp/datasets`,
928
+ `GET ${A}/dlp/datasets/{dataset_id}`,
929
+ `PUT ${A}/dlp/datasets/{dataset_id}`,
930
+ `POST ${A}/dlp/datasets/{dataset_id}/upload/{version}`,
931
+ `GET ${A}/dlp/entries`,
932
+ `GET ${A}/dlp/entries/{entry_id}`,
933
+ `PUT ${A}/dlp/entries/{entry_id}`,
934
+ ].map((key) => [key, safe(DLP_FLAG, "secret")])),
935
+ ...Object.fromEntries([
936
+ `GET ${A}/dlp/profiles`,
937
+ `GET ${A}/dlp/profiles/custom`,
938
+ `POST ${A}/dlp/profiles/custom`,
939
+ `GET ${A}/dlp/profiles/custom/{profile_id}`,
940
+ `PUT ${A}/dlp/profiles/custom/{profile_id}`,
941
+ `POST ${A}/dlp/profiles/predefined`,
942
+ `GET ${A}/dlp/profiles/predefined/{profile_id}`,
943
+ `PUT ${A}/dlp/profiles/predefined/{profile_id}`,
944
+ `GET ${A}/dlp/profiles/predefined/{profile_id}/config`,
945
+ `POST ${A}/dlp/profiles/predefined/{profile_id}/config`,
946
+ `PUT ${A}/dlp/profiles/predefined/{profile_id}/config`,
947
+ `GET ${A}/dlp/profiles/{profile_id}`,
948
+ ].map((key) => [key, safe(DLP_FLAG, "entries.secret", "shared_entries.secret")])),
949
+ [`GET ${A}/email-security/settings/domains/{domain_id}/verification`]: safe("The TXT record value is published in DNS to prove ownership."),
950
+ ...Object.fromEntries([
951
+ `GET ${A}/gateway/locations`,
952
+ `POST ${A}/gateway/locations`,
953
+ `GET ${A}/gateway/locations/{location_id}`,
954
+ `PUT ${A}/gateway/locations/{location_id}`,
955
+ ].map((key) => [key, safe("Gateway locations; require_token is a boolean.")])),
956
+ ...Object.fromEntries([
957
+ `GET ${A}/hyperdrive/configs`,
958
+ `POST ${A}/hyperdrive/configs`,
959
+ `GET ${A}/hyperdrive/configs/{hyperdrive_id}`,
960
+ `PUT ${A}/hyperdrive/configs/{hyperdrive_id}`,
961
+ `PATCH ${A}/hyperdrive/configs/{hyperdrive_id}`,
962
+ `POST ${A}/hyperdrive/configs/{hyperdrive_id}/restart`,
963
+ ].map((key) => [key, HYPERDRIVE])),
964
+ ...Object.fromEntries([
965
+ [`GET ${A}/iam/resource_groups`, "meta.value"],
966
+ [`POST ${A}/iam/resource_groups`, "meta.value"],
967
+ [`GET ${A}/iam/resource_groups/{resource_group_id}`, "meta.value"],
968
+ [`PUT ${A}/iam/resource_groups/{resource_group_id}`, "meta.value"],
969
+ [`GET ${A}/iam/user_groups`, "policies.resource_groups.meta.value"],
970
+ [`POST ${A}/iam/user_groups`, "policies.resource_groups.meta.value"],
971
+ [`GET ${A}/iam/user_groups/{user_group_id}`, "policies.resource_groups.meta.value"],
972
+ [`PUT ${A}/iam/user_groups/{user_group_id}`, "policies.resource_groups.meta.value"],
973
+ [`GET ${A}/members`, "policies.resource_groups.meta.value"],
974
+ [`POST ${A}/members`, "policies.resource_groups.meta.value"],
975
+ [`GET ${A}/members/{member_id}`, "policies.resource_groups.meta.value"],
976
+ [`PUT ${A}/members/{member_id}`, "policies.resource_groups.meta.value"],
977
+ [`GET /memberships`, "policies.resource_groups.meta.value"],
978
+ [`GET /memberships/{membership_id}`, "policies.resource_groups.meta.value"],
979
+ [`PUT /memberships/{membership_id}`, "policies.resource_groups.meta.value"],
980
+ [`GET /user/memberships/{membership_id}`, "policies.resource_groups.meta.value"],
981
+ ].map(([key, path]) => [key, safe("Resource group attributes scope a policy; no credential.", path)])),
982
+ ...Object.fromEntries([
983
+ `GET ${A}/k2/streams`,
984
+ `POST ${A}/k2/streams`,
985
+ `GET ${A}/k2/streams/{stream_id}`,
986
+ `PATCH ${A}/k2/streams/{stream_id}`,
987
+ ].map((key) => [
988
+ key,
989
+ safe("http.authentication is a boolean: whether producers need a token.", "http.authentication"),
990
+ ])),
991
+ ...Object.fromEntries([
992
+ `GET ${A}/magic/cloud/providers`,
993
+ `POST ${A}/magic/cloud/providers`,
994
+ `GET ${A}/magic/cloud/providers/{provider_id}`,
995
+ `PUT ${A}/magic/cloud/providers/{provider_id}`,
996
+ `PATCH ${A}/magic/cloud/providers/{provider_id}`,
997
+ ].map((key) => [key, safe("Cloud provider integrations report credential health timestamps, not credentials.")])),
998
+ ...Object.fromEntries([
999
+ `GET ${A}/mtls_certificates`,
1000
+ `POST ${A}/mtls_certificates`,
1001
+ `GET ${A}/mtls_certificates/{mtls_certificate_id}`,
1002
+ `DELETE ${A}/mtls_certificates/{mtls_certificate_id}`,
1003
+ `GET ${Z}/acm/custom_trust_store`,
1004
+ `POST ${Z}/acm/custom_trust_store`,
1005
+ `GET ${Z}/acm/custom_trust_store/{custom_origin_trust_store_id}`,
1006
+ `GET ${Z}/client_certificates`,
1007
+ `POST ${Z}/client_certificates`,
1008
+ `GET ${Z}/client_certificates/{client_certificate_id}`,
1009
+ `PATCH ${Z}/client_certificates/{client_certificate_id}`,
1010
+ `DELETE ${Z}/client_certificates/{client_certificate_id}`,
1011
+ `GET ${Z}/origin_tls_client_auth/hostnames/certificates`,
1012
+ `POST ${Z}/origin_tls_client_auth/hostnames/certificates`,
1013
+ `GET ${Z}/origin_tls_client_auth/hostnames/certificates/{certificate_id}`,
1014
+ `DELETE ${Z}/origin_tls_client_auth/hostnames/certificates/{certificate_id}`,
1015
+ `GET ${Z}/origin_tls_client_auth/hostnames/{hostname}`,
1016
+ `GET ${Z}/ssl/verification`,
1017
+ ].map((key) => [key, safe(CERTIFICATE)])),
1018
+ ...Object.fromEntries([
1019
+ `GET ${A}/oauth_clients`,
1020
+ `GET ${A}/oauth_clients/{oauth_client_id}`,
1021
+ `PATCH ${A}/oauth_clients/{oauth_client_id}`,
1022
+ ].map((key) => [
1023
+ key,
1024
+ safe("OAuth client registrations: ids, URIs, and whether a secret was rotated; the secret itself is refused at creation."),
1025
+ ])),
1026
+ [`GET ${A}/one/applications/{application_id}/setup-flows`]: safe("Setup flows describe the OAuth authorization URL and form fields to fill, not credentials.", "steps.form_fields.name", "steps.form_fields.type"),
1027
+ ...Object.fromEntries([
1028
+ `GET ${A}/realtime/kit/{app_id}/meetings`,
1029
+ `POST ${A}/realtime/kit/{app_id}/meetings`,
1030
+ `GET ${A}/realtime/kit/{app_id}/meetings/{meeting_id}`,
1031
+ `PUT ${A}/realtime/kit/{app_id}/meetings/{meeting_id}`,
1032
+ `PATCH ${A}/realtime/kit/{app_id}/meetings/{meeting_id}`,
1033
+ ].map((key) => [key, KIT_MEETING_STORAGE])),
1034
+ ...Object.fromEntries([
1035
+ `POST ${A}/realtime/kit/{app_id}/recordings`,
1036
+ `GET ${A}/realtime/kit/{app_id}/recordings/{recording_id}`,
1037
+ `PUT ${A}/realtime/kit/{app_id}/recordings/{recording_id}`,
1038
+ ].map((key) => [key, KIT_RECORDING_STORAGE])),
1039
+ [`GET ${A}/realtime/kit/{app_id}/recordings`]: reviewed(KIT_STORAGE_REASON, storageCredentials("data.storage_config", "data.meeting.recording_config.storage_config")),
1040
+ ...Object.fromEntries([
1041
+ `GET ${A}/realtime/kit/{app_id}/webhooks`,
1042
+ `POST ${A}/realtime/kit/{app_id}/webhooks`,
1043
+ `GET ${A}/realtime/kit/{app_id}/webhooks/{webhook_id}`,
1044
+ `PUT ${A}/realtime/kit/{app_id}/webhooks/{webhook_id}`,
1045
+ `PATCH ${A}/realtime/kit/{app_id}/webhooks/{webhook_id}`,
1046
+ `DELETE ${A}/realtime/kit/{app_id}/webhooks/{webhook_id}`,
1047
+ ].map((key) => [key, KIT_WEBHOOK])),
1048
+ [`GET ${A}/realtime/kit/{app_id}/webhooks/all`]: safe("Lists event names a webhook can subscribe to."),
1049
+ [`POST ${A}/registrar/domain-transfer-check`]: safe("Answers transfer eligibility; no auth code."),
1050
+ [`POST ${A}/registrar/registrations/{domain_name}/transfer-in`]: safe("Answers a workflow status; the auth code is request input only."),
1051
+ [`GET ${A}/registrar/registrations/{domain_name}/transfer-in-status`]: safe("Answers a transfer status."),
1052
+ [`POST ${A}/storage/kv/namespaces/{namespace_id}/bulk/get`]: safe(KV_DATA),
1053
+ [`GET ${A}/storage/kv/namespaces/{namespace_id}/keys`]: safe("Lists key names and metadata in a namespace."),
1054
+ [`GET ${A}/storage/kv/namespaces/{namespace_id}/metadata/{key_name}`]: safe(KV_DATA),
1055
+ [`GET ${A}/storage/kv/namespaces/{namespace_id}/values/{key_name}`]: safe(KV_DATA),
1056
+ [`PUT ${A}/storage/kv/namespaces/{namespace_id}/values/{key_name}`]: safe("Answers a status; the value is request input."),
1057
+ [`DELETE ${A}/storage/kv/namespaces/{namespace_id}/values/{key_name}`]: safe(REVOKES),
1058
+ [`DELETE ${A}/stream/webhook`]: safe(REVOKES),
1059
+ [`GET ${A}/tags/keys`]: safe("Lists resource tag keys; no credential."),
1060
+ [`GET ${A}/tags/summary`]: safe("Summarizes resource tags; no credential."),
1061
+ ...Object.fromEntries([`POST ${A}/vuln_scanner/scans`, `GET ${A}/vuln_scanner/scans/{scan_id}`].map((key) => [
1062
+ key,
1063
+ safe("Scan reports name the credential set a step used; credential values stay write-only.", "report.report.tests.steps.request.credential_set"),
1064
+ ])),
1065
+ ...Object.fromEntries([
1066
+ `GET ${A}/waiting_rooms`,
1067
+ `GET ${Z}/waiting_rooms`,
1068
+ `POST ${Z}/waiting_rooms`,
1069
+ `GET ${Z}/waiting_rooms/{waiting_room_id}`,
1070
+ `PUT ${Z}/waiting_rooms/{waiting_room_id}`,
1071
+ `PATCH ${Z}/waiting_rooms/{waiting_room_id}`,
1072
+ `GET ${Z}/waiting_rooms/settings`,
1073
+ `PUT ${Z}/waiting_rooms/settings`,
1074
+ `PATCH ${Z}/waiting_rooms/settings`,
1075
+ ].map((key) => [key, safe("Waiting room settings; cookie attributes and the crawler bypass are flags.")])),
1076
+ [`GET ${A}/workers/dispatch/namespaces/{dispatch_namespace}/scripts/{script_name}/bindings`]: BINDING_VALUES,
1077
+ ...Object.fromEntries([
1078
+ `GET ${A}/workers/dispatch/namespaces/{dispatch_namespace}/scripts`,
1079
+ `GET ${A}/workers/dispatch/namespaces/{dispatch_namespace}/scripts/{script_name}`,
1080
+ `PUT ${A}/workers/dispatch/namespaces/{dispatch_namespace}/scripts/{script_name}`,
1081
+ `PUT ${A}/workers/dispatch/namespaces/{dispatch_namespace}/scripts/{script_name}/content`,
1082
+ `GET ${A}/workers/scripts`,
1083
+ `PUT ${A}/workers/scripts/{script_name}`,
1084
+ `PUT ${A}/workers/scripts/{script_name}/content`,
1085
+ `GET ${A}/workers/scripts/{script_name}/script-settings`,
1086
+ `PATCH ${A}/workers/scripts/{script_name}/script-settings`,
1087
+ `PUT ${A}/workers/services/{service_name}/environments/{environment_name}/content`,
1088
+ `GET ${A}/workers/services/{service_name}/environments/{environment_name}/settings`,
1089
+ `PATCH ${A}/workers/services/{service_name}/environments/{environment_name}/settings`,
1090
+ ].map((key) => [key, TRACE_POLICY()])),
1091
+ ...Object.fromEntries([
1092
+ `GET ${A}/workers/workers`,
1093
+ `POST ${A}/workers/workers`,
1094
+ `GET ${A}/workers/workers/{worker_id}`,
1095
+ `PUT ${A}/workers/workers/{worker_id}`,
1096
+ `PATCH ${A}/workers/workers/{worker_id}`,
1097
+ ].map((key) => [key, WORKER])),
1098
+ ...Object.fromEntries([
1099
+ [`GET ${A}/workers/observability/queries`, "parameters.filters.value", "parameters.havings.value"],
1100
+ [`POST ${A}/workers/observability/queries`, "parameters.filters.value", "parameters.havings.value"],
1101
+ [`GET ${A}/workers/observability/queries/{queryId}`, "parameters.filters.value", "parameters.havings.value"],
1102
+ [`PATCH ${A}/workers/observability/queries/{queryId}`, "parameters.filters.value", "parameters.havings.value"],
1103
+ [`DELETE ${A}/workers/observability/queries/{queryId}`, "parameters.filters.value", "parameters.havings.value"],
1104
+ [`POST ${A}/workers/observability/telemetry/keys`],
1105
+ [`POST ${A}/workers/observability/telemetry/values`, "value"],
1106
+ ...[`GET ${A}/workers/observability/shared/query/{id}`, `POST ${A}/workers/observability/telemetry/query`].map((key) => [
1107
+ key,
1108
+ "calculations.aggregates.groups.value",
1109
+ "calculations.series.data.groups.value",
1110
+ "compare.aggregates.groups.value",
1111
+ "compare.series.data.groups.value",
1112
+ "run.query.parameters.filters.value",
1113
+ "run.query.parameters.havings.value",
1114
+ ]),
1115
+ ].map(([key, ...paths]) => [key, safe(OBSERVABILITY, ...paths)])),
1116
+ ...Object.fromEntries([
1117
+ `GET ${A}/workflows/concurrency`,
1118
+ `POST ${A}/workflows/concurrency`,
1119
+ `GET ${A}/workflows/concurrency/{key_id}`,
1120
+ `PATCH ${A}/workflows/concurrency/{key_id}`,
1121
+ `DELETE ${A}/workflows/concurrency/{key_id}`,
1122
+ ].map((key) => [key, safe("Workflow concurrency keys: names and limits, not credentials.")])),
1123
+ [`GET /billing/rate_plans/{public_key}`]: safe("A public rate plan catalog entry."),
1124
+ [`PUT /organizations/{organization_id}/invites/{member_code}`]: safe("Accepts an invitation with a code the caller holds; answers the membership."),
1125
+ [`GET /radar/bots/{bot_slug}`]: safe("A verified bot's public profile."),
1126
+ [`GET /user/invites`]: safe("Invitation metadata (organization, roles, status); no invite code."),
1127
+ [`GET /user/invites/{invite_id}`]: safe("Invitation metadata (organization, roles, status); no invite code."),
1128
+ [`PATCH /user/invites/{invite_id}`]: safe("Answers the invitation's status; no invite code."),
1129
+ ...Object.fromEntries([`GET ${Z}/api_gateway/configuration`, `PUT ${Z}/api_gateway/configuration`].map((key) => [
1130
+ key,
1131
+ safe("auth_id_characteristics name the header or cookie that identifies a session, not its value.", "auth_id_characteristics.name"),
1132
+ ])),
1133
+ ...Object.fromEntries([
1134
+ `GET ${Z}/api_gateway/operations`,
1135
+ `POST ${Z}/api_gateway/operations`,
1136
+ `POST ${Z}/api_gateway/operations/item`,
1137
+ `GET ${Z}/api_gateway/operations/{operation_id}`,
1138
+ `GET ${Z}/schema_validation/schemas/{schema_id}/operations`,
1139
+ ].map((key) => [key, safe("API operations with session-count thresholds; no credential.")])),
1140
+ [`DELETE ${Z}/custom_hostnames/{custom_hostname_id}/certificate_pack/{certificate_pack_id}/certificates/{certificate_id}`]: safe(REVOKES),
1141
+ ...Object.fromEntries([`GET ${Z}/images/v1/flows`, `PUT ${Z}/images/v1/flows`].map((key) => [
1142
+ key,
1143
+ safe("Image flow transformation and trigger parameters.", "flows.transformations.value", "flows.trigger.params.value"),
1144
+ ])),
1145
+ [`POST ${Z}/secondary_dns/outgoing/disable`]: safe("Answers outgoing zone transfer status; no TSIG secret."),
1146
+ [`POST ${Z}/secondary_dns/outgoing/enable`]: safe("Answers outgoing zone transfer status; no TSIG secret."),
1147
+ [`GET ${Z}/secondary_dns/outgoing/status`]: safe("Answers outgoing zone transfer status; no TSIG secret."),
1148
+ };
1149
+ /**
1150
+ * Cloudflare's reviewed table. Pagination cursors share the credential
1151
+ * vocabulary but grant nothing; redacting them would break paging, so they
1152
+ * are reviewed metadata wherever they appear.
1153
+ */
1154
+ export const CLOUDFLARE_VALUE_SAFETY = {
1155
+ title: "Cloudflare",
1156
+ operations: OPERATIONS,
1157
+ fields: {
1158
+ ...Object.fromEntries([
1159
+ "page_token",
1160
+ "pageToken",
1161
+ "next_page_token",
1162
+ "nextPageToken",
1163
+ "continuation_token",
1164
+ "continuationToken",
1165
+ "next_continuation_token",
1166
+ "nextContinuationToken",
1167
+ ].map((name) => [name, { verdict: "keep", reason: "A pagination cursor; it grants nothing." }])),
1168
+ signature: {
1169
+ verdict: "redact",
1170
+ reason: "Certificates name their signature algorithm here; withheld as credential vocabulary, as before.",
1171
+ },
1172
+ ...Object.fromEntries([
1173
+ ["claim_value", "An OIDC claim value an Access rule matches."],
1174
+ ["scopes", "OAuth scope names, not tokens."],
1175
+ ["token_url", "An IdP or SCIM token endpoint URL; public configuration."],
1176
+ ["authorization_url", "An OAuth authorization endpoint URL; public configuration."],
1177
+ ["certs_url", "A JWKS URL; public configuration."],
1178
+ ["redirect_uris", "OAuth redirect URIs; public configuration."],
1179
+ ["access_token_lifetime", "A token lifetime setting."],
1180
+ ["refresh_token_options", "Refresh token lifetime settings."],
1181
+ ["lifetime", "A lifetime setting."],
1182
+ ["group_filter_regex", "A group name filter."],
1183
+ ["name_by_idp", "Claim names per identity provider."],
1184
+ ["options_preflight_bypass", "A CORS preflight flag."],
1185
+ ["allow_pkce_without_client_secret", "An OAuth flow flag."],
1186
+ ["return_access_token_from_authorization_endpoint", "An OAuth flow flag."],
1187
+ ["return_id_token_from_authorization_endpoint", "An OAuth flow flag."],
1188
+ ["allow_credentials", "A CORS flag."],
1189
+ ["strict_service_token_auth", "A service token policy flag."],
1190
+ ["service_token_inactivity", "A service token inactivity policy."],
1191
+ ["amr_matching_session_duration", "A session duration."],
1192
+ ["doh_jwt_duration", "A token lifetime setting."],
1193
+ ["token_endpoint_auth_method", "An OAuth client authentication method name."],
1194
+ ["has_rotated_secret", "Whether a client secret was rotated; a flag."],
1195
+ ["secret_preview", "A masked preview of a caller-supplied key."],
1196
+ ["token_pricing", "Per-token model pricing."],
1197
+ ["tokens_in", "A token count."],
1198
+ ["tokens_out", "A token count."],
1199
+ ["message_tokens", "A token count."],
1200
+ ["request_tokens", "A token count."],
1201
+ ["response_tokens", "A token count."],
1202
+ ["prompt_tokens", "A token count."],
1203
+ ["completion_tokens", "A token count."],
1204
+ ["priority_token_surcharge", "A request cost."],
1205
+ ["auth_id_tokens", "A count of session identifiers seen."],
1206
+ ["keyword_tokenizer", "A search tokenizer name."],
1207
+ ["require_token", "Whether a DoH endpoint requires a token; a flag."],
1208
+ ["check_private_key", "A posture check flag."],
1209
+ ["search_engine_crawler_bypass", "A waiting room flag."],
1210
+ ["allow_child_bypass", "A gateway rule flag."],
1211
+ ["bypass_parent_rule", "A gateway rule flag."],
1212
+ ["cookie_attributes", "Cookie attribute settings (SameSite, Secure)."],
1213
+ ["strip_set_cookie", "A cache rule flag."],
1214
+ ["cookie_fields", "Cookie names a rule logs."],
1215
+ ["cookieDomain", "The domain Zaraz writes cookies for."],
1216
+ ["enable_binding_cookie", "An Access flag."],
1217
+ ["http_only_cookie_attribute", "An Access cookie flag."],
1218
+ ["same_site_cookie_attribute", "An Access cookie setting."],
1219
+ ["path_cookie_attribute", "An Access cookie flag."],
1220
+ ["eager_redirect_cookie_setting", "An Access cookie setting."],
1221
+ ["host_header", "A hostname a rule sets."],
1222
+ ["propagation_policy", "A trace context propagation policy name."],
1223
+ ["credentials_good_since", "A credential health timestamp."],
1224
+ ["credentials_missing_since", "A credential health timestamp."],
1225
+ ["credentials_rejected_since", "A credential health timestamp."],
1226
+ ["is_secret", "Whether a variable is hidden; a flag."],
1227
+ ["is_selectable", "Whether a permission group is selectable; a flag."],
1228
+ ["case_sensitive", "A DLP matching flag."],
1229
+ ["byok_only", "Whether a gateway requires caller-supplied keys; a flag."],
1230
+ ["sign_request", "Whether SAML requests are signed; a flag."],
1231
+ ["signatureAgentUrl", "A verified bot's public key directory URL."],
1232
+ ["reg_who_authorization_statement", "An abuse reporter's statement."],
1233
+ ["password_expression", "An expression locating a password field, not a password."],
1234
+ ["username_expression", "An expression locating a username field."],
1235
+ ["token_sources", "Header or cookie names a token is read from."],
1236
+ ["http_body", "A domain control validation token, published on the origin."],
1237
+ ["http_url", "Where a domain control validation token is published."],
1238
+ ["txt_record_value", "A TXT record value published in DNS."],
1239
+ ["author_email", "A deployment author's email."],
1240
+ ["BilledCost", "A billed amount."],
1241
+ ["EffectiveCost", "A billed amount."],
1242
+ ["quota", "A request quota."],
1243
+ ["remaining", "A remaining request count."],
1244
+ ["id", "An identifier."],
1245
+ ].map(([name, reason]) => [name, { verdict: "keep", reason }])),
1246
+ },
1247
+ };