@veilio-inc/cli 0.9.1 → 0.11.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 +98 -20
- package/dist/args.d.ts +8 -0
- package/dist/args.d.ts.map +1 -1
- package/dist/args.js +14 -0
- package/dist/args.js.map +1 -1
- package/dist/client/blocks.d.ts.map +1 -1
- package/dist/client/blocks.js +2 -1
- package/dist/client/blocks.js.map +1 -1
- package/dist/client/fingerprint.d.ts +4 -0
- package/dist/client/fingerprint.d.ts.map +1 -0
- package/dist/client/fingerprint.js +20 -0
- package/dist/client/fingerprint.js.map +1 -0
- package/dist/client/maps.d.ts.map +1 -1
- package/dist/client/maps.js +29 -8
- package/dist/client/maps.js.map +1 -1
- package/dist/client/wording.d.ts +3 -1
- package/dist/client/wording.d.ts.map +1 -1
- package/dist/client/wording.js +10 -2
- package/dist/client/wording.js.map +1 -1
- package/dist/client/wrap-judge.d.ts +30 -0
- package/dist/client/wrap-judge.d.ts.map +1 -0
- package/dist/client/wrap-judge.js +59 -0
- package/dist/client/wrap-judge.js.map +1 -0
- package/dist/cloud-commands.d.ts +21 -1
- package/dist/cloud-commands.d.ts.map +1 -1
- package/dist/cloud-commands.js +342 -5
- package/dist/cloud-commands.js.map +1 -1
- package/dist/cloud.d.ts +5 -1
- package/dist/cloud.d.ts.map +1 -1
- package/dist/cloud.js +7 -1
- package/dist/cloud.js.map +1 -1
- package/dist/commands.d.ts +3 -0
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +82 -47
- package/dist/commands.js.map +1 -1
- package/dist/flags.d.ts +14 -0
- package/dist/flags.d.ts.map +1 -1
- package/dist/flags.js +40 -0
- package/dist/flags.js.map +1 -1
- package/dist/git-index.d.ts +8 -0
- package/dist/git-index.d.ts.map +1 -0
- package/dist/git-index.js +161 -0
- package/dist/git-index.js.map +1 -0
- package/dist/hashed-bases.d.ts +6 -1
- package/dist/hashed-bases.d.ts.map +1 -1
- package/dist/hashed-bases.js +16 -3
- package/dist/hashed-bases.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -19
- package/dist/index.js.map +1 -1
- package/dist/key-pins.d.ts +46 -0
- package/dist/key-pins.d.ts.map +1 -0
- package/dist/key-pins.js +165 -0
- package/dist/key-pins.js.map +1 -0
- package/dist/reservations.d.ts +6 -4
- package/dist/reservations.d.ts.map +1 -1
- package/dist/reservations.js +19 -21
- package/dist/reservations.js.map +1 -1
- package/dist/staged-blobs.d.ts +21 -0
- package/dist/staged-blobs.d.ts.map +1 -0
- package/dist/staged-blobs.js +150 -0
- package/dist/staged-blobs.js.map +1 -0
- package/dist/store.d.ts +39 -0
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +243 -24
- package/dist/store.js.map +1 -1
- package/dist/team-anonymize.d.ts +21 -4
- package/dist/team-anonymize.d.ts.map +1 -1
- package/dist/team-anonymize.js +123 -51
- package/dist/team-anonymize.js.map +1 -1
- package/dist/team-unlock.d.ts +36 -0
- package/dist/team-unlock.d.ts.map +1 -1
- package/dist/team-unlock.js +25 -1
- package/dist/team-unlock.js.map +1 -1
- package/package.json +2 -2
package/dist/store.js
CHANGED
|
@@ -8,9 +8,11 @@
|
|
|
8
8
|
// The map holds real identifier names, so it is written 0600 and the store
|
|
9
9
|
// directory carries a .gitignore. Committing it would undo the anonymization
|
|
10
10
|
// for anyone reading the repo.
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
11
|
+
import { closeSync, existsSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, renameSync, rmSync, writeFileSync, writeSync, } from 'node:fs';
|
|
12
|
+
import { randomBytes } from 'node:crypto';
|
|
13
|
+
import { basename, delimiter, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
13
14
|
import { STORE_DIR } from '@veilio-inc/engine';
|
|
15
|
+
import { trackedPaths } from './git-index.js';
|
|
14
16
|
export { STORE_DIR };
|
|
15
17
|
export const STORE_FILE = 'map.json';
|
|
16
18
|
/** Walk up from `from` looking for an existing store or a repo root, so running
|
|
@@ -19,7 +21,11 @@ export const STORE_FILE = 'map.json';
|
|
|
19
21
|
export function findProjectRoot(from) {
|
|
20
22
|
let dir = resolve(from);
|
|
21
23
|
for (;;) {
|
|
22
|
-
|
|
24
|
+
// Another user's .veilio is not this project's store (spec 085 L2): on a
|
|
25
|
+
// shared machine anyone can make /tmp/.veilio.
|
|
26
|
+
const store = join(dir, STORE_DIR);
|
|
27
|
+
if ((existsSync(store) && (ownerOf(store) !== 'other' || trustedStore(store))) ||
|
|
28
|
+
existsSync(join(dir, '.git')))
|
|
23
29
|
return dir;
|
|
24
30
|
const parent = dirname(dir);
|
|
25
31
|
if (parent === dir)
|
|
@@ -33,10 +39,158 @@ export function resolveMapPath(override, cwd) {
|
|
|
33
39
|
return resolve(cwd, override);
|
|
34
40
|
return join(findProjectRoot(cwd), STORE_DIR, STORE_FILE);
|
|
35
41
|
}
|
|
42
|
+
/** The longest real name kept, as for aliases.json (reservations.ts). */
|
|
43
|
+
const MAX_NAME = 100_000;
|
|
44
|
+
// C0 and C1 controls (line feed, tab, NEL, escape, ...) and the Unicode line
|
|
45
|
+
// and paragraph separators. A map value is not always an identifier (a manual
|
|
46
|
+
// mark can be words with spaces, spec 082 adds non-ASCII letters), so no exact
|
|
47
|
+
// name pattern exists; a character that breaks a line or drives a terminal is
|
|
48
|
+
// never part of a name.
|
|
49
|
+
const NOT_IN_A_NAME = /[\p{Cc}\u2028\u2029]/u;
|
|
50
|
+
/** What a map or aliases.json may restore: 1 to 100000 characters, none of them a control or line separator. */
|
|
51
|
+
export function isName(v) {
|
|
52
|
+
return typeof v === 'string' && v.length > 0 && v.length <= MAX_NAME && !NOT_IN_A_NAME.test(v);
|
|
53
|
+
}
|
|
36
54
|
function isSymbolMap(value) {
|
|
37
55
|
if (typeof value !== 'object' || value === null || Array.isArray(value))
|
|
38
56
|
return false;
|
|
39
|
-
return Object.values(value).every(
|
|
57
|
+
return Object.values(value).every(isName);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Refuses to write a value the store would not read back (review round 1):
|
|
61
|
+
* a map with one would be refused whole on its next read. Refused, not
|
|
62
|
+
* dropped, so a pull never quietly loses a teammate's entry.
|
|
63
|
+
*/
|
|
64
|
+
export function refuseNonNames(what, map) {
|
|
65
|
+
const bad = Object.keys(map).find((k) => !isName(map[k]));
|
|
66
|
+
if (bad !== undefined)
|
|
67
|
+
throw new StoreRefusal(`refusing to write ${what}: the value of ${bad.replace(new RegExp(NOT_IN_A_NAME.source, 'gu'), '').slice(0, 60)} is not a name (1 to 100000 characters, no control character or line break), so nothing was written.`);
|
|
68
|
+
}
|
|
69
|
+
/** A store the CLI will not use: exit 1 in the CLI, a tool error in the MCP server. */
|
|
70
|
+
export class StoreRefusal extends Error {
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* The one way a store file (map.json, aliases.json, reserved.json) is read
|
|
74
|
+
* (spec 085 R1): its text, or null when there is none. Refused, whatever the
|
|
75
|
+
* file: when `.veilio/` or the file is a link (a cloned repository can commit
|
|
76
|
+
* one to another project's map), and when git tracks `.veilio`, map.json or
|
|
77
|
+
* aliases.json (a map in the repository is not yours to restore from). Git is
|
|
78
|
+
* asked first, so a tracked map is refused even where the file is absent under
|
|
79
|
+
* this spelling. Outside git, or with an index this reader cannot follow, the
|
|
80
|
+
* tracked check cannot answer and the file is read as before.
|
|
81
|
+
*/
|
|
82
|
+
export function openStoreFile(what, path) {
|
|
83
|
+
const dir = dirname(path);
|
|
84
|
+
const found = trackedStoreFile(path);
|
|
85
|
+
if (found !== null) {
|
|
86
|
+
const { root, tracked } = found;
|
|
87
|
+
// The path comes from the checkout: shown without control characters. A
|
|
88
|
+
// command only off Windows (its shells read quotes differently) and only
|
|
89
|
+
// for a root and path of plain characters; both single-quoted.
|
|
90
|
+
const shown = tracked.replace(new RegExp(NOT_IN_A_NAME.source, 'gu'), '');
|
|
91
|
+
const plain = /^[A-Za-z0-9._/ -]+$/;
|
|
92
|
+
const how = process.platform !== 'win32' && plain.test(root) && plain.test(tracked)
|
|
93
|
+
? ` (\`git -C ${shellQuote(root)} rm --cached -- ${shellQuote(tracked)}\`)`
|
|
94
|
+
: '';
|
|
95
|
+
throw new StoreRefusal(`\`${shown}\` is tracked by git: a map in the repository is not yours to restore from. ` +
|
|
96
|
+
`Remove it from git${how}, then scrub again to build your own.`);
|
|
97
|
+
}
|
|
98
|
+
for (const p of [dir, path])
|
|
99
|
+
if (isLink(p))
|
|
100
|
+
throw new StoreRefusal(`refusing to read ${what}: ${p} is a link. The map is read only where it appears to be.`);
|
|
101
|
+
refuseOthers(dir, path);
|
|
102
|
+
if (!existsSync(path))
|
|
103
|
+
return null;
|
|
104
|
+
return readFileSync(path, 'utf8');
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Whose `path` is: 'me' for the running user, 'other' for anyone else, 'none'
|
|
108
|
+
* when it is not there. Windows (no uid): always 'me'. Under sudo (root, with
|
|
109
|
+
* SUDO_UID), a file of the user who ran sudo is 'sudo': readable, not writable
|
|
110
|
+
* (security review: a file root writes there would be root's).
|
|
111
|
+
*/
|
|
112
|
+
function ownerOf(path) {
|
|
113
|
+
const me = process.getuid?.();
|
|
114
|
+
let uid;
|
|
115
|
+
try {
|
|
116
|
+
uid = lstatSync(path).uid;
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return 'none';
|
|
120
|
+
}
|
|
121
|
+
if (me === undefined || uid === me)
|
|
122
|
+
return 'me';
|
|
123
|
+
return me === 0 && process.env.SUDO_UID === String(uid) ? 'sudo' : 'other';
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* The stores VEILIO_TRUST_STORE_OWNER lists (absolute paths, separated as in
|
|
127
|
+
* PATH), by real path, as git's safe.directory: each one exactly, no other.
|
|
128
|
+
*/
|
|
129
|
+
function trustedStore(dir) {
|
|
130
|
+
const listed = (process.env.VEILIO_TRUST_STORE_OWNER ?? '').split(delimiter).filter(isAbsolute);
|
|
131
|
+
if (listed.length === 0)
|
|
132
|
+
return false;
|
|
133
|
+
const real = (p) => {
|
|
134
|
+
try {
|
|
135
|
+
return realpathSync(p);
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return resolve(p);
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
const here = real(dir);
|
|
142
|
+
return listed.some((p) => real(p) === here);
|
|
143
|
+
}
|
|
144
|
+
const sudoWriteRefusal = (dir) => new StoreRefusal(`refusing to write ${dir} as root: it belongs to the user who ran sudo, and a file root writes there would be root's. Run veilio without sudo.`);
|
|
145
|
+
/** The store directory and its file are this user's, or not used (spec 085 L2, Q2 = A). */
|
|
146
|
+
function refuseOthers(dir, path, write = false) {
|
|
147
|
+
const owners = [ownerOf(dir), ownerOf(path)];
|
|
148
|
+
if (owners.includes('sudo') && write && !trustedStore(dir))
|
|
149
|
+
throw sudoWriteRefusal(dir);
|
|
150
|
+
if (owners.includes('other') && !trustedStore(dir))
|
|
151
|
+
throw new StoreRefusal(`refusing to use ${dir}: it belongs to another user on this machine. Run veilio inside your own project, or remove that directory. If you trust it, add its full path to VEILIO_TRUST_STORE_OWNER.`);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Write a store file as a new file beside it, then rename it into place
|
|
155
|
+
* (spec 085 L2): never written through the file already there, which may be
|
|
156
|
+
* another name for a file elsewhere (a hard link) or another user's.
|
|
157
|
+
*/
|
|
158
|
+
export function writeStoreFile(what, path, text) {
|
|
159
|
+
checkStoreWrite(what, path);
|
|
160
|
+
const tmp = join(dirname(path), `.${basename(path)}.${randomBytes(6).toString('hex')}.tmp`);
|
|
161
|
+
const fd = openSync(tmp, 'wx', 0o600);
|
|
162
|
+
try {
|
|
163
|
+
try {
|
|
164
|
+
writeSync(fd, text);
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
closeSync(fd);
|
|
168
|
+
}
|
|
169
|
+
renameSync(tmp, path);
|
|
170
|
+
}
|
|
171
|
+
catch (err) {
|
|
172
|
+
rmSync(tmp, { force: true });
|
|
173
|
+
throw err;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/** One POSIX shell word, for a string of plain characters (no quote in it). */
|
|
177
|
+
const shellQuote = (s) => `'${s}'`;
|
|
178
|
+
/** The store path git tracks, as git names it, with its work tree root; null when none, or no way to tell. */
|
|
179
|
+
function trackedStoreFile(path) {
|
|
180
|
+
const dir = dirname(path);
|
|
181
|
+
const git = trackedPaths(dir);
|
|
182
|
+
if (!git)
|
|
183
|
+
return null;
|
|
184
|
+
const rel = (p) => relative(git.root, p).split(sep).join('/');
|
|
185
|
+
const candidates = [path];
|
|
186
|
+
if (basename(dir) === STORE_DIR)
|
|
187
|
+
candidates.unshift(dir, join(dir, STORE_FILE), join(dir, 'aliases.json'));
|
|
188
|
+
for (const p of candidates) {
|
|
189
|
+
const name = rel(p);
|
|
190
|
+
if (name && !name.startsWith('..') && git.paths.has(name.toLowerCase()))
|
|
191
|
+
return { root: git.root, tracked: name };
|
|
192
|
+
}
|
|
193
|
+
return null;
|
|
40
194
|
}
|
|
41
195
|
/**
|
|
42
196
|
* The Cloud provenance recorded alongside the local map, if any.
|
|
@@ -46,10 +200,11 @@ function isSymbolMap(value) {
|
|
|
46
200
|
* `remote` — which reads correctly as "this map did not come from Cloud".
|
|
47
201
|
*/
|
|
48
202
|
export function loadRemote(path) {
|
|
49
|
-
|
|
203
|
+
const text = openStoreFile('the map', path);
|
|
204
|
+
if (text === null)
|
|
50
205
|
return undefined;
|
|
51
206
|
try {
|
|
52
|
-
const parsed = JSON.parse(
|
|
207
|
+
const parsed = JSON.parse(text);
|
|
53
208
|
const remote = parsed.remote;
|
|
54
209
|
if (!remote || typeof remote.id !== 'string' || typeof remote.updatedAt !== 'string') {
|
|
55
210
|
return undefined;
|
|
@@ -64,11 +219,12 @@ export function loadRemote(path) {
|
|
|
64
219
|
* file exists but cannot be understood — silently starting from empty there
|
|
65
220
|
* would orphan every placeholder the user already has in flight. */
|
|
66
221
|
export function loadMap(path) {
|
|
67
|
-
|
|
222
|
+
const text = openStoreFile('the map', path);
|
|
223
|
+
if (text === null)
|
|
68
224
|
return {};
|
|
69
225
|
let parsed;
|
|
70
226
|
try {
|
|
71
|
-
parsed = JSON.parse(
|
|
227
|
+
parsed = JSON.parse(text);
|
|
72
228
|
}
|
|
73
229
|
catch {
|
|
74
230
|
throw new Error(`map file at ${path} is not valid JSON`);
|
|
@@ -100,6 +256,7 @@ export class MapOverwriteError extends Error {
|
|
|
100
256
|
* another session's store, or by a future caller that forgets to load first.
|
|
101
257
|
*/
|
|
102
258
|
export function saveMap(path, map, options = {}) {
|
|
259
|
+
refuseNonNames('the map', map);
|
|
103
260
|
if (!options.force && existsSync(path)) {
|
|
104
261
|
const dropped = Object.entries(loadMap(path)).filter(([placeholder, real]) => map[placeholder] !== real);
|
|
105
262
|
if (dropped.length > 0) {
|
|
@@ -112,32 +269,94 @@ export function saveMap(path, map, options = {}) {
|
|
|
112
269
|
`could never be restored. Pass --force to overwrite anyway.`);
|
|
113
270
|
}
|
|
114
271
|
}
|
|
115
|
-
|
|
116
|
-
// Security audit 2026-11-01: a store that is a link (one a repository
|
|
117
|
-
// committed) would put the real names in a file outside the project.
|
|
118
|
-
refuseLinks('the map', dir, path);
|
|
119
|
-
mkdirSync(dir, { recursive: true });
|
|
120
|
-
// A store directory inside a repo must never be committed — it holds the real
|
|
121
|
-
// names the anonymization exists to hide.
|
|
122
|
-
const ignore = join(dir, '.gitignore');
|
|
123
|
-
if (dir.endsWith(STORE_DIR) && !existsSync(ignore)) {
|
|
124
|
-
writeFileSync(ignore, '*\n', { mode: 0o600 });
|
|
125
|
-
}
|
|
272
|
+
prepareStoreWrite('the map', path);
|
|
126
273
|
// Carried forward when the caller does not supply one, so an ordinary `scrub`
|
|
127
274
|
// does not quietly erase the provenance a `pull` recorded.
|
|
128
275
|
const remote = options.remote ?? loadRemote(path);
|
|
129
276
|
const payload = { version: 1, map, ...(remote ? { remote } : {}) };
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
277
|
+
// A new 0600 file each time, so a world-readable map already there is replaced too.
|
|
278
|
+
writeStoreFile('the map', path, `${JSON.stringify(payload, null, 2)}\n`);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Everything that must hold before a store file is written: neither the store
|
|
282
|
+
* directory nor the file is a link (security audit 2026-11-01: a link a
|
|
283
|
+
* repository committed would put the real names outside the project), and a
|
|
284
|
+
* `.veilio` directory carries a `.gitignore` that keeps it out of git. One
|
|
285
|
+
* there already must be a plain file whose only pattern is `*` (spec 085 L4: a
|
|
286
|
+
* repository can commit its own, which ignores nothing); a missing one is
|
|
287
|
+
* written. It is never rewritten: it may be tracked, and a silent change to a
|
|
288
|
+
* tracked file is worse than a refusal.
|
|
289
|
+
*/
|
|
290
|
+
export function prepareStoreWrite(what, path) {
|
|
291
|
+
const dir = dirname(path);
|
|
292
|
+
// Under sudo, in a project the invoking user owns, root would make a store
|
|
293
|
+
// that user cannot use (review round 2): refused before anything is made.
|
|
294
|
+
if (ownerOf(dirname(dir)) === 'sudo' && !trustedStore(dir))
|
|
295
|
+
throw sudoWriteRefusal(dir);
|
|
296
|
+
checkStoreWrite(what, path);
|
|
297
|
+
// Made 0700 and not recursively, so a directory already there is checked
|
|
298
|
+
// again rather than taken: another user may have swapped it in meanwhile.
|
|
299
|
+
mkdirSync(dirname(dir), { recursive: true });
|
|
300
|
+
try {
|
|
301
|
+
mkdirSync(dir, { mode: 0o700 });
|
|
302
|
+
}
|
|
303
|
+
catch (err) {
|
|
304
|
+
if (err.code !== 'EEXIST')
|
|
305
|
+
throw err;
|
|
306
|
+
}
|
|
307
|
+
checkStoreWrite(what, path);
|
|
308
|
+
if (basename(dir) !== STORE_DIR)
|
|
309
|
+
return;
|
|
310
|
+
const ignore = join(dir, '.gitignore');
|
|
311
|
+
let st;
|
|
312
|
+
try {
|
|
313
|
+
st = lstatSync(ignore);
|
|
314
|
+
}
|
|
315
|
+
catch {
|
|
316
|
+
// None there: written, and never through a link planted after the check.
|
|
317
|
+
writeFileSync(ignore, '*\n', { mode: 0o600, flag: 'wx' });
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (!st.isFile() || !onlyStar(readFileSync(ignore, 'utf8')))
|
|
321
|
+
throw new StoreRefusal(`refusing to write ${what}: ${dir}/.gitignore does not keep it out of git (it must be a plain file whose only pattern is \`*\`). Fix that file, then run again.`);
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* The store directory is a real directory and neither it nor the file is a
|
|
325
|
+
* link or another user's. Run before mkdir, after it, and again right before
|
|
326
|
+
* the rename (security review). Node has no openat, so a window remains
|
|
327
|
+
* between the last check and the rename; the 0700 directory bounds it.
|
|
328
|
+
*/
|
|
329
|
+
function checkStoreWrite(what, path) {
|
|
330
|
+
const dir = dirname(path);
|
|
331
|
+
refuseLinks(what, dir, path);
|
|
332
|
+
let st;
|
|
333
|
+
try {
|
|
334
|
+
st = lstatSync(dir);
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
st = null; // not made yet
|
|
338
|
+
}
|
|
339
|
+
if (st && !st.isDirectory())
|
|
340
|
+
throw new StoreRefusal(`refusing to write ${what}: ${dir} is not a directory`);
|
|
341
|
+
refuseOthers(dir, path, true);
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* A .gitignore whose only pattern is `*` (security review): `*` then
|
|
345
|
+
* `!map.json` would let git track the map, and the CLI cannot ask git which
|
|
346
|
+
* files it ignores. Blank lines and `#` comments are allowed. No trimming:
|
|
347
|
+
* git keeps leading spaces and a trailing tab (` *`, `*\t` match nothing), so
|
|
348
|
+
* only a line that is exactly `*` (CRLF accepted) counts.
|
|
349
|
+
*/
|
|
350
|
+
function onlyStar(text) {
|
|
351
|
+
const patterns = text.split(/\r?\n/).filter((l) => l !== '' && !l.startsWith('#'));
|
|
352
|
+
return patterns.length > 0 && patterns.every((l) => l === '*');
|
|
134
353
|
}
|
|
135
354
|
/** Throws when any of `paths` is a link: the store's files are written only
|
|
136
355
|
* where they appear to be (security audit 2026-11-01). */
|
|
137
356
|
export function refuseLinks(what, ...paths) {
|
|
138
357
|
for (const p of paths)
|
|
139
358
|
if (isLink(p))
|
|
140
|
-
throw new
|
|
359
|
+
throw new StoreRefusal(`refusing to write ${what}: ${p} is a link`);
|
|
141
360
|
}
|
|
142
361
|
function isLink(path) {
|
|
143
362
|
try {
|
package/dist/store.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"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"}
|
package/dist/team-anonymize.d.ts
CHANGED
|
@@ -100,8 +100,12 @@ export declare class ReservationFailed extends Error {
|
|
|
100
100
|
readonly cause: unknown;
|
|
101
101
|
constructor(cause: unknown);
|
|
102
102
|
}
|
|
103
|
+
/** Cloud's reserve route refuses more numbers per base, or more bases, in one request. */
|
|
104
|
+
export declare const RESERVE_MAX_COUNT = 5000;
|
|
105
|
+
export declare const RESERVE_MAX_BASES = 32;
|
|
103
106
|
/**
|
|
104
|
-
* `anonymizeOverTeam
|
|
107
|
+
* `anonymizeOverTeam` for the files of one call, with every NEW number taken
|
|
108
|
+
* from the team's allocation.
|
|
105
109
|
*
|
|
106
110
|
* Two passes, because only this machine can read the identifiers and so only
|
|
107
111
|
* this machine can know how many new names there are — but it may not choose
|
|
@@ -119,13 +123,26 @@ export declare class ReservationFailed extends Error {
|
|
|
119
123
|
* Step 4 is not belt-and-braces. If it ever fires, the alternative is a map
|
|
120
124
|
* that looks correct, publishes, and collides with a teammate's — the exact
|
|
121
125
|
* failure that is invisible until someone restores the wrong name.
|
|
126
|
+
*
|
|
127
|
+
* Every file of one call goes through these steps together, with one
|
|
128
|
+
* reservation for all of them (e40: a 164-file project made 164 reservations
|
|
129
|
+
* and met Cloud's rate limit) - or one per group of files when they need more
|
|
130
|
+
* than one request may ask. Pass 1 carries each file's names into the next, so
|
|
131
|
+
* a name several files share is counted once; pass 2 numbers file after file
|
|
132
|
+
* inside the reserved runs. A mismatch in any file fails the whole call - no
|
|
133
|
+
* file comes back with numbers nobody reserved.
|
|
122
134
|
*/
|
|
123
|
-
export declare function
|
|
135
|
+
export declare function reservedAnonymizeFilesOverTeam(files: ReadonlyArray<{
|
|
136
|
+
source: string;
|
|
137
|
+
options: Omit<AnonymizeOptions, 'existingMap'>;
|
|
138
|
+
}>, local: Record<string, string>, team: {
|
|
124
139
|
namespace: Record<string, string>;
|
|
125
140
|
highest: Record<string, number>;
|
|
126
141
|
conflicts?: Record<string, number>;
|
|
127
|
-
},
|
|
128
|
-
|
|
142
|
+
}, reserve: Reserve): Promise<{
|
|
143
|
+
results: ReturnType<typeof anonymize>[];
|
|
144
|
+
/** How many entries each file added to the store. */
|
|
145
|
+
added: number[];
|
|
129
146
|
toPersist: Record<string, string>;
|
|
130
147
|
}>;
|
|
131
148
|
//# sourceMappingURL=team-anonymize.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"team-anonymize.d.ts","sourceRoot":"","sources":["../src/team-anonymize.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"team-anonymize.d.ts","sourceRoot":"","sources":["../src/team-anonymize.ts"],"names":[],"mappings":"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"}
|
package/dist/team-anonymize.js
CHANGED
|
@@ -192,8 +192,12 @@ export class ReservationFailed extends Error {
|
|
|
192
192
|
this.name = 'ReservationFailed';
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
|
+
/** Cloud's reserve route refuses more numbers per base, or more bases, in one request. */
|
|
196
|
+
export const RESERVE_MAX_COUNT = 5000;
|
|
197
|
+
export const RESERVE_MAX_BASES = 32;
|
|
195
198
|
/**
|
|
196
|
-
* `anonymizeOverTeam
|
|
199
|
+
* `anonymizeOverTeam` for the files of one call, with every NEW number taken
|
|
200
|
+
* from the team's allocation.
|
|
197
201
|
*
|
|
198
202
|
* Two passes, because only this machine can read the identifiers and so only
|
|
199
203
|
* this machine can know how many new names there are — but it may not choose
|
|
@@ -211,61 +215,129 @@ export class ReservationFailed extends Error {
|
|
|
211
215
|
* Step 4 is not belt-and-braces. If it ever fires, the alternative is a map
|
|
212
216
|
* that looks correct, publishes, and collides with a teammate's — the exact
|
|
213
217
|
* failure that is invisible until someone restores the wrong name.
|
|
218
|
+
*
|
|
219
|
+
* Every file of one call goes through these steps together, with one
|
|
220
|
+
* reservation for all of them (e40: a 164-file project made 164 reservations
|
|
221
|
+
* and met Cloud's rate limit) - or one per group of files when they need more
|
|
222
|
+
* than one request may ask. Pass 1 carries each file's names into the next, so
|
|
223
|
+
* a name several files share is counted once; pass 2 numbers file after file
|
|
224
|
+
* inside the reserved runs. A mismatch in any file fails the whole call - no
|
|
225
|
+
* file comes back with numbers nobody reserved.
|
|
214
226
|
*/
|
|
215
|
-
export async function
|
|
227
|
+
export async function reservedAnonymizeFilesOverTeam(files, local, team, reserve) {
|
|
216
228
|
const settled = Object.fromEntries(Object.entries(team.namespace).filter(([p]) => !(p in (team.conflicts ?? {}))));
|
|
217
229
|
const existingMap = mergeNamespace(local, settled);
|
|
218
|
-
// Pass 1:
|
|
219
|
-
//
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
base,
|
|
239
|
-
count,
|
|
240
|
-
floor: Math.max(team.highest[base] ?? 0, inMap[base] ?? 0, inText[base] ?? 0),
|
|
241
|
-
}));
|
|
242
|
-
let ranges;
|
|
243
|
-
try {
|
|
244
|
-
ranges = await reserve(requests);
|
|
245
|
-
}
|
|
246
|
-
catch (err) {
|
|
247
|
-
throw new ReservationFailed(err);
|
|
230
|
+
// Pass 1: each file over the names the earlier ones minted, so a name several
|
|
231
|
+
// files share is counted once, for the first file that has it. The numbers
|
|
232
|
+
// this pass chooses are discarded. The engine copies the map it is given.
|
|
233
|
+
const seen = { ...existingMap };
|
|
234
|
+
const firsts = [];
|
|
235
|
+
const newIn = [];
|
|
236
|
+
for (const { source, options } of files) {
|
|
237
|
+
const result = anonymize(source, { ...options, existingMap: seen });
|
|
238
|
+
const counts = new Map();
|
|
239
|
+
for (const p of Object.keys(result.map)) {
|
|
240
|
+
if (p in seen)
|
|
241
|
+
continue;
|
|
242
|
+
const m = NUMBERED.exec(p);
|
|
243
|
+
if (!m)
|
|
244
|
+
throw new ReservationMismatch(p);
|
|
245
|
+
counts.set(m[1], (counts.get(m[1]) ?? 0) + 1);
|
|
246
|
+
}
|
|
247
|
+
Object.assign(seen, result.map);
|
|
248
|
+
firsts.push(result);
|
|
249
|
+
newIn.push(counts);
|
|
248
250
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
251
|
+
/** The store after each result, and how many entries each added. */
|
|
252
|
+
const keep = (results) => {
|
|
253
|
+
let toPersist = local;
|
|
254
|
+
const added = results.map((result) => {
|
|
255
|
+
const before = Object.keys(toPersist).length;
|
|
256
|
+
toPersist = persisted(toPersist, result, settled);
|
|
257
|
+
return Object.keys(toPersist).length - before;
|
|
258
|
+
});
|
|
259
|
+
return { results, added, toPersist };
|
|
260
|
+
};
|
|
261
|
+
// Nothing new, so nothing to reserve. Returning the first pass is correct AND
|
|
262
|
+
// is the only way to avoid a reservation of zero numbers, which the server
|
|
263
|
+
// would answer with an empty run the verification below rejects.
|
|
264
|
+
if (newIn.every((c) => c.size === 0))
|
|
265
|
+
return keep(firsts);
|
|
266
|
+
// Files in groups, each within one request's limits - one group, one
|
|
267
|
+
// reservation, for any project short of thousands of new names per base.
|
|
268
|
+
// A single file over a limit cannot be split: it fails here, with the reason.
|
|
269
|
+
const groups = [];
|
|
270
|
+
newIn.forEach((counts, i) => {
|
|
271
|
+
const over = [...counts].find(([, n]) => n > RESERVE_MAX_COUNT);
|
|
272
|
+
if (over || counts.size > RESERVE_MAX_BASES)
|
|
273
|
+
throw new ReservationFailed(new Error(over
|
|
274
|
+
? `one file needs ${over[1]} new ${over[0]} names, more than the ${RESERVE_MAX_COUNT} one reservation may ask - scrub it in parts`
|
|
275
|
+
: `one file needs new names in ${counts.size} kinds, more than the ${RESERVE_MAX_BASES} one reservation may ask - scrub it in parts`));
|
|
276
|
+
const last = groups.at(-1);
|
|
277
|
+
const fits = last !== undefined &&
|
|
278
|
+
[...counts].every(([base, n]) => (last.counts.get(base) ?? 0) + n <= RESERVE_MAX_COUNT) &&
|
|
279
|
+
new Set([...last.counts.keys(), ...counts.keys()]).size <= RESERVE_MAX_BASES;
|
|
280
|
+
if (last && fits) {
|
|
281
|
+
for (const [base, n] of counts)
|
|
282
|
+
last.counts.set(base, (last.counts.get(base) ?? 0) + n);
|
|
283
|
+
last.to = i + 1;
|
|
284
|
+
}
|
|
285
|
+
else
|
|
286
|
+
groups.push({ from: i, to: i + 1, counts: new Map(counts) });
|
|
287
|
+
});
|
|
288
|
+
// A number already taken - in this project's store (also one the merge with
|
|
289
|
+
// the team's namespace left out), or in any file's text - is below every floor.
|
|
290
|
+
const taken = highestPerBase(local);
|
|
291
|
+
for (const { source } of files)
|
|
292
|
+
for (const [base, n] of Object.entries(highestInText(source)))
|
|
293
|
+
if (n > (taken[base] ?? 0))
|
|
294
|
+
taken[base] = n;
|
|
295
|
+
const map = { ...existingMap };
|
|
296
|
+
const results = [];
|
|
297
|
+
for (const group of groups) {
|
|
298
|
+
const inMap = highestPerBase(map);
|
|
299
|
+
const requests = [...group.counts].map(([base, count]) => ({
|
|
300
|
+
base,
|
|
301
|
+
count,
|
|
302
|
+
floor: Math.max(team.highest[base] ?? 0, inMap[base] ?? 0, taken[base] ?? 0),
|
|
303
|
+
}));
|
|
304
|
+
let ranges = [];
|
|
305
|
+
if (requests.length > 0) {
|
|
306
|
+
try {
|
|
307
|
+
ranges = await reserve(requests);
|
|
308
|
+
}
|
|
309
|
+
catch (err) {
|
|
310
|
+
throw new ReservationFailed(err);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
const byBase = new Map(ranges.map((r) => [r.base, r]));
|
|
314
|
+
// Pass 2: `start - 1` as the floor, so the first new number IS `start`;
|
|
315
|
+
// each later file of the group numbers above the earlier ones, inside the run.
|
|
316
|
+
const floors = {};
|
|
317
|
+
for (const { base } of requests) {
|
|
318
|
+
const range = byBase.get(base);
|
|
319
|
+
if (!range || !isSaneBlock(range))
|
|
320
|
+
throw new ReservationMismatch(`${base}*`);
|
|
321
|
+
floors[base] = range.start - 1;
|
|
322
|
+
}
|
|
323
|
+
const before = new Set(Object.keys(map));
|
|
324
|
+
for (let i = group.from; i < group.to; i++) {
|
|
325
|
+
const result = anonymizeAbove(files[i].source, { ...files[i].options, existingMap: map }, floors);
|
|
326
|
+
Object.assign(map, result.map);
|
|
327
|
+
results.push(result);
|
|
328
|
+
}
|
|
329
|
+
// Every new placeholder of the group - none expected where nothing was reserved.
|
|
330
|
+
for (const placeholder of Object.keys(map)) {
|
|
331
|
+
if (before.has(placeholder))
|
|
332
|
+
continue;
|
|
333
|
+
const m = NUMBERED.exec(placeholder);
|
|
334
|
+
const range = m ? byBase.get(m[1]) : undefined;
|
|
335
|
+
const n = m ? Number(m[2]) : NaN;
|
|
336
|
+
if (!range || n < range.start || n > range.end)
|
|
337
|
+
throw new ReservationMismatch(placeholder);
|
|
338
|
+
}
|
|
267
339
|
}
|
|
268
|
-
return
|
|
340
|
+
return keep(results);
|
|
269
341
|
}
|
|
270
342
|
/** What the project's store keeps: everything it held, whatever was minted, and
|
|
271
343
|
* only the team entries the output actually used (spec 005 US4). Shared with
|