Skip to content

Commit d10e190

Browse files
Merge main after #26 landed
Only CHANGELOG.md conflicted: #26 added an Added and a Fixed entry where this branch has a Changed block. All seven entries belong, so the section is now Added / Changed / Fixed, the order 0.2.0 uses. The source changes merged on their own.
2 parents bca373e + e96ce2b commit d10e190

28 files changed

Lines changed: 344 additions & 110 deletions

‎.github/workflows/ci.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ jobs:
3737
# six-hour default before anyone hears about it. That is not hypothetical —
3838
# a test that blocked on `accept()` with no deadline wedged the Windows leg
3939
# for its full six hours, and the only reason it went unnoticed for a day
40-
# is that every run on `main` was cancelled by the next push first.
40+
# is that every run on `main` was canceled by the next push first.
4141
#
4242
# On all three rather than Windows alone: nobody here runs Windows as a
4343
# daily driver, so CI is the only signal it has — but a Unix leg that
@@ -307,7 +307,7 @@ jobs:
307307
"https://github.com/rustsec/rustsec/releases/download/cargo-audit%2Fv${AUDIT_VERSION}/${name}.tgz"
308308
echo "${AUDIT_SHA256} /tmp/cargo-audit.tgz" | sha256sum -c -
309309
# The archive has a versioned top-level directory and carries a
310-
# README and two licences beside the binary; name the one file that
310+
# README and two licenses beside the binary; name the one file that
311311
# belongs on PATH.
312312
tar xzf /tmp/cargo-audit.tgz -C "$HOME/.cargo/bin" \
313313
--strip-components=1 "${name}/cargo-audit"

‎CHANGELOG.md‎

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ that may never merge. They are not releases and are not listed here.
1919

2020
## Unreleased
2121

22+
### Added
23+
24+
- The README now documents installing without the install script: the
25+
archives are plain HTTP downloads, `manifest.json` lists every target with
26+
its checksum, and the commands to verify and extract one are written out.
27+
Nothing new is published — this is the same channel the install script
28+
reads, for anyone whose employer does not allow piping a script into a
29+
shell.
30+
2231
### Changed
2332

2433
- The skill `mapbox generate-skills` writes now tells an agent which of the
@@ -70,6 +79,15 @@ that may never merge. They are not releases and are not listed here.
7079
the token still works and gives the `MAPBOX_ACCESS_TOKEN` line that keeps
7180
using it. The token itself is never printed, and a test holds that.
7281

82+
### Fixed
83+
84+
- The README described the published builds as signed. They are not
85+
code-signed with a Developer ID or an Authenticode certificate; what the
86+
install script checks is a SHA-256 checksum. The claim is gone, and the new
87+
section says what a macOS user hits because of it: Gatekeeper refuses an
88+
unsigned binary carrying a quarantine flag, which a browser download sets
89+
and `curl` does not.
90+
7391
## 0.2.2 - 2026-09-15
7492

7593
### Changed
@@ -175,15 +193,15 @@ that may never merge. They are not releases and are not listed here.
175193
`unsupported scheme socks5` in the message is the part that distinguishes
176194
it from the network being down.
177195

178-
- `rand` moved from 0.8 to 0.10. No behaviour changes: the two places it is
196+
- `rand` moved from 0.8 to 0.10. No behavior changes: the two places it is
179197
used — the PKCE verifier and the OAuth `state` in `mapbox auth login` —
180198
draw from `ThreadRng` before and after, which `rand` declares a CSPRNG, and
181199
`thread_rng().gen()` becoming `random()` is a rename. Recorded because it
182200
is the crate that generates those two values, so a login problem around
183201
this release should be able to find it. Both are now covered by tests
184202
against RFC 7636, which they were not before.
185203

186-
- Both installers now honour `MAPBOX_CLI_NO_TELEMETRY`, the name the binary
204+
- Both installers now honor `MAPBOX_CLI_NO_TELEMETRY`, the name the binary
187205
reads. They were left on the old `DISABLE_TELEMETRY` when the binary was
188206
renamed, so neither name silenced both halves: the documented variable
189207
stopped the CLI's markers but not the installer's, and the old one did the

‎CONTRIBUTING.md‎

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,19 @@ logged in.
4141

