@aifabrix/builder 2.44.6 → 2.45.5
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/rules/cli-layout.mdc +7 -3
- package/.cursor/rules/docs-rules.mdc +3 -1
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-credential-real.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-hubspot-env-vars.yaml +1 -1
- package/integration/hubspot-test/wizard-hubspot-e2e.yaml +1 -1
- package/jest.projects.js +100 -1
- package/lib/api/agent-metadata-validation.api.js +93 -0
- package/lib/api/audit-api-helpers.js +68 -0
- package/lib/api/audit.api.js +119 -0
- package/lib/api/auth-cache.api.js +44 -0
- package/lib/api/certificates.api.js +4 -4
- package/lib/api/credential.api.js +2 -2
- package/lib/api/dataplane-health.api.js +137 -0
- package/lib/api/dataplane-sync.api.js +27 -0
- package/lib/api/datasources-core.api.js +21 -18
- package/lib/api/datasources-extended.api.js +22 -22
- package/lib/api/dimensions.api.js +3 -0
- package/lib/api/external-systems.api.js +13 -13
- package/lib/api/governance-scenarios.api.js +39 -0
- package/lib/api/groups.api.js +79 -0
- package/lib/api/index.js +45 -2
- package/lib/api/pipeline.api.js +4 -4
- package/lib/api/protection.api.js +157 -0
- package/lib/api/records-bulk.api.js +30 -0
- package/lib/api/records-search-parse.js +49 -0
- package/lib/api/records-search.api.js +29 -0
- package/lib/api/types/agent-metadata-validation.types.js +67 -0
- package/lib/api/types/audit.types.js +72 -0
- package/lib/api/types/dataplane-health.types.js +27 -0
- package/lib/api/types/dimensions.types.js +2 -0
- package/lib/api/types/governance-scenarios.types.js +39 -0
- package/lib/api/types/protection.types.js +69 -0
- package/lib/api/types/records-bulk.types.js +35 -0
- package/lib/api/types/records-search.types.js +28 -0
- package/lib/api/user-groups.api.js +50 -0
- package/lib/api/users.api.js +95 -0
- package/lib/api/validation-run.api.js +3 -3
- package/lib/api/validation-runner.js +3 -3
- package/lib/api/wizard-platform.api.js +3 -3
- package/lib/api/wizard.api.js +21 -21
- package/lib/app/deploy.js +34 -19
- package/lib/app/helpers.js +3 -3
- package/lib/app/index.js +3 -3
- package/lib/app/register.js +7 -6
- package/lib/app/restart-display.js +52 -21
- package/lib/app/rotate-secret.js +7 -6
- package/lib/app/run-helpers.js +15 -8
- package/lib/app/run.js +57 -9
- package/lib/app/show-display.js +7 -0
- package/lib/app/show.js +87 -5
- package/lib/build/index.js +9 -5
- package/lib/cli/index.js +4 -2
- package/lib/cli/infra-guided.js +62 -28
- package/lib/cli/installation-log-command.js +73 -0
- package/lib/cli/setup-app.help.js +50 -2
- package/lib/cli/setup-app.js +44 -25
- package/lib/cli/setup-app.test-commands.js +80 -21
- package/lib/cli/setup-auth.js +124 -52
- package/lib/cli/setup-external-system.js +37 -3
- package/lib/cli/setup-infra-up-dataplane-action.js +111 -0
- package/lib/cli/setup-infra-up-platform-action.js +131 -0
- package/lib/cli/setup-infra.js +60 -119
- package/lib/cli/setup-platform.js +1 -1
- package/lib/cli/setup-utility-help-after.js +45 -0
- package/lib/cli/setup-utility-resolve.js +132 -0
- package/lib/cli/setup-utility.js +148 -116
- package/lib/commands/app-logs.js +81 -33
- package/lib/commands/auth-config.js +116 -18
- package/lib/commands/auth-status-dataplane-version.js +231 -0
- package/lib/commands/auth-status-display.js +94 -0
- package/lib/commands/auth-status.js +70 -6
- package/lib/commands/credential-push.js +10 -5
- package/lib/commands/datasource-load-export-cli.js +178 -0
- package/lib/commands/datasource-test-trust-cli.js +114 -0
- package/lib/commands/datasource-unified-test-cli.js +25 -17
- package/lib/commands/datasource-unified-test-cli.options.js +18 -3
- package/lib/commands/datasource-unified-test-e2e-cli-helpers.js +5 -5
- package/lib/commands/datasource-verify-audit-cli.js +96 -0
- package/lib/commands/datasource.js +68 -1
- package/lib/commands/dimension-value.js +43 -13
- package/lib/commands/dimension.js +38 -7
- package/lib/commands/identity-apply-sync.js +131 -0
- package/lib/commands/identity-group-cli.js +146 -0
- package/lib/commands/identity-membership-role-cache.js +175 -0
- package/lib/commands/identity-shared.js +94 -0
- package/lib/commands/identity-user-cli.js +158 -0
- package/lib/commands/identity.js +43 -0
- package/lib/commands/login.js +46 -16
- package/lib/commands/protection-cli-leaves.js +286 -0
- package/lib/commands/protection.js +50 -0
- package/lib/commands/repair.js +13 -3
- package/lib/commands/setup-modes.js +19 -6
- package/lib/commands/setup-prompts.js +41 -8
- package/lib/commands/setup.js +114 -9
- package/lib/commands/teardown.js +54 -5
- package/lib/commands/test-e2e-external.js +40 -9
- package/lib/commands/test-governance-cli-options.js +47 -0
- package/lib/commands/test-governance-command-action.js +55 -0
- package/lib/commands/test-governance-external.js +88 -0
- package/lib/commands/test-trust-cli-options.js +32 -0
- package/lib/commands/test-trust-command-action.js +118 -0
- package/lib/commands/test-trust-external.js +127 -0
- package/lib/commands/up-common.js +48 -14
- package/lib/commands/up-dataplane.js +21 -18
- package/lib/commands/up-miso.js +12 -8
- package/lib/commands/upload.js +38 -15
- package/lib/commands/wizard-core.js +3 -0
- package/lib/core/audit-logger.js +1 -34
- package/lib/core/config-admin-email.js +56 -0
- package/lib/core/config-device-dataplane.js +185 -0
- package/lib/core/config-normalize.js +60 -0
- package/lib/core/config-registered-controller-urls.js +54 -0
- package/lib/core/config.js +33 -50
- package/lib/core/secrets-ensure-infra.js +1 -1
- package/lib/core/secrets-env-content.js +86 -90
- package/lib/core/secrets-env-declarative-expand.js +170 -0
- package/lib/core/secrets-env-write.js +2 -0
- package/lib/core/secrets-load.js +106 -102
- package/lib/datasource/agent-trust-debug-log.js +45 -0
- package/lib/datasource/agent-trust-fetch.js +115 -0
- package/lib/datasource/agent-trust-map.js +101 -0
- package/lib/datasource/agent-trust-mock.js +44 -0
- package/lib/datasource/agent-trust-run.js +93 -0
- package/lib/datasource/agent-trust-timeout.js +25 -0
- package/lib/datasource/audit-evidence-display.js +80 -0
- package/lib/datasource/audit-evidence-extract-debug.js +103 -0
- package/lib/datasource/audit-evidence-extract.js +177 -0
- package/lib/datasource/audit-evidence-matrix-rows.js +158 -0
- package/lib/datasource/audit-evidence-operation-aliases.js +63 -0
- package/lib/datasource/audit-evidence-poll.js +109 -0
- package/lib/datasource/audit-evidence-run.js +177 -0
- package/lib/datasource/audit-evidence-verify-helpers.js +167 -0
- package/lib/datasource/audit-evidence-verify-matrix.js +177 -0
- package/lib/datasource/audit-evidence-verify.js +108 -0
- package/lib/datasource/bulk-loader-run-batches.js +88 -0
- package/lib/datasource/bulk-loader-service-retry.js +52 -0
- package/lib/datasource/bulk-loader-service.js +127 -0
- package/lib/datasource/capability/run-capability-dimension.js +2 -1
- package/lib/datasource/datasource-exporter-resolve.js +82 -0
- package/lib/datasource/datasource-exporter-service.js +144 -0
- package/lib/datasource/datasource-identifier.js +148 -0
- package/lib/datasource/datasource-load-export-context.js +92 -0
- package/lib/datasource/integration-context.js +6 -4
- package/lib/datasource/local-data-paths.js +145 -0
- package/lib/datasource/log-cleaner.js +241 -0
- package/lib/datasource/log-viewer.js +111 -6
- package/lib/datasource/record-file-parser.js +85 -0
- package/lib/datasource/record-mapper.js +129 -0
- package/lib/datasource/resolve-app.js +74 -55
- package/lib/datasource/test-e2e.js +26 -2
- package/lib/datasource/unified-validation-run-resolve.js +45 -12
- package/lib/datasource/unified-validation-run.js +43 -17
- package/lib/datasource/validate.js +37 -20
- package/lib/external-system/deploy.js +5 -1
- package/lib/external-system/test-system-level.js +25 -4
- package/lib/external-system/test.js +3 -1
- package/lib/governance/governance-pack-loader.js +70 -0
- package/lib/governance/governance-run-display.js +119 -0
- package/lib/identity/identity-apply-core.js +108 -0
- package/lib/identity/identity-apply-phases.js +244 -0
- package/lib/identity/identity-apply-service.js +77 -0
- package/lib/identity/identity-csv-parser.js +114 -0
- package/lib/internal/fs-real-sync.js +29 -1
- package/lib/internal/node-fs.js +2 -0
- package/lib/protection/auth-context.js +45 -0
- package/lib/protection/convert-batch.js +90 -0
- package/lib/protection/load.js +41 -0
- package/lib/protection/paths.js +158 -0
- package/lib/protection/preflight-datasource-ready.js +46 -0
- package/lib/protection/protection-create-probe-lines.js +142 -0
- package/lib/protection/protection-create-probes.js +95 -0
- package/lib/protection/protection-create-scaffold.js +281 -0
- package/lib/protection/protection-display-helpers.js +445 -0
- package/lib/protection/protection-display.js +215 -0
- package/lib/protection/protection-preset-registry.js +97 -0
- package/lib/protection/report-exit.js +62 -0
- package/lib/protection/resolve.js +202 -0
- package/lib/protection/run-commands-validate.js +130 -0
- package/lib/protection/run-commands.js +216 -0
- package/lib/protection/run-protection-create-helpers.js +134 -0
- package/lib/protection/run-protection-create-probes-flow.js +43 -0
- package/lib/protection/run-protection-create.js +191 -0
- package/lib/protection/scope.js +22 -0
- package/lib/protection/sync-after-upload.js +64 -0
- package/lib/protection/upload-batch.js +127 -0
- package/lib/protection/validate-batch.js +113 -0
- package/lib/protection/validate-local.js +65 -0
- package/lib/resolvers/dimension-file.js +29 -4
- package/lib/schema/application-schema.json +4 -0
- package/lib/schema/external-datasource.schema.json +47 -13
- package/lib/schema/flag-map-validation-run.json +2 -2
- package/lib/schema/infra.parameter.yaml +10 -0
- package/lib/schema/protection.schema.json +374 -0
- package/lib/schema/type/credential-field-registry.json +636 -0
- package/lib/schema/wizard-config.schema.json +1 -1
- package/lib/utils/agent-trust-run-display.js +231 -0
- package/lib/utils/agent-trust-run-exit.js +59 -0
- package/lib/utils/agent-trust-wait-ui.js +94 -0
- package/lib/utils/app-config-resolver.js +24 -1
- package/lib/utils/applications-config-defaults.js +206 -0
- package/lib/utils/auth-config-validator.js +2 -12
- package/lib/utils/bash-secret-env.js +1 -1
- package/lib/utils/cli-exit-codes.js +30 -0
- package/lib/utils/cli-sync-options.js +33 -0
- package/lib/utils/compose-generate-docker-compose.js +111 -6
- package/lib/utils/compose-generator.js +17 -8
- package/lib/utils/controller-url.js +50 -7
- package/lib/utils/credential-push-ui.js +90 -0
- package/lib/utils/dataplane-cli-version-gate.js +202 -0
- package/lib/utils/dataplane-cli-version-help.js +74 -0
- package/lib/utils/datasource-export-display.js +137 -0
- package/lib/utils/datasource-load-display.js +174 -0
- package/lib/utils/datasource-load-export-ui.js +120 -0
- package/lib/utils/datasource-test-run-capability-scope.js +3 -3
- package/lib/utils/datasource-test-run-display.js +3 -3
- package/lib/utils/datasource-test-run-tty-log.js +5 -1
- package/lib/utils/env-copy.js +99 -14
- package/lib/utils/env-template.js +5 -1
- package/lib/utils/health-check-url.js +18 -15
- package/lib/utils/health-check.js +7 -5
- package/lib/utils/help-builder.js +30 -24
- package/lib/utils/infra-optional-service-flags.js +69 -0
- package/lib/utils/installation-log-core.js +282 -0
- package/lib/utils/installation-log-record.js +237 -0
- package/lib/utils/installation-log.js +123 -0
- package/lib/utils/log-redaction.js +105 -0
- package/lib/utils/manifest-location.js +164 -0
- package/lib/utils/manifest-source-emit.js +184 -0
- package/lib/utils/paths.js +238 -89
- package/lib/utils/remote-secrets-loader.js +7 -1
- package/lib/utils/run-cli-flags.js +29 -0
- package/lib/utils/secrets-canonical.js +10 -3
- package/lib/utils/secrets-path.js +3 -4
- package/lib/utils/secrets-utils.js +20 -10
- package/lib/utils/semver-compare.js +127 -0
- package/lib/utils/system-builder-root.js +10 -2
- package/lib/utils/upload-pipeline-ui.js +91 -0
- package/lib/utils/url-declarative-public-base.js +80 -12
- package/lib/utils/url-declarative-resolve-build-urls.js +238 -0
- package/lib/utils/url-declarative-resolve-build.js +24 -393
- package/lib/utils/url-declarative-resolve-expand-token.js +189 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +12 -3
- package/lib/utils/url-declarative-resolve-surface-state.js +102 -0
- package/lib/utils/url-declarative-resolve.js +47 -7
- package/lib/utils/url-declarative-runtime-base-path.js +21 -1
- package/lib/utils/urls-local-registry-scan.js +103 -0
- package/lib/utils/urls-local-registry.js +161 -90
- package/lib/utils/validation-poll-ui.js +14 -7
- package/lib/validation/wizard-config-validator.js +58 -19
- package/package.json +3 -1
- package/templates/applications/dataplane/application.yaml +4 -0
- package/templates/applications/dataplane/env.template +13 -1
- package/templates/applications/dataplane/rbac.yaml +4 -0
- package/templates/applications/miso-controller/application.yaml +2 -0
- package/templates/applications/miso-controller/env.template +27 -29
- package/templates/external-system/README.md.hbs +56 -8
- package/.npmrc.token +0 -1
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview TTY display for agent metadata trust runs (plan 143).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const logger = require('./logger');
|
|
11
|
+
const { sectionTitle, headerKeyValue, metadata: metaGray } = require('./cli-test-layout-chalk');
|
|
12
|
+
const { statusGlyph } = require('./datasource-test-run-display');
|
|
13
|
+
const { trustDecisionToRowStatus } = require('../datasource/agent-trust-map');
|
|
14
|
+
|
|
15
|
+
const SEP = '────────────────────────────────';
|
|
16
|
+
|
|
17
|
+
/** @type {{ datasource: number, trust: number, conf: number, status: number, cache: number }} */
|
|
18
|
+
const TRUST_TABLE_COLS = {
|
|
19
|
+
datasource: 30,
|
|
20
|
+
trust: 24,
|
|
21
|
+
conf: 6,
|
|
22
|
+
status: 8,
|
|
23
|
+
cache: 8
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
function trustGlyph(trustDecision) {
|
|
27
|
+
return statusGlyph(trustDecisionToRowStatus(trustDecision));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function publishGateLine(trustDecision, strict) {
|
|
31
|
+
if (trustDecision === 'notTrusted') return chalk.red('blocked (trustDecision notTrusted)');
|
|
32
|
+
if (strict) {
|
|
33
|
+
return trustDecision === 'trusted'
|
|
34
|
+
? chalk.green('allowed (strict: trusted)')
|
|
35
|
+
: chalk.yellow('blocked (strict requires trusted)');
|
|
36
|
+
}
|
|
37
|
+
return chalk.green('allowed (warning-only); use --strict to require trusted');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function logTrustHeader(run, env) {
|
|
41
|
+
logger.log(SEP);
|
|
42
|
+
logger.log(sectionTitle(`Semantic trust — ${run.datasourceKey}`));
|
|
43
|
+
logger.log(headerKeyValue('Environment:', env));
|
|
44
|
+
logger.log(headerKeyValue('System:', run.systemKey || '—'));
|
|
45
|
+
logger.log(SEP);
|
|
46
|
+
logger.log(metaGray(' Layer checked: business metadata (404.5 agent validation)'));
|
|
47
|
+
logger.log(metaGray(' Not checked here: vendor connectivity, sync, record counts (use test-e2e)'));
|
|
48
|
+
logger.log('');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function logTrustSummaryBlock(run) {
|
|
52
|
+
const confPct = Math.round((run.confidence || 0) * 100);
|
|
53
|
+
logger.log(
|
|
54
|
+
headerKeyValue(
|
|
55
|
+
'Trust:',
|
|
56
|
+
`${trustGlyph(run.trustDecision)} ${run.trustDecision} · confidence ${confPct}% · ${run.validationStatus}`
|
|
57
|
+
)
|
|
58
|
+
);
|
|
59
|
+
if (!run.validatedAt) return;
|
|
60
|
+
const hashShort = run.inputHash ? `${String(run.inputHash).slice(0, 8)}…` : '—';
|
|
61
|
+
logger.log(
|
|
62
|
+
metaGray(
|
|
63
|
+
` Validated: ${run.validatedAt} · inputHash ${hashShort} · cache: ${run.cacheHit ? 'hit' : 'miss'}`
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function logTrustWarningsAndFindings(run, opts) {
|
|
69
|
+
if (run.summary) {
|
|
70
|
+
logger.log('');
|
|
71
|
+
logger.log(chalk.white(' Summary'));
|
|
72
|
+
logger.log(` ${run.summary}`);
|
|
73
|
+
}
|
|
74
|
+
const warnings = Array.isArray(run.highLevelWarnings) ? run.highLevelWarnings : [];
|
|
75
|
+
const findings = Array.isArray(run.findings) ? run.findings : [];
|
|
76
|
+
const showVerboseFindings = opts.verbose === true && findings.length > 0;
|
|
77
|
+
if (warnings.length && !showVerboseFindings) {
|
|
78
|
+
logger.log('');
|
|
79
|
+
logger.log(chalk.yellow(' Warnings (high level)'));
|
|
80
|
+
warnings.forEach(w => logger.log(` • ${w}`));
|
|
81
|
+
}
|
|
82
|
+
if (!showVerboseFindings) return;
|
|
83
|
+
logger.log('');
|
|
84
|
+
logger.log(chalk.white(' Findings (verbose, max 10)'));
|
|
85
|
+
findings.slice(0, 10).forEach(f => {
|
|
86
|
+
logger.log(` • [${f.severity || 'info'}] ${f.code || 'FINDING'}: ${f.message || ''}`);
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function logTrustFooter(run, opts) {
|
|
91
|
+
logger.log('');
|
|
92
|
+
logger.log(metaGray(' ── Integration reality (informative) ──'));
|
|
93
|
+
logger.log(metaGray(` Local manifest: ${opts.noSync ? 'not uploaded (--no-sync)' : 'uploaded before run'}`));
|
|
94
|
+
logger.log(metaGray(` Publish gate: ${publishGateLine(run.trustDecision, opts.strict === true)}`));
|
|
95
|
+
logger.log(SEP);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function displayAgentTrustRunTTY(run, opts = {}) {
|
|
99
|
+
if (!run || opts.json === true) return;
|
|
100
|
+
const env = opts.environment ? String(opts.environment) : 'dev';
|
|
101
|
+
logTrustHeader(run, env);
|
|
102
|
+
logTrustSummaryBlock(run);
|
|
103
|
+
logTrustWarningsAndFindings(run, opts);
|
|
104
|
+
logTrustFooter(run, opts);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function trustCacheLabel(trustRun) {
|
|
108
|
+
if (!trustRun || typeof trustRun !== 'object') return '—';
|
|
109
|
+
if (trustRun.readLatest === true) return 'latest';
|
|
110
|
+
if (trustRun.cacheHit === true) return 'hit';
|
|
111
|
+
if (trustRun.cacheHit === false) return 'miss';
|
|
112
|
+
return '—';
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @param {boolean} showCache
|
|
117
|
+
* @returns {number}
|
|
118
|
+
*/
|
|
119
|
+
function trustTableLineWidth(showCache) {
|
|
120
|
+
const { datasource, trust, conf, status, cache } = TRUST_TABLE_COLS;
|
|
121
|
+
let w = 2 + datasource + 1 + trust + 1 + conf + 1 + status;
|
|
122
|
+
if (showCache) w += 1 + cache;
|
|
123
|
+
return w;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* @param {string} key
|
|
128
|
+
* @returns {string}
|
|
129
|
+
*/
|
|
130
|
+
function formatTrustTableDatasourceCol(key) {
|
|
131
|
+
return String(key || '').padEnd(TRUST_TABLE_COLS.datasource).slice(0, TRUST_TABLE_COLS.datasource);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @param {Object|null|undefined} tr
|
|
136
|
+
* @returns {string}
|
|
137
|
+
*/
|
|
138
|
+
function formatTrustTableTrustCol(tr) {
|
|
139
|
+
const w = TRUST_TABLE_COLS.trust;
|
|
140
|
+
if (!tr || !tr.trustDecision) return '—'.padEnd(w);
|
|
141
|
+
const decision = String(tr.trustDecision);
|
|
142
|
+
const cell = `${trustGlyph(decision)} ${decision}`;
|
|
143
|
+
return cell.length > w ? cell.slice(0, w) : cell.padEnd(w);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* @param {Object|null|undefined} tr
|
|
148
|
+
* @returns {string}
|
|
149
|
+
*/
|
|
150
|
+
function formatTrustTableConfCol(tr) {
|
|
151
|
+
const w = TRUST_TABLE_COLS.conf;
|
|
152
|
+
if (!tr || typeof tr.confidence !== 'number') return '—'.padStart(w);
|
|
153
|
+
return `${Math.round(tr.confidence * 100)}%`.padStart(w);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* @param {Object|null|undefined} tr
|
|
158
|
+
* @param {Object} row
|
|
159
|
+
* @returns {string}
|
|
160
|
+
*/
|
|
161
|
+
function formatTrustTableStatusCol(tr, row) {
|
|
162
|
+
const w = TRUST_TABLE_COLS.status;
|
|
163
|
+
const raw = tr ? String(tr.validationStatus || '—') : row.error || 'fail';
|
|
164
|
+
return raw.padEnd(w).slice(0, w);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @param {boolean} showCache
|
|
169
|
+
*/
|
|
170
|
+
function logSystemTrustTableHeader(showCache) {
|
|
171
|
+
const { datasource, trust, conf, status, cache } = TRUST_TABLE_COLS;
|
|
172
|
+
let header = ` ${'Datasource'.padEnd(datasource)} ${'Trust'.padEnd(trust)} ${'Conf.'.padStart(conf)} ${'Status'.padEnd(status)}`;
|
|
173
|
+
if (showCache) header += ` ${'Cache'.padEnd(cache)}`;
|
|
174
|
+
logger.log(chalk.white(header));
|
|
175
|
+
logger.log(chalk.gray(` ${'─'.repeat(trustTableLineWidth(showCache))}`));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @param {Object} row
|
|
180
|
+
* @param {boolean} showCache
|
|
181
|
+
* @returns {string}
|
|
182
|
+
*/
|
|
183
|
+
function formatTrustTableRow(row, showCache) {
|
|
184
|
+
const tr = row.trustRun;
|
|
185
|
+
let line = ` ${formatTrustTableDatasourceCol(row.key)} ${formatTrustTableTrustCol(tr)} ${formatTrustTableConfCol(tr)} ${formatTrustTableStatusCol(tr, row)}`;
|
|
186
|
+
if (showCache) {
|
|
187
|
+
line += ` ${trustCacheLabel(tr).padEnd(TRUST_TABLE_COLS.cache).slice(0, TRUST_TABLE_COLS.cache)}`;
|
|
188
|
+
}
|
|
189
|
+
return line;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function logSystemTrustTable(list, opts = {}) {
|
|
193
|
+
const showCache = opts.showCache === true;
|
|
194
|
+
logSystemTrustTableHeader(showCache);
|
|
195
|
+
for (const row of list) {
|
|
196
|
+
logger.log(formatTrustTableRow(row, showCache));
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function displaySystemTrustRollupTTY(systemKey, rows, opts = {}) {
|
|
201
|
+
if (opts.json === true) return;
|
|
202
|
+
const list = Array.isArray(rows) ? rows : [];
|
|
203
|
+
logger.log(SEP);
|
|
204
|
+
logger.log(sectionTitle(`Semantic trust — system ${systemKey} (${list.length} datasources)`));
|
|
205
|
+
const { deriveSystemStatus } = require('./external-system-system-test-tty');
|
|
206
|
+
const worst = deriveSystemStatus(
|
|
207
|
+
list.map(r => ({
|
|
208
|
+
success: r.success !== false,
|
|
209
|
+
datasourceTestRun: {
|
|
210
|
+
status: r.trustRun ? trustDecisionToRowStatus(r.trustRun.trustDecision) : 'fail'
|
|
211
|
+
}
|
|
212
|
+
}))
|
|
213
|
+
);
|
|
214
|
+
logger.log(
|
|
215
|
+
headerKeyValue('System trust:', `${statusGlyph(worst)} ${worst} (worst-of rollup)`)
|
|
216
|
+
);
|
|
217
|
+
logger.log('');
|
|
218
|
+
logSystemTrustTable(list, opts);
|
|
219
|
+
logger.log('');
|
|
220
|
+
logger.log(metaGray(' ── What this run proved ──'));
|
|
221
|
+
logger.log(metaGray(` ✔ Semantic metadata reviewed for ${list.length} datasource(s) on dataplane`));
|
|
222
|
+
logger.log(metaGray(' ✖ Did not call external APIs or run CIP (not E2E)'));
|
|
223
|
+
logger.log(SEP);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
module.exports = {
|
|
227
|
+
displayAgentTrustRunTTY,
|
|
228
|
+
displaySystemTrustRollupTTY,
|
|
229
|
+
formatTrustTableRow,
|
|
230
|
+
TRUST_TABLE_COLS
|
|
231
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Exit codes for agent metadata trust CLI runs (plan 143).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 1.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const { trustDecisionToRowStatus } = require('../datasource/agent-trust-map');
|
|
10
|
+
const { deriveSystemStatus } = require('./external-system-system-test-tty');
|
|
11
|
+
const { computeExitCodeFromDatasourceTestRun } = require('./datasource-test-run-exit');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {Object|null|undefined} run
|
|
15
|
+
* @param {Object} [opts]
|
|
16
|
+
* @param {boolean} [opts.warningsAsErrors]
|
|
17
|
+
* @param {boolean} [opts.strict]
|
|
18
|
+
* @returns {number}
|
|
19
|
+
*/
|
|
20
|
+
function computeExitCodeFromTrustRun(run, opts = {}) {
|
|
21
|
+
if (!run || typeof run !== 'object') return 3;
|
|
22
|
+
const td = run.trustDecision;
|
|
23
|
+
if (run.validationStatus === 'failed' || td === 'notTrusted') return 1;
|
|
24
|
+
if (opts.strict === true && td !== 'trusted') return 1;
|
|
25
|
+
if (opts.warningsAsErrors === true && td === 'usableWithWarnings') return 1;
|
|
26
|
+
if (td === 'trusted' || td === 'usableWithWarnings' || td === 'pending') return 0;
|
|
27
|
+
return 3;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {Array<{ success?: boolean, trustRun?: Object|null }>} rows
|
|
32
|
+
* @param {Object} [opts]
|
|
33
|
+
* @returns {number}
|
|
34
|
+
*/
|
|
35
|
+
function computeSystemExitCodeFromTrustRows(rows, opts = {}) {
|
|
36
|
+
const list = Array.isArray(rows) ? rows : [];
|
|
37
|
+
let worst = 0;
|
|
38
|
+
for (const row of list) {
|
|
39
|
+
const code = computeExitCodeFromTrustRun(row && row.trustRun, opts);
|
|
40
|
+
if (code === 3) return 3;
|
|
41
|
+
if (code > worst) worst = code;
|
|
42
|
+
}
|
|
43
|
+
if (worst > 0) return worst;
|
|
44
|
+
const synthetic = list.map(r => {
|
|
45
|
+
const tr = r && r.trustRun;
|
|
46
|
+
const st = tr ? trustDecisionToRowStatus(tr.trustDecision) : 'fail';
|
|
47
|
+
return { success: st !== 'fail', datasourceTestRun: { status: st } };
|
|
48
|
+
});
|
|
49
|
+
const rollup = deriveSystemStatus(synthetic);
|
|
50
|
+
return computeExitCodeFromDatasourceTestRun(
|
|
51
|
+
{ status: rollup },
|
|
52
|
+
{ warningsAsErrors: opts.warningsAsErrors === true }
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
module.exports = {
|
|
57
|
+
computeExitCodeFromTrustRun,
|
|
58
|
+
computeSystemExitCodeFromTrustRows
|
|
59
|
+
};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTY ora spinner for slow agent metadata validation POST (non-cached path).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Agent trust wait presentation (aligned with validation-poll-ui)
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const chalk = require('chalk');
|
|
12
|
+
const logger = require('./logger');
|
|
13
|
+
|
|
14
|
+
function shouldUseAgentTrustWaitSpinner() {
|
|
15
|
+
return Boolean(process && process.stdout && process.stdout.isTTY);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @param {string} [datasourceKey]
|
|
20
|
+
* @param {number} deadlineMs
|
|
21
|
+
* @returns {string}
|
|
22
|
+
*/
|
|
23
|
+
function buildAgentTrustWaitSpinnerText(datasourceKey, deadlineMs) {
|
|
24
|
+
const remainingSec = Math.max(0, Math.ceil((deadlineMs - Date.now()) / 1000));
|
|
25
|
+
const key =
|
|
26
|
+
datasourceKey && String(datasourceKey).trim() ? String(datasourceKey).trim() : 'datasource';
|
|
27
|
+
return `Waiting for semantic trust validation… ${key} (~${remainingSec}s left)`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Run a blocking validate POST behind a TTY spinner (skipped when not a TTY).
|
|
32
|
+
*
|
|
33
|
+
* @async
|
|
34
|
+
* @param {Function} work - Zero-arg async function performing the HTTP call
|
|
35
|
+
* @param {Object} opts
|
|
36
|
+
* @param {string} [opts.datasourceKey]
|
|
37
|
+
* @param {number} opts.timeoutMs
|
|
38
|
+
* @returns {Promise<*>}
|
|
39
|
+
*/
|
|
40
|
+
async function runWithAgentTrustWaitSpinner(work, opts = {}) {
|
|
41
|
+
const timeoutMs =
|
|
42
|
+
Number.isFinite(opts.timeoutMs) && opts.timeoutMs > 0 ? opts.timeoutMs : 120000;
|
|
43
|
+
const deadlineMs = Date.now() + timeoutMs;
|
|
44
|
+
const datasourceKey = opts.datasourceKey;
|
|
45
|
+
|
|
46
|
+
if (!shouldUseAgentTrustWaitSpinner()) {
|
|
47
|
+
return work();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const ora = require('ora');
|
|
51
|
+
const spinner = ora({
|
|
52
|
+
text: buildAgentTrustWaitSpinnerText(datasourceKey, deadlineMs),
|
|
53
|
+
spinner: 'dots'
|
|
54
|
+
}).start();
|
|
55
|
+
|
|
56
|
+
const tick = setInterval(() => {
|
|
57
|
+
spinner.text = buildAgentTrustWaitSpinnerText(datasourceKey, deadlineMs);
|
|
58
|
+
}, 1000);
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
return await work();
|
|
62
|
+
} finally {
|
|
63
|
+
clearInterval(tick);
|
|
64
|
+
spinner.stop();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const NON_TTY_LOG_MS = 5000;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Optional one-line hint on non-TTY before a slow validate (throttled by caller usage).
|
|
72
|
+
*
|
|
73
|
+
* @param {string} [datasourceKey]
|
|
74
|
+
* @param {number} timeoutMs
|
|
75
|
+
*/
|
|
76
|
+
function logAgentTrustWaitHintOnce(datasourceKey, timeoutMs) {
|
|
77
|
+
if (shouldUseAgentTrustWaitSpinner()) return;
|
|
78
|
+
const budgetSec = Math.max(1, Math.ceil(timeoutMs / 1000));
|
|
79
|
+
const key =
|
|
80
|
+
datasourceKey && String(datasourceKey).trim() ? String(datasourceKey).trim() : 'datasource';
|
|
81
|
+
logger.log(
|
|
82
|
+
chalk.gray(
|
|
83
|
+
`Waiting for semantic trust validation… ${key} (may take up to ~${budgetSec}s; not cached)`
|
|
84
|
+
)
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = {
|
|
89
|
+
shouldUseAgentTrustWaitSpinner,
|
|
90
|
+
buildAgentTrustWaitSpinnerText,
|
|
91
|
+
runWithAgentTrustWaitSpinner,
|
|
92
|
+
logAgentTrustWaitHintOnce,
|
|
93
|
+
NON_TTY_LOG_MS
|
|
94
|
+
};
|
|
@@ -12,7 +12,28 @@
|
|
|
12
12
|
'use strict';
|
|
13
13
|
|
|
14
14
|
const path = require('path');
|
|
15
|
-
const
|
|
15
|
+
const defaultFs = require('fs');
|
|
16
|
+
const { nodeFs } = require('../internal/node-fs');
|
|
17
|
+
|
|
18
|
+
const realFs = nodeFs();
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Prefer real disk when `fs` is not mocked (avoids `jest.mock('fs')` bleed in other suites).
|
|
22
|
+
* Use `require('fs')` when Jest replaced it so tests with virtual file stores still work.
|
|
23
|
+
*
|
|
24
|
+
* @returns {Pick<import('fs'), 'existsSync'|'renameSync'>}
|
|
25
|
+
*/
|
|
26
|
+
function getResolverFs() {
|
|
27
|
+
if (
|
|
28
|
+
typeof jest !== 'undefined' &&
|
|
29
|
+
defaultFs.existsSync &&
|
|
30
|
+
typeof jest.isMockFunction === 'function' &&
|
|
31
|
+
jest.isMockFunction(defaultFs.existsSync)
|
|
32
|
+
) {
|
|
33
|
+
return defaultFs;
|
|
34
|
+
}
|
|
35
|
+
return realFs;
|
|
36
|
+
}
|
|
16
37
|
|
|
17
38
|
/**
|
|
18
39
|
* Resolves path to application config file (application.yaml, application.json, or legacy variables.yaml).
|
|
@@ -23,6 +44,7 @@ const fs = require('fs');
|
|
|
23
44
|
* @throws {Error} If no config file found
|
|
24
45
|
*/
|
|
25
46
|
function resolveApplicationConfigPath(appPath) {
|
|
47
|
+
const fs = getResolverFs();
|
|
26
48
|
if (!appPath || typeof appPath !== 'string') {
|
|
27
49
|
throw new Error('App path is required and must be a string');
|
|
28
50
|
}
|
|
@@ -59,6 +81,7 @@ const RBAC_NAMES = ['rbac.yaml', 'rbac.yml', 'rbac.json'];
|
|
|
59
81
|
* @returns {string|null} Absolute path to RBAC file, or null if none exist
|
|
60
82
|
*/
|
|
61
83
|
function resolveRbacPath(appPath) {
|
|
84
|
+
const fs = getResolverFs();
|
|
62
85
|
if (!appPath || typeof appPath !== 'string') {
|
|
63
86
|
throw new Error('App path is required and must be a string');
|
|
64
87
|
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* User `applications` entries in config.yaml (read by `aifabrix resolve`, written by `aifabrix run` dev).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Per-app reload and `proxy` (Traefik/public URL hints) in ~/.aifabrix/config.yaml
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const config = require('../core/config');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Persist `applications.<appKey>.reload` from the last `aifabrix run` (dev only; CLI is source of truth).
|
|
15
|
+
*
|
|
16
|
+
* @async
|
|
17
|
+
* @param {string} appKey - Application key
|
|
18
|
+
* @param {boolean} reload - Same as passing `--reload` on run
|
|
19
|
+
* @returns {Promise<void>}
|
|
20
|
+
*/
|
|
21
|
+
async function persistApplicationReloadFlag(appKey, reload) {
|
|
22
|
+
if (!appKey || typeof appKey !== 'string') {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const cfg = await config.getConfig();
|
|
26
|
+
if (!cfg.applications || typeof cfg.applications !== 'object') {
|
|
27
|
+
cfg.applications = {};
|
|
28
|
+
}
|
|
29
|
+
const prev = cfg.applications[appKey];
|
|
30
|
+
const nextEntry =
|
|
31
|
+
prev && typeof prev === 'object' && !Array.isArray(prev) ? { ...prev, reload: Boolean(reload) } : { reload: Boolean(reload) };
|
|
32
|
+
cfg.applications[appKey] = nextEntry;
|
|
33
|
+
await config.saveConfig(cfg);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* True when `applications.<appKey>.reload` is explicitly **true** (bind-mount + hot reload for `aifabrix run`).
|
|
38
|
+
* Does **not** control other compose overrides (e.g. Python image `command` when the image lacks `uvicorn` on PATH).
|
|
39
|
+
*
|
|
40
|
+
* @param {Object|null|undefined} userConfig - Parsed config.yaml root
|
|
41
|
+
* @param {string} appKey - Application key (folder / app.key)
|
|
42
|
+
* @returns {boolean} True when `applications.<appKey>.reload` is explicitly true
|
|
43
|
+
*/
|
|
44
|
+
function isApplicationsReloadDefaultOn(userConfig, appKey) {
|
|
45
|
+
if (!userConfig || !appKey || typeof appKey !== 'string') {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const apps = userConfig.applications;
|
|
49
|
+
if (!apps || typeof apps !== 'object') {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const entry = apps[appKey];
|
|
53
|
+
if (!entry || typeof entry !== 'object') {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
return entry.reload === true;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* True when `remote-server` is a non-empty string (after trim).
|
|
61
|
+
*
|
|
62
|
+
* @param {string|null|undefined} remoteServer
|
|
63
|
+
* @returns {boolean}
|
|
64
|
+
*/
|
|
65
|
+
function isRemoteServerConfigured(remoteServer) {
|
|
66
|
+
return Boolean(remoteServer && String(remoteServer).trim());
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Whether `build.envOutputPath` should be regenerated with the **local** profile (`generateEnvContent(..., 'local')`).
|
|
71
|
+
* **False** only when **both** `remote-server` is set and `applications.<appKey>.reload` is true — then the host file
|
|
72
|
+
* uses the same **docker**-flavor expansion as `builder/<app>/.env` (copy path). All other cases use **local**.
|
|
73
|
+
*
|
|
74
|
+
* @param {Object|null|undefined} userConfig - Parsed config.yaml root
|
|
75
|
+
* @param {string} appKey - Application key
|
|
76
|
+
* @param {string|null|undefined} remoteServer - `remote-server` value (or null)
|
|
77
|
+
* @returns {boolean}
|
|
78
|
+
*/
|
|
79
|
+
function isPreferLocalEnvOutputPath(userConfig, appKey, remoteServer) {
|
|
80
|
+
if (!isRemoteServerConfigured(remoteServer)) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
return !isApplicationsReloadDefaultOn(userConfig, appKey);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* For `aifabrix resolve`: reads `remote-server` and returns {@link isPreferLocalEnvOutputPath}.
|
|
88
|
+
*
|
|
89
|
+
* @async
|
|
90
|
+
* @param {Object|null|undefined} userConfig
|
|
91
|
+
* @param {string} appKey
|
|
92
|
+
* @returns {Promise<boolean>}
|
|
93
|
+
*/
|
|
94
|
+
async function resolvePreferLocalEnvOutputPathFlag(userConfig, appKey) {
|
|
95
|
+
let remoteServer = null;
|
|
96
|
+
try {
|
|
97
|
+
const rs = await config.getRemoteServer();
|
|
98
|
+
if (rs && String(rs).trim()) {
|
|
99
|
+
remoteServer = String(rs).trim();
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
remoteServer = null;
|
|
103
|
+
}
|
|
104
|
+
return isPreferLocalEnvOutputPath(userConfig, appKey, remoteServer);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Normalize YAML boolean-ish values.
|
|
109
|
+
* @param {unknown} v
|
|
110
|
+
* @returns {boolean|undefined} undefined if absent / not coercible
|
|
111
|
+
*/
|
|
112
|
+
function coerceTriStateBool(v) {
|
|
113
|
+
if (v === true || v === 'true' || v === 'yes' || v === 'on' || v === 1 || v === '1') {
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
if (v === false || v === 'false' || v === 'no' || v === 'off' || v === 0 || v === '0') {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Whether `aifabrix run` / resolve should use Traefik-style public URL hints for this app when infra allows.
|
|
124
|
+
* Default **false** when unset. Legacy `noProxy: true` ⇒ false; legacy `noProxy: false` with no `proxy` ⇒ true.
|
|
125
|
+
*
|
|
126
|
+
* @param {Object|null|undefined} userConfig - Parsed config.yaml root
|
|
127
|
+
* @param {string} appKey - Application key
|
|
128
|
+
* @returns {boolean}
|
|
129
|
+
*/
|
|
130
|
+
function getApplicationsRunProxyHint(userConfig, appKey) {
|
|
131
|
+
if (!userConfig || !appKey || typeof appKey !== 'string') {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
const apps = userConfig.applications;
|
|
135
|
+
if (!apps || typeof apps !== 'object') {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
const entry = apps[appKey];
|
|
139
|
+
if (!entry || typeof entry !== 'object') {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
const proxyCoerced = coerceTriStateBool(entry.proxy);
|
|
143
|
+
if (proxyCoerced !== undefined) {
|
|
144
|
+
return proxyCoerced;
|
|
145
|
+
}
|
|
146
|
+
const legacyNo = coerceTriStateBool(entry.noProxy);
|
|
147
|
+
if (legacyNo === true) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
if (legacyNo === false) {
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Persist `applications.<appKey>.proxy` from each `aifabrix run` (same pattern as `reload` for dev-only reload flag).
|
|
158
|
+
* `proxy: true` means use Traefik/front-door URL hints when infra + that app's `application.yaml` allow; `false` means docker `url://` **public** bases for **that app** use localhost + published port. During `resolve`/`run`, each `url://` token uses the **target** app's `applications.<targetKey>.proxy`, not only the app whose `env.template` is being expanded.
|
|
159
|
+
* Removes legacy `noProxy` on the same entry when present.
|
|
160
|
+
*
|
|
161
|
+
* @async
|
|
162
|
+
* @param {string} appKey - Application key
|
|
163
|
+
* @param {boolean} proxyEnabled - Same as a normal `aifabrix run` with proxy hints on (`!isRunCliNoProxy(options)`)
|
|
164
|
+
* @returns {Promise<void>}
|
|
165
|
+
*/
|
|
166
|
+
async function persistApplicationRunProxyFlag(appKey, proxyEnabled) {
|
|
167
|
+
if (!appKey || typeof appKey !== 'string') {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const cfg = await config.getConfig();
|
|
171
|
+
if (!cfg.applications || typeof cfg.applications !== 'object') {
|
|
172
|
+
cfg.applications = {};
|
|
173
|
+
}
|
|
174
|
+
const prev = cfg.applications[appKey];
|
|
175
|
+
const nextEntry =
|
|
176
|
+
prev && typeof prev === 'object' && !Array.isArray(prev)
|
|
177
|
+
? { ...prev, proxy: Boolean(proxyEnabled) }
|
|
178
|
+
: { proxy: Boolean(proxyEnabled) };
|
|
179
|
+
if (Object.prototype.hasOwnProperty.call(nextEntry, 'noProxy')) {
|
|
180
|
+
delete nextEntry.noProxy;
|
|
181
|
+
}
|
|
182
|
+
cfg.applications[appKey] = nextEntry;
|
|
183
|
+
await config.saveConfig(cfg);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Whether declarative `url://*` expansion should treat Traefik as on (infra Traefik + per-app `proxy: true`).
|
|
188
|
+
*
|
|
189
|
+
* @param {Object|null|undefined} userConfig
|
|
190
|
+
* @param {string} appKey
|
|
191
|
+
* @returns {boolean}
|
|
192
|
+
*/
|
|
193
|
+
function isDeclarativeTraefikUrlsEnabled(userConfig, appKey) {
|
|
194
|
+
return Boolean(userConfig && userConfig.traefik === true) && getApplicationsRunProxyHint(userConfig, appKey);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
module.exports = {
|
|
198
|
+
getApplicationsRunProxyHint,
|
|
199
|
+
isApplicationsReloadDefaultOn,
|
|
200
|
+
isDeclarativeTraefikUrlsEnabled,
|
|
201
|
+
isPreferLocalEnvOutputPath,
|
|
202
|
+
isRemoteServerConfigured,
|
|
203
|
+
persistApplicationRunProxyFlag,
|
|
204
|
+
persistApplicationReloadFlag,
|
|
205
|
+
resolvePreferLocalEnvOutputPathFlag
|
|
206
|
+
};
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @version 2.0.0
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
const {
|
|
11
|
+
const { hasStoredDeviceTokenForController } = require('./controller-url');
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Validate controller URL format
|
|
@@ -72,17 +72,7 @@ async function checkUserLoggedIn(controllerUrl) {
|
|
|
72
72
|
if (!controllerUrl) {
|
|
73
73
|
return false;
|
|
74
74
|
}
|
|
75
|
-
|
|
76
|
-
const normalizedUrl = controllerUrl.trim().replace(/\/+$/, '');
|
|
77
|
-
const loggedInControllerUrl = await getControllerUrlFromLoggedInUser();
|
|
78
|
-
|
|
79
|
-
if (!loggedInControllerUrl) {
|
|
80
|
-
return false;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Normalize both URLs for comparison
|
|
84
|
-
const normalizedLoggedIn = loggedInControllerUrl.trim().replace(/\/+$/, '');
|
|
85
|
-
return normalizedLoggedIn === normalizedUrl;
|
|
75
|
+
return hasStoredDeviceTokenForController(controllerUrl);
|
|
86
76
|
}
|
|
87
77
|
|
|
88
78
|
module.exports = {
|
|
@@ -41,7 +41,7 @@ function collectBashPrefixedEnv(secrets) {
|
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
|
-
* Overlay for `child_process` `env`: values from user
|
|
44
|
+
* Overlay for `child_process` `env`: values from primary user `secrets.local.yaml` plus `aifabrix-secrets`
|
|
45
45
|
* for every `BASH_*` key (merged via {@link secretsLoad.loadSecrets}).
|
|
46
46
|
*
|
|
47
47
|
* @param {string|null} [secretsPath] - Optional explicit secrets file (same as resolve)
|