diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e905a7..f046b74 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,42 +14,48 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 > That `v2.0.2` tag is the only thing carrying the retraction — the `v2/` directory no > longer exists on `main` — so the tag must not be deleted or the retraction is lost. -## [Unreleased] +## [v1.12.0] - 2026-10-31 `githubauth token --exec` now revokes the token when the command exits, and the CLI can find the installation and narrow the token on its own. A security review closed six -ways a credential could reach somewhere it should not, listed under Security. Four -changes can affect existing code or scripts; they are listed under Changed. +ways a credential could reach somewhere it should not, listed under Security with the +released versions each affects; upgrade if you use `--exec` or pass the key through the +environment. Six changes can affect existing code or scripts; they are listed under +Changed. ### Security - `githubauth token --exec` and `jwt --exec` no longer pass `$GITHUB_APP_PRIVATE_KEY` to - the command, nor to the `git` that reads a clone's origin, in any letter case on - Windows. A child that leaked its environment leaked the key that mints tokens for every - installation, past `--repos`, `--permissions` and revocation + the command, in any letter case on Windows. A child that leaked its environment leaked + the key that mints tokens for every installation, past `--repos`, `--permissions` and + revocation. Affects v1.10.0 and v1.11.0. The `git` that reads a clone's origin, new in + this release, never gets it either (#93) - A `--key` that is neither PEM nor a readable file, such as a base64-encoded key from a CI secret, was repeated in full in the error, and so in logs and agent transcripts. The - error no longer includes a value longer than a path + error no longer includes a value longer than a path. Affects v1.10.0 and v1.11.0 (#93) - `--exec` set `$GH_HOST` without the API URL's port, so `gh` sent the credential to port - 443 of that host. The port is kept, and a clone's https origin must name the same port - as the API for the token to be scoped to it + 443 of that host. The port is kept. Affects v1.11.0, which began setting `$GH_HOST`. A + clone's https origin, new in this release, must name the API's port too (#93) - An exported `$GH_HOST` naming another instance than an installation token's made `gh` send the token there. `githubauth token --exec` now exits 2 before minting (see Changed). The JWT is not checked: it is signed locally, and only you know which instance its App - lives on + lives on. Affects v1.10.0 and v1.11.0 (#93) - A SIGINT sent to githubauth alone, as a supervisor does, left the command running with the credential. On Linux and macOS, unless the command is in the terminal's foreground job, - where a Ctrl-C reaches it directly, SIGINT is now passed on like SIGTERM + where a Ctrl-C reaches it directly, SIGINT is now passed on like SIGTERM. Affects + v1.10.0 and v1.11.0 (#93) - Every GitHub Action in the workflows is pinned to a commit. The release job holds the token that publishes the Homebrew cask and the gh extension, and a moved tag could have - run code with it. A successful API response is also capped at 16 MiB + run code with it. A successful API response is also capped at 16 MiB (#93) ### Added - `RevokeInstallationToken` ends an installation token before its hour is up. `githubauth token --exec` calls it once the command exits; `--keep` leaves the token - valid. A revocation that fails is reported on stderr, the token then stays valid until - it expires, and the exit code stays the command's. A cached source that handed the token + valid. A revocation that fails leaves the token valid until it expires: after a command + that ran, githubauth warns on stderr and keeps the command's exit code; when the + command never started, the failure joins githubauth's own error report, the JSON + document under `--agent`. A cached source that handed the token out keeps returning it, so build a new one (#87, #88) - `githubauth token --permissions contents:read,pull_requests:write` scopes the token below what the App was granted. Any permission name GitHub has is accepted; GitHub @@ -64,7 +70,7 @@ changes can affect existing code or scripts; they are listed under Changed. `ExtraPermissions` and, for a token limited to some repositories, `ExtraRepositories`. `githubauth token --json` prints both (#90) - `NewApplicationTokenSource(12345, key)` compiles: `Identifier` admits `~int`, so an - untyped constant needs no `int64(...)` conversion + untyped constant needs no `int64(...)` conversion (#95) - The CLI is a GitHub CLI extension: `gh extension install jferrl/gh-githubauth`, run as `gh githubauth` (#91) @@ -74,12 +80,16 @@ changes can affect existing code or scripts; they are listed under Changed. command leaves running on the token starts getting 401s. `--keep` restores the old behaviour (#87) - **An exported `$GH_HOST` that differs from the installation token's instance exits 2** - under `token --exec`, before anything is minted. It used to be kept, which v1.11.0 suggested for a - `--base-url` proxy in front of github.com; set it inside the command instead: - `--exec -- env GH_HOST=github.com gh …` + under `token --exec`, before anything is minted. It used to be kept, which v1.11.0 + suggested for a `--base-url` proxy in front of github.com; set it inside the command + instead: `--exec -- env GH_HOST=github.com gh …` (#93) - `NewPersonalAccessTokenSource("")`'s error now reads "personal access token is required", like the package's other missing-argument errors. Match errors with - `errors.Is`/`errors.As`, not their text + `errors.Is`/`errors.As`, not their text (#96) +- **A token from this package reports `Valid() == false` once it is inside the skew**, 30s + before expiry by default, where it reported `true` until oauth2's 10s. The cache now + stores the skew in the tokens it returns, which is what lets `oauth2.NewClient` honour + it. Code that checks `tok.Valid()` itself sees the change (#95) - **`InstallationPermissions` is no longer comparable**, because `Other` is a map. Code that compares two values with `==` or uses one as a map key no longer compiles (#88) - **Comparing installation token values, `*a == *b`, now panics** when GitHub's answer @@ -93,17 +103,17 @@ changes can affect existing code or scripts; they are listed under Changed. expiry, not 30s.** `NewClient` added its own cache over this package's. `ReuseTokenSourceWithSkew` is now oauth2's cache with the longer window, which `NewClient` uses as is. It works on copies of the tokens it caches, so caches sharing a - source no longer race + source no longer race (#95) - A `Retry-After` past about 292 years overflowed to a negative wait and retried at once. - It is capped at an hour, as documented + It is capped at an hour, as documented (#95) - `$GITHUB_APP_INSTALLATION_ID` or `$GITHUB_APP_ID` past the int64 range became the - largest int64 instead of being reported as malformed -- One `WithApplicationTokenExpiration` value applied by concurrent constructors raced + largest int64 instead of being reported as malformed (#95) +- One `WithApplicationTokenExpiration` value applied by concurrent constructors raced (#95) - `--json` or `--agent` after a malformed flag, as in `token --bogus --json`, still - produced a plain-text error; it now produces the JSON document -- `githubauth version` and `help` exited 0 when stdout could not be written + produced a plain-text error; it now produces the JSON document (#95) +- `githubauth version` and `help` exited 0 when stdout could not be written (#95) - Errors from a missing key file or a command that cannot start now wrap their cause, so - `errors.Is(err, fs.ErrNotExist)` and `exec.ErrNotFound` match + `errors.Is(err, fs.ErrNotExist)` and `exec.ErrNotFound` match (#95) - The exit-2 hint for a 422 names `--permissions` as well as `--repos`, and the exit-5 hint for a 404 names `--owner` (#88)