From 7b926dc65a88019f005ffe4d8d7a70ed38fc0aa5 Mon Sep 17 00:00:00 2001 From: rogu3bear Date: Wed, 1 Jul 2026 01:03:42 -0500 Subject: [PATCH] fix sender-domain lane guidance Sender-domain enablement is an Email Sending write path that needs the global lane for private maildesk zones. The catalog already drives command generation and capabilities docs, so pin the operation to the global lane, teach guide/classify to fall back to a single policy lane when live lane comparison has no answer, and add static contract coverage for the generated global-lane commands. --- catalog/surfaces.json | 1 + commands/cfctl.sh | 28 ++++++++++++++++++++++++---- docs/capabilities.md | 2 +- scripts/verify_static_contract.sh | 21 +++++++++++++++++++++ 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/catalog/surfaces.json b/catalog/surfaces.json index 898531e..59ff1c0 100644 --- a/catalog/surfaces.json +++ b/catalog/surfaces.json @@ -574,6 +574,7 @@ "enable": { "risk": "write", "required_selectors": ["zone", "name"], + "allowed_lanes": ["global"], "public_example": "cfctl apply sender_domain enable --zone example.com --name example.com --plan" } } diff --git a/commands/cfctl.sh b/commands/cfctl.sh index 25f9de8..809ea18 100644 --- a/commands/cfctl.sh +++ b/commands/cfctl.sh @@ -706,6 +706,26 @@ cfctl_recommended_lane_from_comparison() { jq -r '.summary.allowed_lanes[0] // empty' <<< "${comparison_json}" } +cfctl_recommended_lane_from_policy_or_comparison() { + local comparison_json="$1" + local policy_json="$2" + local recommended_lane + + recommended_lane="$(cfctl_recommended_lane_from_comparison "${comparison_json}")" + if [[ -n "${recommended_lane}" ]]; then + printf '%s\n' "${recommended_lane}" + return + fi + + jq -r ' + if ((.allowed_lanes // []) | length) == 1 then + .allowed_lanes[0] + else + "" + end + ' <<< "${policy_json}" +} + cfctl_select_requested_lane_if_available() { local requested_lane="${CF_TOKEN_LANE:-${CF_TOKEN_LANE_DEFAULT}}" @@ -2070,7 +2090,7 @@ cfctl_handle_classify() { selector_requirements_json="$(cfctl_requirement_check_json "${surface}" "${target_action}" "${operation}")" comparison_json="$(cfctl_compare_permission_all_lanes "${surface}" "${target_action}" "${operation}")" permission_json="$(jq -c --arg lane "${CF_ACTIVE_TOKEN_LANE:-}" '(.lanes | map(select(.lane == $lane)) | .[0].permission) // {state:"unknown", basis:"lane_unavailable", errors: [], request: null, status_code: null, permission_family: "Cloudflare API"}' <<< "${comparison_json}")" - recommended_lane="$(cfctl_recommended_lane_from_comparison "${comparison_json}")" + recommended_lane="$(cfctl_recommended_lane_from_policy_or_comparison "${comparison_json}" "${policy_json}")" public_example="$(jq -r '.public_example // empty' <<< "${policy_json}")" if [[ -z "${public_example}" || "${public_example}" == "null" ]]; then if [[ "${target_action}" == "apply" ]]; then @@ -2146,7 +2166,7 @@ cfctl_handle_classify() { "true" \ "${permission_json}" \ '{"state":"not_applicable"}' \ - "$(jq '{risk: .policy.risk, preview_required: .policy.preview_required, confirmation: .policy.confirmation, lock_strategy: .policy.lock_strategy, secret_policy: .policy.secret_policy, allowed_lanes: (.lane_comparison.summary.allowed_lanes // []), selector_ready: .selector_readiness.ready, recommended_lane: .lane_hint.recommended_lane, likely_failure_class: .likely_failure_class}' <<< "${result_json}")" \ + "$(jq '{risk: .policy.risk, preview_required: .policy.preview_required, confirmation: .policy.confirmation, lock_strategy: .policy.lock_strategy, secret_policy: .policy.secret_policy, allowed_lanes: (if ((.lane_comparison.summary.allowed_lanes // []) | length) > 0 then (.lane_comparison.summary.allowed_lanes // []) else (.policy.allowed_lanes // []) end), selector_ready: .selector_readiness.ready, recommended_lane: .lane_hint.recommended_lane, likely_failure_class: .likely_failure_class}' <<< "${result_json}")" \ "${result_json}" \ "" \ "" \ @@ -2361,11 +2381,11 @@ cfctl_handle_guide() { fi lane_comparison="$(cfctl_compare_permission_all_lanes "${surface}" "apply" "${requested_operation}")" current_lane="${CF_ACTIVE_TOKEN_LANE:-}" - recommended_lane="$(jq -r '.summary.allowed_lanes[0] // empty' <<< "${lane_comparison}")" + policy_json="$(cfctl_operation_policy_json "${surface}" "apply" "${requested_operation}")" + recommended_lane="$(cfctl_recommended_lane_from_policy_or_comparison "${lane_comparison}" "${policy_json}")" if [[ -n "${recommended_lane}" && "${recommended_lane}" != "${current_lane}" ]]; then command_prefix="CF_TOKEN_LANE=${recommended_lane} " fi - policy_json="$(cfctl_operation_policy_json "${surface}" "apply" "${requested_operation}")" preview_command="${command_prefix}$(cfctl_build_apply_command "${surface}" "${requested_operation}" " --plan")" apply_command="${command_prefix}$(cfctl_build_apply_command "${surface}" "${requested_operation}" " --ack-plan ")" diff --git a/docs/capabilities.md b/docs/capabilities.md index 7ce9f1d..c038bf3 100644 --- a/docs/capabilities.md +++ b/docs/capabilities.md @@ -79,7 +79,7 @@ This matrix is derived from the same catalogs used by `cfctl explain`, `cfctl cl | `security.txt` | `delete` | `destructive` | yes | `lease` | yes | `delete` | `dev`, `global` | required: zone | | `security.txt` | `upsert` | `write` | yes | `apply` | yes | `-` | `dev`, `global` | required: zone | | `security.txt` | `sync` | `write` | yes | `apply` | yes | `-` | `dev`, `global` | state match: zone | -| `sender_domain` | `enable` | `write` | yes | `apply` | yes | `-` | `dev`, `global` | required: zone, name | +| `sender_domain` | `enable` | `write` | yes | `apply` | yes | `-` | `global` | required: zone, name | | `tunnel` | `cleanup-connections` | `destructive` | yes | `lease` | yes | `delete` | `dev`, `global` | required: id | | `tunnel` | `configure` | `write` | yes | `apply` | yes | `-` | `dev`, `global` | required: id | | `tunnel` | `create` | `write` | yes | `apply` | yes | `-` | `dev`, `global` | - | diff --git a/scripts/verify_static_contract.sh b/scripts/verify_static_contract.sh index 84ac6d3..08d035f 100755 --- a/scripts/verify_static_contract.sh +++ b/scripts/verify_static_contract.sh @@ -290,6 +290,26 @@ jq -e ' and (.recommended_command | contains("--plan")) ' <<< "${email_routing_zone_guidance_json}" >/dev/null || die "email routing zone resolution lane guidance assertion failed" +sender_domain_guide_json="$( + env \ + -u CF_DEV_TOKEN \ + -u CF_GLOBAL_TOKEN \ + -u CLOUDFLARE_API_TOKEN \ + -u CLOUDFLARE_ACCOUNT_ID \ + CF_SHARED_ENV_FILE="/nonexistent/cfctl-empty-env" \ + CF_REPO_ENV_FILE="/nonexistent/cfctl-empty-env" \ + "${ROOT_DIR}/cfctl" guide sender_domain enable --zone example.com --name example.com +)" +jq -e ' + .ok == true + and .surface == "sender_domain" + and .operation == "enable" + and .result.lane_hint.recommended_lane == "global" + and (.result.commands.preview | startswith("CF_TOKEN_LANE=global cfctl apply sender_domain enable ")) + and (.result.commands.apply | startswith("CF_TOKEN_LANE=global cfctl apply sender_domain enable ")) + and (.result.commands.verify | startswith("CF_TOKEN_LANE=global cfctl verify sender_domain ")) +' <<< "${sender_domain_guide_json}" >/dev/null || die "sender-domain guide global lane assertion failed" + assert_jq_file "permission profile minimality policy" ' .profiles.read.allowed_surfaces != null and (.profiles.read.allowed_surfaces | index("audit.log")) != null @@ -731,6 +751,7 @@ assert_jq_file "surface module bindings" ' and .surfaces["sender_domain"].actions.apply.preview_required == true and .surfaces["sender_domain"].actions.apply.verification_required == true and .surfaces["sender_domain"].actions.apply.operations.enable.required_selectors == ["zone", "name"] + and .surfaces["sender_domain"].actions.apply.operations.enable.allowed_lanes == ["global"] and .surfaces["worker.route"].module == "worker_route" and .surfaces["worker.route"].standards_ref == "worker.route" and (.surfaces["worker.route"].docs_topics | index("workers-routes")) != null