@supacloud/admin 0.8.2 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +129 -1
  2. package/dist/index.js +1495 -206
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -6,12 +6,59 @@ Platform administration CLI for SupaCloud operators.
6
6
 
7
7
  Typical environment variables:
8
8
 
9
+ - `SUPACLOUD_ENV` — environment identity such as `test` or `production`
10
+ - `SUPACLOUD_READ_ONLY=true` — block every remote write
9
11
  - `SUPACLOUD_HOST`
10
12
  - `SUPACLOUD_SSH_KEY` or `SUPACLOUD_SSH_PASS`
11
13
  - `SUPACLOUD_SSH_HOST_FINGERPRINT` — required for SSH actions, in OpenSSH `SHA256:<base64>` form
12
14
  - `SUPACLOUD_API_URL`
13
15
  - `SUPACLOUD_API_TOKEN`
14
16
 
17
+ ## Environment selection and production confirmation
18
+
19
+ Use `--env <name>` to load `.env.supacloud.<name>` from the current directory,
20
+ or `--env-file <path>` to load one exact file. Every selected file must declare
21
+ `SUPACLOUD_ENV`; a named file's declared value must match the selector. Global
22
+ flags may appear before or after the command.
23
+
24
+ Selected files are atomic context sources: Admin does not fill missing API,
25
+ project, SSH, credential, or safety values from the process environment or a
26
+ different dotenv file. Without a selector, a complete process context declaring
27
+ `SUPACLOUD_ENV` is used as one source. If that process context is incomplete,
28
+ `SUPACLOUD_ENV` selects `.env.supacloud.<value>` instead. The legacy `.env`
29
+ fallback remains available only when no Admin context variables are present in
30
+ the process.
31
+
32
+ Production writes require `--confirm-production` before any HTTP or SSH action:
33
+
34
+ - Project-scoped writes use the exact requested project ref. If the selected
35
+ profile declares `SUPACLOUD_PROJECT_REF`, an explicit different ref is
36
+ rejected for both reads and writes.
37
+ - Platform API writes that genuinely have no project ref use
38
+ `platform:<API host>`, for example `platform:management.example.com`.
39
+ - SSH writes that genuinely have no project ref use `host:<SSH host[:port]>`,
40
+ for example `host:production.example.com:2201`.
41
+
42
+ A generic value such as `production` is never accepted. Project-scoped actions
43
+ that omit a required ref do not fall back to a platform or host confirmation.
44
+ `SUPACLOUD_READ_ONLY=true` blocks every remote write in every environment,
45
+ including when it is set only in the process environment. Remote writes also
46
+ require an explicit `SUPACLOUD_ENV`; unclassified process and legacy dotenv
47
+ contexts remain usable for read-only actions but cannot mutate remote state.
48
+
49
+ Management API URLs must be origin-and-path URLs without credentials, query
50
+ strings, or fragments. This prevents URL-embedded secrets from being sent to a
51
+ remote target or displayed by `status` and `--help`.
52
+
53
+ ```bash
54
+ npx @supacloud/admin --env test status
55
+ npx @supacloud/admin --env production project delete \
56
+ --ref abc123 --confirm-production abc123
57
+ npx @supacloud/admin --env production ssh upgrade \
58
+ --version 0.50.31 --edge_runtime_version 0.16.8 \
59
+ --confirm-production host:production.example.com:2201
60
+ ```
61
+
15
62
  SSH host keys are fail-closed: setting `SUPACLOUD_HOST` and credentials is not
16
63
  enough to enable SSH actions. Obtain the fingerprint through a trusted channel,
17
64
  compare it out of band, then set it explicitly. For example, the discovery
@@ -29,8 +76,11 @@ npx @supacloud/admin status
29
76
  npx @supacloud/admin ssh ping
30
77
  npx @supacloud/admin ssh versions
31
78
  npx @supacloud/admin ssh diagnose
32
- npx @supacloud/admin project create --name my-app --domain example.com
79
+ npx @supacloud/admin project create --name my-app --domain example.com \
80
+ --env_file /secure/path/.env.project-credentials.test --environment test
33
81
  npx @supacloud/admin project list
