Skip to content

Add mapbox report, sent with the CLI's token first - #100

Merged
zmofei merged 9 commits into
cli-token-endpointfrom
report-command
Oct 19, 2026
Merged

zmofei merged 9 commits into
cli-token-endpointfrom
report-command

Conversation

@zmofei

@zmofei zmofei commented Oct 19, 2026 •

Copy link
Copy Markdown
Member

Adds mapbox report "<message>", which sends feedback about the CLI to the Feedback API's CLI endpoint. Stacked on #99.

  • Feedback is filed under Mapbox's own account, so report is the CLI's request rather than the user's. It is the first entry in CLI_TOKEN_COMMANDS as Use::Preferred: it sends with the CLI's token and its Referer (see Fetch the CLI's token from cli.mapbox.com instead of building it in #99), and falls back to the user's token while the CLI's can't be used. The request then carries the user's token, but the message is still filed under Mapbox's account. A typed --token or --use-login sends with the user's token, and the CLI's is not tried. With no user token either, it fails with cli_token_unavailable or cli_token_forbidden, with a fix pointing at mapbox auth login or --token.
  • The message goes out with the CLI's version and OS appended (— mapbox-cli <version> on <os>). The Feedback API has no field for them, so they go in the text, where --dry-run shows them.
  • A command someone is waiting on is never paced. It uses the token on disk or fetches past any backoff, and a miss on that fetch is not counted, so report never lengthens telemetry's backoff. When report's request is refused (401/403), a fresh token is fetched and the message sent again if a different one comes back, unless this run just fetched it. A 429 on the CLI's token falls back to the user's token without being counted: every install shares that token, and a 429 was not acted on. The next run tries the CLI's token again, so a token republished or fixed in the Console works at once. Telemetry keeps Fetch the CLI's token from cli.mapbox.com instead of building it in #99's cooldown.
  • Telemetry settings don't apply to report: the token is shared and public, and fetching it sends nothing about the user.
  • The rules for sending with the CLI's token live in cli_token::send_with_cli_token, used by telemetry and commands alike; Disk::Background, Disk::Command and Disk::Unchecked hold where they differ.
  • MAPBOX_CLI_TOKEN is tried first, sent once, and never checked, counted or replaced, as telemetry treats it. A resend doesn't ask for confirmation again, and a command on the list may not read its body from stdin (held by a test), since a resend couldn't read it twice.
  • An empty or blank message is refused before sending. A message starting with - gets a tip that quotes it whole and says to put it after --.
  • Under -o text, a successful report shows only that it was sent, the message and its id; -o json prints the answer whole. A dry run under -o text shows the body and which token it would use.

Testing: unit tests for send_with_cli_token against a fake ledger (a dead token replaced and resent, a command retrying after any refusal, the same token not resent, only a 2xx accepted), for which ledgers retry, for only a 429 falling back, for the version and OS suffix, and for the report rendering. End-to-end tests for what is decided before any request reaches Mapbox, through a dead proxy and a loopback token endpoint: no token at all (and the fix it gives), a typed --token outranking the CLI's, a cooldown not holding report back, report fetching through the backoff, an unreachable endpoint reported as such during a backoff, a command's miss leaving the backoff alone, the Referer going with the CLI's token but not the user's, a dry run planning with the user's token, the dry run's body and token under -o text, an empty message refused, and the tip for a message starting with -. Ran the end-to-end tests against the commit before each round of fixes and watched the new ones fail. Posted to the real endpoint with curl: the CLI's token answers 401 without its Referer and 200 with it; a user's token answers 200 with and without any user-feedback scope. Sent a real mapbox report on the CLI's token: 200, and the API kept the version and OS suffix. The Outputs in docs/commands.md are that send, shown both ways.

Not tested: a real 429 on the CLI's token, and a refused MAPBOX_CLI_TOKEN not being replaced end to end (no way to point the API at loopback; unit-tested only). A run on the CLI's token is not recorded as a token source in history or telemetry, which would need a new auth.source value.

@zmofei
zmofei added this pull request to stack #101 October 19, 2026 12:08
@zmofei
zmofei force-pushed the report-command branch 3 times, most recently from eff5f80 to 79af713 Compare October 19, 2026 13:55
@zmofei
zmofei marked this pull request as ready for review October 19, 2026 14:03
@zmofei
zmofei requested a review from a team as a code owner October 19, 2026 14:03

@mattpodwysocki mattpodwysocki left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Read through this one and ran the tests locally, all green. What goes out is just the message and category, nothing from the environment, and a resend only follows a 401/403 so there's no double send. Mostly UX and wording inline. Two broader thoughts:

  • Reports carry no CLI version or OS. The User-Agent has the version, but I doubt the Feedback API keeps it, so a "tilesets query hangs" report arrives with nothing to go on. Adding version and OS to the body (so --dry-run shows them) seems worth it.
  • Only 401/403 fall back. Every install shares one token, so if the Feedback API rate-limits that account, everyone gets a 429 even though their own token would work. A 429 wasn't processed either, so falling back on it looks safe.

Small ones: an empty or whitespace-only message is accepted and sent, a message starting with - hits a usage error with no hint about --, and the two ids in the commands.md outputs table don't match.

Comment thread custom-openapi/report/openapi/report.yaml Outdated
Comment thread src/main.rs Outdated
Comment thread docs/commands.md Outdated
Comment thread README.md Outdated
@zmofei

zmofei commented Oct 19, 2026

Copy link
Copy Markdown
Member Author

Thanks! Addressed in 9d0c15d.

  • Version and OS are appended to the message (— mapbox-cli <version> on <os>), so --dry-run shows them. The Feedback API has no field for them, and I didn't check whether it keeps unknown fields, so they go in the text.
  • A 429 on the CLI's token now falls back to the user's token. It doesn't count against the CLI's token. With no token of their own, the 429 is returned as is.
  • An empty or blank message is refused before sending. A message starting with - gets a tip that quotes it whole and says to put it after --.

Not done yet: the ids in the commands.md outputs. They need a fresh live capture, which will also pick up the version suffix. I'll push that separately.

Tested: fmt, clippy and the full suite. The 5 new or changed end-to-end tests fail on 009a3b0. Not tested: a real send with the suffix, or a real 429 on the CLI's token.

Sends one message to the Feedback API's CLI endpoint, which files it under Mapbox's own account rather than the caller's. The message is the positional; lat/lon are sent as 0 and never typed.
Feedback about the CLI is filed under Mapbox's own account, so report is
the CLI's request rather than the user's. It is the first command in
CLI_TOKEN_COMMANDS, as Use::Preferred: it sends with the CLI's token, and
falls back to the user's only while the CLI's can't be used. With no token
of the user's either, it fails with cli_token_unavailable or
cli_token_forbidden, saying when the CLI's will be tried again.

The rules for sending with the CLI's token now live in one place,
cli_token::send_with_cli_token, which telemetry and commands both use:
check a refusal at once, replace a dead token and resend once, rest from
an API that refuses a valid one, and end the rest on a 2xx.

MAPBOX_CLI_TOKEN is tried before a cooldown, which is the fetched token's.
A refused request is resent without asking for confirmation again, and a
command on the list may not read its body from stdin, which a resend
could not read twice.
A command on the CLI's token now sends cli_token::REFERER, through a referer field on RunFlags that only the CLI-token attempt sets; the user's token, when it stands in, goes without. --debug prints the Referer when there is one.
A command someone is waiting on is never paced. When report's request is refused, for any reason, the token endpoint is asked there and then, past any backoff, and the message is sent again with a different token if there is one; otherwise the user's token stands in. The next run tries the CLI's token again, so a token republished or fixed in the Console works at once. Telemetry keeps the cooldown.
Under -o text, a successful report says it was sent and shows the message and its id. The timestamps, the always-received status, the 0,0 place and the screenshot flag are the Feedback API's record, which the sender neither chose nor can act on. -o json still prints the answer whole.
A typed --token or --use-login now sends with the user's token, and the CLI's is not tried. MAPBOX_CLI_TOKEN is sent once and never checked, counted or replaced, as telemetry treats it. A command uses the token on disk or fetches past the backoff, and a miss on that fetch is not counted, so report no longer lengthens telemetry's backoff or reports a wait it never took. A token fetched this run is not fetched again after a refusal. An unchecked refusal is cli_token_forbidden, not cli_token_unavailable.

Also: the repository URL is built from one macro, body fields are no longer cloned per request, and the report Outputs are captured live.
A report now ends with the CLI's version and OS, appended to the message since the Feedback API has no field for them. A 429 on the CLI's token falls back to the user's token, as 401/403 do: every install shares that token, and a 429 was not acted on. With no token of their own, the 429 is the answer.

An empty or blank message is refused, and a message starting with `-` gets a tip that quotes it whole and says to put it after `--`. The dry run shows the body and which token it would use under `-o text`, and no longer says "from --data". When the CLI's token can't be used and there is no other, the error explains what that token is and points at `mapbox auth login` or `--token`.

The help text, README and changelog now say the CLI's token goes first, that the user's token is on the request after a fallback, and that the version and OS are sent.
The token report fetches is shared and public, and fetching it sends nothing about the user, so it is not telemetry.
A report's message now has the CLI's version and OS on lines of its own, and -o text printed them back at the label column. They now go under the first line.

The Outputs in docs/commands.md are one live send, shown under -o text and -o json, so the two ids match. It was sent on the CLI's token with its Referer, and the API kept the version and OS.

@mattpodwysocki mattpodwysocki left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All addressed, thanks. The dry run showing the token and the full body is a nice improvement.

@zmofei
zmofei merged commit 4c8dd09 into main Oct 19, 2026
16 checks passed
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.

2 participants