Skip to content

feat: support project tokens linked to several projects, and rotate them from the CLI - #411

Open
gregberge wants to merge 4 commits into
mainfrom
claude/gracious-rhodes-ec05c1
Open

gregberge wants to merge 4 commits into
mainfrom
claude/gracious-rhodes-ec05c1

Conversation

@gregberge

@gregberge gregberge commented Nov 5, 2026 •

Copy link
Copy Markdown
Member

Important

Needs argos-ci/argos#2747 deployed before release. Until then the token commands answer 404. The project field is harmless on today's API, which strips unknown fields, but it does nothing.

Description

argos-ci/argos#2747 replaces the single projects.token with project tokens. A token can be linked to several projects, carries permissions and can expire. This PR makes the SDK and the CLI work with them.

Name the project on the CI endpoints

A token linked to several projects does not identify a project by itself, so the API answers 400 unless the request names one. When ARGOS_PROJECT (or the project option) is set, @argos-ci/core now sends it as project to:

  • GET /project (query)
  • POST /builds, POST /builds/finalize, POST /baseline, POST /deployments (body)

POST /media already took it. When project is unset, nothing is sent, so single-project tokens behave exactly as today.

  • finalize() and deploy() gain a project parameter, like upload(). skip() accepts one too.
  • argos finalize, skip, deploy and baseline download take --project.
  • @argos-ci/gitlab reads ARGOS_PROJECT for its GET /project.

Behaviour change: a token linked to one project used to ignore an ARGOS_PROJECT that named some other project. Now the API rejects it with a 401 (This project token does not have access to the project "…").

Rotate tokens from the CLI

argos project token list    [--project owner/project]
argos project token create  --name <name> [--permissions <p…>] [--expire-at <iso> | --expires-in <days>]
argos project token revoke  <tokenId>

argos account project-token list|revoke
argos account project-token create --projects web docs --name <name> […]
  • The project commands use /projects/{owner}/{project}/tokens. The account commands use /accounts/{accountSlug}/project-tokens, the only endpoint that can create a token linked to several projects.
  • create prints the token, since the API returns it only once. With --json, the value is in token.
  • --permissions and --projects take space-separated values, like upload --files. If --permissions is omitted, the API grants every permission. Commander rejects unknown permissions before the request is sent.
  • --expire-at and --expires-in can't be used together. The date must be in the future, and it is sent as UTC ISO, the only format z.iso.datetime() accepts.
  • Output follows the existing JSON contract. revoke returns { revoked, tokenId }, like contributor remove. Token names go through sanitizeTerminalText.

API client

packages/api-client/src/schema.ts is regenerated from the #2747 branch with pnpm --filter @argos/backend generate-openapi. Most of the diff is drift that production already serves (capture, Agent, awaitingReviewStatus, analytics storybook…). I checked this by diffing production's openapi.yaml against the PR spec: they differ only in the token changes.

Skills

argos-cli and argos-upload now cover tokens linked to several projects, the 403 for a missing permission, and the rotation flow, which pipes create --json | jq -r .token | gh secret set ARGOS_TOKEN so the value is never echoed.

No changeset files: Lerna versions from the conventional commits.

Tests

  • @argos-ci/core: upload, skip, finalize and deploy send project when it is passed or set in ARGOS_PROJECT, and send no field or query param when it is not. The upload test also covers the /baseline lookup.
  • @argos-ci/cli: unit tests for expiration handling, the request body and the token formatters.
  • Smoke test: I ran the built CLI against a local mock API and checked every new command, plus finalize, skip, deploy and baseline download with and without --project/ARGOS_PROJECT.
  • I did not add e2e tests for the token commands: the e2e suite runs against production, which doesn't serve these endpoints yet.

Follow-ups

  • argos login does not request the account:admin OAuth scope. The account endpoints require it, so argos account project-token * (like the existing account member|invite|domain commands) works only with a personal access token, not with an argos login session.
  • The docs PR docs(tokens): several project tokens per project, shown once docs#273 says baseline download has no --project flag. It now has one, so the CLI reference needs a follow-up there.

Refs ARG-519

🤖 Generated with Claude Code

