Skip to content

fix: explain account-or-zone scope and reject an empty --zone - #422

Open
khoinguyenpham04 wants to merge 8 commits into
cloudflare:mainfrom
khoinguyenpham04:noah/account-or-zone-scope
Open

khoinguyenpham04 wants to merge 8 commits into
cloudflare:mainfrom
khoinguyenpham04:noah/account-or-zone-scope

Conversation

@khoinguyenpham04

@khoinguyenpham04 khoinguyenpham04 commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Closes #33.

Commands generated from /{account_or_zone}/{account_or_zone_id} paths already
run against the account by default, switch to a zone with --zone, and show
the chosen scope in --dry-run. This PR covers the rest of the issue:

  • Help: those 124 commands now say how they pick a scope.
  • Missing context: --zone without a value now fails. Before, it switched
    to zone scope with no zone ID.
  • Tests: CLOUDFLARE_ZONE_ID on its own keeps the account route. A command
    fails before any request when no account can be picked (a zone name needs
    one too) or the --zone name isn't found.

Before and after

1. Help explains which scope runs

Before, help only repeated the API description:

$ cf load-balancers account list --help
cf load-balancers account list

List configured account or zone-scoped load balancers.

Global flags
  ...

After, two lines say how the scope is picked:

$ cf load-balancers account list --help
cf load-balancers account list

List configured account or zone-scoped load balancers.

Runs against your account. Pass --zone to run against a zone instead.
CLOUDFLARE_ZONE_ID is ignored.

Global flags
  ...

2. --zone without a value fails

Before, the command switched to zone scope with an empty zone ID, so the
preview shows zones//:

$ cf load-balancers account list --zone --dry-run
{
  "command": "cf load-balancers account list",
  "method": "GET",
  "url": "https://api.cloudflare.com/client/v4/zones//load_balancers",
  "pathParams": {
    "account-or-zone": "zones",
    "account-or-zone-id": ""
  },
  "bodyKind": "none"
}

After, it stops with an error:

$ cf load-balancers account list --zone --dry-run

┌ Error
│ --zone requires a non-empty value.
└

Notes

  • These commands ignore CLOUDFLARE_ZONE_ID, so a variable set for zone-only
    commands can't quietly redirect them.
  • The global --zone is now validated like --mode: an empty value,
    --no-zone, or a repeated --zone fails. An empty value used to fall back
    to CLOUDFLARE_ZONE_ID only because an empty string is falsy, so this ships
    as a patch.
  • Pass-through commands still need -- before arguments that clash with cf's
    global flags. cf containers ssh <id> ls -z now fails instead of silently
    dropping the -z.
  • --dry-run makes no requests, so it doesn't resolve a zone name:
    --zone example.com --dry-run previews /zones/example.com/…, as zone-only
    commands already do.
  • The "no account" error comes from @cloudflare/workers-auth and doesn't
    mention --zone. I've left it as is.

An empty --zone switched account-or-zone commands to zone scope with no
zone ID, so --dry-run previewed /zones//… and a real run fell back to
CLOUDFLARE_ZONE_ID. Validate the global flag the way --mode is validated.
The 124 commands generated from /{account_or_zone}/{account_or_zone_id}
paths run against the account unless --zone is passed, but their help
only repeated the API description. Add one line to their usage saying so,
including that CLOUDFLARE_ZONE_ID doesn't switch the scope, and
regenerate.
…ands

Pin the rest of cloudflare#33's expected behaviour: CLOUDFLARE_ZONE_ID alone keeps
the account route, and a command fails before any request when no account
can be picked or the --zone name isn't found. The route tests now record
which scope each request went to.
"Doesn't switch the scope" sat oddly above the global --zone line, which
says the flag overrides CLOUDFLARE_ZONE_ID. These commands never read it,
so say that. The architecture note now says dry-run keeps a zone name as
given, since it makes no request.
Check the global flag on a zone-only command (-z, --zone=, --no-zone and a
repeated --zone), show that a zone name needs an account too, and stop
asserting on @cloudflare/workers-auth's wording.
@pkg-pr-new

pkg-pr-new Bot commented Oct 26, 2026 •

Copy link
Copy Markdown
npm i https://pkg.pr.new/cf@422

commit: 9a31384

@khoinguyenpham04
khoinguyenpham04 marked this pull request as ready for review October 26, 2026 16:41
@khoinguyenpham04
khoinguyenpham04 requested a review from a team as a code owner October 26, 2026 16:41
@clanky-the-clanker

clanky-the-clanker Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

💬 Approved with comments — No problems found. The generator change, the --zone validation and the tests look correct, and the earlier changeset suggestion has been addressed. Most of the regenerated command files were checked by sampling, not read one by one.

Findings: 2 info

The decision is advisory: this comment never approves, blocks or requests changes on the pull request.


🔒 Security: 💬 1 info

No security problems. Not every regenerated file was opened.

Recommendation: 💬 Optional Nits

  • [INFO] Not opened: the test files and most of the regenerated _generated/ command files, which change only help text.
View full review

No security problems found. With the new validation, an empty --zone can no longer produce a request to a /zones// path. Because the account-or-zone commands ignore CLOUDFLARE_ZONE_ID, a zone ID set in the environment cannot redirect them.


📋 Code Quality: 💬 1 info

No defects. Most of the regenerated command files were not read one by one.

Recommendation: 💬 Optional Nits

  • [INFO] Not reviewed line by line: about 121 regenerated files under packages/cli/src/commands/_generated/. The sampled files differ only by the appended scope help line.
View full review

No problems found in the generator (ACCOUNT_OR_ZONE_HELP is added only when ctx.hasAccountOrZoneScope is set), the --zone coerce in global-options.ts, or the new tests. The coerce does not affect other options, because no command defines its own zone option.


✅ All other checks passed

🚀 Release: ✅ LGTM

Risk: low. Both changesets describe their user-facing changes. .changeset/empty-zone-flag.md now says that a forwarded -z with no value fails and that forwarded arguments go after --, which resolves the earlier suggestion.


📖 AGENTS.md: ✅ LGTM

The change follows the repository conventions. Generated output comes from the generator plugin, and each user-facing change has a changeset.


⚡ Performance: ✅ LGTM

No performance concerns. The change adds help text and a check on the flag value.


📝 Documentation: ✅ LGTM

The docs/architecture.md note and the help text match the implemented behaviour.


Reviewed commit: 9a313845

@edmundhung

Copy link
Copy Markdown
Member

clanky review

Upstream moved GLOBAL_OPTIONS from src/index.ts to src/lib/global-options.ts,
so the --zone coerce moves with it. Regenerating at the new OpenAPI pin
(e2b8c60b0222) changes nothing: the same 124 account-or-zone commands carry
the scope help line.
@khoinguyenpham04

Copy link
Copy Markdown
Contributor Author

clanky review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Handle API operations that support either account or zone scope

2 participants