@bluealba/platform-cli 0.3.1-feature-platform-cli-229 → 0.3.1-feature-platform-cli-231

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/dist/index.js CHANGED
@@ -2095,6 +2095,139 @@ var statusCommand = {
2095
2095
  hidden: (ctx) => !ctx.platformInitialized
2096
2096
  };
2097
2097
 
2098
+ // src/commands/manage-platform-admins/manage-platform-admins.command.ts
2099
+ import { join as join25 } from "path";
2100
+ import { fetch as undiciFetch2, Agent as Agent2 } from "undici";
2101
+ var MANAGE_PLATFORM_ADMINS_COMMAND_NAME = "manage-platform-admins";
2102
+ var managePlatformAdminsCommand = {
2103
+ name: MANAGE_PLATFORM_ADMINS_COMMAND_NAME,
2104
+ description: "Manage platform administrators (list, add, remove)",
2105
+ hidden: (ctx) => !ctx.platformInitialized
2106
+ };
2107
+ async function getGatewayConfig(logger) {
2108
+ const layout = await findPlatformLayout();
2109
+ if (!layout) {
2110
+ logger.log("Error: Cannot manage platform admins \u2014 no platform initialized in this directory.");
2111
+ return null;
2112
+ }
2113
+ const envPath = join25(layout.localDir, ".env");
2114
+ let env;
2115
+ try {
2116
+ env = await readEnvFile(envPath);
2117
+ } catch (error) {
2118
+ logger.log(`Error: ${error.message}`);
2119
+ return null;
2120
+ }
2121
+ const gatewayUrl = env.get("PAE_GATEWAY_HOST_URL");
2122
+ const accessSecret = env.get("PAE_GATEWAY_SERVICE_ACCESS_SECRET");
2123
+ if (!gatewayUrl) {
2124
+ logger.log("Error: PAE_GATEWAY_HOST_URL is not set in core/local/.env");
2125
+ return null;
2126
+ }
2127
+ if (!accessSecret) {
2128
+ logger.log("Error: PAE_GATEWAY_SERVICE_ACCESS_SECRET is not set in core/local/.env");
2129
+ return null;
2130
+ }
2131
+ return { gatewayUrl, accessSecret };
2132
+ }
2133
+ async function listPlatformAdmins(logger) {
2134
+ const config = await getGatewayConfig(logger);
2135
+ if (!config) return [];
2136
+ const { gatewayUrl, accessSecret } = config;
2137
+ const agent = new Agent2({ connect: { rejectUnauthorized: false } });
2138
+ let response;
2139
+ try {
2140
+ response = await undiciFetch2(`${gatewayUrl}/applications/platform/rules`, {
2141
+ method: "GET",
2142
+ headers: {
2143
+ Accept: "application/json",
2144
+ Authorization: `Bearer ${accessSecret}`
2145
+ },
2146
+ dispatcher: agent
2147
+ });
2148
+ } catch (error) {
2149
+ const err = error;
2150
+ const cause = err.cause instanceof Error ? ` (cause: ${err.cause.message})` : err.cause ? ` (cause: ${String(err.cause)})` : "";
2151
+ logger.log(`Error: Failed to reach gateway \u2014 ${err.message}${cause}`);
2152
+ return [];
2153
+ }
2154
+ if (!response.ok) {
2155
+ const body = await response.text().catch(() => "");
2156
+ logger.log(`Error: Server responded with ${response.status}${body ? ` \u2014 ${body}` : ""}`);
2157
+ return [];
2158
+ }
2159
+ const rules = await response.json();
2160
+ return rules.filter(
2161
+ (r) => r.subjectType === "user" && r.resourceType === "role" && r.resourceName === "admin"
2162
+ ).map((r) => ({ username: r.subject, ruleId: String(r.id) }));
2163
+ }
2164
+ async function addPlatformAdmin(username, logger) {
2165
+ const config = await getGatewayConfig(logger);
2166
+ if (!config) return false;
2167
+ const { gatewayUrl, accessSecret } = config;
2168
+ const agent = new Agent2({ connect: { rejectUnauthorized: false } });
2169
+ let response;
2170
+ try {
2171
+ response = await undiciFetch2(`${gatewayUrl}/applications/platform/rules`, {
2172
+ method: "POST",
2173
+ headers: {
2174
+ "Content-Type": "application/json",
2175
+ Accept: "application/json",
2176
+ Authorization: `Bearer ${accessSecret}`
2177
+ },
2178
+ body: JSON.stringify({
2179
+ subject: username,
2180
+ subjectType: "user",
2181
+ resourceType: "role",
2182
+ resource: "admin"
2183
+ }),
2184
+ dispatcher: agent
2185
+ });
2186
+ } catch (error) {
2187
+ const err = error;
2188
+ const cause = err.cause instanceof Error ? ` (cause: ${err.cause.message})` : err.cause ? ` (cause: ${String(err.cause)})` : "";
2189
+ logger.log(`Error: Failed to reach gateway \u2014 ${err.message}${cause}`);
2190
+ return false;
2191
+ }
2192
+ if (response.status === 409) {
2193
+ logger.log(`'${username}' is already a platform admin.`);
2194
+ return false;
2195
+ }
2196
+ if (!response.ok) {
2197
+ const body = await response.text().catch(() => "");
2198
+ logger.log(`Error: Server responded with ${response.status}${body ? ` \u2014 ${body}` : ""}`);
2199
+ return false;
2200
+ }
2201
+ return true;
2202
+ }
2203
+ async function removePlatformAdmin(ruleId, logger) {
2204
+ const config = await getGatewayConfig(logger);
2205
+ if (!config) return false;
2206
+ const { gatewayUrl, accessSecret } = config;
2207
+ const agent = new Agent2({ connect: { rejectUnauthorized: false } });
2208
+ let response;
2209
+ try {
2210
+ response = await undiciFetch2(`${gatewayUrl}/applications/platform/rules/${ruleId}`, {
2211
+ method: "DELETE",
2212
+ headers: {
2213
+ Authorization: `Bearer ${accessSecret}`
2214
+ },
2215
+ dispatcher: agent
2216
+ });
2217
+ } catch (error) {
2218
+ const err = error;
2219
+ const cause = err.cause instanceof Error ? ` (cause: ${err.cause.message})` : err.cause ? ` (cause: ${String(err.cause)})` : "";
2220
+ logger.log(`Error: Failed to reach gateway \u2014 ${err.message}${cause}`);
2221
+ return false;
2222
+ }
2223
+ if (!response.ok) {
2224
+ const body = await response.text().catch(() => "");
2225
+ logger.log(`Error: Server responded with ${response.status}${body ? ` \u2014 ${body}` : ""}`);
2226
+ return false;
2227
+ }
2228
+ return true;
2229
+ }
2230
+
2098
2231
  // src/commands/registry.ts
