@quatronic/qore 0.1.0 → 0.1.1

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.
package/README.md CHANGED
@@ -20,6 +20,9 @@ qore tenant list # list tenants you have access to
20
20
  qore tenant use <slug> # set the active tenant
21
21
  qore logout
22
22
  qore version # CLI + portal version info
23
+
24
+ qore env pull # write this module's local secrets into an env file
25
+ qore run -- <command> # run a command with those secrets in its environment
23
26
  ```
24
27
 
25
28
  ### Portals
@@ -33,6 +36,146 @@ it reports).
33
36
  qore login --portal staging
34
37
  ```
35
38
 
39
+ ### Repository context
40
+
41
+ Commands like `qore status` need to know which module you mean. By default
42
+ that comes from the git remote of the repository you're standing in:
43
+ `qore` reads `git remote -v`, prefers `origin`, falls back to `upstream`,
44
+ then the rest in git order, and resolves the remote's URL to a module on
45
+ the portal. Working from a personal fork whose `origin` the portal doesn't
46
+ know? As long as an `upstream` remote points at the real repository, that one
47
+ resolves — the context line then says `(upstream)`.
48
+
49
+ Pass `--module <slug|id>` to pick a module explicitly; the flag always wins
50
+ over the git remote. Inside a repository, `qore` still looks up the remote's
51
+ own module (from the cache, or with one extra request) only so the context
52
+ line can tell you when the flag overrides it. If a module is linked to more
53
+ than one app you can read, add `--app <slug|id>` to disambiguate.
54
+
55
+ Every context-aware command prints a context line to stderr (never stdout,
56
+ so it's safe to pipe `--json` output):
57
+
58
+ ```
59
+ → <Tenant> / <App> / <module> (<source>)
60
+ ```
61
+
62
+ `<source>` is the remote name that resolved it (`origin`, `upstream`, …),
63
+ or `--module` when you passed the flag. If `--module` resolves to a
64
+ different module than the repository's own remote would have, it reads
65
+ `--module, overrides <remote>`. With `--json`, this same information is
66
+ under `data.context` instead, and nothing about it goes to stderr.
67
+
68
+ #### `qore status`
69
+
70
+ Shows deployment and health per environment for the current module:
71
+
72
+ ```sh
73
+ qore status
74
+ ```
75
+
76
+ | Column | Meaning |
77
+ |--------|---------|
78
+ | ENV | Environment name |
79
+ | DEPLOY | Deployment status, or `paused` |
80
+ | COMMIT | Deployed commit SHA |
81
+ | DEPLOYED | How long ago that commit was deployed |
82
+ | APP HEALTH | The app's public health check (not the module's) |
83
+
84
+ #### `qore env pull`
85
+
86
+ Writes this module's local secrets into an env file in the current
87
+ repository:
88
+
89
+ ```sh
90
+ qore env pull
91
+ ```
92
+
93
+ - The target file defaults to the module type's own convention (e.g.
94
+ `.env.local`), or `.qore.json`'s `envFile`, or `--target <path>` — always
95
+ resolved against, and required to stay inside, the repository.
96
+ - If the file doesn't exist yet, it's seeded from `.env.example` when one is
97
+ present.
98
+ - Existing values you've hand-edited are kept by default. A key the portal
99
+ manages (e.g. `CONN_*`, `DATABASE_URL`) is always taken from the portal.
100
+ For any other key that differs between your file and the portal, pass
101
+ `--use-portal` to take the portal's value, or answer the interactive
102
+ prompt per key (which shows only the **length** of each value, never its
103
+ content — see "Values are never printed" below).
104
+ - The file is written with mode `0600` via a temp file in the same
105
+ directory, then renamed over the target — it's never truncated in place.
106
+ (On Windows, POSIX file modes don't apply — setting `0600` there is a
107
+ no-op; there's no equivalent file-permission hardening on that platform.)
108
+
109
+ **First use of a repository** requires confirmation — see "Trust on first
110
+ use" below. **Values are never printed**: not in `qore env pull`'s output,
111
+ not in the interactive conflict prompt, not in `--verbose` logs, and not in
112
+ the portal's own audit trail, which records key names only (see
113
+ `app.local_env.fetched`).
114
+
115
+ #### `qore run`
116
+
117
+ Runs a command with this module's local secrets injected into its
118
+ environment, without ever writing them to disk:
119
+
120
+ ```sh
121
+ qore run -- node server.js
122
+ qore run -- pnpm dev
123
+ ```
124
+
125
+ - Secrets are fetched fresh on every `run` — never cached — merged with
126
+ your current environment, and passed only to the child process.
127
+ - The command runs without a shell (`shell: false`); everything after `--`
128
+ is passed to it verbatim, including its own flags (a `--json` or
129
+ `--no-input` after `--` is the child's, never `qore`'s own). On Windows,
130
+ this is true in spirit but not literally for `.cmd` shims (e.g. `pnpm`,
131
+ `npm`, or anything installed as a `.cmd` wrapper): `cross-spawn` runs
132
+ those through `cmd.exe /d /s /c` under the hood, with its own escaping.
133
+ Pressing Ctrl+C there can also surface cmd's own
134
+ `Terminate batch job (Y/N)?` prompt.
135
+ - The child's exit code, or the signal it was killed with (e.g. Ctrl+C →
136
+ 128+signal), becomes `qore run`'s own exit code.
137
+ - **Secrets live in the child's environment**, which is inherited by any
138
+ process the child spawns (its grandchildren) and is readable by other
139
+ processes running as the same user (`/proc/<pid>/environ`, `ps eww`) —
140
+ no worse than a `.env.local` on disk, but worth knowing before running an
141
+ untrusted command this way.
142
+
143
+ #### `.qore.json`
144
+
145
+ An optional file at the repository root that configures `qore env pull`
146
+ for that repository. Schema:
147
+ [`schema/qore.schema.json`](./schema/qore.schema.json).
148
+
149
+ ```json
150
+ {
151
+ "$schema": "https://unpkg.com/@quatronic/qore/schema/qore.schema.json",
152
+ "envFile": ".env.local",
153
+ "localSecrets": ["MY_LOCAL_OVERRIDE"]
154
+ }
155
+ ```
156
+
157
+ It never holds a portal URL, tenant, app or module id — those are always
158
+ resolved from the git remote or `--module`/`--app`, never committed.
159
+
160
+ #### Trust on first use
161
+
162
+ The first time you run `qore env pull` or `qore run` against a given
163
+ repository (for a given module), `qore` asks you to confirm before pulling
164
+ secrets into it — trust-on-first-use, recorded locally, not a portal-side
165
+ grant. Pass `--yes` to trust non-interactively (CI, scripts) instead of
166
+ being prompted.
167
+
168
+ #### Resolution cache
169
+
170
+ Resolved `git remote` → module lookups are cached at
171
+ `<config dir>/qore/cache/repos.json` so repeat commands in the same
172
+ repository skip an extra request. It's pure cache — deleting the file is
173
+ always harmless, at worst the next command re-resolves.
174
+
175
+ If a repository resolves to no module on any portal you're logged in to,
176
+ the error lists the portals it tried and, when a staging repository looks
177
+ likely, suggests `qore login --portal staging`.
178
+
36
179
  ### `--json`
37
180
 
38
181
  Every command accepts `--json`, which prints exactly one JSON document on
@@ -49,8 +192,8 @@ qore whoami --json
49
192
  | Code | Meaning |
50
193
  |------|---------|
51
194
  | 0 | Success |
52
- | 1 | Internal error, or the OS keychain is unavailable/access was denied |
53
- | 2 | Missing or invalid context (e.g. a bad `--portal` value) |
195
+ | 1 | Internal error, `git` is not installed or not on `PATH`, or the OS keychain is unavailable/access was denied |
196
+ | 2 | Missing or invalid context (e.g. a bad `--portal` value, or no module selected), or the module is part of several apps and no `--app` was given |
54
197
  | 4 | Not logged in, session/login expired, login denied, or clock skew |
55
198
  | 5 | Access denied — lost tenant access, resource not found, no developer access |
56
199
  | 6 | Auth or API temporarily unreachable/unavailable |