@aifabrix/builder 2.50.0 → 2.51.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/.cursor/plans/157.1-security-quality-violations-by-type.csv +374 -0
- package/.cursor/rules/assistant-driven-integration-build.mdc +40 -0
- package/integration/hubspot-test/create-hubspot.js +1 -16
- package/lib/api/evidence-kinds.api.js +128 -0
- package/lib/api/pipeline.api.js +5 -1
- package/lib/api/resource-types.api.js +4 -4
- package/lib/api/roles.api.js +121 -0
- package/lib/api/types/evidence-kinds.types.js +42 -0
- package/lib/api/types/roles.types.js +36 -0
- package/lib/app/certification-verify-rows.js +1 -1
- package/lib/app/show.js +2 -2
- package/lib/certification/merge-certification-from-artifact.js +1 -1
- package/lib/channels/channel-artifact-generator.js +2 -1
- package/lib/cli/index.js +4 -0
- package/lib/cli/setup-app.js +22 -5
- package/lib/cli/setup-dev.js +23 -7
- package/lib/cli/setup-utility-help-after.js +12 -0
- package/lib/cli/setup-utility-validate.js +41 -2
- package/lib/commands/deploy-gate-failure-details.js +21 -0
- package/lib/commands/deploy-gate-orchestrator.js +64 -18
- package/lib/commands/dev-cli-handlers.js +6 -3
- package/lib/commands/dev-init.js +7 -109
- package/lib/commands/dev-refresh.js +197 -0
- package/lib/commands/evidence-kind.js +428 -0
- package/lib/commands/governance-command-action.js +4 -2
- package/lib/commands/repair-openapi-export.js +1 -1
- package/lib/commands/repair-openapi-sync.js +14 -6
- package/lib/commands/resource-type.js +101 -18
- package/lib/commands/role.js +452 -0
- package/lib/commands/setup.js +1 -1
- package/lib/commands/validate-json.js +230 -0
- package/lib/commands/verify-operations-step-plan.js +78 -40
- package/lib/core/audit-logger.js +1 -1
- package/lib/core/secrets-load.js +1 -3
- package/lib/datasource/capability/relate-operations.js +1 -1
- package/lib/generator/helpers.js +13 -5
- package/lib/generator/split-variables.js +9 -3
- package/lib/infrastructure/helpers-docker-check.js +6 -0
- package/lib/infrastructure/helpers.js +1 -1
- package/lib/programmatic/auth-config.js +3 -2
- package/lib/programmatic/bearer-auth.js +1 -1
- package/lib/programmatic/enterprise-mcp-client.js +18 -2
- package/lib/programmatic/manifest-section-registry.js +18 -1
- package/lib/programmatic/openapi-result-schemas.js +28 -11
- package/lib/programmatic/openapi-schema-descriptions-core.js +5 -2
- package/lib/programmatic/openapi-schema-helpers.js +16 -1
- package/lib/programmatic/openapi-spec.js +1 -1
- package/lib/programmatic/run-repository-emcp.js +11 -3
- package/lib/programmatic/run-template-workspace.js +14 -1
- package/lib/resolvers/evidence-kind-file.js +230 -0
- package/lib/resolvers/resource-type-file.js +36 -1
- package/lib/resolvers/role-file.js +227 -0
- package/lib/schema/application-schema.json +22 -2
- package/lib/schema/external-datasource.schema.json +85 -2
- package/lib/schema/external-system.schema.json +16 -2
- package/lib/schema/infra.parameter.yaml +25 -1
- package/lib/schema/type/credential-field-registry.json +19 -3
- package/lib/utils/api.js +8 -2
- package/lib/utils/app-register-config.js +4 -3
- package/lib/utils/cli-sync-options.js +59 -3
- package/lib/utils/cli-utils.js +11 -3
- package/lib/utils/dev-ca-install.js +5 -6
- package/lib/utils/dev-config.js +2 -2
- package/lib/utils/dev-list-sort.js +145 -0
- package/lib/utils/dev-platform-tls.js +0 -63
- package/lib/utils/docker-build.js +46 -27
- package/lib/utils/docker-daemon-tls-ca.js +1 -1
- package/lib/utils/docker-exec.js +91 -6
- package/lib/utils/env-copy.js +1 -3
- package/lib/utils/error-formatters/error-parser.js +0 -3
- package/lib/utils/external-env-template.js +1 -1
- package/lib/utils/external-system-readiness-compact-blocks.js +28 -1
- package/lib/utils/health-check-request.js +2 -3
- package/lib/utils/help-builder.js +3 -0
- package/lib/utils/image-name.js +22 -4
- package/lib/utils/logger.js +37 -4
- package/lib/utils/manifest-source-emit.js +1 -1
- package/lib/utils/paths.js +32 -4
- package/lib/utils/pipeline-upload-auth-retry.js +4 -0
- package/lib/utils/postgres-platform-bootstrap.js +24 -17
- package/lib/utils/postgres-wipe.js +5 -2
- package/lib/utils/remote-dev-auth.js +39 -4
- package/lib/utils/resolve-docker-image-ref.js +36 -6
- package/lib/utils/token-manager.js +16 -0
- package/lib/utils/upload-sync-options.js +17 -3
- package/lib/validation/openapi-contract-surface-validator.js +4 -0
- package/lib/validation/validator.js +6 -5
- package/package.json +34 -12
- package/scripts/export-builder-api-evidence.js +2 -2
- package/scripts/lib/plan-actor.js +2 -2
- package/scripts/lib/plan-meta.js +1 -1
- package/scripts/lib/plan-parse.js +1 -1
- package/scripts/lib/plan-prevalidate-gates.js +12 -1
- package/scripts/lib/plan-run-report.js +13 -2
- package/scripts/pnpm/lib/resolve-aifabrix-bin.mjs +10 -10
- package/templates/applications/dataplane/application.yaml +26 -4
- package/templates/applications/dataplane/env.template +28 -9
- package/templates/applications/dataplane/rbac.yaml +64 -2
- package/templates/applications/miso-controller/application.yaml +10 -1
- package/templates/applications/miso-controller/env.template +10 -7
- package/templates/applications/miso-controller/rbac.yaml +72 -0
- package/templates/channels/slack/integration/slack-system.json +60 -2
- package/templates/python/requirements.txt +1 -1
package/lib/api/pipeline.api.js
CHANGED
|
@@ -247,11 +247,15 @@ async function testDatasourceViaPipeline({ dataplaneUrl, systemKey, datasourceKe
|
|
|
247
247
|
* @returns {Promise<Object>} API envelope `{ success, data }` where `data` is PublicationResult (uploadId, system, datasources, generateMcpContract, …)
|
|
248
248
|
* @throws {Error} If upload fails
|
|
249
249
|
*/
|
|
250
|
+
/** Multi-datasource publish often exceeds the default 30s HTTP timeout. */
|
|
251
|
+
const PIPELINE_UPLOAD_TIMEOUT_MS = 300000;
|
|
252
|
+
|
|
250
253
|
async function uploadApplicationViaPipeline(dataplaneUrl, authConfig, payload) {
|
|
251
254
|
const body = { ...payload, status: payload.status ?? 'draft' };
|
|
252
255
|
const client = createDataplaneApiClient(dataplaneUrl, authConfig);
|
|
253
256
|
return await client.post('/api/v1/pipeline/upload', {
|
|
254
|
-
body
|
|
257
|
+
body,
|
|
258
|
+
timeoutMs: PIPELINE_UPLOAD_TIMEOUT_MS
|
|
255
259
|
});
|
|
256
260
|
}
|
|
257
261
|
|
|
@@ -12,7 +12,7 @@ const BASE = '/api/v1/resource-types';
|
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* List resource types (paginated)
|
|
15
|
-
* @requiresPermission {Controller}
|
|
15
|
+
* @requiresPermission {Controller} resource-types:read
|
|
16
16
|
* @async
|
|
17
17
|
* @function listResourceTypes
|
|
18
18
|
* @param {string} controllerUrl
|
|
@@ -34,7 +34,7 @@ async function listResourceTypes(controllerUrl, authConfig, options = {}) {
|
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Get a resource type by id or key
|
|
37
|
-
* @requiresPermission {Controller}
|
|
37
|
+
* @requiresPermission {Controller} resource-types:read
|
|
38
38
|
* @async
|
|
39
39
|
* @function getResourceType
|
|
40
40
|
* @param {string} controllerUrl
|
|
@@ -49,7 +49,7 @@ async function getResourceType(controllerUrl, authConfig, resourceTypeIdOrKey) {
|
|
|
49
49
|
|
|
50
50
|
/**
|
|
51
51
|
* Create a resource type
|
|
52
|
-
* @requiresPermission {Controller}
|
|
52
|
+
* @requiresPermission {Controller} resource-types:create
|
|
53
53
|
* @async
|
|
54
54
|
* @function createResourceType
|
|
55
55
|
* @param {string} controllerUrl
|
|
@@ -75,7 +75,7 @@ async function createResourceType(controllerUrl, authConfig, body) {
|
|
|
75
75
|
|
|
76
76
|
/**
|
|
77
77
|
* Create-if-missing (idempotent): if a resource type already exists for the key, return success.
|
|
78
|
-
* @requiresPermission {Controller}
|
|
78
|
+
* @requiresPermission {Controller} resource-types:read + resource-types:create
|
|
79
79
|
* @async
|
|
80
80
|
* @function createResourceTypeIdempotent
|
|
81
81
|
* @param {string} controllerUrl
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Business roles API (Controller /api/v1/roles)
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const { ApiClient } = require('./index');
|
|
10
|
+
|
|
11
|
+
const BASE = '/api/v1/roles';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* List business roles (paginated)
|
|
15
|
+
* @requiresPermission {Controller} roles:read
|
|
16
|
+
* @async
|
|
17
|
+
* @param {string} controllerUrl
|
|
18
|
+
* @param {Object} authConfig
|
|
19
|
+
* @param {Object} [options]
|
|
20
|
+
* @returns {Promise<Object>}
|
|
21
|
+
*/
|
|
22
|
+
async function listRoles(controllerUrl, authConfig, options = {}) {
|
|
23
|
+
const client = new ApiClient(controllerUrl, authConfig);
|
|
24
|
+
return await client.get(BASE, { params: options });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Get a business role by id or key
|
|
29
|
+
* @requiresPermission {Controller} roles:read
|
|
30
|
+
* @async
|
|
31
|
+
* @param {string} controllerUrl
|
|
32
|
+
* @param {Object} authConfig
|
|
33
|
+
* @param {string} roleIdOrKey
|
|
34
|
+
* @returns {Promise<Object>}
|
|
35
|
+
*/
|
|
36
|
+
async function getRole(controllerUrl, authConfig, roleIdOrKey) {
|
|
37
|
+
const client = new ApiClient(controllerUrl, authConfig);
|
|
38
|
+
return await client.get(`${BASE}/${encodeURIComponent(roleIdOrKey)}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {Object} payload
|
|
43
|
+
* @param {string} key
|
|
44
|
+
* @param {*} value
|
|
45
|
+
* @returns {void}
|
|
46
|
+
*/
|
|
47
|
+
function assignOptionalString(payload, key, value) {
|
|
48
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
49
|
+
payload[key] = value;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* @param {import('./types/roles.types').CreateBusinessRoleRequest} body
|
|
55
|
+
* @returns {Object}
|
|
56
|
+
*/
|
|
57
|
+
function buildCreateRoleBody(body) {
|
|
58
|
+
const payload = {
|
|
59
|
+
key: body.key,
|
|
60
|
+
domainKey: body.domainKey,
|
|
61
|
+
displayName: body.displayName
|
|
62
|
+
};
|
|
63
|
+
assignOptionalString(payload, 'description', body.description);
|
|
64
|
+
assignOptionalString(payload, 'purpose', body.purpose);
|
|
65
|
+
assignOptionalString(payload, 'businessOutcome', body.businessOutcome);
|
|
66
|
+
assignOptionalString(payload, 'source', body.source);
|
|
67
|
+
if (body.isActive !== undefined && body.isActive !== null) {
|
|
68
|
+
payload.isActive = Boolean(body.isActive);
|
|
69
|
+
}
|
|
70
|
+
if (body.metadata && typeof body.metadata === 'object') {
|
|
71
|
+
payload.metadata = body.metadata;
|
|
72
|
+
}
|
|
73
|
+
return payload;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Create a business role
|
|
78
|
+
* @requiresPermission {Controller} roles:create
|
|
79
|
+
* @async
|
|
80
|
+
* @param {string} controllerUrl
|
|
81
|
+
* @param {Object} authConfig
|
|
82
|
+
* @param {import('./types/roles.types').CreateBusinessRoleRequest} body
|
|
83
|
+
* @returns {Promise<Object>}
|
|
84
|
+
*/
|
|
85
|
+
async function createRole(controllerUrl, authConfig, body) {
|
|
86
|
+
const client = new ApiClient(controllerUrl, authConfig);
|
|
87
|
+
return await client.post(BASE, { body: buildCreateRoleBody(body) });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Create-if-missing (idempotent): if a role already exists for the key, return success.
|
|
92
|
+
* @requiresPermission {Controller} roles:read + roles:create
|
|
93
|
+
* @async
|
|
94
|
+
* @param {string} controllerUrl
|
|
95
|
+
* @param {Object} authConfig
|
|
96
|
+
* @param {import('./types/roles.types').CreateBusinessRoleRequest} body
|
|
97
|
+
* @returns {Promise<{ created: boolean, response: Object }>}
|
|
98
|
+
*/
|
|
99
|
+
async function createRoleIdempotent(controllerUrl, authConfig, body) {
|
|
100
|
+
const key = String(body?.key || '').trim();
|
|
101
|
+
if (!key) {
|
|
102
|
+
throw new Error('Role key is required');
|
|
103
|
+
}
|
|
104
|
+
const getRes = await getRole(controllerUrl, authConfig, key);
|
|
105
|
+
if (getRes && getRes.success === true) {
|
|
106
|
+
return { created: false, response: getRes };
|
|
107
|
+
}
|
|
108
|
+
const createRes = await createRole(controllerUrl, authConfig, body);
|
|
109
|
+
if (createRes && createRes.success === true) {
|
|
110
|
+
return { created: true, response: createRes };
|
|
111
|
+
}
|
|
112
|
+
const msg = createRes?.error || createRes?.formattedError || 'Failed to create role';
|
|
113
|
+
throw new Error(msg);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
listRoles,
|
|
118
|
+
getRole,
|
|
119
|
+
createRole,
|
|
120
|
+
createRoleIdempotent
|
|
121
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Evidence kind API type definitions (Controller /api/v1/evidence-kinds)
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Create evidence kind request body (API shape uses domainKey)
|
|
9
|
+
* @typedef {Object} CreateEvidenceKindRequest
|
|
10
|
+
* @property {string} key - Catalog key (lowercase, digits, underscores)
|
|
11
|
+
* @property {string} domainKey - Enterprise domain key
|
|
12
|
+
* @property {string} displayName - Human-readable name
|
|
13
|
+
* @property {string} purpose - Purpose (required by Controller)
|
|
14
|
+
* @property {string} [description] - Optional description
|
|
15
|
+
* @property {string} [expectedUse] - Expected use guidance
|
|
16
|
+
* @property {string} [defaultSeverity] - low | medium | high | critical
|
|
17
|
+
* @property {boolean} [requiresApproval] - Approval flag
|
|
18
|
+
* @property {boolean} [isActive] - Active flag
|
|
19
|
+
* @property {number} [sortOrder] - Sort order
|
|
20
|
+
* @property {string} [source] - Provenance source
|
|
21
|
+
* @property {Object} [metadata] - Extensions
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Evidence kind record
|
|
26
|
+
* @typedef {Object} EvidenceKindRecord
|
|
27
|
+
* @property {string} id - Controller id
|
|
28
|
+
* @property {string} key - Catalog key
|
|
29
|
+
* @property {string} domainKey - Enterprise domain key
|
|
30
|
+
* @property {string} displayName - Display name
|
|
31
|
+
* @property {string} purpose - Purpose
|
|
32
|
+
* @property {string} [description] - Description
|
|
33
|
+
* @property {string} [expectedUse] - Expected use
|
|
34
|
+
* @property {string} [defaultSeverity] - Default severity
|
|
35
|
+
* @property {boolean} requiresApproval - Approval flag
|
|
36
|
+
* @property {boolean} isActive - Active flag
|
|
37
|
+
* @property {number} sortOrder - Sort order
|
|
38
|
+
* @property {string} [source] - Source
|
|
39
|
+
* @property {Object} [metadata] - Metadata
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
module.exports = {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Business role API type definitions (Controller /api/v1/roles)
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Create business role request body (API shape uses domainKey)
|
|
9
|
+
* @typedef {Object} CreateBusinessRoleRequest
|
|
10
|
+
* @property {string} key - Catalog key (lowercase, hyphens)
|
|
11
|
+
* @property {string} domainKey - Enterprise domain key
|
|
12
|
+
* @property {string} displayName - Human-readable name
|
|
13
|
+
* @property {string} [description] - Optional description
|
|
14
|
+
* @property {string} [purpose] - Role purpose
|
|
15
|
+
* @property {string} [businessOutcome] - Business outcome
|
|
16
|
+
* @property {boolean} [isActive] - Active flag
|
|
17
|
+
* @property {string} [source] - Provenance source
|
|
18
|
+
* @property {Object} [metadata] - Compiler fields and extensions
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Business role record
|
|
23
|
+
* @typedef {Object} BusinessRoleRecord
|
|
24
|
+
* @property {string} id - Controller id
|
|
25
|
+
* @property {string} key - Catalog key
|
|
26
|
+
* @property {string} domainKey - Enterprise domain key
|
|
27
|
+
* @property {string} displayName - Display name
|
|
28
|
+
* @property {string} [description] - Description
|
|
29
|
+
* @property {string} [purpose] - Purpose
|
|
30
|
+
* @property {string} [businessOutcome] - Business outcome
|
|
31
|
+
* @property {boolean} isActive - Active flag
|
|
32
|
+
* @property {string} [source] - Source
|
|
33
|
+
* @property {Object} [metadata] - Metadata
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
module.exports = {};
|
|
@@ -16,7 +16,7 @@ const { getActiveIntegrationCertificate, verifyIntegrationCertificate } = requir
|
|
|
16
16
|
function certificateIdString(id) {
|
|
17
17
|
if (id === undefined || id === null) return null;
|
|
18
18
|
if (typeof id === 'string') return id.trim() || null;
|
|
19
|
-
if (typeof id === 'object' &&
|
|
19
|
+
if (typeof id === 'object' && typeof id.id === 'string') return id.id.trim() || null;
|
|
20
20
|
return null;
|
|
21
21
|
}
|
|
22
22
|
|
package/lib/app/show.js
CHANGED
|
@@ -347,7 +347,7 @@ async function getShowAuthToken(controllerUrl, config) {
|
|
|
347
347
|
}
|
|
348
348
|
|
|
349
349
|
const formatted = formatAuthenticationError({
|
|
350
|
-
controllerUrl:
|
|
350
|
+
controllerUrl: undefined,
|
|
351
351
|
message: 'No valid authentication found'
|
|
352
352
|
});
|
|
353
353
|
logger.error(formatted);
|
|
@@ -477,7 +477,7 @@ function resolveExternalSystemMeta(res, config, system, application, appKey) {
|
|
|
477
477
|
|
|
478
478
|
function buildBaseExternalResult(configData, appKey, openapiFiles, openapiEndpoints, res) {
|
|
479
479
|
const system = configData.system || configData;
|
|
480
|
-
const dataSources = configData.dataSources ||
|
|
480
|
+
const dataSources = configData.dataSources || [];
|
|
481
481
|
const application = configData.application || configData.app || {};
|
|
482
482
|
const config = res && res.config && typeof res.config === 'object' ? res.config : {};
|
|
483
483
|
const meta = resolveExternalSystemMeta(res, config, system, application, appKey);
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
function certificateIdToString(id) {
|
|
14
14
|
if (id === undefined || id === null) return '';
|
|
15
15
|
if (typeof id === 'string') return id.trim();
|
|
16
|
-
if (typeof id === 'object' &&
|
|
16
|
+
if (typeof id === 'object' && typeof id.id === 'string') return String(id.id).trim();
|
|
17
17
|
return String(id).trim();
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -16,6 +16,7 @@ const { getChannelTarget } = require('./channel-targets');
|
|
|
16
16
|
const { BUILDER_ROOT } = require('./channel-integration-template');
|
|
17
17
|
|
|
18
18
|
const SECRET_PATTERNS = [/xoxb-/i, /xoxp-/i, /client_secret/i, /signing_secret/i, /Bearer\s+/i];
|
|
19
|
+
const PLACEHOLDER_DOMAIN_RE = /\byour-domain\.com\b/i;
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* @param {string} content
|
|
@@ -27,7 +28,7 @@ function assertNoSecretsInArtifact(content) {
|
|
|
27
28
|
throw new Error('Generated artifact must not contain secret-like values');
|
|
28
29
|
}
|
|
29
30
|
}
|
|
30
|
-
if (
|
|
31
|
+
if (PLACEHOLDER_DOMAIN_RE.test(content)) {
|
|
31
32
|
throw new Error('Generated artifact still contains placeholder domain your-domain.com');
|
|
32
33
|
}
|
|
33
34
|
}
|
package/lib/cli/index.js
CHANGED
|
@@ -23,6 +23,8 @@ const { setupAppCommands: setupAppManagementCommands } = require('../commands/ap
|
|
|
23
23
|
const { setupDatasourceCommands } = require('../commands/datasource');
|
|
24
24
|
const { setupDimensionCommands } = require('../commands/dimension');
|
|
25
25
|
const { setupResourceTypeCommands } = require('../commands/resource-type');
|
|
26
|
+
const { setupRoleCommands } = require('../commands/role');
|
|
27
|
+
const { setupEvidenceKindCommands } = require('../commands/evidence-kind');
|
|
26
28
|
const { setupEnterpriseKnowledgeCommands } = require('../commands/enterprise-knowledge');
|
|
27
29
|
const { setupIdentityCommands } = require('../commands/identity');
|
|
28
30
|
const { setupProtectionCommands } = require('../commands/protection');
|
|
@@ -73,6 +75,8 @@ function setupCoreCliCommands(program) {
|
|
|
73
75
|
function setupExtendedCliCommands(program) {
|
|
74
76
|
setupDimensionCommands(program);
|
|
75
77
|
setupResourceTypeCommands(program);
|
|
78
|
+
setupRoleCommands(program);
|
|
79
|
+
setupEvidenceKindCommands(program);
|
|
76
80
|
setupEnterpriseKnowledgeCommands(program);
|
|
77
81
|
setupIdentityCommands(program);
|
|
78
82
|
setupProtectionCommands(program);
|
package/lib/cli/setup-app.js
CHANGED
|
@@ -62,6 +62,8 @@ Notes:
|
|
|
62
62
|
- Login or set MISO_CONTROLLER_URL + environment (aifabrix login / aifabrix auth).
|
|
63
63
|
- CI: register once (aifabrix app register <appKey>), store DEV_MISO_CLIENTID and DEV_MISO_CLIENTSECRET in pipeline secrets.
|
|
64
64
|
- upload = dataplane publish for dev iteration; deploy = controller validate + deploy (Azure or local Docker).
|
|
65
|
+
- Default output is a compact status card; use -v for expanded preflight and readiness detail.
|
|
66
|
+
- Controller deploy always polls to a terminal status (no --poll / --no-poll on this command).
|
|
65
67
|
- --repository-url overrides repo URL for pipeline validate (default: application.yaml repository.repositoryUrl).
|
|
66
68
|
`;
|
|
67
69
|
|
|
@@ -219,7 +221,7 @@ Examples:
|
|
|
219
221
|
});
|
|
220
222
|
}
|
|
221
223
|
|
|
222
|
-
function
|
|
224
|
+
function registerBuildCommand(program) {
|
|
223
225
|
program.command('build <appKey>')
|
|
224
226
|
.description('Build Docker image for builder appKey (auto-detect runtime)')
|
|
225
227
|
.option('-l, --language <lang>', 'Override language detection')
|
|
@@ -243,9 +245,9 @@ function setupBuildRunLogsDownCommands(program) {
|
|
|
243
245
|
process.exit(1);
|
|
244
246
|
}
|
|
245
247
|
});
|
|
248
|
+
}
|
|
246
249
|
|
|
247
|
-
|
|
248
|
-
|
|
250
|
+
function registerLogsCommand(program) {
|
|
249
251
|
program.command('logs <appKey>')
|
|
250
252
|
.description('Tail container logs for appKey (optional env summary; secrets masked)')
|
|
251
253
|
.option('-f', 'Follow log stream')
|
|
@@ -256,14 +258,22 @@ function setupBuildRunLogsDownCommands(program) {
|
|
|
256
258
|
try {
|
|
257
259
|
const { runAppLogs } = require('../commands/app-logs');
|
|
258
260
|
const tailNum = parseInt(options.tail, 10);
|
|
259
|
-
const level = options.level !== undefined && options.level !== null && options.level !== ''
|
|
260
|
-
|
|
261
|
+
const level = options.level !== undefined && options.level !== null && options.level !== ''
|
|
262
|
+
? String(options.level).trim()
|
|
263
|
+
: undefined;
|
|
264
|
+
await runAppLogs(appName, {
|
|
265
|
+
follow: options.f,
|
|
266
|
+
tail: Number.isNaN(tailNum) ? 100 : tailNum,
|
|
267
|
+
level
|
|
268
|
+
});
|
|
261
269
|
} catch (error) {
|
|
262
270
|
handleCommandError(error, 'logs');
|
|
263
271
|
process.exit(1);
|
|
264
272
|
}
|
|
265
273
|
});
|
|
274
|
+
}
|
|
266
275
|
|
|
276
|
+
function registerDownAppCommand(program) {
|
|
267
277
|
program.command('down-app <appKey>')
|
|
268
278
|
.description('Stop and remove container for appKey (--volumes removes data volume)')
|
|
269
279
|
.option('--volumes', 'Remove application Docker volume')
|
|
@@ -278,6 +288,13 @@ function setupBuildRunLogsDownCommands(program) {
|
|
|
278
288
|
});
|
|
279
289
|
}
|
|
280
290
|
|
|
291
|
+
function setupBuildRunLogsDownCommands(program) {
|
|
292
|
+
registerBuildCommand(program);
|
|
293
|
+
registerRunCommand(program);
|
|
294
|
+
registerLogsCommand(program);
|
|
295
|
+
registerDownAppCommand(program);
|
|
296
|
+
}
|
|
297
|
+
|
|
281
298
|
function setupShellTestStopCommands(program) {
|
|
282
299
|
program.command('stop <appKey>')
|
|
283
300
|
.description('Alias for down-app: stop and remove container for appKey')
|
package/lib/cli/setup-dev.js
CHANGED
|
@@ -12,7 +12,8 @@ const config = require('../core/config');
|
|
|
12
12
|
const logger = require('../utils/logger');
|
|
13
13
|
const { handleCommandError } = require('../utils/cli-utils');
|
|
14
14
|
const { setupDevPathAndFormatCommands } = require('./setup-dev-path-commands');
|
|
15
|
-
const { runDevInit
|
|
15
|
+
const { runDevInit } = require('../commands/dev-init');
|
|
16
|
+
const { runDevRefresh, ensureDevCertFreshIfDue } = require('../commands/dev-refresh');
|
|
16
17
|
const { displayDevConfig } = require('../commands/dev-show-display');
|
|
17
18
|
const {
|
|
18
19
|
handleDevList,
|
|
@@ -49,11 +50,21 @@ Examples:
|
|
|
49
50
|
Requires a configured remote Builder Server and an admin client certificate (same machine setup as dev list / dev pin). After add, run dev pin <id> once to create a PIN for aifabrix dev init.
|
|
50
51
|
`;
|
|
51
52
|
|
|
53
|
+
/** Appended to `dev list --help` (sort examples). */
|
|
54
|
+
const DEV_LIST_HELP_AFTER = `
|
|
55
|
+
Examples:
|
|
56
|
+
$ aifabrix dev list
|
|
57
|
+
$ aifabrix dev list --sort id
|
|
58
|
+
$ aifabrix dev list --sort -until
|
|
59
|
+
|
|
60
|
+
Sort fields: id, name, email, until. Prefix - for descending (default: name ascending).
|
|
61
|
+
`;
|
|
62
|
+
|
|
52
63
|
/** Appended to `aifabrix dev --help` (overview; keep subcommand .description lines short). */
|
|
53
64
|
const DEV_GROUP_HELP_AFTER = `
|
|
54
65
|
Categories:
|
|
55
66
|
Local config show, set-id, set-scoped-resources, set-env-config, set-home, set-work, set-format, print-home, print-work
|
|
56
|
-
Onboarding init (PIN onboarding), refresh (sync settings / renew cert)
|
|
67
|
+
Onboarding init (PIN onboarding), refresh (sync settings / renew cert); show auto-renews when due
|
|
57
68
|
Remote admin list, add, update, pin, delete, platform-install, platform-update, platform-install-cli (need remote-server + client cert in ~/.aifabrix)
|
|
58
69
|
Sync / stop down (Mutagen; optional --apps for containers)
|
|
59
70
|
|
|
@@ -168,9 +179,10 @@ async function handleSetScopedResources(value) {
|
|
|
168
179
|
function setupDevShowAndSetId(dev) {
|
|
169
180
|
dev
|
|
170
181
|
.command('show')
|
|
171
|
-
.description('Show dev ports and ~/.aifabrix config')
|
|
182
|
+
.description('Show dev ports and ~/.aifabrix config (auto-renews cert when due)')
|
|
172
183
|
.action(async() => {
|
|
173
184
|
try {
|
|
185
|
+
await ensureDevCertFreshIfDue();
|
|
174
186
|
const devId = await config.getDeveloperId();
|
|
175
187
|
await displayDevConfig(devId);
|
|
176
188
|
} catch (error) {
|
|
@@ -286,9 +298,14 @@ function setupDevListAddCommands(dev) {
|
|
|
286
298
|
dev
|
|
287
299
|
.command('list')
|
|
288
300
|
.description('List developers (remote Builder Server)')
|
|
289
|
-
.
|
|
301
|
+
.option(
|
|
302
|
+
'--sort <field>',
|
|
303
|
+
'Sort field/direction (id|name|email|until; prefix - for descending; default name)'
|
|
304
|
+
)
|
|
305
|
+
.addHelpText('after', DEV_LIST_HELP_AFTER)
|
|
306
|
+
.action(async(options) => {
|
|
290
307
|
try {
|
|
291
|
-
await handleDevList();
|
|
308
|
+
await handleDevList(options);
|
|
292
309
|
} catch (error) {
|
|
293
310
|
handleCommandError(error, 'dev list');
|
|
294
311
|
process.exit(1);
|
|
@@ -398,8 +415,6 @@ function setupDevUpdatePinDeleteCommands(dev) {
|
|
|
398
415
|
process.exit(1);
|
|
399
416
|
}
|
|
400
417
|
});
|
|
401
|
-
|
|
402
|
-
setupDevDownCommand(dev);
|
|
403
418
|
}
|
|
404
419
|
|
|
405
420
|
/**
|
|
@@ -457,6 +472,7 @@ function setupDevPlatformCommands(dev) {
|
|
|
457
472
|
function setupDevUserCommands(dev) {
|
|
458
473
|
setupDevListAddCommands(dev);
|
|
459
474
|
setupDevUpdatePinDeleteCommands(dev);
|
|
475
|
+
setupDevDownCommand(dev);
|
|
460
476
|
setupDevPlatformCommands(dev);
|
|
461
477
|
}
|
|
462
478
|
|
|
@@ -18,6 +18,17 @@ Examples:
|
|
|
18
18
|
$ aifabrix validate --builder
|
|
19
19
|
`;
|
|
20
20
|
|
|
21
|
+
const VALIDATE_JSON_HELP_AFTER = `
|
|
22
|
+
Examples:
|
|
23
|
+
$ aifabrix validate-json myapp
|
|
24
|
+
$ aifabrix validate-json my-system
|
|
25
|
+
$ aifabrix validate-json --integration
|
|
26
|
+
$ aifabrix validate-json --builder
|
|
27
|
+
$ aifabrix validate-json --integration --builder --format json
|
|
28
|
+
|
|
29
|
+
Runs full local validation first; writes *-deploy.json only when validation succeeds (offline).
|
|
30
|
+
`;
|
|
31
|
+
|
|
21
32
|
const REPAIR_HELP_AFTER = `
|
|
22
33
|
Examples:
|
|
23
34
|
$ aifabrix repair hubspot-demo
|
|
@@ -63,6 +74,7 @@ Examples:
|
|
|
63
74
|
module.exports = {
|
|
64
75
|
JSON_HELP_AFTER,
|
|
65
76
|
VALIDATE_HELP_AFTER,
|
|
77
|
+
VALIDATE_JSON_HELP_AFTER,
|
|
66
78
|
REPAIR_HELP_AFTER,
|
|
67
79
|
RESOLVE_HELP_AFTER
|
|
68
80
|
};
|
|
@@ -12,7 +12,7 @@ const fs = require('fs');
|
|
|
12
12
|
const chalk = require('chalk');
|
|
13
13
|
const logger = require('../utils/logger');
|
|
14
14
|
const { handleCommandError } = require('../utils/cli-utils');
|
|
15
|
-
const { VALIDATE_HELP_AFTER } = require('./setup-utility-help-after');
|
|
15
|
+
const { VALIDATE_HELP_AFTER, VALIDATE_JSON_HELP_AFTER } = require('./setup-utility-help-after');
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* @param {string} appOrFile
|
|
@@ -154,7 +154,7 @@ async function runValidateCommand(appOrFile, options) {
|
|
|
154
154
|
/**
|
|
155
155
|
* @param {import('commander').Command} program
|
|
156
156
|
*/
|
|
157
|
-
function
|
|
157
|
+
function setupValidateCommand(program) {
|
|
158
158
|
program.command('validate [appKey|systemKey|file]')
|
|
159
159
|
.description('Validate appKey, systemKey, file path, .protection batch, or all under integration/ and builder/')
|
|
160
160
|
.addHelpText('after', VALIDATE_HELP_AFTER)
|
|
@@ -173,7 +173,37 @@ function setupValidateDiffCommands(program) {
|
|
|
173
173
|
process.exit(1);
|
|
174
174
|
});
|
|
175
175
|
});
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @param {import('commander').Command} program
|
|
180
|
+
*/
|
|
181
|
+
function setupValidateJsonCommand(program) {
|
|
182
|
+
program.command('validate-json [appKey|systemKey]')
|
|
183
|
+
.description(
|
|
184
|
+
'Validate locally then write *-deploy.json only when validation succeeds (offline; no file-path mode)'
|
|
185
|
+
)
|
|
186
|
+
.addHelpText('after', VALIDATE_JSON_HELP_AFTER)
|
|
187
|
+
.option('--format <format>', 'Output format: json | default (human-readable)')
|
|
188
|
+
.option('--integration', 'Validate and write deploy JSON for all apps under integration/')
|
|
189
|
+
.option('--builder', 'Validate and write deploy JSON for all apps under builder/')
|
|
190
|
+
.action((appKey, options) => {
|
|
191
|
+
const { runValidateJsonCommand } = require('../commands/validate-json');
|
|
192
|
+
runValidateJsonCommand(appKey, options)
|
|
193
|
+
.then(({ exitCode }) => {
|
|
194
|
+
if (exitCode !== 0) process.exit(exitCode);
|
|
195
|
+
})
|
|
196
|
+
.catch((error) => {
|
|
197
|
+
handleCommandError(error, 'validate-json');
|
|
198
|
+
process.exit(1);
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
}
|
|
176
202
|
|
|
203
|
+
/**
|
|
204
|
+
* @param {import('commander').Command} program
|
|
205
|
+
*/
|
|
206
|
+
function setupDiffCommand(program) {
|
|
177
207
|
program.command('diff <file1> <file2>')
|
|
178
208
|
.description('Diff two config files (optional schema validate)')
|
|
179
209
|
.option('--no-validate', 'Skip schema validation (type check still applied)')
|
|
@@ -191,6 +221,15 @@ function setupValidateDiffCommands(program) {
|
|
|
191
221
|
});
|
|
192
222
|
}
|
|
193
223
|
|
|
224
|
+
/**
|
|
225
|
+
* @param {import('commander').Command} program
|
|
226
|
+
*/
|
|
227
|
+
function setupValidateDiffCommands(program) {
|
|
228
|
+
setupValidateCommand(program);
|
|
229
|
+
setupValidateJsonCommand(program);
|
|
230
|
+
setupDiffCommand(program);
|
|
231
|
+
}
|
|
232
|
+
|
|
194
233
|
module.exports = {
|
|
195
234
|
setupValidateDiffCommands,
|
|
196
235
|
runValidateCommand
|
|
@@ -124,6 +124,27 @@ function formatIntegrationGateFailure(result) {
|
|
|
124
124
|
if (result?.message) {
|
|
125
125
|
return String(result.message);
|
|
126
126
|
}
|
|
127
|
+
const rows = Array.isArray(result?.datasourceResults) ? result.datasourceResults : [];
|
|
128
|
+
const hints = [];
|
|
129
|
+
for (const row of rows) {
|
|
130
|
+
if (!row || row.success !== false) {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const key = row.key || row.datasourceKey || 'datasource';
|
|
134
|
+
const issues = row.datasourceTestRun?.validation?.issues;
|
|
135
|
+
if (Array.isArray(issues) && issues.length > 0) {
|
|
136
|
+
const first = issues[0];
|
|
137
|
+
const code = first.code ? `${first.code}: ` : '';
|
|
138
|
+
hints.push(`${key}: ${code}${first.message || 'validation failed'}`);
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (row.error) {
|
|
142
|
+
hints.push(`${key}: ${row.error}`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (hints.length > 0) {
|
|
146
|
+
return hints.slice(0, 3).join('; ');
|
|
147
|
+
}
|
|
127
148
|
return 'integration test did not succeed';
|
|
128
149
|
}
|
|
129
150
|
|