2099
2232
  var CommandRegistry = class {
2100
2233
  commands = /* @__PURE__ */ new Map();
@@ -2134,6 +2267,7 @@ for (const cmd of localScriptCommands) {
2134
2267
  registry.register(cmd);
2135
2268
  }
2136
2269
  registry.register(statusCommand);
2270
+ registry.register(managePlatformAdminsCommand);
2137
2271
 
2138
2272
  // src/app-state.ts
2139
2273
  var APP_STATE = {
@@ -2498,6 +2632,131 @@ function createLocalScriptUiController(scriptName) {
2498
2632
  };
2499
2633
  }
2500
2634
 
2635
+ // src/controllers/ui/manage-platform-admins.ui-controller.ts
2636
+ import { execSync } from "child_process";
2637
+
2638
+ // src/services/manage-platform-admins.service.ts
2639
+ async function listAdminsService(logger) {
2640
+ return listPlatformAdmins(logger);
2641
+ }
2642
+ async function addAdminService(username, logger) {
2643
+ return addPlatformAdmin(username, logger);
2644
+ }
2645
+ async function removeAdminService(ruleId, logger) {
2646
+ return removePlatformAdmin(ruleId, logger);
2647
+ }
2648
+
2649
+ // src/controllers/ui/manage-platform-admins.ui-controller.ts
2650
+ function getDefaultUsername() {
2651
+ try {
2652
+ const email = execSync("git config user.email", { encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] }).trim();
2653
+ return email || void 0;
2654
+ } catch {
2655
+ return void 0;
2656
+ }
2657
+ }
2658
+ async function managePlatformAdminsUiController(ctx) {
2659
+ if (!await isPlatformInitialized()) {
2660
+ ctx.log("Error: Cannot manage platform admins \u2014 no platform initialized in this directory.");
2661
+ return;
2662
+ }
2663
+ while (true) {
2664
+ const action = await ctx.select("What would you like to do?", [
2665
+ { label: "List current admins", value: "list" },
2666
+ { label: "Add admin(s)", value: "add" },
2667
+ { label: "Remove admin(s)", value: "remove" },
2668
+ { label: "Back to main menu", value: "back" }
2669
+ ]);
2670
+ if (action === "list") {
2671
+ await handleList(ctx);
2672
+ } else if (action === "add") {
2673
+ await handleAdd(ctx);
2674
+ } else if (action === "remove") {
2675
+ await handleRemove(ctx);
2676
+ } else if (action === "back") {
2677
+ break;
2678
+ }
2679
+ }
2680
+ }
2681
+ async function handleList(ctx) {
2682
+ const admins = await listAdminsService(ctx);
2683
+ if (admins.length === 0) {
2684
+ ctx.log("No platform admins found.");
2685
+ } else {
2686
+ ctx.log("Current platform admins:");
2687
+ for (const admin of admins) {
2688
+ ctx.log(` - ${admin.username}`);
2689
+ }
2690
+ }
2691
+ }
2692
+ async function handleAdd(ctx) {
2693
+ const currentAdmins = await listAdminsService(ctx);
2694
+ const existingUsernames = new Set(currentAdmins.map((a) => a.username));
2695
+ const pendingAdmins = [];
2696
+ const suggestedUsername = getDefaultUsername();
2697
+ let isFirstIteration = true;
2698
+ while (true) {
2699
+ const defaultValue = isFirstIteration ? suggestedUsername : void 0;
2700
+ const username = (await ctx.prompt("Username to add as admin:", defaultValue)).trim();
2701
+ isFirstIteration = false;
2702
+ if (!username) {
2703
+ ctx.log("Username cannot be empty, skipping.");
2704
+ } else if (existingUsernames.has(username)) {
2705
+ ctx.log(`'${username}' is already a platform admin.`);
2706
+ } else if (pendingAdmins.includes(username)) {
2707
+ ctx.log(`'${username}' is already in the pending list.`);
2708
+ } else {
2709
+ pendingAdmins.push(username);
2710
+ ctx.log(`Admins to add: ${pendingAdmins.join(", ")}`);
2711
+ }
2712
+ const addAnother = await ctx.confirm("Add another admin?", false);
2713
+ if (!addAnother) break;
2714
+ }
2715
+ if (pendingAdmins.length === 0) {
2716
+ ctx.log("No admins to add.");
2717
+ return;
2718
+ }
2719
+ let successCount = 0;
2720
+ for (const username of pendingAdmins) {
2721
+ const ok = await addAdminService(username, ctx);
2722
+ if (ok) {
2723
+ ctx.log(`'${username}' granted platform admin access.`);
2724
+ successCount++;
2725
+ }
2726
+ }
2727
+ ctx.log(`Successfully added ${successCount} of ${pendingAdmins.length} admin(s).`);
2728
+ }
2729
+ async function handleRemove(ctx) {
2730
+ const admins = await listAdminsService(ctx);
2731
+ if (admins.length === 0) {
2732
+ ctx.log("No platform admins to remove.");
2733
+ return;
2734
+ }
2735
+ const selected = await ctx.multiselect(
2736
+ "Select admins to remove:",
2737
+ admins.map((a) => ({ label: a.username, value: a.ruleId }))
2738
+ );
2739
+ if (selected.length === 0) {
2740
+ ctx.log("No admins selected.");
2741
+ return;
2742
+ }
2743
+ const confirmed = await ctx.confirm(`Remove ${selected.length} admin(s)?`, false);
2744
+ if (!confirmed) {
2745
+ ctx.log("Cancelled.");
2746
+ return;
2747
+ }
2748
+ let successCount = 0;
2749
+ for (const ruleId of selected) {
2750
+ const admin = admins.find((a) => a.ruleId === ruleId);
2751
+ const ok = await removeAdminService(ruleId, ctx);
2752
+ if (ok) {
2753
+ ctx.log(`'${admin?.username ?? ruleId}' removed from platform admins.`);
2754
+ successCount++;
2755
+ }
2756
+ }
2757
+ ctx.log(`Successfully removed ${successCount} of ${selected.length} admin(s).`);
2758
+ }
2759
+
2501
2760
  // src/controllers/ui/registry.ts
