datagrok-tools 6.5.2 → 6.5.3
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/CHANGELOG.md +4 -0
- package/bin/commands/server.js +88 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Datagrok-tools changelog
|
|
2
2
|
|
|
3
|
+
## 6.5.3 (2026-08-04)
|
|
4
|
+
|
|
5
|
+
* GROK-18695: Security — bumped `adm-zip` to 0.6.0 (CVE-2026-39244). Below 0.6.0 it sized a buffer from the ZIP header's declared uncompressed size before validating it, so a ~120-byte crafted archive forced a multi-GB allocation; `grok report` opens archives fetched from a server. The APIs it uses are unchanged. Also refreshed the lockfile to clear five more high-severity audit findings (`brace-expansion`, `fast-uri`, `ip-address`, `js-yaml`, `postcss`), all within existing ranges.
|
|
6
|
+
|
|
3
7
|
## 6.5.2 (2026-07-27)
|
|
4
8
|
|
|
5
9
|
* `grok publish` — a failed `docker push` is no longer reported as a successful one. `image.json` claimed the tag regardless, so the server recorded a container image that was never published and the spawner failed validation forever ("Image ... not found in any registry") with no recovery short of another publish. The push failure now falls back to an image that is actually in the registry, and says so.
|
package/bin/commands/server.js
CHANGED
|
@@ -45,6 +45,7 @@ async function server(argv) {
|
|
|
45
45
|
if (entity === 'raw') return handleRaw(dapi, verb, rest, output);
|
|
46
46
|
if (entity === 'describe') return handleDescribe(dapi, verb ?? rest[0], output);
|
|
47
47
|
if (entity === 'healthcheck') return handleHealthcheck(dapi, argv, output);
|
|
48
|
+
if (entity === 'sync') return handleSync(dapi, verb, rest, argv, output);
|
|
48
49
|
if (entity === 'functions' && verb === 'run') return handleFuncRun(dapi, rest, argv, output);
|
|
49
50
|
if (entity === 'functions' && verb === 'list') return handleFunctionsList(dapi, argv, limit, offset, filter, output);
|
|
50
51
|
if (entity === 'files' && verb === 'list') {
|
|
@@ -235,6 +236,89 @@ async function handleRaw(dapi, method, rest, output) {
|
|
|
235
236
|
(0, _serverOutput.printOutput)(result, output);
|
|
236
237
|
return true;
|
|
237
238
|
}
|
|
239
|
+
async function handleSync(dapi, subject, rest, argv, output) {
|
|
240
|
+
// `grok s sync` subcommands. Mirrors the API surface in
|
|
241
|
+
// core/server/datlas/lib/src/routers/sync.dart — pairs / setups /
|
|
242
|
+
// runs are read-only here; `run` triggers an actual push and prints
|
|
243
|
+
// the per-item summary. Full reference in
|
|
244
|
+
// core/docs/plans/instance-sync.md (Phase 7 / operational polish).
|
|
245
|
+
//
|
|
246
|
+
// `_callSync` does dual-path routing: tries `/api/sync/...` first
|
|
247
|
+
// (nginx-fronted deployments) and falls back to `/sync/...` (bare
|
|
248
|
+
// datlas on :8082). Same approach as the server-side handshake
|
|
249
|
+
// code so the CLI works against either layout.
|
|
250
|
+
const verb = rest[0];
|
|
251
|
+
const callSync = async (method, path, body) => {
|
|
252
|
+
for (const prefix of ['/api', '']) {
|
|
253
|
+
const r = body !== undefined ? await dapi.raw(method, `${prefix}${path}`, body) : await dapi.raw(method, `${prefix}${path}`);
|
|
254
|
+
// raw() returns `null` for 404, but the server returns HTML for
|
|
255
|
+
// 404 too — treat anything that isn't a sync-shaped object/array
|
|
256
|
+
// as a miss and fall through to the alternate prefix.
|
|
257
|
+
if (r && (Array.isArray(r) || typeof r === 'object') && r['#type'] !== 'ApiError') return r;
|
|
258
|
+
}
|
|
259
|
+
return null;
|
|
260
|
+
};
|
|
261
|
+
if (subject === 'pairs' && verb === 'list') {
|
|
262
|
+
const status = argv.status ? `?status=${encodeURIComponent(argv.status)}` : '';
|
|
263
|
+
const pairs = await callSync('GET', `/sync/pairs${status}`);
|
|
264
|
+
(0, _serverOutput.printOutput)(pairs, output);
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
if (subject === 'setups' && verb === 'list') {
|
|
268
|
+
const pairId = argv.pair ?? rest[1];
|
|
269
|
+
if (!pairId) {
|
|
270
|
+
(0, _serverOutput.printError)(new Error('Usage: grok s sync setups list --pair <pair-id>'));
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
const setups = await callSync('GET', `/sync/pairs/${encodeURIComponent(pairId)}/setups`);
|
|
274
|
+
(0, _serverOutput.printOutput)(setups, output);
|
|
275
|
+
return true;
|
|
276
|
+
}
|
|
277
|
+
if (subject === 'setup' && verb === 'get') {
|
|
278
|
+
const id = rest[1];
|
|
279
|
+
if (!id) {
|
|
280
|
+
(0, _serverOutput.printError)(new Error('Usage: grok s sync setup get <setup-id>'));
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
const setup = await callSync('GET', `/sync/setups/${encodeURIComponent(id)}`);
|
|
284
|
+
(0, _serverOutput.printOutput)(setup, output);
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
if (subject === 'run') {
|
|
288
|
+
// grok s sync run <setup-id>
|
|
289
|
+
const id = rest[1] ?? verb;
|
|
290
|
+
if (!id) {
|
|
291
|
+
(0, _serverOutput.printError)(new Error('Usage: grok s sync run <setup-id>'));
|
|
292
|
+
return false;
|
|
293
|
+
}
|
|
294
|
+
const result = await callSync('POST', `/sync/setups/${encodeURIComponent(id)}/run`, {});
|
|
295
|
+
if (output === 'json' || output === 'csv') {
|
|
296
|
+
(0, _serverOutput.printOutput)(result, output);
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
if (output === 'quiet') {
|
|
300
|
+
console.log(result?.runId ?? '');
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
if (!result) {
|
|
304
|
+
(0, _serverOutput.printError)(new Error(`Sync setup ${id} not found, or server has no /sync routes.`));
|
|
305
|
+
return false;
|
|
306
|
+
}
|
|
307
|
+
console.log(`Run ${result?.runId} → ${result?.remoteUrl} (${result?.status})`);
|
|
308
|
+
if (result?.counts) {
|
|
309
|
+
const cs = Object.keys(result.counts).filter(k => (result.counts[k] ?? 0) > 0).map(k => `${result.counts[k]} ${k}`).join(', ');
|
|
310
|
+
if (cs) console.log(` ${cs}`);
|
|
311
|
+
}
|
|
312
|
+
const items = Array.isArray(result?.items) ? result.items : [];
|
|
313
|
+
if (items.length) {
|
|
314
|
+
console.log('\nItems:');
|
|
315
|
+
(0, _serverOutput.printOutput)(items, 'table');
|
|
316
|
+
}
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
(0, _serverOutput.printError)(new Error('Usage:\n' + ' grok s sync pairs list [--status active|pending|revoked]\n' + ' grok s sync setups list --pair <pair-id>\n' + ' grok s sync setup get <setup-id>\n' + ' grok s sync run <setup-id>'));
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
238
322
|
async function handleHealthcheck(dapi, argv, output) {
|
|
239
323
|
const module = argv.module;
|
|
240
324
|
const path = module ? `/api/public/v1/healthcheck?module=${encodeURIComponent(module)}` : '/api/public/v1/healthcheck';
|
|
@@ -618,6 +702,10 @@ Special commands:
|
|
|
618
702
|
grok s batch <entity> <verb> arg1 [arg2 ...] Batch operation (one round-trip)
|
|
619
703
|
grok s batch <entity> <verb> --json params.json Batch from JSON array
|
|
620
704
|
grok s batch manifest.json Run a workflow manifest
|
|
705
|
+
grok s sync pairs list [--status <s>] List cross-instance sync pairs (status: active|pending|revoked)
|
|
706
|
+
grok s sync setups list --pair <pair-id> List the named sync setups under a pair
|
|
707
|
+
grok s sync setup get <setup-id> Inspect a setup (selections, direction, last run)
|
|
708
|
+
grok s sync run <setup-id> Trigger a push run; prints per-item outcome
|
|
621
709
|
|
|
622
710
|
Options:
|
|
623
711
|
--host <alias|url> Server alias from config or full URL
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "datagrok-tools",
|
|
3
|
-
"version": "6.5.
|
|
3
|
+
"version": "6.5.3",
|
|
4
4
|
"description": "Utility to upload and publish packages to Datagrok",
|
|
5
5
|
"homepage": "https://github.com/datagrok-ai/public/tree/master/tools#readme",
|
|
6
6
|
"dependencies": {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"@babel/traverse": "^7.29.7",
|
|
10
10
|
"@typescript-eslint/typescript-estree": "^8.61.1",
|
|
11
11
|
"@typescript-eslint/visitor-keys": "^8.61.1",
|
|
12
|
-
"adm-zip": "^0.
|
|
12
|
+
"adm-zip": "^0.6.0",
|
|
13
13
|
"archiver": "^7.0.1",
|
|
14
14
|
"datagrok-api": "^1.27.6",
|
|
15
15
|
"estraverse": "^5.3.0",
|