82
+ npx @supacloud/admin project services --ref abc123
83
+ npx @supacloud/admin project service_control --ref abc123 --service gotrue --service_action stop
34
84
  ```
35
85
 
36
86
  `ssh versions` emits JSON with `schema_version: 1` and fixed
@@ -106,6 +156,84 @@ Project commands owned by this CLI:
106
156
  - `project restore`
107
157
  - `project restart`
108
158
  - `project update_settings`
159
+ - `project services` — read-only project service inventory
160
+ - `project service_control` — constrained project service lifecycle control
161
+
162
+ `project create` never prints project credentials. Pass an absolute
163
+ `--env_file` path to explicitly request one-time service-role delivery. This
164
+ mode requires both a complete bare `--api_domain` (or bare base `--domain`)
165
+ and an exact `--environment test|production`; invalid or missing bindings fail
166
+ before the remote project mutation. `--environment` is used only in the local
167
+ credential file and is never sent to the Management API. Credential delivery is
168
+ supported only on Linux, where Admin holds the canonical parent directory open
169
+ and performs create, verification, and cleanup through `/proc/self/fd`. macOS
170
+ and Windows fail with `ENV_FILE_PLATFORM_UNSUPPORTED` before creating a file or
171
+ requesting remote credentials. On Linux, the target is exclusively reserved at
172
+ mode `0600` before the remote mutation. The direct parent must be owned by the
173
+ Admin process user. Every ancestor must be owned by root or that user and must
174
+ not grant group/world write access; paths below writable sticky directories
175
+ such as `/tmp` are rejected. Parent ownership, mode, and device/inode identity,
176
+ plus file ownership, mode, and device/inode identity, are checked before and
177
+ after writing through the held parent descriptor. The file and parent directory
178
+ are synced before success is reported.
179
+ The response API URL and project name must exactly match the request binding;
180
+ the origin comparison includes the port. Existing files, symlinks, replaced
181
+ parents, non-canonical paths, and missing or untrusted directories are rejected.
182
+ The recommended name is
183
+ `.env.project-credentials.<environment>`; verify that the target repository
184
+ ignores it before running the command (SupaCloud's own `.env.*` rule does).
185
+ This is an application credential file, not a SupaCloud Admin/Management
186
+ profile: Admin rejects it before registering HTTP tools, so never select it
187
+ with `supacloud-admin --env` or `--env-file`. Selected Admin files that contain
188
+ project application credentials must also contain an explicit Management API
189
+ URL and `SUPACLOUD_API_TOKEN`; Admin never substitutes the service-role key.
190
+ The generated file contains only `SUPACLOUD_ENV`, `SUPACLOUD_PROJECT_REF`,
191
+ `SUPABASE_URL`, and `SUPABASE_SERVICE_ROLE_KEY`; the public project origin is deliberately not
192
+ written as `SUPACLOUD_API_URL`, which Admin reserves for the Management API.
193
+ The success receipt marks `env_file_scope` as `project_application`. Standard
194
+ output otherwise contains only credential-free fields. Supply
195
+ `SUPACLOUD_API_TOKEN` through the process environment, never as a command
196
+ argument.
197
+
198
+ If the remote project is created but local env writing fails, the error receipt
199
+ retains only the safe project ref and API URL, sets `remote_created: true` and
200
+ `retry_safe: false`, and never includes the credential. A
201
+ `credential_file_state: "absent"` receipt confirms cleanup and includes
202
+ `credentials_written: false`. A `credential_file_state: "unknown"` receipt
203
+ omits `credentials_written`; treat the target path as secret-bearing until an
204
+ operator securely removes it or completes credential recovery/rotation. Repair
205
+ the local path only after reading back the existing project and following that
206
+ recovery flow; never blindly retry project creation.
207
+
208
+ Service control accepts canonical service names only. `postgrest` supports
209
+ `start`, `stop`, `restart`, `pause`, `resume`, and `status`; `gotrue`, `storage`,
210
+ `postgresql`, `realtime`, and `gateway` support `start`, `stop`, and `restart`.
211
+ The command calls only the Management API's existing
212
+ `/v1/projects/{ref}/services` routes. A non-2xx response, a `success: false`
213
+ receipt, or a response that does not match the requested service and action
214
+ exits non-zero. Successful inventory and control responses are emitted as JSON
215
+ with `project_ref` for strict read-back.
216
+
217
+ The Management API remains authoritative for SupAuth ownership. Controlling
218
+ GoTrue on a shared-auth project fails with `AUTH_RUNTIME_MANAGED_BY_OWNER`;
219
+ the CLI does not redirect the operation to the owner project. Supply
220
+ `SUPACLOUD_API_TOKEN` through the environment only; service-control commands do
221
+ not accept credential flags.
222
+
223
+ Create a completed full physical backup before a release with:
224
+
225
+ ```bash
226
+ supacloud-admin platform create_backup --ref abc123 --backup_type full
227
+ ```
228
+
229
+ The command reads the physical backup inventory before the write and performs
230
+ one bounded reconciliation read after every mutation attempt. It exits non-zero
231
+ unless the API confirms success and the inventory contains exactly one new,
232
+ completed full backup with a nonzero size. The Management API rejects unknown
233
+ project refs and resolves inventory from the persisted project database name.
234
+ The JSON receipt contains only the project ref, requested type, backup ID,
235
+ database, timestamps, and size. `platform list_backups --ref abc123` applies the
236
+ same strict, sanitized inventory validation without creating a backup.
109
237
 
110
238
  Gateway / Caddy commands (config is injected via the Caddy JSON Admin API; requires admin privileges):
111
239