2502
2761
  var uiControllers = /* @__PURE__ */ new Map([
2503
2762
  [CREATE_APPLICATION_COMMAND_NAME, createApplicationUiController],
@@ -2510,7 +2769,8 @@ var uiControllers = /* @__PURE__ */ new Map([
2510
2769
  [BUILD_COMMAND_NAME, createLocalScriptUiController(BUILD_COMMAND_NAME)],
2511
2770
  [START_COMMAND_NAME, createLocalScriptUiController(START_COMMAND_NAME)],
2512
2771
  [STOP_COMMAND_NAME, createLocalScriptUiController(STOP_COMMAND_NAME)],
2513
- [DESTROY_COMMAND_NAME, createLocalScriptUiController(DESTROY_COMMAND_NAME)]
2772
+ [DESTROY_COMMAND_NAME, createLocalScriptUiController(DESTROY_COMMAND_NAME)],
2773
+ [MANAGE_PLATFORM_ADMINS_COMMAND_NAME, managePlatformAdminsUiController]
2514
2774
  ]);
2515
2775
 
2516
2776
  // src/hooks/use-command-runner.ts
@@ -3074,6 +3334,69 @@ var statusCliController = async (_args) => {
3074
3334
  }
3075
3335
  };
3076
3336
 
3337
+ // src/controllers/cli/manage-platform-admins.cli-controller.ts
3338
+ async function managePlatformAdminsCliController(args2) {
3339
+ const logger = { log: console.log };
3340
+ if (!await isPlatformInitialized()) {
3341
+ console.error("Error: Cannot manage platform admins \u2014 no platform initialized in this directory.");
3342
+ process.exit(1);
3343
+ }
3344
+ const { action } = args2;
3345
+ if (!action || !["list", "add", "remove"].includes(action)) {
3346
+ logger.log("Error: Missing or invalid 'action' argument. Valid values: list, add, remove");
3347
+ logger.log("Usage:");
3348
+ logger.log(" platform manage-platform-admins action=list");
3349
+ logger.log(" platform manage-platform-admins action=add usernames=alice,bob");
3350
+ logger.log(" platform manage-platform-admins action=remove usernames=alice");
3351
+ process.exit(1);
3352
+ }
3353
+ if (action === "list") {
3354
+ const admins = await listAdminsService(logger);
3355
+ if (admins.length === 0) {
3356
+ logger.log("No platform admins found.");
3357
+ } else {
3358
+ logger.log("Current platform admins:");
3359
+ for (const admin of admins) {
3360
+ logger.log(` - ${admin.username}`);
3361
+ }
3362
+ }
3363
+ return;
3364
+ }
3365
+ const { usernames } = args2;
3366
+ if (!usernames) {
3367
+ logger.log(`Error: Missing required argument 'usernames' for action '${action}'`);
3368
+ process.exit(1);
3369
+ }
3370
+ const usernameList = usernames.split(",").map((u) => u.trim()).filter(Boolean);
3371
+ if (usernameList.length === 0) {
3372
+ logger.log("Error: 'usernames' argument is empty.");
3373
+ process.exit(1);
3374
+ }
3375
+ if (action === "add") {
3376
+ for (const username of usernameList) {
3377
+ const ok = await addAdminService(username, logger);
3378
+ if (ok) {
3379
+ logger.log(`'${username}' granted platform admin access.`);
3380
+ }
3381
+ }
3382
+ return;
3383
+ }
3384
+ if (action === "remove") {
3385
+ const admins = await listAdminsService(logger);
3386
+ for (const username of usernameList) {
3387
+ const admin = admins.find((a) => a.username === username);
3388
+ if (!admin) {
3389
+ logger.log(`'${username}' is not currently a platform admin.`);
3390
+ continue;
3391
+ }
3392
+ const ok = await removeAdminService(admin.ruleId, logger);
3393
+ if (ok) {
3394
+ logger.log(`'${username}' removed from platform admins.`);
3395
+ }
3396
+ }
3397
+ }
3398
+ }
3399
+
3077
3400
  // src/controllers/cli/registry.ts
3078
3401
  var cliControllers = /* @__PURE__ */ new Map([
3079
3402
  [CREATE_APPLICATION_COMMAND_NAME, createApplicationCliController],
@@ -3086,7 +3409,8 @@ var cliControllers = /* @__PURE__ */ new Map([
3086
3409
  [BUILD_COMMAND_NAME, createLocalScriptCliController(BUILD_COMMAND_NAME)],
3087
3410
  [START_COMMAND_NAME, createLocalScriptCliController(START_COMMAND_NAME)],
3088
3411
  [STOP_COMMAND_NAME, createLocalScriptCliController(STOP_COMMAND_NAME)],
3089
- [DESTROY_COMMAND_NAME, createLocalScriptCliController(DESTROY_COMMAND_NAME)]
3412
+ [DESTROY_COMMAND_NAME, createLocalScriptCliController(DESTROY_COMMAND_NAME)],
3413
+ [MANAGE_PLATFORM_ADMINS_COMMAND_NAME, managePlatformAdminsCliController]
3090
3414
  ]);
3091
3415
 
3092
3416
  // src/utils/parse-args.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bluealba/platform-cli",
3
- "version": "0.3.1-feature-platform-cli-229",
3
+ "version": "0.3.1-feature-platform-cli-231",
4
4
  "description": "Blue Alba Platform CLI",
5
5
  "license": "PolyForm-Noncommercial-1.0.0",
6
6
  "type": "module",
@@ -13,8 +13,8 @@
13
13
  "lint:fix": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix"
14
14
  },
15
15
  "dependencies": {
16
- "@bluealba/pae-bootstrap-lib": "3.0.0",
17
- "@bluealba/pae-core": "5.2.0",
16
+ "@bluealba/pae-bootstrap-lib": "3.1.1",
17
+ "@bluealba/pae-core": "5.4.0",
18
18
  "copyfiles": "^2.4.1",
19
19
  "express": "^4.21.2"
20
20
  },
@@ -47,7 +47,7 @@
47
47
  "webpack-merge": "^5.8.0"
48
48
  },
49
49
  "dependencies": {
50
- "@bluealba/pae-ui-react-core": "4.3.0",
50
+ "@bluealba/pae-ui-react-core": "4.5.0",
51
51
  "css-loader": "^7.1.2",
52
52
  "react": "^18.3.1",
53
53
  "react-dom": "^18.3.1",
@@ -26,7 +26,7 @@ services:
26
26
  retries: 20
27
27
 
28
28
  pae-nestjs-gateway-service:
29
- image: bluealba-ba-docker-virtual.jfrog.io/bluealba-pae-nestjs-gateway-service:3.6.1
29
+ image: bluealba-ba-docker-virtual.jfrog.io/bluealba-pae-nestjs-gateway-service:3.8.0
30
30
  ports:
31
31
  - 9080:80
32
32
  - 9443:443
@@ -50,22 +50,22 @@ services:
50
50
  condition: service_healthy
51
51
 
52
52
  pae-shell-ui:
53
- image: bluealba-ba-docker-virtual.jfrog.io/bluealba-pae-shell-ui:3.3.0
53
+ image: bluealba-ba-docker-virtual.jfrog.io/bluealba-pae-shell-ui:3.3.2
54
54
  ports:
55
55
  - 9004:80
56
56
 
57
57
  pae-admin-ui:
58
- image: bluealba-ba-docker-virtual.jfrog.io/bluealba-pae-admin-ui:4.4.0
58
+ image: bluealba-ba-docker-virtual.jfrog.io/bluealba-pae-admin-ui:4.6.0
59
59
  ports:
60
60
  - 9005:80
61
61
 
62
62
  pae-documentation-ui:
63
- image: bluealba-ba-docker-virtual.jfrog.io/bluealba-pae-documentation-ui:1.0.7
63
+ image: bluealba-ba-docker-virtual.jfrog.io/bluealba-pae-documentation-ui:1.0.9
64
64
  ports:
65
65
  - 9006:80
66
66
 
67
67
  pae-documentation:
68
- image: bluealba-ba-docker-virtual.jfrog.io/bluealba-pae-documentation:1.0.7
68
+ image: bluealba-ba-docker-virtual.jfrog.io/bluealba-pae-documentation:1.0.9
69
69
  ports:
70
70
  - 8585:80
71
71
 
@@ -10,7 +10,7 @@
10
10
  "lint:fix": "pae-ui-sdk lint --fix"
11
11
  },
12
12
  "devDependencies": {
13
- "@bluealba/pae-ui-react-core": "4.4.0",
13
+ "@bluealba/pae-ui-react-core": "4.5.0",
14
14
  "@bluealba/pae-ui-react-sdk": "1.0.2",
15
15
  "@types/react": "18.3.3",
16
16
  "@types/react-dom": "18.3.0",