Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions .changeset/21360-environments-cloud-session.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
'@objectstack/cli': minor
---

`os environments list | show | create | bind | switch` run on the `os cloud login` session

Clause-②: yes (widening)

The documented hosted flow is `os cloud login`, then `os environments create`. The five
`os environments` subcommands read only `~/.objectstack/credentials.json` (the `os login`
session), so with only `~/.objectstack/cloud.json` they exited 1 with
`Authentication required` before sending any request, while `os login --help` sends hosted
users to `os cloud login`.

All five now choose their session in one shared resolver:

- With no `--url` / `OS_CLOUD_URL`, they use the `os login` session when there is one, which
is the same behaviour as before. Otherwise they use the `os cloud login` session and the URL
it recorded.
- With a `--url`, they use the session whose file names that server, `credentials.json` first.
When neither file names it, they use `credentials.json`'s session as before. The cloud token
is never sent to a URL other than its own.
- The active environment sent with each request comes from the chosen session's file.
`os environments switch` and `create --activate` no longer write a cloud environment id into
`credentials.json` when they ran on the cloud session.

With no session at all, the `Authentication required` message now names `os cloud login` as
well as `os login`. `os package publish` is unchanged: it still reads only `cloud.json`.
17 changes: 11 additions & 6 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,19 @@ Typical flow (build → publish → install into an environment, seeding sample

```bash
os compile # → dist/objectstack.json
os cloud login # one-time; the session os package publish reads
os environments create --org "$ORG" --name "Dev" --activate # does NOT read that session — see below
os cloud login # one-time; the session os package publish and os environments read
os environments create --org "$ORG" --name "Dev" --activate
os package publish --env <env-id> --install --seed-sample-data
```

`os environments create` does not use the session `os cloud login` stored: give
it `--url` and `--token` (or `OS_CLOUD_URL` / `OS_TOKEN`), or an `os login`
session. Without either it exits 1 with `Authentication required`.
`os environments` runs on either stored session. With no `--url` it talks to
the server of the `os login` session (`credentials.json`) when there is one,
else to the server of the `os cloud login` session (`cloud.json`), with that
session's token. A `--url` (or `OS_CLOUD_URL`) picks the session that names
that server, `credentials.json`'s first — so with both stored, a `--url` naming
the cloud uses the cloud session. A `--url` neither file names gets
`credentials.json`'s token as before, never `cloud.json`'s. With no session and
no `--token` / `OS_TOKEN`, it exits 1 with `Authentication required`.

`os package publish` registers a `sys_package` (keyed by a reverse-domain
`--manifest-id`, derived from the artifact when omitted), snapshots the
Expand All @@ -124,7 +129,7 @@ Two stored sessions exist, and each command authenticates with one of them:
| `os cloud login` | `-u, --url` (env `OS_CLOUD_URL`, default `https://cloud.objectos.ai`) | none — `-e, --email` / `-p, --password`, or the browser device flow | writes `~/.objectstack/cloud.json` |
| `os cloud whoami` / `os cloud logout` | — | — | reads / deletes `~/.objectstack/cloud.json` |
| `os package publish`, `os plugin publish` | `-s, --server` (env `OS_CLOUD_URL`); else the URL in `cloud.json`; else `https://cloud.objectos.ai` | `-t, --token` (env `OS_CLOUD_API_KEY`, then `OS_TOKEN`) | `~/.objectstack/cloud.json` — the `os cloud login` session |
| `os environments list` / `show` / `create` / `bind` / `switch` | `-u, --url` (env `OS_CLOUD_URL`); else the URL in `credentials.json`; else `http://localhost:3000` | `-t, --token` (env `OS_TOKEN`) | `~/.objectstack/credentials.json` — the `os login` session, **not** `os cloud login`'s |
| `os environments list` / `show` / `create` / `bind` / `switch` | `-u, --url` (env `OS_CLOUD_URL`); else the URL of the stored session it uses; else `http://localhost:3000` | `-t, --token` (env `OS_TOKEN`) | No `--url`: `~/.objectstack/credentials.json` (the `os login` session), else `~/.objectstack/cloud.json` (the `os cloud login` session). With `--url`: the file that names that server, `credentials.json` first; when neither does, `credentials.json` as before. `cloud.json`'s token is never sent to another URL |

`os package install` is not a cloud command: it installs into a running runtime
(`-r, --runtime`, env `OS_RUNTIME_URL`, default `http://localhost:3000`) and signs
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/src/commands/environments/bind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import path from 'node:path';
import fs from 'node:fs/promises';
import { spawnSync } from 'node:child_process';
import { printError, printStep, printKV, emitJson, isExitSignal, errorCodeFields } from '../../utils/format.js';
import { createApiClient, requireAuth } from '../../utils/api-client.js';
import { createControlPlaneApiClient, requireControlPlaneAuth } from '../../utils/api-client.js';
import { formatOutput } from '../../utils/output-formatter.js';

/**
Expand Down Expand Up @@ -99,8 +99,8 @@ export default class EnvironmentsBind extends Command {
this.exit(1);
}

const { client, token } = await createApiClient({ url: flags.url, token: flags.token });
requireAuth(token);
const { client, token } = await createControlPlaneApiClient({ url: flags.url, token: flags.token });
requireControlPlaneAuth(token);

// Fetch existing metadata so we don't blow it away.
const current = await client.environments.get(args.environmentId);
Expand Down
Loading
Loading