4242
Four rules the compiler holds rather than a reviewer, declared in
4343
`Cargo.toml` with the reasoning beside each: no `unsafe`, no `println!`
44-
(stdout belongs to `output::emit`, the single place `--output` is honoured),
44+
(stdout belongs to `output::emit`, the single place `--output` is honored),
4545
no `dbg!`, no `todo!`/`unimplemented!`.
4646

47+
Write American English: comments, documentation, commit messages, and every
48+
string the CLI prints. `prose_is_american_english` in
49+
`tests/source_guards.rs` reads the files and fails on the British spelling,
50+
so this is a test rather than something a reviewer has to notice, and the
51+
failure names the file and the line. It leaves two things alone on purpose.
52+
Fenced code blocks, because sample output and captured API responses are
53+
quoted rather than written, and rewriting a word inside one would make the
54+
document misquote its source. And the `cancelled` error code, which is a
55+
compatibility promise scripts may match on rather than a spelling.
56+
4757
## Where the commands come from
4858

4959
Commands are generated at build time from the OpenAPI specs in `openapi/`,

‎Cargo.toml‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ edition = "2021"
55
description = "A command-line interface for Mapbox APIs, with commands generated at build time from OpenAPI specs."
66
repository = "https://github.com/mapbox/cli"
77
# The file rather than an SPDX expression: LICENSE is Mapbox's own terms and
8-
# not an OSI licence, so there is no identifier that says what it grants.
8+
# not an OSI license, so there is no identifier that says what it grants.
99
license-file = "LICENSE"
1010
# A rail against an accidental `cargo publish`, not a decision that it never
1111
# could be reconsidered: crates.io is for crates anyone may use under an open
12-
# licence, and a publish cannot be taken back.
12+
# license, and a publish cannot be taken back.
1313
publish = false
1414
# The oldest Rust this crate compiles on, measured rather than aspirational:
1515
# `CredentialLock` in src/auth.rs calls `File::lock`/`unlock`, stabilised in
@@ -46,7 +46,7 @@ unsafe_code = "deny"
4646
[lints.clippy]
4747
# The output contract, made mechanical. This repo's rule is: don't reintroduce a
4848
# `println!` for a result — stdout belongs to `output::emit`, which is the
49-
# single place `--output` is honoured and the single place a result is
49+
# single place `--output` is honored and the single place a result is
5050
# written. There are no violations today; this keeps it that way.
5151
# `print_stderr` is deliberately *not* denied: warnings and progress go to
5252
# stderr from a dozen places on purpose, several of them outside the output

‎README.md‎

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ time from OpenAPI specs, so they always match the specs.
77

88
- [Build from source](#build-from-source)
99
- [Install a released binary](#install-a-released-binary)
10+
- [Download the archive yourself](#download-the-archive-yourself)
1011
- [Commands](#commands)
1112
- [Auth](#auth)
1213
- [Named profiles](#named-profiles)
@@ -42,9 +43,9 @@ The OpenAPI specs the commands are generated from are vendored in
4243

4344
## Install a released binary
4445

45-
Mapbox publishes signed builds for macOS, Linux and Windows from a separate
46-
repository. The install script detects your platform, checks a SHA-256
47-
checksum, and installs `mapbox`. No `sudo`, no admin rights:
46+
Mapbox publishes builds for macOS, Linux and Windows. The install script
47+
detects your platform, checks a SHA-256 checksum, and installs `mapbox`.
48+
No `sudo`, no admin rights:
4849

4950
```sh
5051
curl -fsSL https://cli.mapbox.com/install.sh | sh
@@ -60,6 +61,65 @@ them end to end without touching the network.
6061

6162
Run `mapbox --help` once it's on your `PATH`.
6263

64+
### Download the archive yourself
65+
66+
Nothing about the install script is required. If piping one into a shell is
67+
not allowed where you work, the archives are ordinary HTTP downloads, and
68+
`manifest.json` lists every target with its checksum:
69+
70+
```sh
71+
curl -fsSL https://cli.mapbox.com/latest/manifest.json
72+
```
73+
74+
Five targets are published: `aarch64-apple-darwin`, `x86_64-apple-darwin`,
75+
`aarch64-unknown-linux-musl`, `x86_64-unknown-linux-musl` and
76+
`x86_64-pc-windows-msvc`. Pick yours, check it, then extract:
77+
78+
```sh
79+
version=v0.2.1
80+
file=mapbox-${version}-aarch64-apple-darwin.tar.gz
81+
82+
curl -fsSLO "https://cli.mapbox.com/${version}/${file}"
83+
curl -fsSL "https://cli.mapbox.com/${version}/SHA256SUMS" |
84+
grep "$file" | shasum -a 256 -c -
85+
86+
tar -xzf "$file"
87+
mv mapbox ~/.local/bin/
88+
```
89+
90+
On Windows the archive is a `.zip` and PowerShell can read the manifest
91+
directly, so there is no text file to parse:
92+
93+
```powershell
94+
$version = 'v0.2.1'
95+
$target = 'x86_64-pc-windows-msvc'
96+
97+
$manifest = Invoke-RestMethod "https://cli.mapbox.com/$version/manifest.json"
98+
$artifact = $manifest.artifacts.$target
99+
100+
Invoke-WebRequest "https://cli.mapbox.com/$version/$($artifact.file)" -OutFile $artifact.file
101+
if ((Get-FileHash -Algorithm SHA256 $artifact.file).Hash -ine $artifact.sha256) {
102+
throw 'checksum mismatch'
103+
}
104+
105+
Expand-Archive $artifact.file -DestinationPath .
106+
```
107+
108+
`Invoke-WebRequest` and `Get-FileHash` rather than `curl` and `sha256sum`:
109+
the first is an alias for something else in Windows PowerShell and neither of
110+
the others is guaranteed to be present.
111+
112+
Use `latest` in place of the version for whatever is current. Each archive
113+
holds one file, the `mapbox` executable, so there is no directory to step
114+
into and nothing else to place. `~/.local/bin` is where the install script
115+
puts it too, and `MAPBOX_INSTALL_DIR` is the variable it reads if you prefer
116+
somewhere else.
117+
118+
The macOS builds are not code-signed with a Developer ID. `curl` attaches no
119+
quarantine flag, which is why the commands above run, but a download through
120+
a browser does, and Gatekeeper will refuse an unsigned binary that carries
121+
one. Clear it with `xattr -d com.apple.quarantine mapbox`.
122+
63123
## Commands
64124

65125
### Auth

‎docs/commands.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,7 +1586,7 @@ mapbox sprites delete ckstyle00000000000000001a zz-clitest-1 --username user
15861586

15871587
The sprite index **after** the delete — the named icon is gone from it, and
15881588
everything else is still there. A 200 with the full layout, not a 204: the
1589-
absence of the icon is the only acknowledgement there is.
1589+
absence of the icon is the only acknowledgment there is.
15901590

15911591
<table>
15921592
<tr><th width="50%">Terminal — <code>-o text</code></th><th width="50%">Agent — <code>-o json</code></th></tr>
@@ -1723,7 +1723,7 @@ one, so a plain map image needs no overlay expression.
17231723

17241724
### `mapbox static get-image`
17251725

1726-
A map image centred on a point.
1726+
A map image centered on a point.
17271727

17281728
#### Parameters
17291729

@@ -2083,7 +2083,7 @@ mapbox styles delete ckstyle00000000000000003c --username user
20832083

20842084
A 204 carries no body. Rather than print nothing, the CLI confirms what
20852085
happened — nothing is asked beforehand, so the line after the fact is the
2086-
only acknowledgement there is.
2086+
only acknowledgment there is.
20872087

20882088
<table>
20892089
<tr><th width="50%">Terminal — <code>-o text</code></th><th width="50%">Agent — <code>-o json</code></th></tr>
@@ -2524,7 +2524,7 @@ security, style quality, geospatial operations and the mobile and web SDKs.
25242524
Twenty skills, each a directory of Markdown.
25252525

25262526
**Not the same as [`generate-skills`](#generate-skills)**, which is its
2527-
neighbour in `--help` and writes something else entirely: that one renders a
2527+
neighbor in `--help` and writes something else entirely: that one renders a
25282528
skill describing *this CLI's own commands*, from the specs compiled into the
25292529
binary. These are about using Mapbox; that one is about using `mapbox`. They
25302530
share the destination flags below and nothing else.
@@ -2834,7 +2834,7 @@ mapbox/mapbox-agent-skills@main.` and `"updated": []`.
28342834
### `mapbox agent-skills uninstall`
28352835

28362836
Removes installed skill directories. At least one `NAME` is required — an
2837-
empty list is not a licence to remove everything.
2837+
empty list is not a license to remove everything.
28382838

28392839
**This is the one subcommand that makes no request.** It works from what is on
28402840
disk, which also means it can remove a skill that has since been unpublished.
@@ -3476,7 +3476,7 @@ names the flag rather than offering a login that could not outrank it.
34763476
| `http_<status>` | The API answered non-2xx. Carries `status` and the response `body`. |
34773477
| `request_failed` | Transport failure — proxy, DNS, TLS. Never carries the URL, because the access token rides in its query string. |
34783478

3479-
The CLI honours `HTTPS_PROXY`, `HTTP_PROXY`, `ALL_PROXY` and `NO_PROXY`, and
3479+
The CLI honors `HTTPS_PROXY`, `HTTP_PROXY`, `ALL_PROXY` and `NO_PROXY`, and
34803480
needs no proxy configuration of its own. Two things that look like network
34813481
faults and are not:
34823482

‎scripts/install.ps1‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# irm https://cli.mapbox.com/install.ps1 | iex
66
#
77
# This is the Windows half of scripts/install.sh, which is POSIX sh and stops
8-
# with instructions when it recognises Git Bash, MSYS2 or Cygwin. The two are
8+
# with instructions when it recognizes Git Bash, MSYS2 or Cygwin. The two are
99
# the same script in two languages: same environment variables, same order of
1010
# operations, and the same things said about a checksum that does not match, an
1111
# install directory that cannot be written, and a `mapbox` that came from
@@ -86,7 +86,7 @@
8686
# because this value comes from the environment and ends up in a header.
8787
$InstallSource = $env:MAPBOX_CLI_INSTALL_SOURCE
8888

89-
# The switch src/telemetry.rs honours for the CLI's own User-Agent, read
89+
# The switch src/telemetry.rs honors for the CLI's own User-Agent, read
9090
# here the same way, because someone who put it in a Dockerfile and then
9191
# runs `irm ... | iex` in the same file has already said which way they
9292
# want it. The product token above survives it - the equivalent of
@@ -95,7 +95,7 @@
9595
#
9696
# Two names, and only the binary dropped the old one.
9797
# MAPBOX_CLI_NO_TELEMETRY is the documented switch; DISABLE_TELEMETRY is
98-
# what it was called before, and this script still honours it. The rename
98+
# what it was called before, and this script still honors it. The rename
9999
# was announced as breaking for the binary; nothing announced it for the
100100
# installers, which are fetched and run in one line with no release notes
101101
# in front of the reader - and breaking an opt-out is the one change that

‎scripts/install.sh‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ USER_AGENT='mapbox-cli-install/1'
6262
# header.
6363
INSTALL_SOURCE="${MAPBOX_CLI_INSTALL_SOURCE:-}"
6464

65-
# The switch `src/telemetry.rs` honours for the CLI's own User-Agent, read here
65+
# The switch `src/telemetry.rs` honors for the CLI's own User-Agent, read here
6666
# the same way, because someone who put it in a Dockerfile and then pipes this
6767
# script into sh in the same file has already said which way they want it. The
6868
# product token above is what survives it — the equivalent of
@@ -71,7 +71,7 @@ INSTALL_SOURCE="${MAPBOX_CLI_INSTALL_SOURCE:-}"
7171
#
7272
# **Two names, and only the binary dropped the old one.**
7373
# `MAPBOX_CLI_NO_TELEMETRY` is the documented switch; `DISABLE_TELEMETRY` is
74-
# what it was called before, and this script still honours it. The rename was
74+
# what it was called before, and this script still honors it. The rename was
7575
# announced as breaking for the binary, so a `DISABLE_TELEMETRY=1` there
7676
# genuinely stopped working and the changelog says so. Nothing announced it for
7777
# the installers — this file is fetched and run in one line, so a reader has no
@@ -625,7 +625,7 @@ install_tilesets() {
625625
return 2
626626
}
627627

628-
# Honour MAPBOX_TILESETS_CLI, the override the CLI itself respects: someone
628+
# Honor MAPBOX_TILESETS_CLI, the override the CLI itself respects: someone
629629
# who has pointed it at a particular executable has already made this
630630
# decision, whether or not that executable is currently there.
631631
if [ -n "${MAPBOX_TILESETS_CLI:-}" ]; then

‎scripts/test-install.ps1‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#
99
# ci.yml runs it under both, because that is the split install.ps1 has to cope
1010
# with: 5.1 is what `powershell` opens on a stock Windows 11 and is where the
11-
# TLS default, the progress bar and the stderr-is-an-error behaviour bite.
11+
# TLS default, the progress bar and the stderr-is-an-error behavior bite.
1212
#
1313
# It also runs on macOS and Linux under pwsh, which is how it is developed -
1414
# there is no Windows to hand. The cases that cannot mean anything there (the
@@ -486,7 +486,7 @@ try {
486486
$tagged = @($logged | Where-Object { $_ -like '*src/onboardingscriptrm-rf' })
487487
Expect-Equal '2' ([string]$logged.Count) 'made the two requests a run makes: the manifest and the archive'
488488
Expect-Equal '2' ([string]$marked.Count) 'both name the installer and the triple'
489-
Expect-Equal '2' ([string]$tagged.Count) 'both carry the source tag, sanitised for a header'
489+
Expect-Equal '2' ([string]$tagged.Count) 'both carry the source tag, sanitized for a header'
490490
Clear-Env 'MAPBOX_CLI_INSTALL_SOURCE'
491491

492492
Start-Case 'DISABLE_TELEMETRY keeps it down to the product token'
@@ -514,10 +514,10 @@ try {
514514
Clear-Env 'DISABLE_TELEMETRY'
515515
Clear-Env 'MAPBOX_CLI_INSTALL_SOURCE'
516516

517-
Start-Case 'MAPBOX_CLI_NO_TELEMETRY is honoured, and outranks the old name'
517+
Start-Case 'MAPBOX_CLI_NO_TELEMETRY is honored, and outranks the old name'
518518
New-CaseEnv 'telemetry-new-name'
519519
$env:MAPBOX_CLI_INSTALL_SOURCE = 'dockerfile'
520-
# The documented name, which the binary reads and this script honours too.
520+
# The documented name, which the binary reads and this script honors too.
521521
$env:MAPBOX_CLI_NO_TELEMETRY = '1'
522522
[IO.File]::WriteAllText($RequestLog, '')
523523
Invoke-Installer

‎scripts/test-install.sh‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ expect_says() { # command-output want label
198198
# and `sha256` has to choose between entries rather than match the only one
199199
# there. One of the decoys is the Windows `.zip`, sitting immediately after
200200
# the entry being read: extensions are no longer uniform across targets, and
201-
# the neighbour a greedy match would bleed into is the one that proves it does
201+
# the neighbor a greedy match would bleed into is the one that proves it does
202202
# not.
203203
make_channel() { # dir version [bad-sha|broken]
204204
channel_dir="$1"
@@ -658,15 +658,15 @@ expect_in_file "$CURL_LOG" "-A ${INSTALLER_UA} (${TARGET}" 'DISABLE_TELEMETRY=0
658658
expect_in_file "$CURL_LOG" ' src/dockerfile' 'and the tag comes back with it'
659659
unset MAPBOX_TEST_CURL_LOG DISABLE_TELEMETRY MAPBOX_CLI_INSTALL_SOURCE
660660

661-
start 'MAPBOX_CLI_NO_TELEMETRY is honoured, and outranks the old name'
661+
start 'MAPBOX_CLI_NO_TELEMETRY is honored, and outranks the old name'
662662
new_case_env telemetry-new-name
663663
export MAPBOX_INSTALL_TILESETS=no
664664
export MAPBOX_CLI_INSTALL_SOURCE=dockerfile
665665
shim curl-recording curl
666666
CURL_LOG="${CASE_DIR}/curl-args"
667667
export MAPBOX_TEST_CURL_LOG="$CURL_LOG"
668668

669-
# The documented name, which the binary reads and this script honours too.
669+
# The documented name, which the binary reads and this script honors too.
670670
: >"$CURL_LOG"
671671
export MAPBOX_CLI_NO_TELEMETRY=1
672672
run_piped && status=0 || status=$?
@@ -1026,7 +1026,7 @@ expect_no_out 'is not installed' 'says nothing else about it'
10261026
expect_no_out 'Install it as well?' 'does not ask'
10271027
expect_no_out 'fake pipx' 'installs nothing'
10281028

1029-
start 'MAPBOX_TILESETS_CLI is honoured, set or broken'
1029+
start 'MAPBOX_TILESETS_CLI is honored, set or broken'
10301030
new_case_env tilesets-override
10311031
shim pipx
10321032
mkdir -p "${CASE_DIR}/opt"

0 commit comments

Comments
 (0)