@aifabrix/builder 2.46.0 → 2.47.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/.npmrc.token +1 -0
- package/.temp/jest-protection-convert/run-IFN2nv/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-IvmKLO/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-convert/run-SdvblF/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-b51TsW/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-fiLmb1/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-qYGHMU/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-Mq5re8/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-f3u4YL/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-iQtd1O/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-mdmz5M/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-qbKYxQ/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-yzlJy6/hubspot-companies.yaml +17 -0
- package/.temp/validation/summary.txt +5 -0
- package/jest.isolated-projects.js +18 -2
- package/jest.projects.js +24 -0
- package/lib/api/dataplane-health.api.js +19 -7
- package/lib/api/lifecycle.api.js +22 -1
- package/lib/api/resource-types.api.js +107 -0
- package/lib/api/runtime-configuration.api.js +72 -0
- package/lib/api/types/resource-types.types.js +45 -0
- package/lib/api/user-groups.api.js +9 -9
- package/lib/api/users.api.js +8 -8
- package/lib/api/wizard.api.js +10 -2
- package/lib/app/down.js +58 -26
- package/lib/app/index.js +2 -2
- package/lib/app/run-resolve-image.js +2 -1
- package/lib/app/run-stop-containers.js +113 -0
- package/lib/app/run.js +1 -31
- package/lib/app/show-display.js +35 -0
- package/lib/app/show.js +32 -1
- package/lib/build/index.js +17 -5
- package/lib/build/miso-controller-npm-sdk-guard.js +25 -0
- package/lib/channels/add-channel.js +348 -0
- package/lib/channels/channel-artifact-generator.js +141 -0
- package/lib/channels/channel-audit.js +101 -0
- package/lib/channels/channel-auth-context.js +37 -0
- package/lib/channels/channel-credential.js +200 -0
- package/lib/channels/channel-display-name.js +64 -0
- package/lib/channels/channel-external-system.js +106 -0
- package/lib/channels/channel-integration-generator.js +274 -0
- package/lib/channels/channel-probe.js +89 -0
- package/lib/channels/channel-runtime-resolver.js +152 -0
- package/lib/channels/channel-status-display.js +141 -0
- package/lib/channels/channel-targets.js +115 -0
- package/lib/cli/index.js +16 -4
- package/lib/cli/setup-app.js +54 -3
- package/lib/cli/setup-infra-up-dataplane-action.js +2 -2
- package/lib/cli/setup-infra-up-platform-action.js +2 -1
- package/lib/cli/setup-platform.js +1 -1
- package/lib/cli/setup-utility-help-after.js +4 -1
- package/lib/cli/setup-utility-resolve.js +8 -5
- package/lib/commands/app-logs.js +54 -26
- package/lib/commands/app.js +41 -0
- package/lib/commands/auth-status-dataplane-version.js +97 -61
- package/lib/commands/auth-status.js +2 -7
- package/lib/commands/channel.js +58 -0
- package/lib/commands/datasource.js +1 -1
- package/lib/commands/identity-apply-sync.js +49 -8
- package/lib/commands/identity-group-cli.js +66 -26
- package/lib/commands/identity-membership-role-cache.js +58 -37
- package/lib/commands/identity-shared.js +22 -1
- package/lib/commands/identity-user-cli.js +80 -34
- package/lib/commands/repair-auth-apply.js +30 -4
- package/lib/commands/repair-auth-config.js +8 -13
- package/lib/commands/repair-datasource-com-v2.js +15 -0
- package/lib/commands/repair-datasource-service-contract.js +206 -0
- package/lib/commands/repair-datasource.js +53 -18
- package/lib/commands/repair-env-template.js +12 -12
- package/lib/commands/repair-openapi-sync.js +26 -4
- package/lib/commands/repair-steps.js +28 -13
- package/lib/commands/repair-system-alignment.js +7 -4
- package/lib/commands/resource-type.js +371 -0
- package/lib/commands/setup-modes.js +1 -1
- package/lib/commands/setup-prompts-platform-mode.js +24 -21
- package/lib/commands/test-trust-external.js +39 -90
- package/lib/commands/up-common.js +33 -1
- package/lib/commands/up-dataplane.js +8 -4
- package/lib/commands/upload.js +24 -3
- package/lib/commands/verify-trust-command-action.js +4 -1
- package/lib/commands/verify-trust-external.js +12 -20
- package/lib/core/config-setup-platform-mode.js +3 -3
- package/lib/core/setup-platform-mode.js +41 -6
- package/lib/datasource/capability/capability-diff-slice.js +2 -2
- package/lib/datasource/capability/capability-manifest.js +254 -0
- package/lib/datasource/capability/capability-resolve.js +3 -4
- package/lib/datasource/capability/copy-operations.js +5 -3
- package/lib/datasource/capability/remove-operations.js +2 -1
- package/lib/datasource/capability/run-capability-copy.js +32 -4
- package/lib/datasource/capability/run-capability-diff.js +3 -3
- package/lib/datasource/capability/run-capability-dimension.js +2 -4
- package/lib/datasource/capability/run-capability-edit.js +4 -7
- package/lib/datasource/capability/run-capability-relate.js +2 -4
- package/lib/datasource/capability/run-capability-remove.js +2 -4
- package/lib/datasource/capability/validate-capability-slice.js +2 -1
- package/lib/datasource/datasource-identifier.js +2 -1
- package/lib/datasource/datasource-validate-display.js +1 -1
- package/lib/datasource/field-reference-validator.js +24 -3
- package/lib/datasource/orphan-profiles-validator.js +98 -0
- package/lib/datasource/validate.js +41 -23
- package/lib/external-system/download-helpers.js +87 -0
- package/lib/external-system/download.js +61 -122
- package/lib/external-system/generator.js +1 -59
- package/lib/external-system/test.js +10 -15
- package/lib/generator/builders.js +11 -1
- package/lib/generator/external-controller-manifest.js +5 -2
- package/lib/generator/split.js +3 -1
- package/lib/generator/wizard.js +1 -28
- package/lib/identity/fk-reference.js +65 -0
- package/lib/identity/identity-apply-core.js +13 -58
- package/lib/identity/identity-apply-phases.js +5 -1
- package/lib/identity/identity-display.js +243 -0
- package/lib/identity/identity-response-helpers.js +52 -0
- package/lib/identity/identity-sync-errors.js +62 -0
- package/lib/identity/resolve-user-id.js +129 -0
- package/lib/identity/username-default.js +31 -0
- package/lib/lifecycle/certification-progress.js +2 -2
- package/lib/lifecycle/report-display-trust.js +70 -0
- package/lib/lifecycle/report-display.js +14 -13
- package/lib/resolvers/datasource-resolver.js +2 -3
- package/lib/resolvers/resource-type-file.js +159 -0
- package/lib/schema/application-schema.json +16 -0
- package/lib/schema/deployment-rules.yaml +2 -1
- package/lib/schema/external-datasource.schema.json +372 -58
- package/lib/schema/external-system.schema.json +331 -2
- package/lib/schema/type/document-storage.json +9 -5
- package/lib/utils/app-run-containers.js +25 -2
- package/lib/utils/authentication-shape.js +224 -0
- package/lib/utils/build-copy.js +36 -5
- package/lib/utils/build-resolve-image.js +66 -12
- package/lib/utils/celery-companion-apps.js +53 -0
- package/lib/utils/cli-utils.js +4 -0
- package/lib/utils/compose-celery-worker.js +23 -0
- package/lib/utils/compose-generate-docker-compose.js +9 -1
- package/lib/utils/configuration-env-resolver.js +36 -0
- package/lib/utils/credential-secrets-env-kv.js +216 -0
- package/lib/utils/credential-secrets-env.js +52 -262
- package/lib/utils/dataplane-resolver.js +4 -115
- package/lib/utils/declarative-url-ports.js +24 -1
- package/lib/utils/docker-build.js +1 -4
- package/lib/utils/external-env-template.js +10 -3
- package/lib/utils/external-system-validators.js +8 -2
- package/lib/utils/help-builder.js +2 -0
- package/lib/utils/paths.js +25 -0
- package/lib/utils/platform-controller-url.js +2 -1
- package/lib/utils/platform-kv-ref.js +57 -0
- package/lib/utils/runtime-configuration-download.js +189 -0
- package/lib/utils/runtime-configuration-values.js +119 -0
- package/lib/utils/schema-loader.js +19 -4
- package/lib/utils/worker-sidecars.js +142 -0
- package/lib/validation/external-manifest-validator.js +2 -0
- package/lib/validation/runtime-configuration-rules.js +98 -0
- package/lib/validation/validate-display-dimensions.js +154 -0
- package/lib/validation/validate-display-sections.js +276 -0
- package/lib/validation/validate-display-steps.js +67 -0
- package/lib/validation/validate-display.js +24 -402
- package/package.json +1 -1
- package/templates/applications/dataplane/application.yaml +5 -0
- package/templates/applications/dataplane/env.template +26 -13
- package/templates/applications/dataplane/rbac.yaml +108 -1
- package/templates/applications/miso-controller/application.yaml +2 -2
- package/templates/applications/miso-controller/env.template +37 -122
- package/templates/applications/miso-controller/rbac.yaml +28 -13
- package/templates/channels/chatgpt/install.template.md.hbs +49 -0
- package/templates/channels/chatgpt/manifest.template.json.hbs +9 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +49 -0
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +8 -0
- package/templates/channels/slack/install.template.md.hbs +49 -0
- package/templates/channels/slack/manifest.template.json.hbs +66 -0
- package/templates/channels/teams-bot/install.template.md.hbs +49 -0
- package/templates/channels/teams-bot/manifest.template.json.hbs +13 -0
- package/templates/channels/web-embed/install.template.md.hbs +49 -0
- package/templates/channels/web-embed/manifest.template.json.hbs +8 -0
- package/templates/python/docker-compose.hbs +56 -0
- package/templates/typescript/docker-compose.hbs +52 -0
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
9
|
const logger = require('../utils/logger');
|
|
10
|
-
const { formatBlockingError, formatSuccessLine
|
|
10
|
+
const { formatBlockingError, formatSuccessLine } = require('../utils/cli-layout-chalk');
|
|
11
11
|
const {
|
|
12
12
|
resolveControllerAndAuth,
|
|
13
13
|
requireNonEmpty,
|
|
@@ -15,11 +15,26 @@ const {
|
|
|
15
15
|
throwIfApiFailed
|
|
16
16
|
} = require('./identity-shared');
|
|
17
17
|
const { listGroups, getGroup, createGroup, listGroupMembers } = require('../api/groups.api');
|
|
18
|
+
const {
|
|
19
|
+
extractPaginatedList,
|
|
20
|
+
printGroupMembersTable,
|
|
21
|
+
printGroupRecord,
|
|
22
|
+
printIdentityEmpty,
|
|
23
|
+
printIdentityListHeader,
|
|
24
|
+
printIdentityNotFound,
|
|
25
|
+
printIdentityTable,
|
|
26
|
+
printListPaginationFooter,
|
|
27
|
+
GROUP_LIST_COLUMNS
|
|
28
|
+
} = require('../identity/identity-display');
|
|
18
29
|
|
|
19
30
|
function printJson(data) {
|
|
20
31
|
logger.log(JSON.stringify(data, null, 2));
|
|
21
32
|
}
|
|
22
33
|
|
|
34
|
+
function groupNotFoundHints() {
|
|
35
|
+
return ['af identity group list --search <text>', 'Use group name or id from group list'];
|
|
36
|
+
}
|
|
37
|
+
|
|
23
38
|
function registerGroupCreate(groupCmd) {
|
|
24
39
|
groupCmd
|
|
25
40
|
.command('create')
|
|
@@ -51,7 +66,7 @@ function registerGroupList(groupCmd) {
|
|
|
51
66
|
.description('List groups')
|
|
52
67
|
.option('--page <n>', 'Page', (v) => parseInt(v, 10))
|
|
53
68
|
.option('--page-size <n>', 'Page size', (v) => parseInt(v, 10))
|
|
54
|
-
.option('--search <text>', 'Search groups')
|
|
69
|
+
.option('--search <text>', 'Search groups by name or display name')
|
|
55
70
|
.option('--json', 'JSON output')
|
|
56
71
|
.action(async(options) => {
|
|
57
72
|
try {
|
|
@@ -62,14 +77,24 @@ function registerGroupList(groupCmd) {
|
|
|
62
77
|
search: options.search
|
|
63
78
|
});
|
|
64
79
|
throwIfApiFailed(res);
|
|
65
|
-
const data = unwrapControllerData(res);
|
|
66
80
|
if (options.json) {
|
|
67
|
-
printJson(data);
|
|
81
|
+
printJson(res.data ?? res);
|
|
68
82
|
return;
|
|
69
83
|
}
|
|
70
|
-
const items =
|
|
71
|
-
|
|
72
|
-
|
|
84
|
+
const { items, meta } = extractPaginatedList(res);
|
|
85
|
+
printIdentityListHeader({
|
|
86
|
+
emoji: '👥',
|
|
87
|
+
title: 'Groups',
|
|
88
|
+
context: controllerUrl,
|
|
89
|
+
shown: items.length,
|
|
90
|
+
total: meta?.totalItems ?? items.length
|
|
91
|
+
});
|
|
92
|
+
if (items.length === 0) {
|
|
93
|
+
printIdentityEmpty('No groups found.', ['Try --search']);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
printIdentityTable(GROUP_LIST_COLUMNS, items);
|
|
97
|
+
printListPaginationFooter(meta);
|
|
73
98
|
} catch (e) {
|
|
74
99
|
logger.error(formatBlockingError(e.message));
|
|
75
100
|
process.exit(1);
|
|
@@ -79,22 +104,28 @@ function registerGroupList(groupCmd) {
|
|
|
79
104
|
|
|
80
105
|
function registerGroupGet(groupCmd) {
|
|
81
106
|
groupCmd
|
|
82
|
-
.command('get <
|
|
107
|
+
.command('get <groupIdOrName>')
|
|
83
108
|
.description('Get group by id or name')
|
|
84
109
|
.option('--json', 'JSON output')
|
|
85
|
-
.action(async(
|
|
110
|
+
.action(async(groupIdOrName, options) => {
|
|
86
111
|
try {
|
|
87
112
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
88
|
-
const
|
|
89
|
-
|
|
113
|
+
const value = requireNonEmpty(groupIdOrName, 'groupIdOrName');
|
|
114
|
+
const res = await getGroup(controllerUrl, authConfig, value);
|
|
115
|
+
if (!res || res.success === false) {
|
|
116
|
+
printIdentityNotFound('Group', value, groupNotFoundHints());
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
90
119
|
const row = unwrapControllerData(res);
|
|
120
|
+
if (!row?.id) {
|
|
121
|
+
printIdentityNotFound('Group', value, groupNotFoundHints());
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
91
124
|
if (options.json) {
|
|
92
125
|
printJson(row);
|
|
93
126
|
return;
|
|
94
127
|
}
|
|
95
|
-
|
|
96
|
-
logger.log(headerKeyValue('Name:', row.name));
|
|
97
|
-
logger.log('');
|
|
128
|
+
printGroupRecord(row);
|
|
98
129
|
} catch (e) {
|
|
99
130
|
logger.error(formatBlockingError(e.message));
|
|
100
131
|
process.exit(1);
|
|
@@ -104,26 +135,35 @@ function registerGroupGet(groupCmd) {
|
|
|
104
135
|
|
|
105
136
|
function registerGroupMembers(groupCmd) {
|
|
106
137
|
groupCmd
|
|
107
|
-
.command('members <
|
|
138
|
+
.command('members <groupIdOrName>')
|
|
108
139
|
.description('List members of a group')
|
|
109
140
|
.option('--json', 'JSON output')
|
|
110
|
-
.action(async(
|
|
141
|
+
.action(async(groupIdOrName, options) => {
|
|
111
142
|
try {
|
|
112
143
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
144
|
+
const value = requireNonEmpty(groupIdOrName, 'groupIdOrName');
|
|
145
|
+
const res = await listGroupMembers(controllerUrl, authConfig, value);
|
|
146
|
+
if (!res || res.success === false) {
|
|
147
|
+
printIdentityNotFound('Group', value, groupNotFoundHints());
|
|
148
|
+
process.exit(1);
|
|
149
|
+
}
|
|
119
150
|
const data = unwrapControllerData(res);
|
|
151
|
+
const items = Array.isArray(data) ? data : data?.data || [];
|
|
120
152
|
if (options.json) {
|
|
121
|
-
printJson(
|
|
153
|
+
printJson(items);
|
|
122
154
|
return;
|
|
123
155
|
}
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
156
|
+
printIdentityListHeader({
|
|
157
|
+
emoji: '👤',
|
|
158
|
+
title: `Members of ${value}`,
|
|
159
|
+
shown: items.length,
|
|
160
|
+
total: items.length
|
|
161
|
+
});
|
|
162
|
+
if (items.length === 0) {
|
|
163
|
+
printIdentityEmpty('No members in this group.');
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
printGroupMembersTable(items);
|
|
127
167
|
} catch (e) {
|
|
128
168
|
logger.error(formatBlockingError(e.message));
|
|
129
169
|
process.exit(1);
|
|
@@ -19,30 +19,43 @@ const {
|
|
|
19
19
|
const { addUserToGroup, removeUserFromGroup } = require('../api/user-groups.api');
|
|
20
20
|
const { listEnvironmentRoles, updateRoleGroups } = require('../api/environments.api');
|
|
21
21
|
const { clearAuthCache, invalidateAuthCache } = require('../api/auth-cache.api');
|
|
22
|
+
const {
|
|
23
|
+
printIdentityEmpty,
|
|
24
|
+
printIdentityListHeader,
|
|
25
|
+
printIdentityTable
|
|
26
|
+
} = require('../identity/identity-display');
|
|
22
27
|
|
|
23
28
|
function printJson(data) {
|
|
24
29
|
logger.log(JSON.stringify(data, null, 2));
|
|
25
30
|
}
|
|
26
31
|
|
|
32
|
+
const ROLE_LIST_COLUMNS = [
|
|
33
|
+
{ label: 'Role', width: 36, value: (r) => r.value || r.role || r.name || '—' },
|
|
34
|
+
{
|
|
35
|
+
label: 'Groups',
|
|
36
|
+
width: 44,
|
|
37
|
+
value: (r) => {
|
|
38
|
+
const groups = Array.isArray(r.groups) ? r.groups.filter(Boolean) : [];
|
|
39
|
+
return groups.length > 0 ? groups.join(', ') : '—';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
];
|
|
43
|
+
|
|
27
44
|
/**
|
|
28
45
|
* @param {import('commander').Command} memCmd
|
|
29
46
|
*/
|
|
30
47
|
function setupIdentityMembershipCommands(memCmd) {
|
|
31
48
|
memCmd
|
|
32
|
-
.command('add <
|
|
33
|
-
.description('Add user to group (
|
|
34
|
-
.action(async(
|
|
49
|
+
.command('add <userIdOrEmail> <groupIdOrName>')
|
|
50
|
+
.description('Add user to group (id, email, username + group id or name)')
|
|
51
|
+
.action(async(userIdOrEmail, groupIdOrName) => {
|
|
35
52
|
try {
|
|
36
53
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
requireNonEmpty(userId, 'userId'),
|
|
41
|
-
requireNonEmpty(groupId, 'groupId'),
|
|
42
|
-
{}
|
|
43
|
-
);
|
|
54
|
+
const userRef = requireNonEmpty(userIdOrEmail, 'userIdOrEmail');
|
|
55
|
+
const groupRef = requireNonEmpty(groupIdOrName, 'groupIdOrName');
|
|
56
|
+
const res = await addUserToGroup(controllerUrl, authConfig, userRef, groupRef, {});
|
|
44
57
|
throwIfApiFailed(res);
|
|
45
|
-
logger.log(formatSuccessLine(`Membership created: ${
|
|
58
|
+
logger.log(formatSuccessLine(`Membership created: ${userRef} → ${groupRef}`));
|
|
46
59
|
} catch (e) {
|
|
47
60
|
logger.error(formatBlockingError(e.message));
|
|
48
61
|
process.exit(1);
|
|
@@ -50,19 +63,16 @@ function setupIdentityMembershipCommands(memCmd) {
|
|
|
50
63
|
});
|
|
51
64
|
|
|
52
65
|
memCmd
|
|
53
|
-
.command('remove <
|
|
66
|
+
.command('remove <userIdOrEmail> <groupIdOrName>')
|
|
54
67
|
.description('Remove user from group')
|
|
55
|
-
.action(async(
|
|
68
|
+
.action(async(userIdOrEmail, groupIdOrName) => {
|
|
56
69
|
try {
|
|
57
70
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
requireNonEmpty(userId, 'userId'),
|
|
62
|
-
requireNonEmpty(groupId, 'groupId')
|
|
63
|
-
);
|
|
71
|
+
const userRef = requireNonEmpty(userIdOrEmail, 'userIdOrEmail');
|
|
72
|
+
const groupRef = requireNonEmpty(groupIdOrName, 'groupIdOrName');
|
|
73
|
+
const res = await removeUserFromGroup(controllerUrl, authConfig, userRef, groupRef);
|
|
64
74
|
throwIfApiFailed(res);
|
|
65
|
-
logger.log(formatSuccessLine(`Membership removed: ${
|
|
75
|
+
logger.log(formatSuccessLine(`Membership removed: ${userRef} → ${groupRef}`));
|
|
66
76
|
} catch (e) {
|
|
67
77
|
logger.error(formatBlockingError(e.message));
|
|
68
78
|
process.exit(1);
|
|
@@ -73,29 +83,40 @@ function setupIdentityMembershipCommands(memCmd) {
|
|
|
73
83
|
/**
|
|
74
84
|
* @param {import('commander').Command} roleCmd
|
|
75
85
|
*/
|
|
86
|
+
async function handleRoleListAction(options) {
|
|
87
|
+
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
88
|
+
const envKey = await resolveEnvKey(options);
|
|
89
|
+
const res = await listEnvironmentRoles(controllerUrl, envKey, authConfig);
|
|
90
|
+
throwIfApiFailed(res);
|
|
91
|
+
const data = unwrapControllerData(res);
|
|
92
|
+
if (options.json) {
|
|
93
|
+
printJson(data);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const items = Array.isArray(data) ? data : data?.data || data?.roles || [];
|
|
97
|
+
printIdentityListHeader({
|
|
98
|
+
emoji: '🔐',
|
|
99
|
+
title: 'Role → group mappings',
|
|
100
|
+
context: `environment: ${envKey}`,
|
|
101
|
+
shown: (items || []).length,
|
|
102
|
+
total: (items || []).length
|
|
103
|
+
});
|
|
104
|
+
if (!items || items.length === 0) {
|
|
105
|
+
printIdentityEmpty('No roles found for this environment.');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
printIdentityTable(ROLE_LIST_COLUMNS, items);
|
|
109
|
+
}
|
|
110
|
+
|
|
76
111
|
function setupIdentityRoleCommands(roleCmd) {
|
|
77
112
|
roleCmd
|
|
78
113
|
.command('list')
|
|
79
114
|
.description('List roles and group mappings for an environment')
|
|
80
|
-
.
|
|
115
|
+
.option('-e, --env <key>', 'Environment key (defaults from aifabrix config)')
|
|
81
116
|
.option('--json', 'JSON output')
|
|
82
117
|
.action(async(options) => {
|
|
83
118
|
try {
|
|
84
|
-
|
|
85
|
-
const envKey = await resolveEnvKey(options);
|
|
86
|
-
const res = await listEnvironmentRoles(controllerUrl, envKey, authConfig);
|
|
87
|
-
throwIfApiFailed(res);
|
|
88
|
-
const data = unwrapControllerData(res);
|
|
89
|
-
if (options.json) {
|
|
90
|
-
printJson(data);
|
|
91
|
-
return;
|
|
92
|
-
}
|
|
93
|
-
const items = Array.isArray(data) ? data : data?.data || data?.roles || [];
|
|
94
|
-
(items || []).forEach((r) => {
|
|
95
|
-
const groups = Array.isArray(r.groups) ? r.groups.join(', ') : '';
|
|
96
|
-
logger.log(` ${r.value || r.role || r.name} → ${groups || '—'}`);
|
|
97
|
-
});
|
|
98
|
-
logger.log('');
|
|
119
|
+
await handleRoleListAction(options);
|
|
99
120
|
} catch (e) {
|
|
100
121
|
logger.error(formatBlockingError(e.message));
|
|
101
122
|
process.exit(1);
|
|
@@ -105,7 +126,7 @@ function setupIdentityRoleCommands(roleCmd) {
|
|
|
105
126
|
roleCmd
|
|
106
127
|
.command('set-groups <roleValue>')
|
|
107
128
|
.description('Map role to groups in an environment')
|
|
108
|
-
.
|
|
129
|
+
.option('-e, --env <key>', 'Environment key (defaults from aifabrix config)')
|
|
109
130
|
.requiredOption('--groups <names>', 'Comma-separated group names')
|
|
110
131
|
.action(async(roleValue, options) => {
|
|
111
132
|
try {
|
|
@@ -6,6 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const logger = require('../utils/logger');
|
|
11
|
+
const { formatBlockingError } = require('../utils/cli-layout-chalk');
|
|
9
12
|
const { resolveControllerUrl } = require('../utils/controller-url');
|
|
10
13
|
const { normalizeControllerUrl, resolveEnvironment } = require('../core/config');
|
|
11
14
|
const { getOrRefreshDeviceToken } = require('../utils/token-manager');
|
|
@@ -82,6 +85,23 @@ function parseGroupsList(groupsArg) {
|
|
|
82
85
|
return parts;
|
|
83
86
|
}
|
|
84
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Print a blocking CLI error with optional multi-line guidance in gray.
|
|
90
|
+
*
|
|
91
|
+
* @param {string} message
|
|
92
|
+
* @returns {void}
|
|
93
|
+
*/
|
|
94
|
+
function logIdentityCliError(message) {
|
|
95
|
+
const lines = String(message || '').split('\n');
|
|
96
|
+
const head = lines[0] || 'Request failed';
|
|
97
|
+
logger.error(formatBlockingError(head));
|
|
98
|
+
lines.slice(1).forEach((line) => {
|
|
99
|
+
if (line.trim()) {
|
|
100
|
+
logger.log(chalk.gray(line));
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
85
105
|
module.exports = {
|
|
86
106
|
resolveControllerAndAuth,
|
|
87
107
|
resolveEnvKey,
|
|
@@ -90,5 +110,6 @@ module.exports = {
|
|
|
90
110
|
unwrapControllerData,
|
|
91
111
|
throwIfApiFailed,
|
|
92
112
|
assertSyncStatsOk,
|
|
93
|
-
apiErrorMessage
|
|
113
|
+
apiErrorMessage,
|
|
114
|
+
logIdentityCliError
|
|
94
115
|
};
|
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
-
const chalk = require('chalk');
|
|
10
9
|
const logger = require('../utils/logger');
|
|
11
|
-
const { formatBlockingError, formatSuccessLine
|
|
10
|
+
const { formatBlockingError, formatSuccessLine } = require('../utils/cli-layout-chalk');
|
|
12
11
|
const {
|
|
13
12
|
resolveControllerAndAuth,
|
|
14
13
|
requireNonEmpty,
|
|
@@ -21,11 +20,27 @@ const {
|
|
|
21
20
|
createUser,
|
|
22
21
|
listUserGroups
|
|
23
22
|
} = require('../api/users.api');
|
|
23
|
+
const {
|
|
24
|
+
extractPaginatedList,
|
|
25
|
+
printIdentityEmpty,
|
|
26
|
+
printIdentityListHeader,
|
|
27
|
+
printIdentityNotFound,
|
|
28
|
+
printIdentityTable,
|
|
29
|
+
printListPaginationFooter,
|
|
30
|
+
printUserGroupsTable,
|
|
31
|
+
printUserRecord,
|
|
32
|
+
USER_LIST_COLUMNS
|
|
33
|
+
} = require('../identity/identity-display');
|
|
34
|
+
const { resolveIdentityUsername } = require('../identity/username-default');
|
|
24
35
|
|
|
25
36
|
function printJson(data) {
|
|
26
37
|
logger.log(JSON.stringify(data, null, 2));
|
|
27
38
|
}
|
|
28
39
|
|
|
40
|
+
function userNotFoundHints() {
|
|
41
|
+
return ['af identity user list --search <text>', 'Check email, username, or id spelling'];
|
|
42
|
+
}
|
|
43
|
+
|
|
29
44
|
function registerUserCreate(userCmd) {
|
|
30
45
|
userCmd
|
|
31
46
|
.command('create')
|
|
@@ -38,12 +53,13 @@ function registerUserCreate(userCmd) {
|
|
|
38
53
|
.action(async(options) => {
|
|
39
54
|
try {
|
|
40
55
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
56
|
+
const email = requireNonEmpty(options.email, 'email');
|
|
41
57
|
const res = await createUser(controllerUrl, authConfig, {
|
|
42
|
-
email
|
|
58
|
+
email,
|
|
43
59
|
firstName: options.firstName,
|
|
44
60
|
lastName: options.lastName,
|
|
45
61
|
displayName: options.displayName,
|
|
46
|
-
username: options.username,
|
|
62
|
+
username: resolveIdentityUsername({ username: options.username, email }),
|
|
47
63
|
status: 'active'
|
|
48
64
|
});
|
|
49
65
|
throwIfApiFailed(res);
|
|
@@ -62,26 +78,41 @@ function registerUserList(userCmd) {
|
|
|
62
78
|
.description('List users')
|
|
63
79
|
.option('--page <n>', 'Page', (v) => parseInt(v, 10))
|
|
64
80
|
.option('--page-size <n>', 'Page size', (v) => parseInt(v, 10))
|
|
65
|
-
.option('--search <text>', 'Search users')
|
|
81
|
+
.option('--search <text>', 'Search users (email, username, name)')
|
|
82
|
+
.option('--email <email>', 'Exact email filter')
|
|
66
83
|
.option('--json', 'JSON output')
|
|
67
84
|
.action(async(options) => {
|
|
68
85
|
try {
|
|
69
86
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
70
|
-
const
|
|
87
|
+
const params = {
|
|
71
88
|
page: options.page,
|
|
72
89
|
pageSize: options.pageSize,
|
|
73
90
|
search: options.search
|
|
74
|
-
}
|
|
91
|
+
};
|
|
92
|
+
if (options.email) {
|
|
93
|
+
params.filter = `email:eq:${options.email}`;
|
|
94
|
+
delete params.search;
|
|
95
|
+
}
|
|
96
|
+
const res = await listUsers(controllerUrl, authConfig, params);
|
|
75
97
|
throwIfApiFailed(res);
|
|
76
|
-
const data = unwrapControllerData(res);
|
|
77
98
|
if (options.json) {
|
|
78
|
-
printJson(data);
|
|
99
|
+
printJson(res.data ?? res);
|
|
79
100
|
return;
|
|
80
101
|
}
|
|
81
|
-
const items =
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
102
|
+
const { items, meta } = extractPaginatedList(res);
|
|
103
|
+
printIdentityListHeader({
|
|
104
|
+
emoji: '👤',
|
|
105
|
+
title: 'Users',
|
|
106
|
+
context: controllerUrl,
|
|
107
|
+
shown: items.length,
|
|
108
|
+
total: meta?.totalItems ?? items.length
|
|
109
|
+
});
|
|
110
|
+
if (items.length === 0) {
|
|
111
|
+
printIdentityEmpty('No users found.', ['Try --search or --email']);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
printIdentityTable(USER_LIST_COLUMNS, items);
|
|
115
|
+
printListPaginationFooter(meta);
|
|
85
116
|
} catch (e) {
|
|
86
117
|
logger.error(formatBlockingError(e.message));
|
|
87
118
|
process.exit(1);
|
|
@@ -91,22 +122,28 @@ function registerUserList(userCmd) {
|
|
|
91
122
|
|
|
92
123
|
function registerUserGet(userCmd) {
|
|
93
124
|
userCmd
|
|
94
|
-
.command('get <
|
|
95
|
-
.description('Get user by id or
|
|
125
|
+
.command('get <userIdOrEmail>')
|
|
126
|
+
.description('Get user by id, email, or username')
|
|
96
127
|
.option('--json', 'JSON output')
|
|
97
|
-
.action(async(
|
|
128
|
+
.action(async(userIdOrEmail, options) => {
|
|
98
129
|
try {
|
|
99
130
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
100
|
-
const
|
|
101
|
-
|
|
131
|
+
const value = requireNonEmpty(userIdOrEmail, 'userIdOrEmail');
|
|
132
|
+
const res = await getUser(controllerUrl, authConfig, value);
|
|
133
|
+
if (!res || res.success === false) {
|
|
134
|
+
printIdentityNotFound('User', value, userNotFoundHints());
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
102
137
|
const row = unwrapControllerData(res);
|
|
138
|
+
if (!row?.id) {
|
|
139
|
+
printIdentityNotFound('User', value, userNotFoundHints());
|
|
140
|
+
process.exit(1);
|
|
141
|
+
}
|
|
103
142
|
if (options.json) {
|
|
104
143
|
printJson(row);
|
|
105
144
|
return;
|
|
106
145
|
}
|
|
107
|
-
|
|
108
|
-
logger.log(headerKeyValue('Email:', row.email));
|
|
109
|
-
logger.log('');
|
|
146
|
+
printUserRecord(row);
|
|
110
147
|
} catch (e) {
|
|
111
148
|
logger.error(formatBlockingError(e.message));
|
|
112
149
|
process.exit(1);
|
|
@@ -116,26 +153,35 @@ function registerUserGet(userCmd) {
|
|
|
116
153
|
|
|
117
154
|
function registerUserGroups(userCmd) {
|
|
118
155
|
userCmd
|
|
119
|
-
.command('groups <
|
|
120
|
-
.description('List groups for a user')
|
|
156
|
+
.command('groups <userIdOrEmail>')
|
|
157
|
+
.description('List groups for a user (by id, email, or username)')
|
|
121
158
|
.option('--json', 'JSON output')
|
|
122
|
-
.action(async(
|
|
159
|
+
.action(async(userIdOrEmail, options) => {
|
|
123
160
|
try {
|
|
124
161
|
const { controllerUrl, authConfig } = await resolveControllerAndAuth();
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
162
|
+
const value = requireNonEmpty(userIdOrEmail, 'userIdOrEmail');
|
|
163
|
+
const res = await listUserGroups(controllerUrl, authConfig, value);
|
|
164
|
+
if (!res || res.success === false) {
|
|
165
|
+
printIdentityNotFound('User', value, userNotFoundHints());
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
131
168
|
const data = unwrapControllerData(res);
|
|
169
|
+
const items = Array.isArray(data) ? data : data?.data || [];
|
|
132
170
|
if (options.json) {
|
|
133
|
-
printJson(
|
|
171
|
+
printJson(items);
|
|
134
172
|
return;
|
|
135
173
|
}
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
174
|
+
printIdentityListHeader({
|
|
175
|
+
emoji: '👥',
|
|
176
|
+
title: `Groups for ${value}`,
|
|
177
|
+
shown: items.length,
|
|
178
|
+
total: items.length
|
|
179
|
+
});
|
|
180
|
+
if (items.length === 0) {
|
|
181
|
+
printIdentityEmpty('No group memberships found.');
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
printUserGroupsTable(items);
|
|
139
185
|
} catch (e) {
|
|
140
186
|
logger.error(formatBlockingError(e.message));
|
|
141
187
|
process.exit(1);
|
|
@@ -10,7 +10,11 @@
|
|
|
10
10
|
|
|
11
11
|
'use strict';
|
|
12
12
|
|
|
13
|
-
const {
|
|
13
|
+
const {
|
|
14
|
+
buildAuthenticationFromMethod,
|
|
15
|
+
getAuthCredentialTemplate,
|
|
16
|
+
migrateAuthenticationToNestedSchema
|
|
17
|
+
} = require('../utils/authentication-shape');
|
|
14
18
|
|
|
15
19
|
/** Repair CLI --auth values (normalized lowercase). */
|
|
16
20
|
const ALLOWED_REPAIR_AUTH = [
|
|
@@ -95,9 +99,10 @@ const MISSING_TEST_ENDPOINT_WARNING =
|
|
|
95
99
|
* @param {string[]} warnings - Mutable warnings list
|
|
96
100
|
*/
|
|
97
101
|
function appendTestEndpointWarningIfMissing(authentication, warnings) {
|
|
98
|
-
const
|
|
102
|
+
const credential = getAuthCredentialTemplate(authentication);
|
|
103
|
+
const method = String(credential?.method || authentication?.method || '').toLowerCase();
|
|
99
104
|
if (method !== 'apikey' && method !== 'bearertoken') return;
|
|
100
|
-
const testEndpoint = String(authentication?.variables?.testEndpoint || '').trim();
|
|
105
|
+
const testEndpoint = String(credential?.variables?.testEndpoint || authentication?.variables?.testEndpoint || '').trim();
|
|
101
106
|
if (testEndpoint) return;
|
|
102
107
|
if (warnings.includes(MISSING_TEST_ENDPOINT_WARNING)) return;
|
|
103
108
|
warnings.push(MISSING_TEST_ENDPOINT_WARNING);
|
|
@@ -114,6 +119,25 @@ function auditRepairAuthenticationWarnings(systemParsed, warnings) {
|
|
|
114
119
|
appendTestEndpointWarningIfMissing(authentication, warnings);
|
|
115
120
|
}
|
|
116
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Ensures system file authentication matches nested schema (authType + credential).
|
|
124
|
+
* @param {Object} systemParsed - Parsed system config (mutated)
|
|
125
|
+
* @param {string} systemKey
|
|
126
|
+
* @param {string[]} changes
|
|
127
|
+
* @returns {boolean}
|
|
128
|
+
*/
|
|
129
|
+
function normalizeAuthenticationSchemaShape(systemParsed, systemKey, changes) {
|
|
130
|
+
const current = systemParsed.authentication || systemParsed.auth;
|
|
131
|
+
const { authentication, changed } = migrateAuthenticationToNestedSchema(current, systemKey);
|
|
132
|
+
if (!changed) {
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
systemParsed.authentication = authentication;
|
|
136
|
+
delete systemParsed.auth;
|
|
137
|
+
changes.push('Normalized authentication to authType + credential (schema 2.4.x)');
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
|
|
117
141
|
module.exports = {
|
|
118
142
|
ALLOWED_REPAIR_AUTH,
|
|
119
143
|
MISSING_TEST_ENDPOINT_WARNING,
|
|
@@ -123,5 +147,7 @@ module.exports = {
|
|
|
123
147
|
mergePreservedAuthVariables,
|
|
124
148
|
repairAuthChangeLabel,
|
|
125
149
|
appendTestEndpointWarningIfMissing,
|
|
126
|
-
auditRepairAuthenticationWarnings
|
|
150
|
+
auditRepairAuthenticationWarnings,
|
|
151
|
+
normalizeAuthenticationSchemaShape,
|
|
152
|
+
getAuthCredentialTemplate
|
|
127
153
|
};
|
|
@@ -8,17 +8,7 @@
|
|
|
8
8
|
'use strict';
|
|
9
9
|
|
|
10
10
|
const { systemKeyToKvPrefix, securityKeyToVar, kvEnvKeyToPath } = require('../utils/credential-secrets-env');
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Returns true if a kv value looks like legacy format (KeyVault suffix or no path segments).
|
|
14
|
-
* @param {string} val - Value from authentication.security or configuration
|
|
15
|
-
* @returns {boolean}
|
|
16
|
-
*/
|
|
17
|
-
function isLegacyKvValue(val) {
|
|
18
|
-
if (typeof val !== 'string' || !val.trim().toLowerCase().startsWith('kv://')) return false;
|
|
19
|
-
const after = val.trim().slice(5); // after 'kv://'
|
|
20
|
-
return after.includes('KeyVault') || !after.includes('/');
|
|
21
|
-
}
|
|
11
|
+
const { isLegacyKvValue } = require('../utils/platform-kv-ref');
|
|
22
12
|
|
|
23
13
|
/**
|
|
24
14
|
* Normalizes authentication.security keyvault entries to path-style kv:// values (kv://systemKey/variable).
|
|
@@ -87,7 +77,9 @@ function normalizeConfigurationSection(config, prefix, systemKey, changes) {
|
|
|
87
77
|
function normalizeSystemFileAuthAndConfig(systemParsed, systemKey, changes) {
|
|
88
78
|
const prefix = systemKeyToKvPrefix(systemKey);
|
|
89
79
|
if (!prefix) return false;
|
|
90
|
-
const
|
|
80
|
+
const { getAuthCredentialTemplate } = require('../utils/authentication-shape');
|
|
81
|
+
const credential = getAuthCredentialTemplate(systemParsed.authentication);
|
|
82
|
+
const security = credential?.security ?? systemParsed.authentication?.security;
|
|
91
83
|
let updated = (security && typeof security === 'object' && normalizeSecuritySection(security, prefix, systemKey, changes));
|
|
92
84
|
const config = systemParsed.configuration;
|
|
93
85
|
if (Array.isArray(config)) {
|
|
@@ -96,4 +88,7 @@ function normalizeSystemFileAuthAndConfig(systemParsed, systemKey, changes) {
|
|
|
96
88
|
return updated;
|
|
97
89
|
}
|
|
98
90
|
|
|
99
|
-
module.exports = {
|
|
91
|
+
module.exports = {
|
|
92
|
+
normalizeSystemFileAuthAndConfig,
|
|
93
|
+
isLegacyKvValue
|
|
94
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* COM v2 datasource manifest repair (capabilities objects, strip context).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview repair-datasource-com-v2
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { repairComV2Manifest } = require('../datasource/capability/capability-manifest');
|
|
12
|
+
|
|
13
|
+
module.exports = {
|
|
14
|
+
repairComV2Manifest
|
|
15
|
+
};
|