@veilio-inc/cli 0.7.0 → 0.9.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/README.md +157 -14
- package/dist/client/blocks.d.ts +30 -0
- package/dist/client/blocks.d.ts.map +1 -0
- package/dist/client/blocks.js +125 -0
- package/dist/client/blocks.js.map +1 -0
- package/dist/client/maps.d.ts +8 -0
- package/dist/client/maps.d.ts.map +1 -1
- package/dist/client/maps.js +260 -16
- package/dist/client/maps.js.map +1 -1
- package/dist/client/rules-skipped.d.ts +22 -0
- package/dist/client/rules-skipped.d.ts.map +1 -0
- package/dist/client/rules-skipped.js +30 -0
- package/dist/client/rules-skipped.js.map +1 -0
- package/dist/client/wording.d.ts +2 -2
- package/dist/client/wording.d.ts.map +1 -1
- package/dist/client/wording.js +15 -0
- package/dist/client/wording.js.map +1 -1
- package/dist/cloud-commands.d.ts +5 -3
- package/dist/cloud-commands.d.ts.map +1 -1
- package/dist/cloud-commands.js +109 -28
- package/dist/cloud-commands.js.map +1 -1
- package/dist/cloud.d.ts +74 -7
- package/dist/cloud.d.ts.map +1 -1
- package/dist/cloud.js +205 -3
- package/dist/cloud.js.map +1 -1
- package/dist/commands.d.ts +10 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +95 -15
- package/dist/commands.js.map +1 -1
- package/dist/credential.d.ts +12 -0
- package/dist/credential.d.ts.map +1 -1
- package/dist/credential.js +48 -0
- package/dist/credential.js.map +1 -1
- package/dist/flags.js +2 -2
- package/dist/flags.js.map +1 -1
- package/dist/hashed-bases.d.ts +12 -0
- package/dist/hashed-bases.d.ts.map +1 -0
- package/dist/hashed-bases.js +45 -0
- package/dist/hashed-bases.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/reservations.d.ts +145 -0
- package/dist/reservations.d.ts.map +1 -0
- package/dist/reservations.js +348 -0
- package/dist/reservations.js.map +1 -0
- package/dist/rules-open.d.ts +16 -0
- package/dist/rules-open.d.ts.map +1 -0
- package/dist/rules-open.js +87 -0
- package/dist/rules-open.js.map +1 -0
- package/dist/rules.d.ts +20 -2
- package/dist/rules.d.ts.map +1 -1
- package/dist/rules.js +86 -4
- package/dist/rules.js.map +1 -1
- package/dist/store.d.ts +3 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +19 -1
- package/dist/store.js.map +1 -1
- package/dist/team-anonymize.d.ts +16 -1
- package/dist/team-anonymize.d.ts.map +1 -1
- package/dist/team-anonymize.js +39 -13
- package/dist/team-anonymize.js.map +1 -1
- package/dist/team-namespace.d.ts +59 -4
- package/dist/team-namespace.d.ts.map +1 -1
- package/dist/team-namespace.js +133 -11
- package/dist/team-namespace.js.map +1 -1
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -30,7 +30,7 @@ signed-in `scrub` offline, `veilio logout` first.
|
|
|
30
30
|
| Command | Purpose |
|
|
31
31
|
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
32
32
|
| `scrub [files...]` | Mask identifiers, redact credentials. Reads stdin when given no file. |
|
|
33
|
-
| `restore [files...]` | Swap placeholders back, strip AI-generated noise. Signed in, also a teammate's placeholders — see below. Names anything it could not restore; `--strict` writes nothing if a placeholder would be left. |
|
|
33
|
+
| `restore [files...]` | Swap placeholders back, strip AI-generated noise. Signed in, also a teammate's placeholders — see below. Names anything it could not restore, a redacted value included; `--strict` writes nothing if a placeholder or a redaction would be left. |
|
|
34
34
|
| `scan [files...]` | Detect credentials only. Never rewrites. Exits 1 on a credential; with `--strict`, on any finding. |
|
|
35
35
|
| `map` | Show the symbol map (`--clear` to wipe it). |
|
|
36
36
|
|
|
@@ -49,9 +49,9 @@ veilio maps rm <id> # remove a map from Cloud
|
|
|
49
49
|
veilio projects # the projects your team works in; * marks the one in use
|
|
50
50
|
veilio projects use <name> # work in that project (kept with the sign-in)
|
|
51
51
|
veilio team unlock # open the team key with your vault passphrase (kept 7 days)
|
|
52
|
-
veilio team lock # remove the unlocked team key from this machine
|
|
52
|
+
veilio team lock # remove the unlocked team key, and the team rules, from this machine
|
|
53
53
|
veilio vault unlock # keep the personal-maps key here (7 days), for the MCP server
|
|
54
|
-
veilio vault lock # remove it from this machine
|
|
54
|
+
veilio vault lock # remove it, and the personal rules, from this machine
|
|
55
55
|
veilio rules pull # fetch your custom rules; scrub then applies them offline
|
|
56
56
|
veilio logout # revokes server-side, then removes the local credential
|
|
57
57
|
```
|
|
@@ -119,6 +119,54 @@ Custom rules (whitelist and replace, set in the web app) are applied by
|
|
|
119
119
|
offline - and says on every run how many rules it applied and how old the copy
|
|
120
120
|
is. Pull again after the rules change; `logout` removes the copy.
|
|
121
121
|
|
|
122
|
+
Cloud holds the rules sealed under your keys, so it cannot read them: personal
|
|
123
|
+
rules under your personal-maps key, team rules under your team key. `rules pull`
|
|
124
|
+
opens them on this machine, so it needs `veilio vault unlock` for personal rules
|
|
125
|
+
and `veilio team unlock` for team rules. A rule it cannot open is skipped, never
|
|
126
|
+
an error: `scrub` still masks, with the built-in engine and the rules that did
|
|
127
|
+
open, and both commands say what was skipped and how to fix it, one sentence per
|
|
128
|
+
cause (on every `scrub`, `--quiet` included).
|
|
129
|
+
|
|
130
|
+
The opened rules last only as long as the key they were opened with.
|
|
131
|
+
`veilio vault lock` removes the personal rules from `rules.json`, and
|
|
132
|
+
`veilio team lock` the team rules, until the next unlock and `rules pull`; both
|
|
133
|
+
say how many they removed, and the copy counts them as vault locked or team key
|
|
134
|
+
locked. A key that expires, or is deleted by hand, has the same effect without
|
|
135
|
+
a lock: `scrub` and the MCP server apply a cached rule only while its key is
|
|
136
|
+
still on this machine, unexpired and for this account. A `rules pull` while
|
|
137
|
+
locked does not bring them back:
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
2 custom rules not applied: vault locked - run `veilio vault unlock`, then `veilio rules pull`.
|
|
141
|
+
1 custom rule not applied: team key locked - run `veilio team unlock`, then `veilio rules pull`.
|
|
142
|
+
1 custom rule not applied: could not be opened with the keys on this machine, and skipped.
|
|
143
|
+
1 custom rule not applied: refused as unsafe to apply (an engine placeholder or a pattern rules do not support), and skipped.
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
When some rules applied and others did not, `scrub` says both in one line:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
veilio: applied 1 custom rule pulled just now; 2 not applied: vault locked - run `veilio vault unlock`, then `veilio rules pull`.
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Under `--quiet` it prints only what was not applied, in the sentences above.
|
|
153
|
+
|
|
154
|
+
"Could not be opened" is a rule sealed under a team-key version this machine
|
|
155
|
+
does not hold (run `veilio team unlock` again after a rotation) or a damaged
|
|
156
|
+
one. "Refused" is a rule no tool applies, whoever wrote it: a replace
|
|
157
|
+
placeholder that reuses an engine base such as `__FN__`, a pattern the rule
|
|
158
|
+
matcher does not support (a backreference, lookaround, `\b`, or a bound over
|
|
159
|
+
50), or a sealed body moved to another rule's row.
|
|
160
|
+
|
|
161
|
+
One `scrub` of one input spends a bounded amount of matching work on custom
|
|
162
|
+
rules, all rules and names together. Rules that would take more stop matching
|
|
163
|
+
part-way - the names after that point are masked as usual, none kept readable
|
|
164
|
+
or given a rule's placeholder - and `scrub` says so, under `--quiet` too:
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
veilio: custom rules stopped matching: too much work. Names after that point were masked as usual, and no rule kept one readable or gave it a rule placeholder.
|
|
168
|
+
```
|
|
169
|
+
|
|
122
170
|
Four files, all `0600`, all under `~/.veilio/`: `credential.json` (the session
|
|
123
171
|
and the chosen project, removed by `logout`), `rules.json` (the rules copy),
|
|
124
172
|
`team-keys.json` (the keys `team unlock` opened, kept seven days) and
|
|
@@ -129,17 +177,90 @@ removes all of them.
|
|
|
129
177
|
|
|
130
178
|
Signed in to a team with the team key unlocked, `veilio scrub` numbers from the
|
|
131
179
|
team's maps, as the web app and the MCP server do: a name the team already knows
|
|
132
|
-
gets the team's placeholder, and a new name is numbered
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
180
|
+
gets the team's placeholder, and a new name is numbered inside this checkout's
|
|
181
|
+
block of team numbers (`.veilio/reserved.json`, below) - or, with no usable
|
|
182
|
+
block, in this checkout's local family `__LOCAL_<TAG>_<KIND>__n` - so it can
|
|
183
|
+
never take a number that means something else to a teammate. It is never
|
|
184
|
+
numbered above the team's highest: that is where the next teammate's block
|
|
185
|
+
starts. Only the team entries the output uses are kept in this project's map.
|
|
186
|
+
The summary says `Namespace: team`. `scrub` only reads `reserved.json`; it never
|
|
187
|
+
reserves, except with `--team`.
|
|
136
188
|
|
|
137
189
|
- **Locked or unreachable, it still masks** — from this project's map — and says
|
|
138
|
-
so on stderr, with the reason, even under `--quiet
|
|
139
|
-
|
|
190
|
+
so on stderr, with the reason, even under `--quiet`. It is still a team, so
|
|
191
|
+
new names go into the local family (`__LOCAL_<TAG>_…`), never above the
|
|
192
|
+
map. The team comes from the team unlock, else from `~/.veilio/team.json`
|
|
193
|
+
(the team this account was last seen in, written by any command that lists
|
|
194
|
+
it and removed by `veilio logout`); with no `reserved.json` yet, scrub writes
|
|
195
|
+
one holding a fresh tag. With no team ever seen, new names still go into a
|
|
196
|
+
local family, under a tag for that run only.
|
|
140
197
|
- **Signed out, it makes no request**, exactly as before. Signed in, it waits at
|
|
141
198
|
most **5 seconds** for Cloud.
|
|
142
199
|
|
|
200
|
+
### Team numbers for the guard
|
|
201
|
+
|
|
202
|
+
The Claude Code guard makes no request, so it cannot ask the team for a number
|
|
203
|
+
each time it masks a new name. Instead, `veilio maps pull` of a team map (and
|
|
204
|
+
`veilio team unlock` in a project that already has a map) reserves a **block**
|
|
205
|
+
of the team's numbers for you - 500 per kind - and keeps it in
|
|
206
|
+
`.veilio/reserved.json`. The guard numbers new names inside it, so two members
|
|
207
|
+
working at the same time never give one placeholder two meanings. A pull takes
|
|
208
|
+
a new block whenever a teammate's newer numbers sit above yours.
|
|
209
|
+
|
|
210
|
+
A reservation sends Cloud a kind, a count and a floor - never a name. The
|
|
211
|
+
engine's own kinds (`__VAR__`, `__FN__`, `__CLS__`, ...) go as they are; a
|
|
212
|
+
custom replace rule's placeholder (`__ACME_ACQUISITION_TARGET__`) names what
|
|
213
|
+
the team considers sensitive, so it is sent as `__H_<16 hex>__`, an HMAC of it
|
|
214
|
+
under the newest team key, and read back locally. Teammates holding the same
|
|
215
|
+
key send the same hash. Cloud counts each hash on its own, so a rule's kind is
|
|
216
|
+
floored above the team's reservations of it under its hash with every team key
|
|
217
|
+
version this machine holds (read from the team's reservations, which are only
|
|
218
|
+
ever asked for by hash): after a key rotation new numbers stay above the old
|
|
219
|
+
hash's while the old key is still held; without it, the floor is the map's.
|
|
220
|
+
Without the team key unlocked, or without that listing (an older instance),
|
|
221
|
+
numbers for a rule's kind are not reserved at all.
|
|
222
|
+
|
|
223
|
+
Only numbers Cloud issued count toward a floor. A number in a map that no run
|
|
224
|
+
of the team's reservations holds - one numbered on this machine, or planted -
|
|
225
|
+
is checked against the team's listing of its kind (`?bases=`, with each kind's
|
|
226
|
+
highest number) and floors nothing; for a kind never reserved yet, a map's
|
|
227
|
+
numbers floor its first run up to 10000. A pull says how many such numbers the
|
|
228
|
+
map held, and restore leaves one above the highest number Cloud has issued for
|
|
229
|
+
its kind. (A map from before team numbering with numbers above 10000, in a kind
|
|
230
|
+
never reserved, therefore floors nothing; such teams existed only on staging.)
|
|
231
|
+
Every reservation asks for an answer per kind: a kind Cloud refuses is numbered
|
|
232
|
+
on this machine (`__LOCAL_…`), with the refusal shown, and the others are
|
|
233
|
+
reserved. An older Cloud that refuses the whole call names the kinds it
|
|
234
|
+
refuses, and is asked again without them.
|
|
235
|
+
|
|
236
|
+
If no block can be reserved - the day's limit, offline, the plan, a server
|
|
237
|
+
error - the pull (or the unlock) still succeeds, exits 0, and says so on its
|
|
238
|
+
normal output, with the reason and, for the day's limit, when the next block is
|
|
239
|
+
possible:
|
|
240
|
+
|
|
241
|
+
```
|
|
242
|
+
veilio: could not reserve team numbers: this account's daily limit for this team is reached; the next block is possible at 09:14 (local time). New names are numbered on this machine as __LOCAL_K7Q2XA_… until a block is held; your next publish gives them team numbers.
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
`reserved.json` is still written, with the reason, and a signed-in
|
|
246
|
+
`veilio scrub` repeats the sentence on stderr - even under `--quiet` - for as
|
|
247
|
+
long as it holds. Until a block is held, the guard, a signed-in
|
|
248
|
+
`veilio scrub` and the MCP server number new names in this checkout's **local
|
|
249
|
+
family**, `__LOCAL_<TAG>_<KIND>__n` (`__LOCAL_K7Q2XA_VAR__3`). The tag is six
|
|
250
|
+
characters drawn for this checkout, so two checkouts never mint the same
|
|
251
|
+
string:
|
|
252
|
+
|
|
253
|
+
- **This machine restores them**, from its map.
|
|
254
|
+
- **A teammate's restore leaves them as written** and names them: only the
|
|
255
|
+
checkout that numbered one knows what it means.
|
|
256
|
+
- **The next team publish renumbers them** into reserved team numbers, keeps
|
|
257
|
+
the old placeholders in `.veilio/aliases.json` (they still restore here),
|
|
258
|
+
and draws a new tag.
|
|
259
|
+
- **No team map ever holds one.** A team map is sealed on your machine, so the
|
|
260
|
+
check is here too: a publish that would still seal one is refused, naming
|
|
261
|
+
them, and a reader drops one it finds - `maps pull` of a team map leaves
|
|
262
|
+
them out of `map.json` and says how many.
|
|
263
|
+
|
|
143
264
|
### Restoring a teammate's placeholders
|
|
144
265
|
|
|
145
266
|
`veilio restore` resolves a placeholder this project's map cannot explain
|
|
@@ -151,6 +272,11 @@ with the real names:
|
|
|
151
272
|
wins and the placeholder stays in the output with a line naming it. Same for
|
|
152
273
|
one this project numbered on its own while the team was out of reach — a
|
|
153
274
|
wrong name restored silently is worse than a placeholder left visibly.
|
|
275
|
+
- **Another checkout's local placeholder is left.** `__LOCAL_<TAG>_…` was
|
|
276
|
+
numbered on a checkout that held no team numbers; only that checkout restores
|
|
277
|
+
it, so it stays in the output, is named, and counts as left for `--strict`.
|
|
278
|
+
Your own restore still reads it, through `.veilio/aliases.json` once a publish
|
|
279
|
+
renumbered it.
|
|
154
280
|
- **Locked, and it says so.** With no team key on this machine it tells you to
|
|
155
281
|
run `veilio team unlock` rather than restoring half the text.
|
|
156
282
|
- **Signed out, it makes no request at all** — that restore is as offline as it
|
|
@@ -176,11 +302,12 @@ a plan feature the web app couldn't.
|
|
|
176
302
|
For: scrub
|
|
177
303
|
-m, --map <path> Use a specific map file
|
|
178
304
|
For: scrub, restore, map, maps pull, maps push, maps
|
|
179
|
-
update
|
|
305
|
+
update, team unlock
|
|
180
306
|
--json Machine-readable output
|
|
181
307
|
For: scan, map
|
|
182
308
|
--strict scan: also fail on advisory findings. restore: write
|
|
183
|
-
nothing and exit 1 if a placeholder
|
|
309
|
+
nothing and exit 1 if a placeholder or a redaction
|
|
310
|
+
would be left
|
|
184
311
|
For: scan, restore
|
|
185
312
|
--keep-docs Keep JSDoc blocks the model wrote
|
|
186
313
|
For: restore
|
|
@@ -222,8 +349,9 @@ command.
|
|
|
222
349
|
placeholder would be left in it — one the AI invented, one whose shape it changed
|
|
223
350
|
(`__fn__1`), one the team's maps disagree on, or one the team's maps could not be
|
|
224
351
|
read for — nothing goes to stdout and it exits 1. Without it, restore writes the
|
|
225
|
-
text, placeholders and all, names each one on stderr and exits 0. A
|
|
226
|
-
redacted
|
|
352
|
+
text, placeholders and all, names each one on stderr and exits 0. A value
|
|
353
|
+
redacted one-way (`__REDACTED_CREDENTIAL_1__`) cannot be restored, so the text is
|
|
354
|
+
not the original file: restore names it every time, and `--strict` refuses it.
|
|
227
355
|
|
|
228
356
|
`--keep-docs` is worth knowing about: the default strip removes JSDoc along with
|
|
229
357
|
the narration and TODOs, which is wrong when the model was _asked_ to document
|
|
@@ -259,7 +387,7 @@ so write files from PowerShell 7 (`pwsh`).
|
|
|
259
387
|
| Code | Meaning |
|
|
260
388
|
| ---- | ------------------------------------------------------------------------------------------------------------------ |
|
|
261
389
|
| 0 | Clean |
|
|
262
|
-
| 1 | Findings that should stop the pipeline: a credential (`scan`), or a placeholder `restore --strict` would have left |
|
|
390
|
+
| 1 | Findings that should stop the pipeline: a credential (`scan`), or a placeholder or redaction `restore --strict` would have left |
|
|
263
391
|
| 2 | Usage or IO error |
|
|
264
392
|
|
|
265
393
|
As a pre-commit hook:
|
|
@@ -272,6 +400,21 @@ git diff --cached | veilio scan || {
|
|
|
272
400
|
}
|
|
273
401
|
```
|
|
274
402
|
|
|
403
|
+
## What is masked
|
|
404
|
+
|
|
405
|
+
Distinctive names - `quaywardThrottle`, `SkerryTariff`, `berth_quorum`, an invented
|
|
406
|
+
`tarnwick` - become placeholders. A name that is a single common English word
|
|
407
|
+
(`total`, `ledger`, `invoice`), shared vocabulary every codebase has (`src`,
|
|
408
|
+
`util`, `com`, `java`) or a toolchain's name (`vitest`, `junit`, `mvn`) is left as
|
|
409
|
+
written as a name or a path segment: it is nobody's secret, and masking it made
|
|
410
|
+
paths and test output unreadable. A codename that is an ordinary word (`phoenix`)
|
|
411
|
+
is therefore readable as a name; a custom replace rule (`veilio rules pull`) keeps
|
|
412
|
+
it masked. In a value - a string literal, a config value, XML text - every word is
|
|
413
|
+
masked. A value whose key contains a credential word (`password: sunshine`,
|
|
414
|
+
`DB_PASSWORD_PROD="sunshine"`, `const DB_PASS = "Summer2024!"`) is redacted one-way,
|
|
415
|
+
whole, under the default `--secrets redact`, so the map never holds it. Credentials
|
|
416
|
+
are redacted whatever they are called.
|
|
417
|
+
|
|
275
418
|
## The symbol map
|
|
276
419
|
|
|
277
420
|
`scrub` writes `.veilio/map.json` at the project root and `restore` reads it, so placeholders stay stable across runs and across a whole session. The store is created `0600` with its own `.gitignore` — it holds the real identifier names, so committing it would undo the anonymization for anyone reading the repo.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type PlaceholderReservation } from '../cloud.js';
|
|
2
|
+
import type { Credential } from '../credential.js';
|
|
3
|
+
import { type Block, type RefusalReason } from '../reservations.js';
|
|
4
|
+
export type BlocksOutcome = {
|
|
5
|
+
status: 'kept';
|
|
6
|
+
} | {
|
|
7
|
+
status: 'reserved';
|
|
8
|
+
blocks: Record<string, Block>;
|
|
9
|
+
}
|
|
10
|
+
/** The pull still succeeded; new names are numbered in the local family
|
|
11
|
+
* until a block is held (spec 066). */
|
|
12
|
+
| {
|
|
13
|
+
status: 'failed';
|
|
14
|
+
reason: RefusalReason;
|
|
15
|
+
detail: string;
|
|
16
|
+
nextAt?: string;
|
|
17
|
+
tag: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Written on every outcome (spec 066 R4): without the file a refused member's
|
|
21
|
+
* guard cannot tell "team, no block" from "no team", and numbers into the next
|
|
22
|
+
* teammate's block. The checkout's tag is drawn once and kept across pulls.
|
|
23
|
+
*/
|
|
24
|
+
export declare function ensureBlocks(credential: Credential, teamId: string, mapPath: string,
|
|
25
|
+
/** Where the team keys are: a rule's base is reserved under its hash. */
|
|
26
|
+
home?: string,
|
|
27
|
+
/** The team's reservations of the map's bases, when the caller listed
|
|
28
|
+
* them; null when the instance keeps no record. */
|
|
29
|
+
reservations?: PlaceholderReservation[] | null): Promise<BlocksOutcome>;
|
|
30
|
+
//# sourceMappingURL=blocks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../src/client/blocks.ts"],"names":[],"mappings":"AASA,OAAO,EAAmC,KAAK,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAE1F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAElD,OAAO,EAML,KAAK,KAAK,EACV,KAAK,aAAa,EAGnB,MAAM,oBAAoB,CAAA;AAE3B,MAAM,MAAM,aAAa,GACrB;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GAClB;IAAE,MAAM,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAA;CAAE;AACvD;wCACwC;GACtC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAW7F;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,UAAU,EAAE,UAAU,EACtB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM;AACf,yEAAyE;AACzE,IAAI,CAAC,EAAE,MAAM;AACb;oDACoD;AACpD,YAAY,CAAC,EAAE,sBAAsB,EAAE,GAAG,IAAI,GAC7C,OAAO,CAAC,aAAa,CAAC,CAmGxB"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
// Spec 063 US1: make sure this member holds a block of the team's numbers for
|
|
2
|
+
// every kind the guard will mint, above everything the project's map holds.
|
|
3
|
+
//
|
|
4
|
+
// The guard makes no request (spec 017's rule, kept): it numbers inside the
|
|
5
|
+
// block offline. Whoever writes the map from Cloud - a pull, an unlock - is
|
|
6
|
+
// what keeps the block usable, because the engine numbers above the map's
|
|
7
|
+
// highest number of a kind and never into a gap below it.
|
|
8
|
+
import { highestPerKind, isSaneBlock } from '@veilio-inc/engine';
|
|
9
|
+
import { reservePlaceholders, CloudError } from '../cloud.js';
|
|
10
|
+
import { teamKeyBytes, teamKeyVersion } from '../hashed-bases.js';
|
|
11
|
+
import { loadMap } from '../store.js';
|
|
12
|
+
import { CORE_BASES, basesNeedingBlocks, drawTag, loadReserved, saveReserved, } from '../reservations.js';
|
|
13
|
+
/** Why a reservation failed, in the four kinds a member can act on (spec 066 R4). */
|
|
14
|
+
function reasonOf(err) {
|
|
15
|
+
if (!(err instanceof CloudError))
|
|
16
|
+
return 'server';
|
|
17
|
+
if (err.kind === 'unentitled')
|
|
18
|
+
return 'payment';
|
|
19
|
+
if (err.kind === 'unreachable')
|
|
20
|
+
return 'offline';
|
|
21
|
+
if (err.status === 429 && err.body?.reason === 'cap')
|
|
22
|
+
return 'cap';
|
|
23
|
+
return 'server';
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Written on every outcome (spec 066 R4): without the file a refused member's
|
|
27
|
+
* guard cannot tell "team, no block" from "no team", and numbers into the next
|
|
28
|
+
* teammate's block. The checkout's tag is drawn once and kept across pulls.
|
|
29
|
+
*/
|
|
30
|
+
export async function ensureBlocks(credential, teamId, mapPath,
|
|
31
|
+
/** Where the team keys are: a rule's base is reserved under its hash. */
|
|
32
|
+
home,
|
|
33
|
+
/** The team's reservations of the map's bases, when the caller listed
|
|
34
|
+
* them; null when the instance keeps no record. */
|
|
35
|
+
reservations) {
|
|
36
|
+
let held;
|
|
37
|
+
try {
|
|
38
|
+
held = loadReserved(mapPath);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
held = null; // malformed: replaced, never numbered from
|
|
42
|
+
}
|
|
43
|
+
// Blocks taken by another account, team or instance are not this member's,
|
|
44
|
+
// and neither is the tag: two checkouts must never share one.
|
|
45
|
+
const same = held !== null &&
|
|
46
|
+
held.instance === credential.instance &&
|
|
47
|
+
held.account === credential.account &&
|
|
48
|
+
held.teamId === teamId;
|
|
49
|
+
let mine = same ? held.blocks : {};
|
|
50
|
+
const tag = (same && held.local?.tag) || drawTag();
|
|
51
|
+
const save = (blocks, refused) => saveReserved(mapPath, {
|
|
52
|
+
version: 1,
|
|
53
|
+
instance: credential.instance,
|
|
54
|
+
account: credential.account,
|
|
55
|
+
teamId,
|
|
56
|
+
blocks,
|
|
57
|
+
local: { tag },
|
|
58
|
+
...(refused ? { refused } : {}),
|
|
59
|
+
});
|
|
60
|
+
const fail = (reason, detail, nextAt) => {
|
|
61
|
+
const short = detail.slice(0, 200);
|
|
62
|
+
save(mine, {
|
|
63
|
+
reason,
|
|
64
|
+
at: new Date().toISOString(),
|
|
65
|
+
...(nextAt ? { nextAt } : {}),
|
|
66
|
+
detail: short,
|
|
67
|
+
});
|
|
68
|
+
return { status: 'failed', reason, detail: short, ...(nextAt ? { nextAt } : {}), tag };
|
|
69
|
+
};
|
|
70
|
+
const map = loadMap(mapPath);
|
|
71
|
+
const need = basesNeedingBlocks(map, mine, CORE_BASES);
|
|
72
|
+
if (need.length === 0 && same) {
|
|
73
|
+
save(mine); // adds a tag to an older file, and clears a refusal nothing needs now
|
|
74
|
+
return { status: 'kept' };
|
|
75
|
+
}
|
|
76
|
+
// Keyed by base: a local kind's numbers are another family and floor nothing.
|
|
77
|
+
const floors = highestPerKind(map);
|
|
78
|
+
let ranges = [];
|
|
79
|
+
// A rule base the server's key version refuses (Cloud 809444d0): no block
|
|
80
|
+
// for it, the engine bases' blocks kept, and the refusal on the band.
|
|
81
|
+
let refused;
|
|
82
|
+
if (need.length) {
|
|
83
|
+
try {
|
|
84
|
+
let sent;
|
|
85
|
+
({
|
|
86
|
+
ranges,
|
|
87
|
+
refused,
|
|
88
|
+
floors: sent,
|
|
89
|
+
} = await reservePlaceholders(credential, teamId, need.map((base) => ({ base, count: 1, floor: floors[base] ?? 0 })), undefined, {
|
|
90
|
+
block: true,
|
|
91
|
+
keys: teamKeyBytes(credential, home, teamId),
|
|
92
|
+
keyVersion: teamKeyVersion(credential, home, teamId),
|
|
93
|
+
...(reservations !== undefined ? { reservations } : {}),
|
|
94
|
+
}));
|
|
95
|
+
// Round 4 (D): the floor the server was sent, once vouched.
|
|
96
|
+
Object.assign(floors, sent ?? {});
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
const retry = err instanceof CloudError ? err.body?.retry_at : undefined;
|
|
100
|
+
const nextAt = typeof retry === 'string' && !Number.isNaN(Date.parse(retry)) ? retry : undefined;
|
|
101
|
+
return fail(reasonOf(err), err instanceof CloudError ? err.message : String(err), nextAt);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// A reply that is not one sane run per kind asked for is no block: the
|
|
105
|
+
// guard would otherwise number from whatever it said.
|
|
106
|
+
const asked = need.filter((base) => !refused?.bases.includes(base));
|
|
107
|
+
const sane = Array.isArray(ranges) &&
|
|
108
|
+
ranges.length === asked.length &&
|
|
109
|
+
ranges.every((r) => asked.includes(r?.base) && isSaneBlock(r) && r.start > (floors[r.base] ?? 0));
|
|
110
|
+
if (!sane)
|
|
111
|
+
return fail('server', 'the server answered without a usable block');
|
|
112
|
+
const blocks = { ...mine };
|
|
113
|
+
for (const r of ranges)
|
|
114
|
+
blocks[r.base] = { start: r.start, end: r.end };
|
|
115
|
+
if (refused) {
|
|
116
|
+
mine = blocks;
|
|
117
|
+
return fail('server', refused.detail);
|
|
118
|
+
}
|
|
119
|
+
save(blocks);
|
|
120
|
+
return {
|
|
121
|
+
status: 'reserved',
|
|
122
|
+
blocks: Object.fromEntries(ranges.map((r) => [r.base, { start: r.start, end: r.end }])),
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=blocks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"blocks.js","sourceRoot":"","sources":["../../src/client/blocks.ts"],"names":[],"mappings":"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"}
|
package/dist/client/maps.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type BlocksOutcome } from './blocks.js';
|
|
1
2
|
import { type Env } from './project-scope.js';
|
|
2
3
|
import { type Outcome } from './wording.js';
|
|
3
4
|
export interface ClientContext {
|
|
@@ -40,6 +41,13 @@ export declare function pullCloudMap(ctx: ClientContext, id: string | null, opts
|
|
|
40
41
|
name: string;
|
|
41
42
|
count: number;
|
|
42
43
|
path: string;
|
|
44
|
+
blocks?: BlocksOutcome;
|
|
45
|
+
/** Local-family keys the team map held and the pull left out (spec 066). */
|
|
46
|
+
localDropped?: number;
|
|
47
|
+
/** Keys numbered above 1e8: kept, never numbered after (security audit). */
|
|
48
|
+
outOfRange?: number;
|
|
49
|
+
/** Round 4 (D): keys outside every run the server issued: no floor. */
|
|
50
|
+
unvouched?: number;
|
|
43
51
|
}>>;
|
|
44
52
|
/**
|
|
45
53
|
* Placeholders the local map and the team's namespace use for DIFFERENT names.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"maps.d.ts","sourceRoot":"","sources":["../../src/client/maps.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"maps.d.ts","sourceRoot":"","sources":["../../src/client/maps.ts"],"names":[],"mappings":"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"}
|