gregberge and others added 3 commits November 5, 2026 12:02
Regenerate the schema from argos-ci/argos#2747, which is not deployed
yet: project tokens (`ProjectToken`, `CreatedProjectToken`,
`ProjectTokenPermission`), their endpoints on
`/projects/{owner}/{project}/tokens` and
`/accounts/{accountSlug}/project-tokens`, and the optional `project`
the CI endpoints take to pick one of a token's projects.

The rest of the diff is what production already serves and the schema
had not caught up with.

Refs ARG-519

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A project token can now be linked to several projects. Such a token
does not identify a project on its own, so Argos rejects it on the CI
endpoints unless the request names one.

When `ARGOS_PROJECT` (or the `project` option) is set, send it as
`project` to `GET /project`, `POST /builds`, `POST /builds/finalize`,
`POST /baseline` and `POST /deployments`. When it is not, send nothing,
so a token linked to a single project behaves exactly as before.
`POST /media` already took it.

- `finalize` and `deploy` take a `project` parameter, like `upload`.
- `argos finalize`, `skip`, `deploy` and `baseline download` take
  `--project`.
- `@argos-ci/gitlab` reads `ARGOS_PROJECT`.

Setting `ARGOS_PROJECT` to a project the token is not linked to now
fails, where the SDK used to ignore it outside tokenless
authentication.

Needs argos-ci/argos#2747 deployed: until then the API does not know
`project` on these endpoints.

Refs ARG-519

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`argos project token list|create|revoke` manage a project's tokens on
`/projects/{owner}/{project}/tokens`, so CI tokens can be rotated from
the terminal: create the replacement, update the CI secret, revoke the
old one.

`argos account project-token list|create|revoke` do the same on
`/accounts/{accountSlug}/project-tokens`, the only place a token linked
to several projects can be created (`--projects web,docs`).

`create` takes `--name`, `--permissions` (comma-separated, all of them
by default) and `--expire-at <iso>` or `--expires-in <days>` (never, by
default), and prints the token: Argos returns it once. Permissions and
dates are checked before the request, and dates are sent in the UTC ISO
format the API takes.

The argos-cli and argos-upload skills cover tokens linked to several
projects, missing permissions and the rotation flow.

Needs argos-ci/argos#2747 deployed: the endpoints answer 404 until then.

Refs ARG-519

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gregberge gregberge added the enhancement New feature or request label Nov 5, 2026
@vercel

vercel Bot commented Nov 5, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
argos-js-sdk-reference Ready Ready Preview Nov 5, 2026 1:46pm UTC

Request Review

@linear-code

linear-code Bot commented Nov 5, 2026

Copy link
Copy Markdown

ARG-519

gregberge added a commit to argos-ci/docs that referenced this pull request Nov 5, 2026
argos-ci/argos-javascript#411 adds `argos project token` and
`argos account project-token` (list, create, revoke), and lets
`finalize`, `skip`, `deploy` and `baseline download` take `--project`
for a token linked to several projects.

- CLI reference: add both command groups, with their defaults (every
  permission, no expiration) and the roles they need; drop "baseline
  download has no --project flag"; say what --project does for a
  multi-project token.
- Project tokens: mention the CLI next to the API, and that ARGOS_PROJECT
  naming another project fails with a 401 for a single-project token.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@gregberge
gregberge requested a review from jsfez November 5, 2026 12:45
…mands

- `--project` / `ARGOS_PROJECT` is resolved by one `resolveProjectPath`
  in `lib/target.ts`, now also used by `baseline download`, which
  checks the `owner/project` format before calling the API.
- `toPositiveInteger` and `toIsoOrFail` move to `options.ts`, shared by
  `--limit`, `--pr`, `analytics --from/--to` and the token expiration
  flags.
- `--permissions` and `--projects` are variadic options, like
  `upload --files`: commander checks permissions against their choices,
  so the hand-written list parsers go.
- The token body type is inferred against the generated schema, and the
  conflict between `--expire-at` and `--expires-in` is declared once.
- Core tests record `POST /builds` and `POST /builds/finalize` bodies
  in the default mock handlers instead of copying them per test.

Refs ARG-519

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — 3160adfb Deployed Nov 5, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant