Skip to content

feat: Install the Flagsmith CLI and authenticate it via OIDC - #1

Open
khvn26 wants to merge 35 commits into
mainfrom
feat/setup-cli-action
Open

feat: Install the Flagsmith CLI and authenticate it via OIDC#1
khvn26 wants to merge 35 commits into
mainfrom
feat/setup-cli-action

Conversation

@khvn26

@khvn26 khvn26 commented Aug 18, 2026

Copy link
Copy Markdown
Member

In this PR, we implement the Flagsmith/setup-cli action.

Here's what it does:

  1. Grabs the installer script for the runner's platform, and requested (or latest) version.
  2. Resolves the actual CLI version via installer's --dry-run mode.
  3. Installs the CLI 🎉
  4. Puts the installed binary in GitHub Actions' tool cache.
  5. Detects whether the static credentials were set for the requested API URL.
  6. If no static credentials detected and the action is not run against a fork PR, performs the OIDC exchange against the requested API URL.
  7. Warns if something went wrong during the OIDC exchange.

Smoke-tested in #2.

khvn26 added 30 commits August 18, 2026 15:07
Adds the composite action from Flagsmith/actions#9: resolve a CLI version,
run the release's own install.sh (or install.ps1 on Windows), then exchange
the job's GitHub OIDC token at POST /api/v1/auth/oidc/token/.

The minted token is exported under the CLI's host-scoped credential name,
because the CLI trusts unscoped FLAGSMITH_ACCESS_TOKEN only for its default
host — a self-hosted api-url would otherwise silently go unauthenticated.

Jobs without id-token: write install the CLI and warn, so the action stays
usable with a Master API key from secrets.
Replaces the action's reimplementation of the release layout with a call to
install.sh/install.ps1, pinned to the version being installed and run with
--bin-dir and --no-modify-path. Platform detection, archive naming and
checksum verification move back to the repository that publishes the
releases, where the CLI's own CI exercises them on every platform; this
action keeps only the installer's flags, which fail loudly rather than
silently when they change. The binary is still cached by version and
architecture, and PATH is still ours to set.

Also, from reading depot/setup-action:

- Skip the exchange when the job already carries a credential the CLI would
  use for this api-url, following the CLI's own precedence, so a workflow
  with a Master API key neither pays for nor fails an exchange it never
  asked for.
- Name the fork pull request case explicitly. GitHub withholds an OIDC
  identity from those runs, so the generic advice to add id-token: write
  sent people to change something that could not help.
Everything they carried is already available from the CLI the action just
installed: `flagsmith --version`, `flagsmith auth status`, and `flagsmith
auth token` for scripts that need the raw credential. The access token in
particular is better left out of the outputs, where it would invite copying
a credential between steps and jobs for no gain.

`authenticated` and `expires-in` existed largely so the workflow had
something to assert; the tests now assert behaviour instead, which is a
stronger check: `flagsmith auth status` for the authenticated path, and the
absence of an exported token for the bring-your-own-credential path.
installerScript, binaryName and installerInvocation all branched on the same
platform check, so they are one platformInstaller now. ExchangedToken.tokenType
was set and never read.
install.sh already fails with its own message when neither is on PATH, so the
pre-flight check was 23 lines of nicer wording plus its own test suite.
They were one-liners exported only so their own tests could reach them.
isForkPullRequest took a readEvent parameter no caller ever passed; the tests
point GITHUB_EVENT_PATH at a tmp file now.
Trim comments to the ones that carry information the code does not.
The JSON-only reading suppressed exactly the bodies that carry a diagnosis
this action cannot produce itself. A proxy demanding authentication, a
captive portal or a load balancer with no backend answers in HTML, and
Flagsmith never sees the request at all; dropping that body left the user
with a hint about trust relationships and nothing about the proxy.

Collapsed to one line and truncated, so the annotation stays readable.
The parser already strips surrounding whitespace and lowercases the host, so
urlHost needs no bare-host fallback and only a single trailing slash is left to
trim.
An unpinned install now runs the installer from main, whose default version is
the latest release, instead of resolving the tag through the GitHub API. Only a
pinned version is cached, so the cache key can never be a moving target.
The dry run reports the version it would install without downloading anything,
so an unpinned install is cached under the same concrete tag a pinned one is.
index.ts exists to start run() and nothing else, so main.ts has no module-level
side effect and needs no test-environment guard.
fetchOk owns the status check, the user agent and the body snippet; callers
supply the first line of the failure.
tsconfig extends @tsconfig/node24 and now checks the test files too, which the
excluded config never did.
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.

1 participant