@synapseone/cli 0.9.0-dev.78 → 0.9.0-dev.79

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.
Files changed (2) hide show
  1. package/bin/synapseone.js +69 -9
  2. package/package.json +1 -1
package/bin/synapseone.js CHANGED
@@ -261,6 +261,15 @@ function parse(argv) {
261
261
  if (!v) throw new Error('missing value for --context-url <url>');
262
262
  (opts.contextUrls ??= []).push(v);
263
263
  }
264
+ // Token management flags.
265
+ else if (a === '--grace') opts.grace = argv[++i];
266
+ else if (a.startsWith('--grace=')) opts.grace = a.slice(8);
267
+ else if (a === '--scopes') opts.scopes = argv[++i];
268
+ else if (a.startsWith('--scopes=')) opts.scopes = a.slice(9);
269
+ else if (a === '--user') opts.user = argv[++i];
270
+ else if (a.startsWith('--user=')) opts.user = a.slice(7);
271
+ else if (a === '--managed') opts.managed = argv[++i];
272
+ else if (a.startsWith('--managed=')) opts.managed = a.slice(10);
264
273
  else args.push(a);
265
274
  }
266
275
  return { args, opts };
@@ -428,7 +437,9 @@ async function cmdPolicies(o) {
428
437
  const [sub, ...rest] = o._;
429
438
  if (sub === 'create') {
430
439
  const [account, slug] = rest;
431
- need(account, 'account'); need(slug, 'slug'); need(o.file, '--file policy.json');
440
+ need(account, 'account'); need(slug, 'slug');
441
+ if (o.managed) return out(await POST(`/v1/accounts/${encodeURIComponent(account)}/policies`, { slug, managed: o.managed }, o), o);
442
+ need(o.file, '--file policy.json (or --managed NAME)');
432
443
  return out(await POST(`/v1/accounts/${encodeURIComponent(account)}/policies`, { slug, document: readJson(o.file) }, o), o);
433
444
  }
434
445
  if (sub === 'delete') {
@@ -475,9 +486,22 @@ async function cmdKeys(o) {
475
486
  const [sub, ...rest] = o._;
476
487
  if (sub === 'create') {
477
488
  need(rest[0], 'account');
478
- const r = await POST(`/v1/accounts/${encodeURIComponent(rest[0])}/keys`, { name: o.name || o.label || 'cli', scopes: ['*'] }, o);
479
- if (!o.json) console.log(`SAVE THIS KEY (shown once):\n${r.apiKey}\nid: ${r.id}`);
480
- else console.log(JSON.stringify(r, null, 2));
489
+ const scopes = o.scopes ? String(o.scopes).split(',').map((x) => x.trim()).filter(Boolean) : ['*'];
490
+ const body = { name: o.name || o.label || 'cli', scopes, ...(o.user ? { userId: o.user } : {}) };
491
+ const r = await POST(`/v1/accounts/${encodeURIComponent(rest[0])}/keys`, body, o);
492
+ // The new secret is printed to stdout once, on purpose (never to a log).
493
+ if (!o.json) process.stdout.write(`SAVE THIS KEY (shown once):\n${r.apiKey}\nid: ${r.id}\n`);
494
+ else process.stdout.write(`${JSON.stringify(r, null, 2)}\n`);
495
+ return;
496
+ }
497
+ if (sub === 'rotate') {
498
+ need(rest[0], 'key-id');
499
+ const graceSeconds = o.grace === undefined ? 0 : Number(o.grace);
500
+ if (!Number.isInteger(graceSeconds) || graceSeconds < 0) throw new Error('--grace must be a non-negative integer (seconds)');
501
+ const r = await POST(`/v1/keys/${encodeURIComponent(rest[0])}/rotate`, { graceSeconds }, o);
502
+ // The new secret is printed to stdout once, on purpose (never to a log).
503
+ if (!o.json) process.stdout.write(`SAVE THIS KEY (shown once):\n${r.apiKey}\nid: ${r.id}\nold key ${r.rotatedFrom} expires at ${r.oldKeyExpiresAt}\n`);
504
+ else process.stdout.write(`${JSON.stringify(r, null, 2)}\n`);
481
505
  return;
482
506
  }
483
507
  if (sub === 'revoke' || sub === 'delete') {
@@ -491,9 +515,9 @@ async function cmdKeys(o) {
491
515
  if (sub === 'list') {
492
516
  need(rest[0], 'account');
493
517
  const r = await GET(`/v1/accounts/${encodeURIComponent(rest[0])}/keys`, o);
494
- return out(Array.isArray(r) ? r : [], o, ['id', 'name', 'prefix', 'revoked_at']);
518
+ return out(Array.isArray(r) ? r : [], o, ['id', 'name', 'prefix', 'scopes', 'user_id', 'last_used_at', 'revoked_at']);
495
519
  }
496
- throw new Error(`usage: keys create <account> [--name N] | keys list <account> | keys revoke <key-id> | keys verify <api-key>`);
520
+ throw new Error(`usage: keys create <account> [--name N] [--scopes a,b] [--user USER_ID] | keys list <account> | keys rotate <key-id> [--grace SECONDS] | keys revoke <key-id> | keys verify <api-key>`);
497
521
  }
498
522
  async function cmdSa(o) {
499
523
  const [sub, ...rest] = o._;
@@ -508,9 +532,42 @@ async function cmdSa(o) {
508
532
  else console.log(JSON.stringify(r, null, 2));
509
533
  return;
510
534
  }
535
+ if (sub === 'roles') {
536
+ need(rest[0], 'sa-id');
537
+ return out(await GET(`/v1/service-accounts/${encodeURIComponent(rest[0])}/roles`, o), o, ['slug', 'id']);
538
+ }
539
+ if (sub === 'grant') {
540
+ need(rest[0], 'sa-id'); need(rest[1], 'role-id');
541
+ return out(await POST(`/v1/service-accounts/${encodeURIComponent(rest[0])}/roles`, { roleId: rest[1] }, o), o);
542
+ }
543
+ if (sub === 'revoke-role') {
544
+ need(rest[0], 'sa-id'); need(rest[1], 'role-id');
545
+ return out(await DEL(`/v1/service-accounts/${encodeURIComponent(rest[0])}/roles/${encodeURIComponent(rest[1])}`, o), o);
546
+ }
511
547
  need(sub, 'account');
512
548
  return out(await GET(`/v1/accounts/${encodeURIComponent(sub)}/service-accounts`, o), o, ['slug', 'id']);
513
549
  }
550
+
551
+ // ---------- token management: sessions, org admins, managed policies ----------
552
+ async function cmdSessions(o) {
553
+ const [sub, ...rest] = o._;
554
+ if (sub === 'revoke') {
555
+ need(rest[0], 'session-id');
556
+ return out(await DEL(`/v1/auth/sessions/${encodeURIComponent(rest[0])}`, o), o);
557
+ }
558
+ if (sub && sub !== 'list') throw new Error('usage: sessions [list] | sessions revoke <session-id>');
559
+ return out(await GET('/v1/auth/sessions', o), o, ['id', 'created_at', 'expires_at']);
560
+ }
561
+ async function cmdOrgAdmin(o) {
562
+ const [userId, flag] = o._;
563
+ need(userId, 'user-id');
564
+ if (flag !== 'on' && flag !== 'off') throw new Error('usage: org-admin <user-id> on|off');
565
+ return out(await req('PUT', `/v1/users/${encodeURIComponent(userId)}/org-admin`, { isOrgAdmin: flag === 'on' }, o), o);
566
+ }
567
+ async function cmdManagedPolicies(o) {
568
+ return out(await GET('/v1/managed-policies', o), o, ['name', 'description']);
569
+ }
570
+
514
571
  async function cmdWorkflows(o) {
515
572
  const [sub, ...rest] = o._;
516
573
  if (!sub || sub === 'list') {
@@ -955,7 +1012,10 @@ const COMMANDS = {
955
1012
  accounts: { fn: cmdAccounts, use: 'accounts [org] [list] | accounts create [org] <slug> [name]', doc: 'Accounts' },
956
1013
  users: { fn: cmdUsers, use: 'users [org] | users create <org> <email> [name] | users policies <user-id>', doc: 'Users + effective policies' },
957
1014
  roles: { fn: cmdRoles, use: 'roles <account> [list] | roles create <account> <slug> | roles delete <id>', doc: 'Roles' },
958
- policies: { fn: cmdPolicies, use: 'policies <account> [list] | policies create <account> <slug> --file p.json | policies delete <id>', doc: 'Policies' },
1015
+ policies: { fn: cmdPolicies, use: 'policies <account> [list] | policies create <account> <slug> (--file p.json | --managed ReadOnlyAccess) | policies delete <id>', doc: 'Policies' },
1016
+ 'managed-policies': { fn: cmdManagedPolicies, use: 'managed-policies', doc: 'AWS-style managed policies (AdministratorAccess, ReadOnlyAccess, ...)' },
1017
+ 'org-admin': { fn: cmdOrgAdmin, use: 'org-admin <user-id> on|off', doc: 'Grant/revoke organization administrator' },
1018
+ sessions: { fn: cmdSessions, use: 'sessions [list] | sessions revoke <session-id>', doc: 'Your login sessions (refresh tokens)' },
959
1019
  attach: { fn: cmdAttach, use: 'attach <role-id> <policy-id>', doc: 'Attach policy to role' },
960
1020
  detach: { fn: cmdDetach, use: 'detach <role-id> <policy-id>', doc: 'Detach policy from role' },
961
1021
  assign: { fn: cmdAssign, use: 'assign <user-id> <role-id>', doc: 'Assign role to user' },
@@ -963,8 +1023,8 @@ const COMMANDS = {
963
1023
  authz: { fn: cmdAuthz, use: 'authz <user> <action> <resource> [--context k=v]', doc: 'Authorize check' },
964
1024
  sim: { fn: cmdSim, use: 'sim --file policy.json <action> <resource> [--context k=v]', doc: 'Policy simulator' },
965
1025
  audit: { fn: cmdAudit, use: 'audit [--limit N] [--actor ID]', doc: 'Audit log' },
966
- keys: { fn: cmdKeys, use: 'keys create <account> [--name N] | keys list <account> | keys revoke <key-id> | keys verify <api-key>', doc: 'API keys' },
967
- sa: { fn: cmdSa, use: 'sa <account> [list] | sa create <account> <slug> | sa token <sa-id>', doc: 'Service accounts' },
1026
+ keys: { fn: cmdKeys, use: 'keys create <account> [--name N] [--scopes a,b] [--user USER_ID] | keys list <account> | keys rotate <key-id> [--grace SECONDS] | keys revoke <key-id> | keys verify <api-key>', doc: 'API keys (scoped, owner-bound, rotatable)' },
1027
+ sa: { fn: cmdSa, use: 'sa <account> [list] | sa create <account> <slug> | sa token <sa-id> | sa roles <sa-id> | sa grant <sa-id> <role-id> | sa revoke-role <sa-id> <role-id>', doc: 'Service accounts + their roles' },
968
1028
  credentials: { fn: cmdCredentials, use: 'credentials create <account> --name N --type bearer|basic|apiKey|oauth2 (--secret S | --secret-file F) [--expires-at ISO] | credentials [list] <account> | credentials get|delete <id> | credentials rotate <id> (--secret S | --secret-file F)', doc: 'Account credentials, secrets write-only (PROPOSED: backend in progress)' },
969
1029
  call: { fn: cmdCall, use: 'call <METHOD> <path> [--data \'{...}\'|body.json] [--file body.json]', doc: 'Generic gateway call (escape hatch for new endpoints)' },
970
1030
  workflows: { fn: cmdWorkflows, use: 'workflows [list] | workflows create --template T [--name N] | workflows create --file def.json [--name N] | workflows get|activate|deactivate <id> | workflows exec|execute <id> [--data \'{...}\'|input.json] [--file payload.json] | workflows update [--name N] [--file def.json] <id> | workflows delete <id> | workflows test-run --file def.json [--input input.json|\'{...}\'] [--workflow-id ID]', doc: 'Workflows (local engine)' },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@synapseone/cli",
3
- "version": "0.9.0-dev.78",
3
+ "version": "0.9.0-dev.79",
4
4
  "license": "Apache-2.0",
5
5
  "description": "synapseone CLI - zero-dependency command line for Tier-1 PaaS (Node 18+)",
6
6
  "homepage": "https://synapseone.space",