Skip to content

CLI v2: TypeScript rewrite against the Registry Service API - #13

Open
roncodes wants to merge 5 commits into
release/v2.0.0from
v2
Open

roncodes wants to merge 5 commits into
release/v2.0.0from
v2

Conversation

@roncodes

Copy link
Copy Markdown
Member

CLI v2 for the Fleetbase Extensions Registry (Phase 2, Workstream G). flb is rewritten in TypeScript (commander) against the Registry Service /v1 API. It is still published as @fleetbase/cli with the flb binary, now at 2.0.0-beta.0.

What changes

  • Config: ~/.fleetbase/config.json, written atomically with mode 600 in a 700 directory.
    • It reads the phase-0 keys (host, registry, tokens by host, defaultOrganization) unchanged and keeps unknown keys.
    • It adds hosts (token metadata, nothing secret) and instances.
    • FLB_TOKEN is supported for CI.
  • Tokens:
    • Output is redacted in one place, and no token is printed unless you pass --show-token.
    • Tokens are never written outside the config file: no .npmrc and no auth.json.
    • token create refuses to mint a token unless you pass --show-token or --save.
  • Commands:
    • accounts and tokens: login (password, --token, --token-stdin), logout, whoami, register, verify, token create|list|revoke
    • extensions: init, build, bump, publish, release list|status|submit|withdraw|yank, listing list|show|update|categories
    • catalog: search, info
    • instances: instance code|register|status|updates|list|forget, install|update|uninstall
    • doctor and config
    • Removed v1 commands now print what replaced them.
  • build: packs the engine with npm pack, writes the API archive in the package/ layout Composer expects, and with --prebuilt --console <path> adds the prebuilt dist from ember-core's build-engine-release (feat: runtime engines (mount prebuilt engine releases without a console rebuild) ember-core#99). It writes .fleetbase/release.json.
  • publish: creates the draft listing if needed, uploads the release, and prints each check result as it lands by polling GET /v1/publisher/releases/{id}.
  • install / update / uninstall: run php artisan registry:* in an API checkout or a docker compose service, then follow the job with registry:job.
  • instance register --path|--docker: pipes a registration code into registry:register --code-stdin, so the instance token never leaves the instance.
  • install-fleetbase moves to packages/installer (@fleetbase/installer); flb install-fleetbase now prints npx @fleetbase/installer.
  • CI:
    • unit tests on Node 20 and 22, plus the installer tests;
    • an end-to-end job against fleetbase/registry@v2 that runs test/e2e/run.sh;
    • on tags, npm publish of both packages; @fleetbase/installer is only published when its version is new.

Depends on

  • fleetbase/registry-bridge, branch feature/cli-job-register-commands-827e43 (registry:job and registry:register). Without it, flb install can't follow queued jobs (--sync still works) and flb instance register --path fails with a hint to pass --store-token.

Testing

  • 99 Vitest unit tests and 3 installer tests pass locally.
  • test/e2e/run.sh passes against a local Registry Service (v2, QUEUE_CONNECTION=sync). It covers:
    • register, verify, login, tokens
    • init, build, publish with streamed checks, listing completion, submit
    • staff approval through the admin API
    • search and info
    • a later release published without review (D6), the beta channel, yank, and the 409 for an existing version
    • instance registration, both with the token kept in the config and handed to the instance
    • install, update and uninstall through a stub artisan
    • doctor and logout
    • and checks that no token is printed or written outside config.json.

Not done yet

  • A link to the release's review status on the publisher website. publish and release status print flb release status <id> until that website exists.

Rewrites flb in TypeScript (commander) for the Registry Service /v1 API,
still published as @fleetbase/cli with the flb binary.

- Config in ~/.fleetbase/config.json (mode 600, atomic writes), reading the
  phase-0 keys (host, registry, tokens by host, defaultOrganization) and
  adding per-host token metadata and instance tokens. FLB_TOKEN for CI.
- login (password or --token), logout, whoami, register, verify,
  token create|list|revoke. No token is printed without --show-token and
  output is redacted centrally.
- init from fleetbase/starter-extension with package names, PHP namespace,
  route and an extension.json with compat ranges; bump keeps
  extension.json, package.json and composer.json on one version.
- build: npm pack engine, Composer api archive, optional prebuilt dist via
  ember-core build-engine-release; .fleetbase/release.json.
- publish creates the listing if needed, uploads, streams checks by
  polling the release; release list|status|submit|withdraw|yank.
- search, info, instance code|register|status|updates|list|forget.
- install|update|uninstall run php artisan registry:* locally or in a
  docker compose service and follow the job with registry:job.
- doctor.
- install-fleetbase moves to packages/installer (@fleetbase/installer);
  flb install-fleetbase prints the npx command.
- Vitest unit tests and test/e2e/run.sh against the service, run in CI
  against fleetbase/registry@v2.
- flb listing list|show|update|categories: PATCH the catalog listing from
  flags or --file, and show what a first release still needs.
- flb instance register --path|--docker mints a code and pipes it to
  php artisan registry:register --code-stdin on the instance, so the
  instance token stays in its encrypted settings. Without a target, or
  with --store-token, the CLI exchanges the code as before.
- The artisan runner can write stdin; doctor reports registry:register.
- The e2e uses flb listing instead of curl, and its stub artisan really
  exchanges the piped code with the service.
Comment thread src/commands/init.ts Fixed
Comment thread src/manifest.ts Outdated

export const SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
export const NPM_NAME = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
export const COMPOSER_NAME = /^[a-z0-9]([_.-]?[a-z0-9]+)*\/[a-z0-9](([_.]|-{1,2})?[a-z0-9]+)*$/;
Comment thread src/manifest.ts Outdated

export const SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
export const NPM_NAME = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/;
export const COMPOSER_NAME = /^[a-z0-9]([_.-]?[a-z0-9]+)*\/[a-z0-9](([_.]|-{1,2})?[a-z0-9]+)*$/;
- Replace the SemVer regex (exponential backtracking on long numeric
  prerelease identifiers) with isSemver(), a strict check on semver.parse's
  canonical form; versions over 256 characters are rejected as npm does.
- Escape backslashes as well as single quotes when the scaffold writes the
  extension name and description into JS and PHP string literals.
@roncodes
roncodes changed the base branch from main to release/v2.0.0 October 23, 2026 05:30
…egex

CodeQL js/redos pointed at COMPOSER_NAME, not the SemVer regex. Rewrite
Composer's vendor/package rule so each separator is required between
alphanumeric runs. Same language (checked exhaustively against the old
pattern for every string up to 8 characters over [a0_.-/]), linear time.
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