Skip to content

cli: os package publish --install cannot use the environment you just switched to — activeEnvironmentId lives in the runtime credential store, which publish must never read #18265

Description

@hotlong

What happens

os cloud login
os environments switch <env-id>       # ✓ Active environment: Dev
os build
os package publish --install
# → `--install` requires `--env <id>`. Skipping auto-install.

The environment the CLI just told you is active — and which os environments list
marks with a ★ on the very next line — is invisible to the one command that would
install into it. Every publish has to carry the UUID again, by flag or by
OS_ENVIRONMENT_ID. Nobody remembers a UUID.

Why it is invisible (measured on origin/main)

Two credential stores, two identities. packages/cli/src/utils/cloud-config.ts
states the split in its own header:

  1. Runtime identity — who you are inside your own ObjectOS instance. Stored in
    credentials.json, written by os login.
  2. Cloud identity — who you are on the official ObjectStack Cloud package
    registry. Stored in cloud.json, written by os cloud login. Used to publish &
    install packages …

Keeping them in separate files … makes it impossible to accidentally publish a
package with a runtime-scoped token
.

  • os environments switch writes cfg.activeEnvironmentId into credentials.json
    (commands/environments/switch.ts:58, path at utils/auth-config.ts:47, field
    declared at utils/auth-config.ts:40).
  • os package publish reads cloud.json (utils/cloud-config.ts:50) and resolves
    its base URL from that file's url (commands/package/publish.ts:501). It never
    opens credentials.json.
  • The only reader of activeEnvironmentId anywhere in the CLI is
    utils/api-client.ts:68, which serves the data / meta / environments families.
  • The refusal itself is commands/package/publish.ts:661
    const shouldInstall = flags.install && flags.env;

⛔ The fix is NOT "let publish read credentials.json"

That is precisely the mixing the file header says the split exists to prevent. It is
also wrong at runtime, not merely impure:

The two files carry different servers. credentials.json's URL falls back to
http://localhost:3000 (utils/api-client.ts:78); cloud.json's default is
https://cloud.objectos.ai (utils/cloud-config.ts:30), and that is the URL the
publish actually POSTs to. So credentials.json's activeEnvironmentId means "an
environment on whatever server I am currently pointed at"
. Handing it to a publish
aimed at cloud.objectos.ai names a UUID belonging to a different control plane
a 404 at best, and the server resolves it with a bare
findOne('sys_environment', { where: { id } }), so there is no name or short-id
rescue on that path either.

Shape of the fix

  1. Add activeEnvironmentId?: string to CloudConfignext to activeOrgId
    (utils/cloud-config.ts:42), which is already there and already documented as
    "Active organization id chosen for publishing". An organization and an
    environment are the same kind of thing: control-plane scope selectors, one level
    apart. The precedent is in the same interface.
  2. os environments switch writes to cloud.json when the control plane it just
    talked to is cloud.json's url; otherwise it keeps writing
    credentials.json. Two files, two control planes, an active environment for each
    — that is the self-consistent model, and it preserves os environments working
    against a self-hosted server with a runtime token, which is deliberate (see
    Out of scope).
  3. os package publish's --env falls back to cloud.json's activeEnvironmentId
    when both the flag and OS_ENVIRONMENT_ID are absent. ⛔ It must never read
    credentials.json.
  4. Migration: existing values live in credentials.json. Copy across once, and
    only when the two files' urls agree.

Guards — both must be measured red-before / green-after

  • Remove the fallback ⇒ a publish with an active cloud environment and no --env
    fails.
  • Point the fallback at credentials.json ⇒ also fails. This is the real
    invariant the card is about. A guard that only pins "a fallback exists" would
    accept the wrong fix, which is the whole reason this card is not the one-line
    change it looks like.

Out of scope — ⛔ do not bundle

Whether the whole os environments family should move to the cloud identity. It
authenticates today from credentials.json / OS_TOKEN against OS_CLOUD_URL
(defaulting to localhost:3000) — right for a self-hosted control plane, odd-looking
against cloud.objectos.ai. Changing it changes which token existing users' commands
send. Separate card, separate decision.


Found while answering "how do I deploy a metadata project into my own cloud dev
environment". The maintainer's words: 「没有人会记得 env_id」. The first fix proposed
in that conversation was the credentials.json one above; the maintainer rejected it
with "activeEnvironmentId 要写也应该是 cloud.json ?", and the server-split argument
above is what confirmed they were right.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions