@vectros-ai/cli 0.22.0 → 0.24.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.
- package/AUTHORING.md +37 -16
- package/CHANGELOG.md +155 -1
- package/README.md +171 -13
- package/dist/cli.js +4174 -2009
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +4175 -2010
- package/dist/cli.mjs.map +1 -1
- package/package.json +3 -3
package/AUTHORING.md
CHANGED
|
@@ -5,9 +5,10 @@ A **blueprint** is a versioned, reviewed bundle for one use case: a schema set
|
|
|
5
5
|
data, all with stable identifiers so applying it twice converges instead of
|
|
6
6
|
duplicating. `vectros bootstrap --blueprint <file>` applies it to provision a
|
|
7
7
|
ready-to-use data model + a narrow `ssk_*` scoped key — no root key, no manual
|
|
8
|
-
admin steps.
|
|
8
|
+
admin steps. `vectros blueprint apply <file> --tenant test|live` applies the same
|
|
9
|
+
blueprint WITHOUT minting a key, for re-applying a change from CI.
|
|
9
10
|
|
|
10
|
-
This guide is the authoring loop. Everything here except `bootstrap` is
|
|
11
|
+
This guide is the authoring loop. Everything here except `bootstrap` and `blueprint apply` is
|
|
11
12
|
**creds-free and offline** — you can iterate on a blueprint with no account.
|
|
12
13
|
|
|
13
14
|
> The examples use the bare `vectros` binary — install it once with
|
|
@@ -22,10 +23,11 @@ vectros blueprint init my-thing # 1. scaffold a starter
|
|
|
22
23
|
vectros blueprint validate ./my-thing.blueprint.yaml # 2. structural + scope-gate + lint (offline)
|
|
23
24
|
vectros blueprint plan ./my-thing.blueprint.yaml # 3. preview what it provisions (offline)
|
|
24
25
|
vectros blueprint-test ./my-thing.blueprint.yaml --env staging # 4. prove it live (creds; auto-teardown)
|
|
25
|
-
vectros bootstrap --blueprint ./my-thing.blueprint.yaml # 5. apply for real (needs a bridge token)
|
|
26
|
+
vectros bootstrap --blueprint ./my-thing.blueprint.yaml # 5. apply for real + mint a key (needs a bridge token)
|
|
27
|
+
vectros blueprint apply ./my-thing.blueprint.yaml --tenant test # 5'. apply for real, no key (CI: add --yes --confirm-existing-principal)
|
|
26
28
|
```
|
|
27
29
|
|
|
28
|
-
Steps 1–3 are **creds-free and offline**. Step 4 (`blueprint-test`) and step 5 (`bootstrap`) hit a live
|
|
30
|
+
Steps 1–3 are **creds-free and offline**. Step 4 (`blueprint-test`) and step 5 (`bootstrap` / `blueprint apply`) hit a live
|
|
29
31
|
environment — sign in once first with `vectros login` (`vectros whoami` shows the active session;
|
|
30
32
|
`vectros logout` clears it), or pass `--token`.
|
|
31
33
|
|
|
@@ -93,7 +95,7 @@ A name must be 2–50 chars: a lowercase letter, then lowercase letters / digits
|
|
|
93
95
|
|
|
94
96
|
```
|
|
95
97
|
Plan for blueprint 'my-thing' (v1.0.0) → context 'mcp':
|
|
96
|
-
+ schema 'thing' (
|
|
98
|
+
+ schema 'thing' (1 field, HYBRID) lookup: [title]
|
|
97
99
|
+ context 'mcp' (MCP — my-thing)
|
|
98
100
|
+ principal 'my-thing-sp' (SERVICE)
|
|
99
101
|
+ profile scopes [records:r, records:c, records:u, search:r, schemas:r] (data-plane ✓)
|
|
@@ -107,7 +109,7 @@ sharing an action set can still carry different `dataScope`:
|
|
|
107
109
|
|
|
108
110
|
```
|
|
109
111
|
Plan for blueprint 'my-thing' (v1.0.0) → context 'mcp':
|
|
110
|
-
+ schema 'thing' (
|
|
112
|
+
+ schema 'thing' (1 field, HYBRID) lookup: [title]
|
|
111
113
|
+ context 'mcp' (MCP — my-thing)
|
|
112
114
|
+ principal 'my-thing-sp' (SERVICE)
|
|
113
115
|
+ role 'case-handler' (1 clause, actions [records:cru])
|
|
@@ -132,6 +134,16 @@ config snippet to stdout instead of merging it into your client's config file. T
|
|
|
132
134
|
touching your account, stop at `blueprint plan` (offline) — `bootstrap`, with or without `--no-merge`,
|
|
133
135
|
always applies.
|
|
134
136
|
|
|
137
|
+
**`vectros blueprint apply`** is the same pipeline without the key. `--tenant test|live` is required (no default);
|
|
138
|
+
it prints the account, tenant and context it is pointed at before anything changes and asks (with no terminal,
|
|
139
|
+
`--yes` is required). It **deletes nothing unless `--prune` is passed**: with it, a trigger the file no longer
|
|
140
|
+
declares is removed when its stored `provisionedBy` marker equals this blueprint's `name` (read from the file) and
|
|
141
|
+
its principal's external id is the one this blueprint would derive. Those are stored markers, not verified
|
|
142
|
+
identities, so a blueprint that reuses another's `name` and omits some of its triggers will remove them. An
|
|
143
|
+
existing service principal needs `--confirm-existing-principal` (standing consent in a pipeline). It writes the
|
|
144
|
+
blueprint's sample `seed` records **only when you pass `--seed`**, in either tenant (the opposite of `bootstrap`,
|
|
145
|
+
which seeds unless `--no-seed`); `--no-seed` is refused on `apply`.
|
|
146
|
+
|
|
135
147
|
**Provisioning a production context — `--no-seed`.** A blueprint's `seed`
|
|
136
148
|
records are illustrative sample data: handy for a getting-started or demo
|
|
137
149
|
context, but synthetic clutter in a context that will hold real data. Pass
|
|
@@ -184,9 +196,10 @@ schemas:
|
|
|
184
196
|
filterable: false # available as a query filter
|
|
185
197
|
validation: { minLength: 1, maxLength: 200 } # server-enforced (ValidationRules)
|
|
186
198
|
renderHints: { label: Title, widget: text, order: 1, displayField: true } # UI hints (displayField = the headline column)
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
199
|
+
# No `externalId` field: it is a first-class identifier the platform reserves. A seed
|
|
200
|
+
# sets its externalId at the TOP LEVEL of the seed (see `seed:` below), never as a
|
|
201
|
+
# schema field and never inside `fields`; declaring it makes the first seeded
|
|
202
|
+
# provision fail with "Required field 'externalId' cannot be empty."
|
|
190
203
|
lookupFields: [title] # extra O(1) exact-match lookup indexes (max 10);
|
|
191
204
|
# object form { fieldName, unique?, rangeEnabled?,
|
|
192
205
|
# sortBy?, allowOverflow? } for constraints/range, or
|
|
@@ -250,9 +263,9 @@ seed:
|
|
|
250
263
|
typeName: thing
|
|
251
264
|
externalId: seed-welcome # stable → idempotent; re-apply converges
|
|
252
265
|
fields: { title: "Hello" }
|
|
253
|
-
# Seeds are illustrative sample data.
|
|
254
|
-
#
|
|
255
|
-
#
|
|
266
|
+
# Seeds are illustrative sample data. `bootstrap` applies them by default (pass
|
|
267
|
+
# `--no-seed` for a production context: schemas + key still apply); `blueprint
|
|
268
|
+
# apply` writes them only when you pass `--seed`.
|
|
256
269
|
|
|
257
270
|
issuers:
|
|
258
271
|
- issuerId: auth0-prod # your slug; 3-31 chars, lowercase letter first
|
|
@@ -264,9 +277,17 @@ issuers:
|
|
|
264
277
|
# in the BOOTSTRAP-token phase, alongside app-context/service-principal
|
|
265
278
|
# creation — NOT the same phase as schemas/accessProfile/roles above (see
|
|
266
279
|
# BLUEPRINT_FIELD_PHASES, exported by @vectros-ai/blueprints). Registration
|
|
267
|
-
# is
|
|
268
|
-
#
|
|
269
|
-
#
|
|
280
|
+
# is idempotent by issuerId, and a re-apply reconciles the editable fields
|
|
281
|
+
# (subClaim, emailClaim, userinfoUri, restrictedToDomain, selfSignupPolicies,
|
|
282
|
+
# capturedClaims). The trust-anchor fields (issuer, jwksUri, audience, contextId)
|
|
283
|
+
# are immutable: editing one on a registered issuer fails the apply with a
|
|
284
|
+
# 400, and rotating one means deleting the issuer and registering it again.
|
|
285
|
+
#
|
|
286
|
+
# On platform 0.45.0 and later an issuer without restrictedToDomain starts
|
|
287
|
+
# pending_verification and accepts no token until you prove you control the
|
|
288
|
+
# identity provider with `vectros issuers verify`. bootstrap still exits 0 and
|
|
289
|
+
# ends its output with the challenge and that command (--require-verified-issuers
|
|
290
|
+
# turns a pending issuer into exit 4). A restrictedToDomain issuer is active at once.
|
|
270
291
|
#
|
|
271
292
|
# Each entry's contextId must equal the blueprint's own contextId. An issuer
|
|
272
293
|
# is a trust anchor — whoever controls its jwksUri can mint identities your
|
|
@@ -637,7 +658,7 @@ one, the loader checks who pushed the current version:
|
|
|
637
658
|
under a different name instead, or coordinate with whoever owns it.
|
|
638
659
|
- **no owner recorded** (hand-authored via `vectros scripts push`, or pushed
|
|
639
660
|
before this check existed) — refused unless the OPERATOR re-runs
|
|
640
|
-
`bootstrap` with `--allow-script-adoption`. This is deliberately a
|
|
661
|
+
`bootstrap` (or `blueprint apply`) with `--allow-script-adoption`. This is deliberately a
|
|
641
662
|
human-supplied CLI flag, never something a blueprint's own YAML/JSON can
|
|
642
663
|
set — the blueprint is untrusted input, and "I already own this name" is not
|
|
643
664
|
something it gets to assert for itself. A successful adopting push reports
|
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,160 @@
|
|
|
3
3
|
All notable changes to `@vectros-ai/cli` are documented here.
|
|
4
4
|
This project adheres to [Semantic Versioning](https://semver.org).
|
|
5
5
|
|
|
6
|
+
## 0.24.0 — 2026-10-01
|
|
7
|
+
|
|
8
|
+
### Added
|
|
9
|
+
|
|
10
|
+
- **`vectros provider-config <create|list|get|update|delete>`** manages your bring-your-own-model provider
|
|
11
|
+
configs (owner-gated). `create` and `list` take `--tenant test|live`; `get`, `update` and `delete` address a
|
|
12
|
+
config by its id. The provider credential is read from `--api-key-secret-file <path>` (`-` for stdin); there is
|
|
13
|
+
no flag that takes the credential on the command line. `update` is a partial patch: an omitted field, including
|
|
14
|
+
`--api-key-secret-file`, keeps the stored value.
|
|
15
|
+
- **`vectros domains <register|list|delete|verify>`** manages domain ownership verification by DNS TXT record
|
|
16
|
+
(owner-gated) — the proof of control that `issuers register --restricted-to-domain` and webhook targets rely on.
|
|
17
|
+
`register` prints the exact TXT record to publish and the `verify` command to run next; registering a domain you
|
|
18
|
+
already hold returns a `409`. `verify` performs one DNS lookup per call and never polls. Domains are shared
|
|
19
|
+
across your live and test tenants, so none of the four verbs take `--tenant`. A verified domain that a webhook
|
|
20
|
+
uses is re-checked periodically; `list` and `verify` report a domain whose re-checks keep failing as
|
|
21
|
+
`REVOKED`.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- **`vectros --version` reports SDK 0.46.0 and blueprints 0.20.1.**
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
|
|
29
|
+
- **`issuers update --clear-restricted-to-domain` is described as the platform applies it.** The platform refuses
|
|
30
|
+
to clear a domain scope unless the registration already holds the unrestricted `(issuer, audience)` pair, which
|
|
31
|
+
a registration created scoped to a domain does not. To get an unrestricted issuer, `issuers delete` the scoped
|
|
32
|
+
registration, register one without `--restricted-to-domain`, and `issuers verify` it. A context holds one
|
|
33
|
+
active issuer, and the delete is refused once any user has been created or matched through the issuer; in that
|
|
34
|
+
case register the new issuer under a different app context. The README, the flag's help and the hints shown for
|
|
35
|
+
a blank `--restricted-to-domain` state this.
|
|
36
|
+
|
|
37
|
+
## 0.23.0 — 2026-09-22
|
|
38
|
+
|
|
39
|
+
### Added
|
|
40
|
+
|
|
41
|
+
- **`vectros blueprint apply <file|name> --tenant test|live`** provisions a blueprint into a tenant WITHOUT minting a
|
|
42
|
+
key: the same credential, gates and loader as `vectros bootstrap`, with no scoped key created, no keyring opened
|
|
43
|
+
and no MCP client config touched, so a CI runner can re-apply a changed blueprint (a key is named per machine, so
|
|
44
|
+
a fresh runner would otherwise mint a new one every run). `--tenant` is required (no default), the account, tenant,
|
|
45
|
+
context and API are printed before anything changes, and with no terminal `--yes` is required (exit `2`).
|
|
46
|
+
**Deletion is opt-in:** nothing is deleted unless `--prune` is passed, and then only triggers whose stored
|
|
47
|
+
`provisionedBy` marker equals the blueprint's `name` and whose principal's external id is the one that blueprint
|
|
48
|
+
would derive, and which the file no longer declares. Those are stored markers, not verified identities, and the
|
|
49
|
+
name is read from the blueprint file after any input substitution, so `--set` and `--values` can change it. A
|
|
50
|
+
matched trigger that cannot be removed makes `apply` exit `1`. An existing service principal needs
|
|
51
|
+
`--confirm-existing-principal` with `--yes` or with no terminal (at a terminal it asks; standing consent in a
|
|
52
|
+
pipeline); every run that proceeds prints which principal it reused and why. **Sample seed records are opt-in:**
|
|
53
|
+
unlike `bootstrap`, `apply` writes none unless `--seed` is passed, in either tenant, and never asks; the plan and the
|
|
54
|
+
summary say whether they will be or were written, and `--no-seed` is refused with exit `2`
|
|
55
|
+
(`apply does not seed by default: pass --seed to write the sample records`). Exit codes `0` to `3`,
|
|
56
|
+
and `4` under `--require-verified-issuers`. The flags shared with `bootstrap` come from one table with a parity
|
|
57
|
+
test; key- and client-related flags are refused with a pointer to `bootstrap`. `bootstrap` itself is unchanged
|
|
58
|
+
except in what it prints: a trigger row with no blueprint marker, which it never deleted, is now reported as
|
|
59
|
+
"left in place" instead of "could NOT be removed … still live".
|
|
60
|
+
|
|
61
|
+
- **`vectros issuers verify <issuerId> --context <ctx>`** answers a `pending_verification` issuer's
|
|
62
|
+
challenge (platform 0.45.0 and later). A registration made without `restrictedToDomain` accepts no
|
|
63
|
+
token until you prove you control the identity provider: add an admin-controlled rule there that
|
|
64
|
+
puts the registration's one-time value in the claim it names, sign in once, and send the resulting
|
|
65
|
+
JWT. The JWT goes in `--idp-token-file <path>` (or `-`, or piped on stdin) or `--idp-token <jwt>`,
|
|
66
|
+
never `--token`, which stays your Vectros credential; a value on the command line is visible in your
|
|
67
|
+
shell history and the process list, so the flag warns. The token is checked once and never printed or
|
|
68
|
+
stored. Exit `0` verified, `1` the request did not report success (the platform's message, and the `issuers get`
|
|
69
|
+
command to check where the registration stands before retrying: a timeout can leave it verified), `2` a bad
|
|
70
|
+
input, reported before any request is made. A value given to `--idp-token-file` that looks like a token is
|
|
71
|
+
refused without being repeated, input over 64 KB is refused, `--idp-token-file -` is refused on a terminal,
|
|
72
|
+
and a mistyped flag or command carrying a token is redacted in the parser's error. Every command it prints for you to run carries the same `--tenant`,
|
|
73
|
+
`--env` and `--base-url` you gave it.
|
|
74
|
+
- **`issuers register` and `issuers get` show a pending registration's challenge**: the claim, the
|
|
75
|
+
one-time value and its expiry, how to add the rule at Auth0, Okta, Microsoft Entra ID or Keycloak, and
|
|
76
|
+
the exact `verify` command. `register` exits `0`, since a pending issuer is its expected result. An
|
|
77
|
+
issuer whose challenge already expired while pending is reported as unverifiable, with the delete
|
|
78
|
+
command, instead of instructions that cannot work. Nothing prints on a platform that predates the
|
|
79
|
+
challenge.
|
|
80
|
+
- **`vectros bootstrap` handles an issuer that needs verification.** A finished apply exits `0`; the
|
|
81
|
+
summary says `pending verification` beside the issuer, and the apply's last output, on stderr, is the
|
|
82
|
+
challenge and the `verify` command. `--require-verified-issuers` exits `4` instead, after the apply
|
|
83
|
+
completed (a one-line notice follows the challenge), for a pipeline that must not go green over an issuer that cannot yet sign anyone in. The
|
|
84
|
+
exit codes are now documented in `bootstrap --help`. The plan preview says up front that an issuer
|
|
85
|
+
without `restrictedToDomain` will start pending, and `vectros blueprint-test` treats a pending issuer
|
|
86
|
+
as a pass and says so.
|
|
87
|
+
- **`vectros bootstrap` applies a blueprint issuer's `restrictedToDomain`** (new in
|
|
88
|
+
`@vectros-ai/blueprints` 0.20.0, which this release requires). The plan lists the domain, it is
|
|
89
|
+
sent when the issuer is registered and again on a re-apply, and a blueprint that leaves it out
|
|
90
|
+
never clears a scope set another way. An unverified domain fails the apply with the platform's
|
|
91
|
+
`400`. The apply also fails, before any schema, profile, role or key is written, when the
|
|
92
|
+
platform's response does not carry a declared domain: a platform that predates the field ignores
|
|
93
|
+
it, and carrying on would report success for an issuer that accepts more tokens than the blueprint
|
|
94
|
+
says. `vectros blueprint-test` checks the same on its readback.
|
|
95
|
+
- **`issuers register` and `issuers update` accept `--restricted-to-domain <domain>`.** Scopes the
|
|
96
|
+
registration to a domain already verified for your account (verified once, in the developer
|
|
97
|
+
portal): a token then matches only when its `hd` claim equals that domain, so the registration is
|
|
98
|
+
never blocked by an unrelated registration of the same issuer and audience. Google Workspace emits
|
|
99
|
+
`hd` natively; other identity providers need a claims-mapping rule that emits a claim named
|
|
100
|
+
exactly `hd`, otherwise none of their tokens will match. An unverified domain is refused by the
|
|
101
|
+
platform with `400`. `issuers register` never changes an existing registration, so when its
|
|
102
|
+
response does not carry the requested scope (an existing `--issuer-id` with a different one, or a
|
|
103
|
+
platform that predates the field) it now fails with exit `1` and names `issuers update`, which
|
|
104
|
+
applies it; a repeat with the same scope is still an idempotent success. `issuers get`,
|
|
105
|
+
`register` and `update` now show `restrictedToDomain`, and `issuers list` gains a
|
|
106
|
+
`restricted to domain` column; `--json` output already carried the field.
|
|
107
|
+
- **`issuers update --clear-restricted-to-domain`** removes the domain scope. It is a separate flag
|
|
108
|
+
because an empty domain is the way the platform spells "remove the scope": a blank
|
|
109
|
+
`--restricted-to-domain ''` (an unset shell variable, say) is refused with exit `2` instead of
|
|
110
|
+
being read as a clear, as is any value that is not a DNS name, and the two flags are mutually
|
|
111
|
+
exclusive. Omitting both leaves the stored scope unchanged. The platform can refuse to clear a
|
|
112
|
+
scope, for example when another registration already holds the unrestricted `(issuer, audience)`
|
|
113
|
+
pair; its message says why.
|
|
114
|
+
|
|
115
|
+
### Changed
|
|
116
|
+
|
|
117
|
+
- `vectros blueprint plan` ends with both ways to apply (`blueprint apply`, no key; `bootstrap`, which also mints one),
|
|
118
|
+
and, for a blueprint that declares sample records, says that `bootstrap` writes them unless `--no-seed` while
|
|
119
|
+
`blueprint apply` writes them only with `--seed`.
|
|
120
|
+
Every plan now states how a trigger is judged to belong to a blueprint (a stored marker, not a verified identity),
|
|
121
|
+
and a plan for `apply` says nothing is deleted unless `--prune` is passed. The existing-principal refusal says what
|
|
122
|
+
is about to happen when no key is minted (the principal's grants are rewritten).
|
|
123
|
+
- Built against the 0.45.0 SDK (`@vectros-ai/sdk`), which adds `verifyIssuer` and the
|
|
124
|
+
`pending_verification` status with its challenge fields.
|
|
125
|
+
|
|
126
|
+
### Security
|
|
127
|
+
|
|
128
|
+
- **`vectros login`'s local callback listener now completes sign-in only on a `GET /callback` carrying that
|
|
129
|
+
sign-in's own one-time `state`; every other request is ignored and the CLI keeps waiting for the real
|
|
130
|
+
redirect.** An identity-provider error redirect that arrives without a `state` is also ignored — Amazon
|
|
131
|
+
Cognito's own error redirects often omit one — and in that case the browser tab says to return to the
|
|
132
|
+
terminal, the CLI prints one notice, and waits until its timeout: press Ctrl+C and run `vectros login`
|
|
133
|
+
again. An error the sign-in page reports is shown with control and invisible formatting characters removed
|
|
134
|
+
and its length capped, and an error code that is not a plain OAuth token is not printed. This does not
|
|
135
|
+
protect against a program on your machine that can read the `state` out of the process list, where the
|
|
136
|
+
browser launcher receives the sign-in URL.
|
|
137
|
+
- **The text of a failed sign-in, or of a failed session refresh, is stripped of control characters and capped.**
|
|
138
|
+
When the token endpoint answers with an error, its response text is now stripped and capped at 500
|
|
139
|
+
characters wherever the message is built, so it applies to every command that refreshes your session (every
|
|
140
|
+
authenticated command), not only `vectros login`. Every `login failed:` line is also stripped (line breaks
|
|
141
|
+
removed) and capped at 1000 characters, whatever the source (a network error, a file error).
|
|
142
|
+
- **Not covered here:** error text that comes from the Vectros API, and the values other commands print (names
|
|
143
|
+
of keys, roles, contexts), is printed as received. This entry changes only the sign-in flow and the token
|
|
144
|
+
endpoint's failure text. The plan preview that `vectros blueprint apply` and `bootstrap` print now uses the
|
|
145
|
+
same, stronger stripping for the issuer fields it shows.
|
|
146
|
+
|
|
147
|
+
### Fixed
|
|
148
|
+
|
|
149
|
+
- The re-apply note in the plan preview listed only some of the issuer fields that reconcile. It now
|
|
150
|
+
names all of them, including `restrictedToDomain` and `capturedClaims`.
|
|
151
|
+
- `AUTHORING.md` said issuer registration is create-once with no update. A re-apply reconciles the
|
|
152
|
+
editable issuer fields and rejects an edited trust-anchor field (`issuer`, `jwksUri`, `audience`,
|
|
153
|
+
`contextId`) with the platform's `400`; the text now says so.
|
|
154
|
+
- **`vectros blueprint init`'s scaffold no longer fails on its first seeded provision.** In CLI 0.22.0 and earlier the
|
|
155
|
+
generated blueprint declared `externalId` as a required schema field, which the platform reserves, so applying it
|
|
156
|
+
with its seed (`vectros bootstrap`, or `vectros blueprint apply --seed`) stopped with `Required field 'externalId'
|
|
157
|
+
cannot be empty.` The scaffold and the authoring guide's example now leave the field out; a seed sets its
|
|
158
|
+
`externalId` at the top level only. A blueprint you scaffolded earlier still needs the field deleted by hand.
|
|
159
|
+
|
|
6
160
|
## 0.22.0 — 2026-09-17
|
|
7
161
|
|
|
8
162
|
### Changed
|
|
@@ -171,7 +325,7 @@ This project adheres to [Semantic Versioning](https://semver.org).
|
|
|
171
325
|
process stage** (`src/base-url.ts`'s doc comment, `src/scope-gate.ts` x3 — a backend method
|
|
172
326
|
name and two sibling-package references, one of them also a monorepo path —
|
|
173
327
|
`THIRD-PARTY-NOTICES.md`'s generation note naming an internal build-script path, and
|
|
174
|
-
`src/harness.ts`'s
|
|
328
|
+
`src/harness.ts`'s comment naming an internal review process) — found by a post-merge
|
|
175
329
|
audit. All reworded to describe the mechanism/sibling generically, keeping the substantive
|
|
176
330
|
rationale; no behavioral change.
|
|
177
331
|
|
package/README.md
CHANGED
|
@@ -6,10 +6,13 @@
|
|
|
6
6
|
The Vectros provisioning CLI — the `vectros` binary:
|
|
7
7
|
|
|
8
8
|
- **`vectros bootstrap`** — provision a least-privilege MCP credential (+ optional blueprint).
|
|
9
|
-
- **`vectros blueprint`** — author + inspect blueprints (`init` / `validate` / `plan` / `list
|
|
9
|
+
- **`vectros blueprint`** — author + inspect blueprints (`init` / `validate` / `plan` / `list`, creds-free), and
|
|
10
|
+
**`apply`** one into a tenant without minting a key (for CI).
|
|
10
11
|
- **`vectros blueprint-test`** — apply a blueprint to a live env, assert it provisioned a working credential, then tear it down.
|
|
11
12
|
- **`vectros context`** — create, list, and destroy app contexts.
|
|
12
13
|
- **`vectros issuers`** — register, update, delete, and inspect third-party IdP issuers (token-exchange trust anchors) for a context.
|
|
14
|
+
- **`vectros provider-config`** — create, list, get, update, and delete BYOM (bring-your-own-model) tenant-level provider configs.
|
|
15
|
+
- **`vectros domains`** — register a domain, list your registrations, and prove DNS TXT ownership.
|
|
13
16
|
- **`vectros namespace`** — register a new scope namespace, and list/get existing ones.
|
|
14
17
|
- **`vectros identity`** — manage tenant-wide principals (users, orgs, clients, and namespaces you register).
|
|
15
18
|
- **`vectros role`** — define reusable, context-scoped access rules.
|
|
@@ -73,7 +76,28 @@ On a machine with no local record of a prior mint (e.g. an ephemeral CI
|
|
|
73
76
|
container re-running `--yes` for the first time) against a blueprint whose
|
|
74
77
|
service principal already exists in the tenant, `--yes` alone isn't enough —
|
|
75
78
|
add `--confirm-existing-principal` to make that expected case explicit and
|
|
76
|
-
non-interactive; see AUTHORING.md's "idempotency contract" for why.
|
|
79
|
+
non-interactive; see AUTHORING.md's "idempotency contract" for why. For a CI re-apply that has no use for the
|
|
80
|
+
key, `vectros blueprint apply` (below) is the better fit.
|
|
81
|
+
|
|
82
|
+
**An issuer that needs verification.** A blueprint's `issuers` entry registered without `restrictedToDomain` starts
|
|
83
|
+
`pending_verification` on platform 0.45.0 and later: it accepts no token until you prove you control the identity
|
|
84
|
+
provider, which takes a real login there after someone adds a claim rule, so no bootstrap can finish it. A finished
|
|
85
|
+
apply is still a successful apply and exits `0`. The summary says `pending verification` next to the issuer, and the
|
|
86
|
+
apply's last output, on stderr, is the challenge (the claim, the one-time value and its expiry), how to add the rule
|
|
87
|
+
at Auth0, Okta, Microsoft Entra ID or Keycloak, and the exact `vectros issuers verify` command that finishes it.
|
|
88
|
+
Re-running bootstrap shows the same challenge until the issuer is verified, then says nothing about it. If the
|
|
89
|
+
challenge has expired while the issuer was still pending it can never be verified: the output says so, and names
|
|
90
|
+
the delete command and the re-run; nothing is deleted for you. Pass `--require-verified-issuers` to make a pending
|
|
91
|
+
issuer exit `4` instead (the apply itself still completes, and a one-line notice of the exit code follows the
|
|
92
|
+
challenge), for a pipeline that must not go green over an issuer that cannot yet sign anyone in. Domain-scoped issuers (`restrictedToDomain`) are active at once and never pending.
|
|
93
|
+
|
|
94
|
+
Exit codes: `0` applied (also `--help`, and answering no at "Apply this plan?"); `1` failed: a bad flag, an
|
|
95
|
+
unknown or malformed blueprint, a missing or invalid `--set` input, a declared issuer scope the platform did not
|
|
96
|
+
apply, or any error while applying (the message says what did and did not run); `2` refused by a gate: the scope
|
|
97
|
+
gate or the capability gate rejected the blueprint, an identity it references could not be resolved, or it declares
|
|
98
|
+
a tenant-wide namespace without the opt-in (the message says what, if anything, was already provisioned); `3` a
|
|
99
|
+
confirmation it did not get (an existing service principal, a key that cannot be recovered); `4` applied in full with
|
|
100
|
+
`--require-verified-issuers` and an issuer still pending verification.
|
|
77
101
|
|
|
78
102
|
A bundled blueprint ships with **sample seed records** so the credential works
|
|
79
103
|
the moment it's minted. For a **production** context that's synthetic clutter:
|
|
@@ -82,9 +106,9 @@ scoped key — but creates no sample records, leaving the context clean for real
|
|
|
82
106
|
data. (Interactively, a blueprint with seeds asks before adding them.) This
|
|
83
107
|
differs from `--blank`, which is credential-only and drops the schemas too.
|
|
84
108
|
|
|
85
|
-
## `vectros blueprint` — authoring (creds-free)
|
|
109
|
+
## `vectros blueprint` — authoring (creds-free), then `apply`
|
|
86
110
|
|
|
87
|
-
Author and inspect blueprints without an account. You'll run these repeatedly,
|
|
111
|
+
Author and inspect blueprints without an account (everything here except `apply`, which is the next section and needs credentials). You'll run these repeatedly,
|
|
88
112
|
so install once and drop the `npx` prefix (`npm i -g @vectros-ai/cli`, or prefix
|
|
89
113
|
each command with `npx -y @vectros-ai/cli`). The inner loop:
|
|
90
114
|
|
|
@@ -92,18 +116,82 @@ each command with `npx -y @vectros-ai/cli`). The inner loop:
|
|
|
92
116
|
vectros blueprint init my-thing # scaffold a commented YAML starter
|
|
93
117
|
# …edit ./my-thing.blueprint.yaml…
|
|
94
118
|
vectros blueprint validate ./my-thing.blueprint.yaml # structural + scope-gate + lint
|
|
95
|
-
vectros blueprint plan ./my-thing.blueprint.yaml # preview what bootstrap would provision
|
|
96
|
-
vectros
|
|
119
|
+
vectros blueprint plan ./my-thing.blueprint.yaml # preview what bootstrap or apply would provision
|
|
120
|
+
vectros blueprint apply ./my-thing.blueprint.yaml --tenant test # provision it, no key (see below)
|
|
121
|
+
vectros bootstrap --blueprint ./my-thing.blueprint.yaml # provision it AND mint a key for your MCP client
|
|
97
122
|
```
|
|
98
123
|
|
|
99
124
|
- `init` — write a starter (`--from <bundled>` copies an exemplar; `--out`, `--force`).
|
|
100
125
|
- `validate` — structural parse → scope gate → linter. Accepts a file **or** a bundled name.
|
|
101
126
|
- `plan` — validate, then a terraform-style preview; mints nothing.
|
|
102
127
|
- `list` — the bundled library.
|
|
128
|
+
- `apply` — provision a blueprint into a tenant, minting no key; needs credentials (next section).
|
|
103
129
|
|
|
104
130
|
Full guide: [AUTHORING.md](./AUTHORING.md). Format reference:
|
|
105
131
|
[`@vectros-ai/blueprints`](https://www.npmjs.com/package/@vectros-ai/blueprints).
|
|
106
132
|
|
|
133
|
+
## `vectros blueprint apply` — provision a blueprint, mint no key
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
vectros blueprint apply ./my-thing.blueprint.yaml --tenant test
|
|
137
|
+
# a CI re-apply, from a machine that has never seen this context:
|
|
138
|
+
vectros blueprint apply ./my-thing.blueprint.yaml --tenant live --yes --confirm-existing-principal
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`apply` runs the same pipeline as `vectros bootstrap` (the same credential, the same scope and capability gates,
|
|
142
|
+
the same loader) with the key step switched off: the context, its service principal and access profile, schemas,
|
|
143
|
+
roles, issuers, triggers and scripts are created or reconciled (and, only if you pass `--seed`, the blueprint's sample
|
|
144
|
+
seed records are written), but **no scoped key is minted,
|
|
145
|
+
nothing is written to a keyring, and no MCP client config is touched**. (Short-lived bootstrap tokens are minted
|
|
146
|
+
to call the platform, as with `bootstrap`; none is a scoped key.) That is what makes it fit for re-applying
|
|
147
|
+
a changed blueprint from CI: a key is named per machine, so a fresh runner would name (and mint) a new one on every
|
|
148
|
+
run. Use `bootstrap` when you also want the credential.
|
|
149
|
+
|
|
150
|
+
- **The target is explicit.** `--tenant test|live` is required; there is no default, so a run never lands on
|
|
151
|
+
`live` by omission. Before it changes anything `apply` prints the account, tenant, context and API it is
|
|
152
|
+
pointed at, then the plan (which has no key step), then asks to proceed.
|
|
153
|
+
- **It never runs unattended without `--yes`.** With no terminal, `--yes` is required (exit `2`, before anything
|
|
154
|
+
is read).
|
|
155
|
+
- **Deletion is opt-in.** `apply` deletes nothing unless you pass `--prune`. With it, each trigger in the context
|
|
156
|
+
whose stored `provisionedBy` marker equals this blueprint's `name` and whose principal's external id is the one
|
|
157
|
+
this blueprint would derive, and which the file no longer declares, is removed (the rule and its access profile;
|
|
158
|
+
the principal is kept). Both are **stored markers, not verified identities**, and the name comes from the
|
|
159
|
+
blueprint **file** (after any `${{ inputs.* }}` substitution, so `--set` and `--values` can change it): the scope gate bounds what a blueprint may grant, not what it may delete, so a blueprint that
|
|
160
|
+
reuses another one's `name` and omits some of its triggers will remove them. Rows with no marker are left
|
|
161
|
+
alone and reported; another blueprint's rows are left alone. If a removal it matched fails (a failed read or
|
|
162
|
+
delete), `apply` exits `1` and names the trigger that may still be live. Without `--prune` the summary says
|
|
163
|
+
undeclared triggers were left in place. (Apply still replaces an access profile's scopes and a role's rules in
|
|
164
|
+
place, as `bootstrap` does.)
|
|
165
|
+
- **An existing service principal needs `--confirm-existing-principal`** (with `--yes`, or with no terminal),
|
|
166
|
+
which is every apply once the principal exists, on any machine: `apply` never reads a local key record, so a
|
|
167
|
+
machine that ran `bootstrap` is not exempt. It lets `apply` rewrite that principal's access profile, and covers the
|
|
168
|
+
blueprint's own service principal only (the principals a blueprint's triggers use are ensured without this check,
|
|
169
|
+
as with `bootstrap`). In a pipeline this flag is standing consent: it also waves through a blueprint whose
|
|
170
|
+
`servicePrincipal.externalId` collides with an unrelated identity, so keep the blueprint's source reviewed. Every
|
|
171
|
+
run that proceeds prints which principal it reused (id, external id, created time) and why.
|
|
172
|
+
- **Sample seed records are opt-in: `apply` writes none unless you pass `--seed`,** in either tenant, and never asks.
|
|
173
|
+
This is the opposite of `bootstrap` (which seeds unless `--no-seed`) on purpose: a blueprint's seeds are
|
|
174
|
+
illustrative, not real data, and a re-apply from a pipeline must not write them by omission. When the blueprint
|
|
175
|
+
declares sample records (or you pass `--seed`), the plan and the summary say plainly whether they will be or were
|
|
176
|
+
written. `--no-seed` is refused here, because a flag that does nothing invites drift:
|
|
177
|
+
`apply does not seed by default: pass --seed to write the sample records`.
|
|
178
|
+
- **Exit codes:** `0` applied (also `--help`, and declining the confirmation); `1` failed while applying, or
|
|
179
|
+
`--prune` could not remove a trigger it matched (steps earlier in the plan may already have been applied; a re-run
|
|
180
|
+
converges); `2` refused, before anything was changed (a usage error, no `--yes` without a terminal, no credential,
|
|
181
|
+
an unknown or malformed blueprint, a missing `--set` input, an invalid base URL, the scope or capability gate, a
|
|
182
|
+
tenant-wide namespace without the opt-in), or, after the context and principal were provisioned, an identity the
|
|
183
|
+
blueprint references that could not be resolved; `3` an existing principal was not confirmed; `4` applied in full
|
|
184
|
+
but `--require-verified-issuers` was given and an issuer is pending verification.
|
|
185
|
+
|
|
186
|
+
Flags it shares with `bootstrap` (`--set`, `--values`, `--allow-tenant-wide-namespaces`,
|
|
187
|
+
`--allow-script-adoption`, `--require-verified-issuers`, `--token`, `--base-url`) behave the same. `--tenant`,
|
|
188
|
+
`--yes` and `--confirm-existing-principal` are shared but behave as described above (`--tenant` is required here,
|
|
189
|
+
`--yes` is required without a terminal, and the principal flag applies to every re-apply). The flags that concern a
|
|
190
|
+
key or your MCP client (`--rotate`, `--client`, `--no-merge`, `--activate`, `--no-activate`, `--use-scoped-token`,
|
|
191
|
+
`--test`) belong to `bootstrap` and are refused with a pointer; the blueprint is an argument, not `--blueprint`, and
|
|
192
|
+
there is no `--blank`. A script pushed onto an existing hand-authored name (`--allow-script-adoption`) is checked
|
|
193
|
+
when the scripts are pushed, partway through, not up front. `vectros blueprint apply --help` lists everything.
|
|
194
|
+
|
|
107
195
|
## `vectros blueprint-test` — verify it actually provisions (creds-required)
|
|
108
196
|
|
|
109
197
|
`validate`/`plan` check a blueprint statically; `blueprint-test` proves it
|
|
@@ -112,11 +200,11 @@ the result (the app-context + each schema are readable back, and the freshly
|
|
|
112
200
|
minted `ssk_*` authenticates as a scoped key with the requested actions), then
|
|
113
201
|
**tears down** what it created — schemas, the AccessProfile, seed records, and
|
|
114
202
|
the key. Teardown is *created-only*: anything that already existed before the run
|
|
115
|
-
is left untouched, so it
|
|
203
|
+
is left untouched, so it can be pointed at a tenant other people use.
|
|
116
204
|
|
|
117
205
|
```bash
|
|
118
|
-
# Apply → assert → teardown against
|
|
119
|
-
vectros blueprint-test ./my-thing.blueprint.yaml --
|
|
206
|
+
# Apply → assert → teardown against your test tenant (sign in first, or pass --token).
|
|
207
|
+
vectros blueprint-test ./my-thing.blueprint.yaml --tenant test
|
|
120
208
|
|
|
121
209
|
# Leave the provisioned graph in place to inspect it.
|
|
122
210
|
vectros blueprint-test task-management --keep
|
|
@@ -170,18 +258,88 @@ vectros issuers list --context my-app
|
|
|
170
258
|
vectros issuers get primary --context my-app
|
|
171
259
|
vectros issuers update primary --context my-app --status suspended
|
|
172
260
|
vectros issuers delete primary --context my-app # re-types the id to confirm
|
|
261
|
+
vectros issuers verify auth0-prod --context my-app --idp-token-file ./idp-token.txt
|
|
173
262
|
```
|
|
174
263
|
|
|
175
264
|
| Subcommand | Flags | Notes |
|
|
176
265
|
|---|---|---|
|
|
177
|
-
| `register` | `--context`, `--issuer-id`, `--issuer`, `--jwks-uri`, `--audience` (all required); `--sub-claim`, `--email-claim`, `--userinfo-uri`, `--self-signup-policy <type:roleId>` (repeatable), `--captured-claim <name>` (repeatable), `--tenant test\|live` | Idempotent by `--issuer-id` within the tenant — a repeat returns the existing registration unchanged, not an error. `--captured-claim` names additional OIDC claims to capture beyond the email claim on every successful token exchange, stored as your tenant's golden identity-provider-asserted copy for that user; omit it to capture nothing beyond email. At most 20 names of at most 64 characters, no duplicates. `--jwks-uri`/`--userinfo-uri` must be `https://` — an `http://` value is refused with 400. A tenant may hold at most 50 registrations at once; registering past that cap is also refused with 400. A `--self-signup-policy` naming a role that authors, updates, or deletes scripts (`scripts:c`/`u`/`d`) is refused — a self-signup role may still read or execute scripts. |
|
|
178
|
-
| `update <issuerId>` | `--context <contextId>` (required); `--sub-claim`, `--email-claim`, `--userinfo-uri`, `--status active\|suspended`, `--self-signup-policy <type:roleId>` (repeatable), `--clear-self-signup-policies`, `--captured-claim <name>` (repeatable), `--clear-captured-claims`, `--tenant test\|live` | Omitting `--captured-claim` leaves the stored list UNCHANGED; `--clear-captured-claims` sends an explicit empty list (capture nothing beyond email). The two are mutually exclusive, and the same absent-vs-clear split applies to `--self-signup-policy`. Only ever sends the SAFE, mutable fields — `issuer`/`jwks-uri`/`audience`/`contextId` are trust-anchor fields, immutable via this route on the platform side; rotating one is `delete` + `register`. `--sub-claim` is refused with 400 once any user has ever bound through this issuer — supplying the value it already has is still a no-op. `--userinfo-uri` must be `https://`, same as at registration. |
|
|
266
|
+
| `register` | `--context`, `--issuer-id`, `--issuer`, `--jwks-uri`, `--audience` (all required); `--sub-claim`, `--email-claim`, `--userinfo-uri`, `--self-signup-policy <type:roleId>` (repeatable), `--captured-claim <name>` (repeatable), `--restricted-to-domain <domain>`, `--tenant test\|live` | Idempotent by `--issuer-id` within the tenant — a repeat returns the existing registration unchanged, not an error. `--captured-claim` names additional OIDC claims to capture beyond the email claim on every successful token exchange, stored as your tenant's golden identity-provider-asserted copy for that user; omit it to capture nothing beyond email. At most 20 names of at most 64 characters, no duplicates. `--jwks-uri`/`--userinfo-uri` must be `https://` — an `http://` value is refused with 400. A tenant may hold at most 50 registrations at once; registering past that cap is also refused with 400. A `--self-signup-policy` naming a role that authors, updates, or deletes scripts (`scripts:c`/`u`/`d`) is refused — a self-signup role may still read or execute scripts. `--restricted-to-domain` scopes the registration to a domain already verified for your account (verified once, in the developer portal): a token then matches only when its `hd` claim equals that domain, so the registration is never blocked by an unrelated registration of the same issuer and audience. Google Workspace emits `hd` natively; other identity providers need a claims-mapping rule that emits a claim named exactly `hd`, otherwise none of their tokens will match. An unverified domain is refused with 400; a value that is not a DNS name (including a blank one) is refused locally. `register` never changes an existing registration, so when the response does not carry the requested scope (an existing `--issuer-id` with a different one, or a platform that predates the field) it fails with exit 1 and names `issuers update`, which does apply it; a repeat with the same scope is still an idempotent success. |
|
|
267
|
+
| `update <issuerId>` | `--context <contextId>` (required); `--sub-claim`, `--email-claim`, `--userinfo-uri`, `--status active\|suspended`, `--self-signup-policy <type:roleId>` (repeatable), `--clear-self-signup-policies`, `--captured-claim <name>` (repeatable), `--clear-captured-claims`, `--restricted-to-domain <domain>`, `--clear-restricted-to-domain`, `--tenant test\|live` | Omitting `--captured-claim` leaves the stored list UNCHANGED; `--clear-captured-claims` sends an explicit empty list (capture nothing beyond email). The two are mutually exclusive, and the same absent-vs-clear split applies to `--self-signup-policy`. Only ever sends the SAFE, mutable fields — `issuer`/`jwks-uri`/`audience`/`contextId` are trust-anchor fields, immutable via this route on the platform side; rotating one is `delete` + `register`. `--sub-claim` is refused with 400 once any user has ever bound through this issuer — supplying the value it already has is still a no-op. `--userinfo-uri` must be `https://`, same as at registration. Omitting `--restricted-to-domain` leaves the stored scope UNCHANGED; `--clear-restricted-to-domain` removes it, and a blank `--restricted-to-domain ''` is refused locally rather than read as a clear. The two are mutually exclusive, and a new domain must already be verified for your account. From platform 0.45.0 the platform refuses to clear the scope unless the registration already holds the unrestricted `(issuer, audience)` pair, which a registration created scoped to a domain normally does not, since it never proved control of that pair. To get an unrestricted issuer instead, `delete` the scoped registration, `register` a new one without `--restricted-to-domain`, and `verify` it. A context holds one active issuer, and `delete` is refused once any user has been created or matched through the issuer; in that case register the new issuer under a different app context. ⚠️ Scoping an existing issuer stops matching every token that carries no matching `hd` claim, including those of users who signed in before. |
|
|
179
268
|
| `delete <issuerId>` | `--context <contextId>` (required), `--force`, `--tenant test\|live` | Re-types the issuer id to confirm (mirrors `context destroy`); `--force` skips the prompt and is required when stdin isn't a TTY. Refused server-side while any user was ever created or matched through this issuer. |
|
|
180
269
|
| `list` | `--context <contextId>` (required), `--tenant test\|live` | Every issuer registered in that context. `--context` has no default — an issuer read is confined to the context you name; there's no tenant-wide "every issuer in every context" view. |
|
|
181
|
-
| `get <issuerId>` | `--context <contextId>` (required), `--tenant test\|live` | One issuer's full registration, including its self-signup policies
|
|
270
|
+
| `get <issuerId>` | `--context <contextId>` (required), `--tenant test\|live` | One issuer's full registration, including its self-signup policies, captured claims and `restrictedToDomain`. |
|
|
271
|
+
| `verify <issuerId>` | `--context <contextId>` (required); `--idp-token-file <path>` (or `-` for stdin), `--idp-token <jwt>`, `--tenant test\|live` | Proves you control the identity provider, activating a `pending_verification` registration (0.45.0+): send a JWT from a real login that carries the registration's one-time value in the claim it names. The JWT can also be piped on stdin, and is checked once and never printed or stored. It is NOT `--token`, which stays your Vectros credential; prefer `--idp-token-file` or stdin, since a value on the command line is visible in your shell history and the process list. Exit `0` verified, `1` this request did not report success (the message says why; `issuers get` shows where the registration stands, which is worth a look before retrying, because a timeout can leave it verified), `2` a bad input (no network is touched). `--idp-token-file` takes a path: a value that looks like a token is refused without being repeated, and so is anything over 64 KB. Given only a pipe, it reads the token from stdin and says so on stderr; `--idp-token-file -` is for a pipe and is refused on a terminal, where a pasted token would be displayed. The provider's OpenID Connect discovery document must list exactly the `jwksUri` you registered. |
|
|
272
|
+
|
|
273
|
+
All six accept `--json`, plus the common auth flags (`--base-url`, `--token`). `register` and `get` print the
|
|
274
|
+
challenge of a `pending_verification` registration (the claim, the one-time value, its expiry) with the same provider
|
|
275
|
+
instructions and the exact `verify` command; a registration made without `--restricted-to-domain` starts that way on
|
|
276
|
+
platform 0.45.0 and later, and `register` exits `0` because a pending issuer is its expected result.
|
|
277
|
+
|
|
278
|
+
## `vectros provider-config` — BYOM tenant-level provider configs
|
|
279
|
+
|
|
280
|
+
Manage per-tenant "bring your own model" provider configs — a customer-supplied inference
|
|
281
|
+
endpoint + credential the platform can route to, instead of (or alongside) Vectros's own
|
|
282
|
+
platform-billed models. A tenant may hold more than one, each independently selected by its
|
|
283
|
+
`alias`. There is no SDK support for this route (it is a dev-portal-only surface, like
|
|
284
|
+
`vectros context`) — every verb here calls the owner-gated developer route directly.
|
|
285
|
+
|
|
286
|
+
```bash
|
|
287
|
+
vectros provider-config create --tenant live --alias primary \
|
|
288
|
+
--provider-type ANTHROPIC_NATIVE --billing-mode CUSTOMER_DIRECT \
|
|
289
|
+
--waiver-type byo-model-inference:customer-key \
|
|
290
|
+
--api-key-secret-file ./anthropic-key.txt
|
|
291
|
+
vectros provider-config list --tenant live
|
|
292
|
+
vectros provider-config get pc_abc123
|
|
293
|
+
vectros provider-config update pc_abc123 --status DISABLED
|
|
294
|
+
vectros provider-config delete pc_abc123 # re-types the id to confirm
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
| Subcommand | Flags | Notes |
|
|
298
|
+
|---|---|---|
|
|
299
|
+
| `create` | `--alias`, `--provider-type ANTHROPIC_NATIVE\|OPENAI_COMPATIBLE`, `--billing-mode PLATFORM_BILLED\|CUSTOMER_DIRECT`, `--waiver-type`, `--api-key-secret-file <path>` (all required); `--endpoint`, `--declared-processing-region`, `--default-provider-model-id`, `--platform-token-factor`, `--platform-output-weight` (required together, only under `PLATFORM_BILLED`), `--status`, `--tenant test\|live` | NOT idempotent — a repeat `--alias` in the same tenant 400s. `--endpoint` is required for `OPENAI_COMPATIBLE` (no default — every self-hosted deployment is a distinct URL) and an optional override for `ANTHROPIC_NATIVE`; it must be an `https://` URL whose host resolves to a public address. `--status ACTIVE` (the default) requires the tenant already hold a granted waiver for `--waiver-type`. |
|
|
300
|
+
| `list` | `--tenant test\|live` | Every config in one tenant — there is no combined test+live view. |
|
|
301
|
+
| `get <id>` | | One config's metadata. The secret is never returned by the platform, on this or any other verb. |
|
|
302
|
+
| `update <id>` | Same fields as `create` except `--tenant`, all optional | Partial update — an omitted field (`--api-key-secret-file` included) leaves the stored value unchanged. Switching `--billing-mode CUSTOMER_DIRECT` clears the platform pricing fields server-side regardless of what else is sent. |
|
|
303
|
+
| `delete <id>` | `--force` | Re-types the id to confirm (mirrors `issuers delete`); `--force` skips the prompt and is required when stdin is not a TTY. |
|
|
304
|
+
|
|
305
|
+
**There is deliberately no `--api-key-secret <value>` flag** — a live provider credential on the
|
|
306
|
+
command line is visible in shell history and the process list. Pass `--api-key-secret-file
|
|
307
|
+
<path>` (`-` for stdin instead of a file), the same shape `issuers verify
|
|
308
|
+
--idp-token-file` already uses for a different live credential.
|
|
182
309
|
|
|
183
310
|
All five accept `--json`, plus the common auth flags (`--base-url`, `--token`).
|
|
184
311
|
|
|
312
|
+
## `vectros domains` — domain ownership verification
|
|
313
|
+
|
|
314
|
+
Prove control of a domain via a DNS TXT record — the same proof-of-control a `vectros issuers
|
|
315
|
+
register --restricted-to-domain` scope, or a webhook target, is checked against. Verification is
|
|
316
|
+
Account-level (shared across your live and test tenants), so none of these commands take
|
|
317
|
+
`--tenant`.
|
|
318
|
+
|
|
319
|
+
```bash
|
|
320
|
+
vectros domains register --domain example.com
|
|
321
|
+
# → prints the TXT record to publish and the exact verify command
|
|
322
|
+
vectros domains list
|
|
323
|
+
vectros domains verify dom_abc123
|
|
324
|
+
vectros domains delete dom_abc123 # re-types the id to confirm
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
| Subcommand | Flags | Notes |
|
|
328
|
+
|---|---|---|
|
|
329
|
+
| `register` | `--domain <domain>` (required) | NOT idempotent — registering a domain you already hold 409s, naming the existing id/status and (if still pending) the `verify` command to run instead. Prints the exact DNS TXT record to publish. |
|
|
330
|
+
| `list` | | Every domain registered for your account, across both tenants. |
|
|
331
|
+
| `verify <id>` | | Performs ONE DNS TXT lookup and reports `VERIFIED`, `FAILED` (never proved) or `REVOKED` (proved once, since lost) — always safe to re-run, never polls for you (the platform's TXT lookup can only succeed once your DNS provider has actually propagated the record). Exit `0` verified, `1` not verified — the platform reports `200` either way, so the exit code (not the HTTP status) is what a script should branch on. |
|
|
332
|
+
| `delete <id>` | `--force` | Re-types the id to confirm; refused server-side (`409`) while any active webhook still references the domain. |
|
|
333
|
+
|
|
334
|
+
All four accept `--json`, plus the common auth flags (`--base-url`, `--token`). A blueprint can
|
|
335
|
+
only REFERENCE an already-verified domain (as `issuers`' `restrictedToDomain` already does) — it
|
|
336
|
+
cannot declare/register one.
|
|
337
|
+
|
|
338
|
+
A verified domain that a webhook uses is re-checked periodically. After repeated consecutive failed
|
|
339
|
+
re-checks it becomes `REVOKED` and the webhooks that use it are suspended; `verify` on a `REVOKED`
|
|
340
|
+
domain restores it to `VERIFIED` once the TXT record is published again, and each suspended webhook is
|
|
341
|
+
then re-enabled individually.
|
|
342
|
+
|
|
185
343
|
## `vectros namespace` — scope-namespace registrations
|
|
186
344
|
|
|
187
345
|
Register and inspect the namespaces a `scope:<namespace>` value can belong
|
|
@@ -236,7 +394,7 @@ vectros identity invite --context my-app --role editor --email bob@example.com \
|
|
|
236
394
|
| `list-all` | `--external-id <id>` (filter), `--tenant test\|live`, `--limit <n>` | **Users only, and requires an account owner login.** Lists every user in the tenant, regardless of app-context access — for recovering a user `identity list` can never show you: one created but not (yet) granted access anywhere, so no context-scoped view can ever reach it, and a `create` retry with the same `--external-id` just collides with the same invisible row. Find it here by `--external-id`, then grant it access or `identity delete` it with an ordinary credential. |
|
|
237
395
|
| `get` | `--type <user\|namespace>` (required), `--id <vectrosId>` (required) | `--id` is the Vectros-assigned id from `create`/`list`, not the `--external-id`. |
|
|
238
396
|
| `delete` | `--type <user\|namespace>` (required), `--id <vectrosId>` (required) | |
|
|
239
|
-
| `invite` | `--context <c>`, `--role <roleId>`, `--email <e>` (all required); `--first-name <n>`, `--accept-url <url>`, `--no-send-email` | Onboards a person into a context by email (`POST /v1/users/invite`) — no root key required, your `vectros login` session already carries enough scope. `--role` is an existing Role's own id (no separate lookup). `--accept-url` is required unless `--no-send-email` is given, in which case the response carries the raw `inviteToken
|
|
397
|
+
| `invite` | `--context <c>`, `--role <roleId>`, `--email <e>` (all required); `--first-name <n>`, `--accept-url <url>`, `--no-send-email` | Onboards a person into a context by email (`POST /v1/users/invite`) — no root key required, your `vectros login` session already carries enough scope. `--role` is an existing Role's own id (no separate lookup). `--accept-url` is required unless `--no-send-email` is given, in which case the response carries the raw `inviteToken` (and an `acceptLink` when you passed `--accept-url`) for you to deliver yourself. Whenever it is supplied, the accept URL must be an `https://` URL with a domain-name host, never an IP literal. |
|
|
240
398
|
|
|
241
399
|
`create`/`list`/`list-all`/`get`/`invite` accept `--json`; `delete` does not.
|
|
242
400
|
|