@aifabrix/builder 2.42.1 → 2.44.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/rules/anchor-docs.mdc +15 -0
- package/README.md +2 -2
- package/anchor-docs/README.md +10 -0
- package/anchor-docs/_TEMPLATE +24 -0
- package/bin/aifabrix.js +13 -4
- package/integration/hubspot-test/README.md +157 -0
- package/integration/{hubspot → hubspot-test}/application.json +6 -6
- package/integration/{hubspot → hubspot-test}/create-hubspot.js +10 -10
- package/integration/hubspot-test/env.template +4 -0
- package/integration/hubspot-test/hubspot-test-datasource-company.json +138 -0
- package/integration/hubspot-test/hubspot-test-datasource-contact.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-deal.json +146 -0
- package/integration/hubspot-test/hubspot-test-datasource-users.json +76 -0
- package/integration/{hubspot/hubspot-deploy.json → hubspot-test/hubspot-test-deploy.json} +201 -24
- package/integration/{hubspot/hubspot-system.json → hubspot-test/hubspot-test-system.json} +8 -7
- package/integration/hubspot-test/rbac.json +166 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-credential-real.yaml +3 -3
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-hubspot-env-vars.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-add-datasource.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-create.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-credential-select.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-known-platform.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-invalid-missing-source.yaml +2 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-mode.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-file.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-openapi-url.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-source.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-array-test.yaml +1 -1
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-key-test.yaml +5 -0
- package/integration/hubspot-test/test-artifacts/wizard-valid-for-dimension-path-test.yaml +5 -0
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-dimension-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-valid-for-rbac-yaml-test.yaml +1 -1
- package/integration/{hubspot → hubspot-test}/test-dataplane-down-tests.js +1 -7
- package/integration/{hubspot → hubspot-test}/test-dataplane-down.js +3 -3
- package/integration/{hubspot → hubspot-test}/test.js +137 -102
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-e2e.yaml +2 -2
- package/integration/{hubspot → hubspot-test}/wizard-hubspot-platform.yaml +1 -1
- package/integration/hubspot-test/wizard-hubspot-test-headless.yaml +23 -0
- package/integration/roundtrip-test-local/README.md +144 -0
- package/integration/roundtrip-test-local/application.yaml +13 -0
- package/integration/roundtrip-test-local/env.template +15 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-datasource-roundtrip-test-company.yaml +14 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-deploy.json +61 -0
- package/integration/roundtrip-test-local/roundtrip-test-local-system.yaml +25 -0
- package/integration/roundtrip-test-local2/README.md +144 -0
- package/integration/roundtrip-test-local2/application.yaml +13 -0
- package/integration/roundtrip-test-local2/env.template +15 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-datasource-company.yaml +31 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-deploy.json +86 -0
- package/integration/roundtrip-test-local2/roundtrip-test-local2-system.yaml +25 -0
- package/integration/test/wizard.yaml +8 -0
- package/jest.config.default.js +10 -0
- package/jest.config.integration.fixtures.js +22 -0
- package/jest.config.integration.js +21 -18
- package/jest.config.isolated.js +10 -0
- package/jest.projects.js +288 -0
- package/lib/api/datasources-core.api.js +3 -3
- package/lib/api/dev-mtls-request.js +110 -0
- package/lib/api/dev-server-https.js +145 -0
- package/lib/api/dev.api.js +133 -144
- package/lib/api/index.js +0 -1
- package/lib/api/pipeline.api.js +67 -20
- package/lib/api/service-users.api.js +111 -2
- package/lib/api/types/dev.types.js +4 -3
- package/lib/api/types/pipeline.types.js +8 -5
- package/lib/api/types/service-users.types.js +41 -0
- package/lib/api/types/validation-run.types.js +56 -0
- package/lib/api/validation-run.api.js +99 -0
- package/lib/api/validation-runner.js +99 -0
- package/lib/app/config.js +1 -1
- package/lib/app/deploy-status-display.js +2 -2
- package/lib/app/deploy.js +7 -6
- package/lib/app/display.js +2 -1
- package/lib/app/dockerfile.js +3 -2
- package/lib/app/down.js +2 -1
- package/lib/app/helpers.js +6 -5
- package/lib/app/index.js +27 -8
- package/lib/app/list.js +7 -6
- package/lib/app/push.js +4 -3
- package/lib/app/register.js +19 -8
- package/lib/app/rotate-secret.js +17 -13
- package/lib/app/run-container-start.js +184 -0
- package/lib/app/run-docker-fallback.js +108 -0
- package/lib/app/run-env-compose.js +30 -42
- package/lib/app/run-helpers.js +49 -126
- package/lib/app/run-infra-requirements.js +30 -0
- package/lib/app/run-resolve-image.js +21 -0
- package/lib/app/run.js +74 -21
- package/lib/app/show-display.js +1 -1
- package/lib/app/show.js +1 -1
- package/lib/build/index.js +13 -10
- package/lib/cli/index.js +2 -0
- package/lib/cli/setup-app.help.js +67 -0
- package/lib/cli/setup-app.js +59 -123
- package/lib/cli/setup-app.test-commands.js +179 -0
- package/lib/cli/setup-auth.js +36 -14
- package/lib/cli/setup-credential-deployment.js +22 -8
- package/lib/cli/setup-dev-path-commands.js +124 -0
- package/lib/cli/setup-dev.js +190 -103
- package/lib/cli/setup-environment.js +11 -20
- package/lib/cli/setup-external-system.js +62 -22
- package/lib/cli/setup-infra.js +139 -47
- package/lib/cli/setup-parameters.js +32 -0
- package/lib/cli/setup-secrets.js +147 -10
- package/lib/cli/setup-service-user.js +146 -20
- package/lib/cli/setup-utility.js +47 -19
- package/lib/commands/app-down.js +5 -7
- package/lib/commands/app-install.js +14 -7
- package/lib/commands/app-logs.js +13 -10
- package/lib/commands/app-shell.js +4 -1
- package/lib/commands/app-test.js +25 -19
- package/lib/commands/app.js +22 -10
- package/lib/commands/auth-config.js +10 -14
- package/lib/commands/auth-status.js +4 -3
- package/lib/commands/credential-env.js +4 -3
- package/lib/commands/credential-list.js +5 -4
- package/lib/commands/credential-push.js +4 -3
- package/lib/commands/datasource-unified-test-cli.js +495 -0
- package/lib/commands/datasource-unified-test-cli.options.js +149 -0
- package/lib/commands/datasource-validation-cli.js +129 -0
- package/lib/commands/datasource.js +123 -71
- package/lib/commands/deployment-list.js +6 -5
- package/lib/commands/dev-cli-handlers.js +122 -18
- package/lib/commands/dev-down.js +4 -3
- package/lib/commands/dev-init.js +231 -116
- package/lib/commands/dev-show-display.js +473 -0
- package/lib/commands/login-credentials.js +3 -2
- package/lib/commands/login-device.js +4 -3
- package/lib/commands/login.js +5 -4
- package/lib/commands/logout.js +8 -7
- package/lib/commands/parameters-validate.js +54 -0
- package/lib/commands/repair-datasource.js +314 -68
- package/lib/commands/repair-env-template.js +16 -10
- package/lib/commands/repair-rbac.js +25 -19
- package/lib/commands/repair.js +116 -32
- package/lib/commands/secrets-list.js +23 -12
- package/lib/commands/secrets-remove-all.js +220 -0
- package/lib/commands/secrets-remove.js +22 -13
- package/lib/commands/secrets-set.js +21 -12
- package/lib/commands/secrets-validate.js +20 -7
- package/lib/commands/secure.js +10 -9
- package/lib/commands/service-user.js +243 -13
- package/lib/commands/test-e2e-external.js +27 -1
- package/lib/commands/up-common.js +28 -2
- package/lib/commands/up-dataplane.js +31 -18
- package/lib/commands/up-miso.js +19 -29
- package/lib/commands/upload.js +138 -39
- package/lib/commands/wizard-core-helpers.js +1 -1
- package/lib/commands/wizard-dataplane.js +4 -3
- package/lib/commands/wizard-helpers.js +3 -3
- package/lib/commands/wizard.js +2 -2
- package/lib/core/admin-secrets.js +16 -5
- package/lib/core/audit-logger.js +12 -4
- package/lib/core/config-attach-extensions.js +46 -0
- package/lib/core/config-runtime-paths.js +29 -0
- package/lib/core/config.js +59 -58
- package/lib/core/diff.js +3 -2
- package/lib/core/ensure-encryption-key.js +2 -4
- package/lib/core/secrets-ensure-infra.js +77 -0
- package/lib/core/secrets-ensure.js +120 -64
- package/lib/core/secrets-env-write.js +35 -7
- package/lib/core/secrets-infra-placeholder-sync.js +61 -0
- package/lib/core/secrets.js +228 -42
- package/lib/core/templates-env.js +4 -3
- package/lib/core/templates.js +1 -1
- package/lib/datasource/abac-validator.js +148 -0
- package/lib/datasource/deploy.js +75 -53
- package/lib/datasource/field-reference-validator.js +77 -36
- package/lib/datasource/integration-context.js +63 -0
- package/lib/datasource/list.js +8 -7
- package/lib/datasource/log-viewer.js +252 -0
- package/lib/datasource/resolve-app.js +109 -0
- package/lib/datasource/test-e2e.js +95 -155
- package/lib/datasource/test-integration.js +121 -109
- package/lib/datasource/unified-validation-run-body.js +65 -0
- package/lib/datasource/unified-validation-run-post.js +23 -0
- package/lib/datasource/unified-validation-run-resolve.js +43 -0
- package/lib/datasource/unified-validation-run.js +92 -0
- package/lib/datasource/validate.js +162 -15
- package/lib/deployment/deployer.js +4 -3
- package/lib/deployment/environment.js +7 -6
- package/lib/deployment/push.js +17 -8
- package/lib/external-system/delete.js +4 -3
- package/lib/external-system/deploy.js +131 -53
- package/lib/external-system/download-helpers.js +1 -1
- package/lib/external-system/download.js +7 -6
- package/lib/external-system/generator.js +104 -14
- package/lib/external-system/integration-test-dispatch.js +26 -0
- package/lib/external-system/test-execution.js +5 -1
- package/lib/external-system/test-helpers.js +0 -4
- package/lib/external-system/test-system-level-helpers.js +110 -0
- package/lib/external-system/test-system-level.js +83 -44
- package/lib/external-system/test.js +59 -8
- package/lib/generator/builders.js +23 -11
- package/lib/generator/deploy-manifest-azure-kv.js +81 -0
- package/lib/generator/external-controller-manifest.js +3 -3
- package/lib/generator/external.js +23 -11
- package/lib/generator/helpers.js +71 -12
- package/lib/generator/index.js +8 -4
- package/lib/generator/split-readme.js +12 -7
- package/lib/generator/split-variables.js +2 -1
- package/lib/generator/split.js +46 -11
- package/lib/generator/wizard-readme.js +3 -3
- package/lib/generator/wizard.js +16 -13
- package/lib/infrastructure/compose.js +60 -6
- package/lib/infrastructure/helpers.js +238 -51
- package/lib/infrastructure/index.js +64 -37
- package/lib/infrastructure/services.js +21 -15
- package/lib/internal/fs-real-sync.js +104 -0
- package/lib/internal/node-fs.js +98 -0
- package/lib/parameters/database-secret-values.js +173 -0
- package/lib/parameters/infra-kv-discovery.js +121 -0
- package/lib/parameters/infra-parameter-catalog.js +458 -0
- package/lib/parameters/infra-parameter-validate.js +64 -0
- package/lib/schema/application-schema.json +37 -17
- package/lib/schema/datasource-test-run.schema.json +493 -0
- package/lib/schema/deployment-rules.yaml +102 -63
- package/lib/schema/external-datasource.schema.json +1201 -433
- package/lib/schema/external-system.schema.json +181 -5
- package/lib/schema/flag-map-validation-run.json +31 -0
- package/lib/schema/infra-parameter.schema.json +106 -0
- package/lib/schema/infra.parameter.yaml +421 -0
- package/lib/schema/type/credential-auth-templates.json +40 -0
- package/lib/schema/type/document-storage.json +213 -0
- package/lib/schema/type/message-service.json +123 -0
- package/lib/schema/type/vector-store.json +88 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +132 -0
- package/lib/utils/api-error-handler.js +2 -2
- package/lib/utils/api.js +49 -14
- package/lib/utils/app-config-resolver.js +23 -1
- package/lib/utils/app-register-api.js +3 -2
- package/lib/utils/app-register-auth.js +1 -1
- package/lib/utils/app-register-config.js +4 -4
- package/lib/utils/app-register-display.js +3 -2
- package/lib/utils/app-register-validator.js +3 -2
- package/lib/utils/app-run-containers.js +26 -22
- package/lib/utils/app-scoped-config.js +31 -0
- package/lib/utils/app-service-env-from-builder.js +164 -0
- package/lib/utils/build-copy.js +1 -1
- package/lib/utils/build-helpers.js +20 -20
- package/lib/utils/build-resolve-image.js +165 -0
- package/lib/utils/cli-layout-chalk.js +8 -0
- package/lib/utils/cli-test-layout-chalk.js +267 -0
- package/lib/utils/cli-utils.js +88 -11
- package/lib/utils/compose-db-passwords.js +138 -0
- package/lib/utils/compose-generate-docker-compose.js +216 -0
- package/lib/utils/compose-generator.js +197 -291
- package/lib/utils/compose-miso-env.js +18 -0
- package/lib/utils/compose-traefik-ingress-base.js +158 -0
- package/lib/utils/config-paths.js +209 -6
- package/lib/utils/config-scoped-resources-preference.js +41 -0
- package/lib/utils/controller-deployment-outcome.js +68 -0
- package/lib/utils/credential-display.js +2 -2
- package/lib/utils/credential-secrets-env.js +16 -1
- package/lib/utils/dataplane-pipeline-warning.js +4 -3
- package/lib/utils/datasource-test-run-capability-scope.js +43 -0
- package/lib/utils/datasource-test-run-debug-display.js +137 -0
- package/lib/utils/datasource-test-run-debug-slice.js +93 -0
- package/lib/utils/datasource-test-run-display.js +442 -0
- package/lib/utils/datasource-test-run-exit.js +58 -0
- package/lib/utils/datasource-test-run-legacy-adapter.js +93 -0
- package/lib/utils/datasource-test-run-report-version.js +51 -0
- package/lib/utils/datasource-test-run-schema-sync.js +59 -0
- package/lib/utils/datasource-test-run-tty-log.js +81 -0
- package/lib/utils/datasource-validation-watch.js +266 -0
- package/lib/utils/declarative-url-ports.js +47 -0
- package/lib/utils/derive-env-key-from-client-id.js +41 -0
- package/lib/utils/dev-ca-install.js +185 -23
- package/lib/utils/dev-cert-helper.js +266 -17
- package/lib/utils/dev-hosts-helper.js +307 -0
- package/lib/utils/dev-init-cert-hints.js +37 -0
- package/lib/utils/dev-init-health-messages.js +52 -0
- package/lib/utils/dev-init-resolve.js +86 -0
- package/lib/utils/dev-init-ssh-merge.js +65 -0
- package/lib/utils/dev-ssh-config-helper.js +196 -0
- package/lib/utils/dev-user-groups.js +93 -0
- package/lib/utils/docker-build.js +42 -17
- package/lib/utils/docker-exec.js +28 -0
- package/lib/utils/docker-manifest-public-port.js +116 -0
- package/lib/utils/docker-not-running-hint.js +52 -0
- package/lib/utils/docker.js +98 -11
- package/lib/utils/ensure-dev-certs-for-remote-docker.js +192 -0
- package/lib/utils/env-config-loader.js +10 -91
- package/lib/utils/env-copy.js +19 -10
- package/lib/utils/env-map.js +42 -11
- package/lib/utils/env-template.js +2 -2
- package/lib/utils/environment-scoped-resources.js +144 -0
- package/lib/utils/error-formatter.js +125 -9
- package/lib/utils/error-formatters/http-status-errors.js +6 -5
- package/lib/utils/error-formatters/network-errors.js +2 -1
- package/lib/utils/error-formatters/permission-errors.js +2 -1
- package/lib/utils/error-formatters/validation-errors.js +2 -1
- package/lib/utils/external-env-template.js +180 -0
- package/lib/utils/external-readme.js +8 -1
- package/lib/utils/external-system-display.js +277 -136
- package/lib/utils/external-system-local-test-tty.js +389 -0
- package/lib/utils/external-system-readiness-core.js +377 -0
- package/lib/utils/external-system-readiness-deploy-display.js +270 -0
- package/lib/utils/external-system-readiness-display-internals.js +150 -0
- package/lib/utils/external-system-readiness-display.js +186 -0
- package/lib/utils/external-system-test-helpers.js +24 -6
- package/lib/utils/external-system-validators.js +32 -14
- package/lib/utils/health-check-url.js +119 -0
- package/lib/utils/health-check.js +59 -25
- package/lib/utils/help-builder.js +14 -13
- package/lib/utils/image-version.js +4 -8
- package/lib/utils/infra-containers.js +4 -7
- package/lib/utils/infra-env-defaults.js +162 -0
- package/lib/utils/infra-status-display.js +167 -0
- package/lib/utils/infra-status.js +16 -8
- package/lib/utils/local-secrets.js +29 -7
- package/lib/utils/paths.js +136 -48
- package/lib/utils/port-resolver.js +10 -23
- package/lib/utils/redis-env-scope.js +62 -0
- package/lib/utils/register-aifabrix-shell-env.js +204 -0
- package/lib/utils/remote-builder-validation.js +99 -0
- package/lib/utils/remote-dev-auth.js +117 -21
- package/lib/utils/remote-docker-env.js +67 -15
- package/lib/utils/remote-secrets-loader.js +13 -4
- package/lib/utils/resolve-docker-image-ref.js +124 -0
- package/lib/utils/schema-loader.js +22 -9
- package/lib/utils/secrets-bash-kv.js +25 -0
- package/lib/utils/secrets-generator.js +171 -51
- package/lib/utils/secrets-helpers.js +70 -59
- package/lib/utils/secrets-kv-scope.js +60 -0
- package/lib/utils/secrets-utils.js +35 -37
- package/lib/utils/secrets-validation.js +3 -1
- package/lib/utils/secrets-yaml-preserve.js +109 -0
- package/lib/utils/secure-file-permissions.js +91 -0
- package/lib/utils/ssh-key-helper.js +4 -2
- package/lib/utils/template-helpers.js +2 -2
- package/lib/utils/test-log-writer.js +3 -3
- package/lib/utils/token-manager.js +37 -5
- package/lib/utils/url-declarative-public-base.js +188 -0
- package/lib/utils/url-declarative-resolve-build.js +493 -0
- package/lib/utils/url-declarative-resolve-load-doc.js +51 -0
- package/lib/utils/url-declarative-resolve.js +220 -0
- package/lib/utils/url-declarative-token-parse.js +74 -0
- package/lib/utils/url-declarative-url-flags.js +50 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +99 -0
- package/lib/utils/url-public-path-prefix.js +34 -0
- package/lib/utils/urls-local-registry.js +220 -0
- package/lib/utils/validation-report-tty-kit.js +77 -0
- package/lib/utils/validation-run-poll.js +89 -0
- package/lib/utils/validation-run-post-retry.js +73 -0
- package/lib/utils/validation-run-request.js +98 -0
- package/lib/utils/variable-transformer.js +21 -4
- package/lib/utils/yaml-preserve.js +78 -1
- package/lib/validation/datasource-warnings.js +56 -0
- package/lib/validation/env-template-auth.js +50 -2
- package/lib/validation/external-manifest-validator.js +35 -7
- package/lib/validation/validate-display.js +37 -31
- package/lib/validation/validate.js +9 -10
- package/lib/validation/validator-unresolved-placeholders.js +98 -0
- package/lib/validation/validator.js +32 -78
- package/lib/validation/wizard-config-validator.js +2 -1
- package/package.json +11 -3
- package/scripts/check-datasource-test-run-schema-sync.js +34 -0
- package/scripts/diagnose-cli.js +150 -0
- package/scripts/install-local.js +304 -55
- package/templates/README.md +15 -2
- package/templates/applications/dataplane/application.yaml +52 -2
- package/templates/applications/dataplane/env.template +80 -18
- package/templates/applications/dataplane/rbac.yaml +8 -0
- package/templates/applications/keycloak/application.yaml +9 -1
- package/templates/applications/keycloak/env.template +15 -6
- package/templates/applications/miso-controller/application.yaml +10 -2
- package/templates/applications/miso-controller/env.template +55 -14
- package/templates/applications/miso-controller/rbac.yaml +5 -0
- package/templates/external-system/README.md.hbs +20 -7
- package/templates/external-system/deploy.js.hbs +5 -5
- package/templates/external-system/env.template.hbs +22 -0
- package/templates/external-system/external-datasource.yaml.hbs +197 -118
- package/templates/infra/compose.yaml.hbs +20 -4
- package/templates/python/docker-compose.hbs +16 -0
- package/templates/typescript/docker-compose.hbs +16 -0
- package/integration/hubspot/README.md +0 -102
- package/integration/hubspot/env.template +0 -4
- package/integration/hubspot/hubspot-datasource-company.json +0 -541
- package/integration/hubspot/hubspot-datasource-contact.json +0 -639
- package/integration/hubspot/hubspot-datasource-deal.json +0 -588
- package/integration/hubspot/hubspot-datasource-users.json +0 -116
- package/integration/hubspot/test-artifacts/wizard-invalid-missing-source.yaml +0 -2
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-key-test.yaml +0 -5
- package/integration/hubspot/test-artifacts/wizard-valid-for-dimension-path-test.yaml +0 -5
- package/lib/api/external-test.api.js +0 -111
- package/lib/schema/env-config.yaml +0 -43
- /package/integration/{hubspot → hubspot-test}/companies.json +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-app-name.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-artifacts/wizard-invalid-missing-app.yaml +0 -0
- /package/integration/{hubspot → hubspot-test}/test-dataplane-down-helpers.js +0 -0
package/lib/commands/repair.js
CHANGED
|
@@ -12,18 +12,19 @@
|
|
|
12
12
|
/* eslint-disable max-lines -- Repair flow with auth, normalization, and steps */
|
|
13
13
|
|
|
14
14
|
'use strict';
|
|
15
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
15
16
|
|
|
16
17
|
const path = require('path');
|
|
17
18
|
const fs = require('fs');
|
|
18
19
|
const chalk = require('chalk');
|
|
19
|
-
const
|
|
20
|
-
const {
|
|
21
|
-
const { resolveApplicationConfigPath } = require('../utils/app-config-resolver');
|
|
20
|
+
const { detectAppType, getDeployJsonPath } = require('../utils/paths');
|
|
21
|
+
const { resolveApplicationConfigPath, resolveRbacPath } = require('../utils/app-config-resolver');
|
|
22
22
|
const { loadConfigFile, writeConfigFile, writeYamlPreservingComments, isYamlPath } = require('../utils/config-format');
|
|
23
23
|
const { systemKeyToKvPrefix, securityKeyToVar } = require('../utils/credential-secrets-env');
|
|
24
24
|
const logger = require('../utils/logger');
|
|
25
25
|
const generator = require('../generator');
|
|
26
26
|
const { repairEnvTemplate, normalizeSystemFileAuthAndConfig } = require('./repair-env-template');
|
|
27
|
+
const { generateReadmeFromDeployJson } = require('../generator/split-readme');
|
|
27
28
|
const { repairDatasourceFile } = require('./repair-datasource');
|
|
28
29
|
const { mergeRbacFromDatasources } = require('./repair-rbac');
|
|
29
30
|
const { discoverIntegrationFiles, buildEffectiveDatasourceFiles } = require('./repair-internal');
|
|
@@ -32,6 +33,22 @@ const { normalizeDatasourceKeysAndFilenames } = require('./repair-datasource-key
|
|
|
32
33
|
/** Allowed authentication methods for repair --auth (matches external-system schema) */
|
|
33
34
|
const ALLOWED_AUTH = ['oauth2', 'aad', 'apikey', 'basic', 'queryParam', 'oidc', 'hmac', 'none'];
|
|
34
35
|
|
|
36
|
+
/**
|
|
37
|
+
* README "Files" section should match integration config format on disk (YAML vs JSON).
|
|
38
|
+
* @param {string} appPath - Integration directory
|
|
39
|
+
* @returns {string} '.yaml' or '.json'
|
|
40
|
+
*/
|
|
41
|
+
function inferExternalReadmeFileExt(appPath) {
|
|
42
|
+
try {
|
|
43
|
+
const configPath = resolveApplicationConfigPath(appPath);
|
|
44
|
+
const ext = path.extname(configPath).toLowerCase();
|
|
45
|
+
if (ext === '.yaml' || ext === '.yml') return '.yaml';
|
|
46
|
+
} catch {
|
|
47
|
+
/* use default */
|
|
48
|
+
}
|
|
49
|
+
return '.json';
|
|
50
|
+
}
|
|
51
|
+
|
|
35
52
|
/**
|
|
36
53
|
* Extracts roles and permissions from system object for rbac.yaml
|
|
37
54
|
* @param {Object} system - Parsed system config
|
|
@@ -249,6 +266,11 @@ function normalizedAuthPartFromConfigName(name, systemKey) {
|
|
|
249
266
|
const rest = n.slice(kvPrefix.length);
|
|
250
267
|
return rest.toUpperCase().replace(/_/g, '');
|
|
251
268
|
}
|
|
269
|
+
// Old-style or other KV_* names: treat last segment as var (e.g. KV_HUBSPOT_CLIENTID → CLIENTID)
|
|
270
|
+
if (n.toUpperCase().startsWith('KV_')) {
|
|
271
|
+
const parts = n.split('_').filter(Boolean);
|
|
272
|
+
if (parts.length >= 2) return parts[parts.length - 1].toUpperCase();
|
|
273
|
+
}
|
|
252
274
|
return n.toUpperCase().replace(/_/g, '');
|
|
253
275
|
}
|
|
254
276
|
|
|
@@ -273,26 +295,25 @@ function removeAuthVarsFromConfiguration(systemParsed, systemKey, dryRun, change
|
|
|
273
295
|
return true;
|
|
274
296
|
}
|
|
275
297
|
|
|
276
|
-
function createRbacFromSystemIfNeeded(appPath, systemFilePath, systemParsed, dryRun, changes) {
|
|
277
|
-
|
|
278
|
-
const rbacYmlPath = path.join(appPath, 'rbac.yml');
|
|
279
|
-
if (fs.existsSync(rbacPath) || fs.existsSync(rbacYmlPath)) return false;
|
|
298
|
+
function createRbacFromSystemIfNeeded(appPath, systemFilePath, systemParsed, dryRun, changes, format) {
|
|
299
|
+
if (resolveRbacPath(appPath)) return false;
|
|
280
300
|
const rbacFromSystem = extractRbacFromSystem(systemParsed);
|
|
281
301
|
if (!rbacFromSystem) return false;
|
|
282
302
|
if (!dryRun) {
|
|
283
|
-
const
|
|
284
|
-
|
|
303
|
+
const rbacFormat = format === 'json' ? 'json' : 'yaml';
|
|
304
|
+
const defaultRbacPath = path.join(appPath, rbacFormat === 'json' ? 'rbac.json' : 'rbac.yaml');
|
|
305
|
+
writeConfigFile(defaultRbacPath, rbacFromSystem, rbacFormat);
|
|
285
306
|
delete systemParsed.roles;
|
|
286
307
|
delete systemParsed.permissions;
|
|
287
308
|
writeConfigFile(systemFilePath, systemParsed);
|
|
288
309
|
}
|
|
289
310
|
changes.push('Created rbac.yaml from system roles/permissions');
|
|
290
|
-
changes.push('Removed roles/permissions from system file (now in rbac
|
|
311
|
+
changes.push('Removed roles/permissions from system file (now in rbac file)');
|
|
291
312
|
return true;
|
|
292
313
|
}
|
|
293
314
|
|
|
294
315
|
/**
|
|
295
|
-
* Runs datasource repair for each file (dimensions, metadataSchema
|
|
316
|
+
* Runs datasource repair for each file (v2.4 root dimensions, metadataSchema; optional expose/sync/test).
|
|
296
317
|
* @param {string} appPath - Application path
|
|
297
318
|
* @param {string[]} datasourceFiles - Datasource file names
|
|
298
319
|
* @param {Object} options - { expose?: boolean, sync?: boolean, test?: boolean }
|
|
@@ -338,13 +359,44 @@ async function regenerateManifest(appName, appPath, changes) {
|
|
|
338
359
|
}
|
|
339
360
|
}
|
|
340
361
|
|
|
362
|
+
/**
|
|
363
|
+
* Regenerates README.md from deployment manifest when options.doc is set.
|
|
364
|
+
* @param {string} appName - Application name
|
|
365
|
+
* @param {string} appPath - Application path
|
|
366
|
+
* @param {Object} options - Options (doc, dryRun)
|
|
367
|
+
* @param {string[]} changes - Array to append change messages to
|
|
368
|
+
* @returns {Promise<boolean>} True if README was regenerated
|
|
369
|
+
*/
|
|
370
|
+
async function regenerateReadmeIfRequested(appName, appPath, options, changes) {
|
|
371
|
+
if (!options.doc) return false;
|
|
372
|
+
const deployJsonPath = getDeployJsonPath(appName, 'external', true);
|
|
373
|
+
if (!fs.existsSync(deployJsonPath) && !options.dryRun) {
|
|
374
|
+
await regenerateManifest(appName, appPath, changes);
|
|
375
|
+
}
|
|
376
|
+
if (!fs.existsSync(deployJsonPath)) return false;
|
|
377
|
+
try {
|
|
378
|
+
const deployment = JSON.parse(fs.readFileSync(deployJsonPath, 'utf8'));
|
|
379
|
+
const fileExt = inferExternalReadmeFileExt(appPath);
|
|
380
|
+
const readmeContent = generateReadmeFromDeployJson(deployment, { fileExt });
|
|
381
|
+
const readmePath = path.join(appPath, 'README.md');
|
|
382
|
+
if (!options.dryRun) {
|
|
383
|
+
fs.writeFileSync(readmePath, readmeContent, { mode: 0o644, encoding: 'utf8' });
|
|
384
|
+
}
|
|
385
|
+
changes.push('Regenerated README.md from deployment manifest');
|
|
386
|
+
return true;
|
|
387
|
+
} catch (err) {
|
|
388
|
+
logger.log(chalk.yellow(`⚠ Could not regenerate README: ${err.message}`));
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
341
393
|
function persistChangesAndRegenerate(configPath, variables, appName, appPath, changes, originalYamlContent) {
|
|
342
394
|
if (originalYamlContent !== null && originalYamlContent !== undefined && typeof originalYamlContent === 'string' && isYamlPath(configPath)) {
|
|
343
395
|
writeYamlPreservingComments(configPath, originalYamlContent, variables);
|
|
344
396
|
} else {
|
|
345
397
|
writeConfigFile(configPath, variables);
|
|
346
398
|
}
|
|
347
|
-
logger.log(
|
|
399
|
+
logger.log(formatSuccessLine(`Updated ${path.basename(configPath)}`));
|
|
348
400
|
changes.forEach(c => logger.log(chalk.gray(` ${c}`)));
|
|
349
401
|
return regenerateManifest(appName, appPath, changes);
|
|
350
402
|
}
|
|
@@ -410,7 +462,7 @@ function runRepairSteps(ctx) {
|
|
|
410
462
|
ctx.appPath, ctx.datasourceFiles, ctx.systemKey, ctx.dryRun, ctx.changes
|
|
411
463
|
);
|
|
412
464
|
const rbacFileCreated = createRbacFromSystemIfNeeded(
|
|
413
|
-
ctx.appPath, ctx.systemFilePath, ctx.systemParsed, ctx.dryRun, ctx.changes
|
|
465
|
+
ctx.appPath, ctx.systemFilePath, ctx.systemParsed, ctx.dryRun, ctx.changes, ctx.format
|
|
414
466
|
);
|
|
415
467
|
const envTemplateRepaired = repairEnvTemplate(
|
|
416
468
|
ctx.appPath, ctx.systemParsed, ctx.systemKey, ctx.dryRun, ctx.changes
|
|
@@ -431,7 +483,8 @@ function runRepairSteps(ctx) {
|
|
|
431
483
|
* @param {string} appName - Application/integration name
|
|
432
484
|
* @param {Object} [options] - Options
|
|
433
485
|
* @param {boolean} [options.dryRun] - If true, only report changes; do not write
|
|
434
|
-
* @
|
|
486
|
+
* @param {boolean} [options.doc] - If true, regenerate README.md from deployment manifest
|
|
487
|
+
* @returns {Promise<{ updated: boolean, changes: string[], systemFiles: string[], datasourceFiles: string[], appKeyFixed?: boolean, datasourceKeysFixed?: boolean, rbacFileCreated?: boolean, envTemplateRepaired?: boolean, manifestRegenerated?: boolean, readmeRegenerated?: boolean }>}
|
|
435
488
|
*/
|
|
436
489
|
/**
|
|
437
490
|
* Loads application config and discovers integration files; validates at least one system file exists.
|
|
@@ -453,7 +506,36 @@ function loadConfigAndDiscover(appPath, configPath) {
|
|
|
453
506
|
return { variables, originalYamlContent, systemFiles, datasourceFiles };
|
|
454
507
|
}
|
|
455
508
|
|
|
456
|
-
|
|
509
|
+
/**
|
|
510
|
+
* Builds the repair result object from steps and flags.
|
|
511
|
+
* @param {Object} steps - Result of runRepairSteps
|
|
512
|
+
* @param {boolean} anyUpdated - Whether any repair made changes
|
|
513
|
+
* @param {boolean} manifestRegenerated - Whether manifest was regenerated
|
|
514
|
+
* @param {boolean} readmeRegenerated - Whether README was regenerated
|
|
515
|
+
* @param {{ changes: string[], systemFiles: string[], datasourceFiles: string[] }} ctx - changes and file lists
|
|
516
|
+
* @returns {Object} Combined result object
|
|
517
|
+
*/
|
|
518
|
+
function buildRepairResult(steps, anyUpdated, manifestRegenerated, readmeRegenerated, ctx) {
|
|
519
|
+
return Object.assign(
|
|
520
|
+
{ updated: anyUpdated, changes: ctx.changes, systemFiles: ctx.systemFiles, datasourceFiles: ctx.datasourceFiles },
|
|
521
|
+
{
|
|
522
|
+
appKeyFixed: steps.appKeyFixed,
|
|
523
|
+
datasourceKeysFixed: steps.datasourceKeysFixed,
|
|
524
|
+
rbacFileCreated: steps.rbacFileCreated,
|
|
525
|
+
envTemplateRepaired: steps.envTemplateRepaired,
|
|
526
|
+
manifestRegenerated,
|
|
527
|
+
readmeRegenerated
|
|
528
|
+
}
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Validates repair inputs and resolves app path and config path.
|
|
534
|
+
* @param {string} appName - Application name
|
|
535
|
+
* @param {Object} options - Command options (auth)
|
|
536
|
+
* @returns {Promise<{ appPath: string, configPath: string, dryRun: boolean, authOption: string|undefined }>}
|
|
537
|
+
*/
|
|
538
|
+
async function validateAndResolveRepairPaths(appName, options) {
|
|
457
539
|
if (!appName || typeof appName !== 'string') throw new Error('App name is required');
|
|
458
540
|
const { dryRun = false, auth: authOption } = options;
|
|
459
541
|
if (authOption !== undefined && authOption !== null && typeof authOption !== 'string') {
|
|
@@ -463,6 +545,11 @@ async function repairExternalIntegration(appName, options = {}) {
|
|
|
463
545
|
if (!isExternal) throw new Error(`App '${appName}' is not an external integration`);
|
|
464
546
|
const configPath = resolveApplicationConfigPath(appPath);
|
|
465
547
|
if (!fs.existsSync(configPath)) throw new Error(`Application config not found: ${configPath}`);
|
|
548
|
+
return { appPath, configPath, dryRun, authOption };
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
async function repairExternalIntegration(appName, options = {}) {
|
|
552
|
+
const { appPath, configPath, dryRun, authOption } = await validateAndResolveRepairPaths(appName, options);
|
|
466
553
|
|
|
467
554
|
const { variables, originalYamlContent, systemFiles, datasourceFiles: initialDatasourceFiles } = loadConfigAndDiscover(appPath, configPath);
|
|
468
555
|
const changes = [];
|
|
@@ -486,30 +573,27 @@ async function repairExternalIntegration(appName, options = {}) {
|
|
|
486
573
|
datasourceFiles,
|
|
487
574
|
dryRun,
|
|
488
575
|
changes,
|
|
489
|
-
auth: authOption
|
|
576
|
+
auth: authOption,
|
|
577
|
+
format: options.format === 'json' ? 'json' : 'yaml'
|
|
490
578
|
});
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
579
|
+
const datasourceRepairUpdated = runDatasourceRepairs(appPath, datasourceFiles, {
|
|
580
|
+
expose: Boolean(options.expose),
|
|
581
|
+
sync: Boolean(options.sync),
|
|
582
|
+
test: Boolean(options.test)
|
|
583
|
+
}, dryRun, changes);
|
|
494
584
|
const rbacMergeUpdated = options.rbac
|
|
495
|
-
? mergeRbacFromDatasources(appPath, systemParsed, datasourceFiles, extractRbacFromSystem,
|
|
585
|
+
? mergeRbacFromDatasources(appPath, systemParsed, datasourceFiles, extractRbacFromSystem, {
|
|
586
|
+
format: options.format === 'json' ? 'json' : 'yaml',
|
|
587
|
+
dryRun,
|
|
588
|
+
changes
|
|
589
|
+
})
|
|
496
590
|
: false;
|
|
497
591
|
const anyUpdated = keysNormalized || steps.updated || datasourceRepairUpdated || rbacMergeUpdated;
|
|
498
592
|
const manifestRegenerated = (anyUpdated && !dryRun)
|
|
499
593
|
? await persistChangesAndRegenerate(configPath, variables, appName, appPath, changes, originalYamlContent)
|
|
500
594
|
: false;
|
|
501
|
-
|
|
502
|
-
return {
|
|
503
|
-
updated: anyUpdated,
|
|
504
|
-
changes,
|
|
505
|
-
systemFiles,
|
|
506
|
-
datasourceFiles,
|
|
507
|
-
appKeyFixed: steps.appKeyFixed,
|
|
508
|
-
datasourceKeysFixed: steps.datasourceKeysFixed,
|
|
509
|
-
rbacFileCreated: steps.rbacFileCreated,
|
|
510
|
-
envTemplateRepaired: steps.envTemplateRepaired,
|
|
511
|
-
manifestRegenerated
|
|
512
|
-
};
|
|
595
|
+
const readmeRegenerated = await regenerateReadmeIfRequested(appName, appPath, options, changes);
|
|
596
|
+
return buildRepairResult(steps, anyUpdated, manifestRegenerated, readmeRegenerated, { changes, systemFiles, datasourceFiles });
|
|
513
597
|
}
|
|
514
598
|
|
|
515
599
|
module.exports = {
|
|
@@ -11,7 +11,7 @@ const chalk = require('chalk');
|
|
|
11
11
|
const logger = require('../utils/logger');
|
|
12
12
|
const { getAifabrixSecretsPath } = require('../core/config');
|
|
13
13
|
const pathsUtil = require('../utils/paths');
|
|
14
|
-
const
|
|
14
|
+
const remoteDevAuth = require('../utils/remote-dev-auth');
|
|
15
15
|
const devApi = require('../api/dev.api');
|
|
16
16
|
|
|
17
17
|
const REMOTE_NOT_CONFIGURED_MSG = 'Remote server is not configured. Set remote-server and run "aifabrix dev init" first.';
|
|
@@ -38,8 +38,8 @@ function listKeysAndValuesFromFile(filePath) {
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
const KEY_COL_WIDTH =
|
|
42
|
-
const TABLE_SEPARATOR_LENGTH =
|
|
41
|
+
const KEY_COL_WIDTH = 55;
|
|
42
|
+
const TABLE_SEPARATOR_LENGTH = 130;
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* Log a list of secret keys and values as a table (header, column headers, separator, rows).
|
|
@@ -70,19 +70,26 @@ function logKeyValueList(emptyMessage, title, items) {
|
|
|
70
70
|
* @returns {Promise<void>}
|
|
71
71
|
*/
|
|
72
72
|
async function listSharedSecrets(generalSecretsPath) {
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
const target = await remoteDevAuth.resolveSharedSecretsEndpoint(generalSecretsPath);
|
|
74
|
+
if (remoteDevAuth.isRemoteSecretsUrl(target)) {
|
|
75
|
+
const auth = await remoteDevAuth.getRemoteDevAuth();
|
|
75
76
|
if (!auth) {
|
|
76
77
|
throw new Error(REMOTE_NOT_CONFIGURED_MSG);
|
|
77
78
|
}
|
|
78
|
-
const items = await devApi.listSecrets(
|
|
79
|
+
const items = await devApi.listSecrets(
|
|
80
|
+
auth.serverUrl,
|
|
81
|
+
auth.clientCertPem,
|
|
82
|
+
auth.serverCaPem || undefined,
|
|
83
|
+
target
|
|
84
|
+
);
|
|
79
85
|
const keyValues = items.map(i => ({ key: i.name || i.key || '', value: (i.value !== null && i.value !== undefined) ? String(i.value) : '' }));
|
|
80
|
-
|
|
86
|
+
const { title, emptyMessage } = remoteDevAuth.getSharedSecretsRemoteListLabels(target);
|
|
87
|
+
logKeyValueList(emptyMessage, title, keyValues);
|
|
81
88
|
return;
|
|
82
89
|
}
|
|
83
|
-
const resolvedPath = path.isAbsolute(
|
|
84
|
-
?
|
|
85
|
-
: path.resolve(process.cwd(),
|
|
90
|
+
const resolvedPath = path.isAbsolute(target)
|
|
91
|
+
? target
|
|
92
|
+
: path.resolve(process.cwd(), target);
|
|
86
93
|
const keyValues = listKeysAndValuesFromFile(resolvedPath);
|
|
87
94
|
const fileTitle = `Shared secrets (file: ${resolvedPath})`;
|
|
88
95
|
logKeyValueList('No shared secrets in file.', fileTitle, keyValues);
|
|
@@ -90,9 +97,13 @@ async function listSharedSecrets(generalSecretsPath) {
|
|
|
90
97
|
|
|
91
98
|
/** List user secrets and log key and value. */
|
|
92
99
|
function listUserSecrets() {
|
|
93
|
-
const userSecretsPath =
|
|
100
|
+
const userSecretsPath = pathsUtil.getPrimaryUserSecretsLocalPath();
|
|
94
101
|
const keyValues = listKeysAndValuesFromFile(userSecretsPath);
|
|
95
|
-
logKeyValueList(
|
|
102
|
+
logKeyValueList(
|
|
103
|
+
`No user secrets (file: ${userSecretsPath}). Use "aifabrix secret set <KEY> <value>" or resolve/up-infra to populate.`,
|
|
104
|
+
'User secrets',
|
|
105
|
+
keyValues
|
|
106
|
+
);
|
|
96
107
|
}
|
|
97
108
|
|
|
98
109
|
/**
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview aifabrix secret remove-all – remove every secret (user file, shared file, or remote API)
|
|
4
|
+
* @author AI Fabrix Team
|
|
5
|
+
* @version 2.0.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const readline = require('readline');
|
|
11
|
+
const yaml = require('js-yaml');
|
|
12
|
+
const chalk = require('chalk');
|
|
13
|
+
const logger = require('../utils/logger');
|
|
14
|
+
const { getAifabrixSecretsPath } = require('../core/config');
|
|
15
|
+
const pathsUtil = require('../utils/paths');
|
|
16
|
+
const remoteDevAuth = require('../utils/remote-dev-auth');
|
|
17
|
+
const devApi = require('../api/dev.api');
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {string} question
|
|
21
|
+
* @returns {Promise<string>}
|
|
22
|
+
*/
|
|
23
|
+
function promptLine(question) {
|
|
24
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
25
|
+
return new Promise(resolve => {
|
|
26
|
+
rl.question(question, answer => {
|
|
27
|
+
rl.close();
|
|
28
|
+
resolve((answer || '').trim());
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Read secret keys from a YAML secrets file.
|
|
35
|
+
* @param {string} filePath - Absolute path
|
|
36
|
+
* @returns {string[]} Sorted unique keys
|
|
37
|
+
*/
|
|
38
|
+
function listKeysFromYamlFile(filePath) {
|
|
39
|
+
if (!fs.existsSync(filePath)) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const content = fs.readFileSync(filePath, 'utf8');
|
|
44
|
+
const data = yaml.load(content) || {};
|
|
45
|
+
if (typeof data !== 'object' || Array.isArray(data)) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
return Object.keys(data).sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }));
|
|
49
|
+
} catch {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Write an empty secrets map to file (same options as single-key remove).
|
|
56
|
+
* @param {string} filePath - Absolute path
|
|
57
|
+
*/
|
|
58
|
+
function writeEmptySecretsFile(filePath) {
|
|
59
|
+
const yamlContent = yaml.dump({}, { indent: 2, lineWidth: -1, noRefs: true, sortKeys: false });
|
|
60
|
+
fs.writeFileSync(filePath, yamlContent, { mode: 0o600 });
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* @param {boolean} skipPrompt - When true (--yes), skip confirmation
|
|
65
|
+
* @param {string} whereLabel - Human-readable target
|
|
66
|
+
* @param {number} count - Number of keys
|
|
67
|
+
* @returns {Promise<boolean>}
|
|
68
|
+
*/
|
|
69
|
+
async function confirmRemoveAll(skipPrompt, whereLabel, count) {
|
|
70
|
+
if (skipPrompt) {
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
logger.log(chalk.yellow(`\nThis will permanently remove all ${count} secret key(s) from ${whereLabel}.`));
|
|
74
|
+
logger.log(chalk.gray('This cannot be undone.\n'));
|
|
75
|
+
const answer = (await promptLine(chalk.bold('Type "yes" to confirm (anything else cancels): '))).toLowerCase();
|
|
76
|
+
return answer === 'yes';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {Object} auth - Remote dev auth (serverUrl, clientCertPem, serverCaPem)
|
|
81
|
+
* @param {string} target - Secrets endpoint URL
|
|
82
|
+
* @returns {Promise<string[]>}
|
|
83
|
+
*/
|
|
84
|
+
async function listRemoteSecretKeys(auth, target) {
|
|
85
|
+
const items = await devApi.listSecrets(
|
|
86
|
+
auth.serverUrl,
|
|
87
|
+
auth.clientCertPem,
|
|
88
|
+
auth.serverCaPem || undefined,
|
|
89
|
+
target
|
|
90
|
+
);
|
|
91
|
+
return (Array.isArray(items) ? items : [])
|
|
92
|
+
.map(i => i.name || i.key || '')
|
|
93
|
+
.filter(k => typeof k === 'string' && k.length > 0)
|
|
94
|
+
.sort((a, b) => a.localeCompare(b, undefined, { sensitivity: 'base' }));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @param {string} target - Secrets endpoint URL
|
|
99
|
+
* @returns {string}
|
|
100
|
+
*/
|
|
101
|
+
function labelForRemoteSharedSecrets(target) {
|
|
102
|
+
const host = remoteDevAuth.getSharedSecretsRemoteHostname(target);
|
|
103
|
+
return host ? `shared secrets (remote - ${host})` : 'shared secrets (remote)';
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @param {Object} auth
|
|
108
|
+
* @param {string[]} keys
|
|
109
|
+
* @param {string} target
|
|
110
|
+
* @returns {Promise<void>}
|
|
111
|
+
*/
|
|
112
|
+
async function deleteRemoteSecretKeys(auth, keys, target) {
|
|
113
|
+
const ca = auth.serverCaPem || undefined;
|
|
114
|
+
for (const key of keys) {
|
|
115
|
+
await devApi.deleteSecret(auth.serverUrl, auth.clientCertPem, key, ca, target);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Remove every shared secret via remote API.
|
|
121
|
+
* @param {string} target - Resolved secrets endpoint URL
|
|
122
|
+
* @param {Object} options - { yes?: boolean }
|
|
123
|
+
* @returns {Promise<void>}
|
|
124
|
+
*/
|
|
125
|
+
async function removeAllRemoteSharedSecrets(target, options) {
|
|
126
|
+
const auth = await remoteDevAuth.getRemoteDevAuth();
|
|
127
|
+
if (!auth) {
|
|
128
|
+
throw new Error('Remote server not configured or certificate missing. Run "aifabrix dev init" first.');
|
|
129
|
+
}
|
|
130
|
+
const keys = await listRemoteSecretKeys(auth, target);
|
|
131
|
+
if (keys.length === 0) {
|
|
132
|
+
logger.log(chalk.gray('No shared secrets to remove.'));
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const where = labelForRemoteSharedSecrets(target);
|
|
136
|
+
const ok = await confirmRemoveAll(!!options.yes, where, keys.length);
|
|
137
|
+
if (!ok) {
|
|
138
|
+
logger.log(chalk.gray('Cancelled. No secrets were removed.'));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
await deleteRemoteSecretKeys(auth, keys, target);
|
|
142
|
+
logger.log(formatSuccessLine(`Removed ${keys.length} secret key(s) from ${where}.`));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Remove every key from a shared secrets YAML file.
|
|
147
|
+
* @param {string} resolvedPath - Absolute file path
|
|
148
|
+
* @param {Object} options - { yes?: boolean }
|
|
149
|
+
* @returns {Promise<void>}
|
|
150
|
+
*/
|
|
151
|
+
async function removeAllSharedFileSecrets(resolvedPath, options) {
|
|
152
|
+
const keys = listKeysFromYamlFile(resolvedPath);
|
|
153
|
+
if (keys.length === 0) {
|
|
154
|
+
logger.log(chalk.gray('No shared secrets to remove.'));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const ok = await confirmRemoveAll(!!options.yes, `shared secrets file (${resolvedPath})`, keys.length);
|
|
158
|
+
if (!ok) {
|
|
159
|
+
logger.log(chalk.gray('Cancelled. No secrets were removed.'));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
writeEmptySecretsFile(resolvedPath);
|
|
163
|
+
logger.log(formatSuccessLine(`Removed ${keys.length} secret key(s) from shared secrets file.`));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Remove every key from shared store (remote API or file).
|
|
168
|
+
* @param {string} generalSecretsPath - Path or URL from config
|
|
169
|
+
* @param {Object} options - { yes?: boolean }
|
|
170
|
+
* @returns {Promise<void>}
|
|
171
|
+
*/
|
|
172
|
+
async function removeAllSharedSecrets(generalSecretsPath, options) {
|
|
173
|
+
const target = await remoteDevAuth.resolveSharedSecretsEndpoint(generalSecretsPath);
|
|
174
|
+
if (remoteDevAuth.isRemoteSecretsUrl(target)) {
|
|
175
|
+
await removeAllRemoteSharedSecrets(target, options);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const resolvedPath = path.isAbsolute(target) ? target : path.resolve(process.cwd(), target);
|
|
179
|
+
await removeAllSharedFileSecrets(resolvedPath, options);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @param {Object} options - { yes?: boolean }
|
|
184
|
+
* @returns {Promise<void>}
|
|
185
|
+
*/
|
|
186
|
+
async function removeAllUserSecrets(options) {
|
|
187
|
+
const userSecretsPath = pathsUtil.getPrimaryUserSecretsLocalPath();
|
|
188
|
+
const keys = listKeysFromYamlFile(userSecretsPath);
|
|
189
|
+
if (keys.length === 0) {
|
|
190
|
+
logger.log(chalk.gray('No user secrets to remove.'));
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
const ok = await confirmRemoveAll(!!options.yes, `user secrets (${userSecretsPath})`, keys.length);
|
|
194
|
+
if (!ok) {
|
|
195
|
+
logger.log(chalk.gray('Cancelled. No secrets were removed.'));
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
writeEmptySecretsFile(userSecretsPath);
|
|
199
|
+
logger.log(formatSuccessLine(`Removed ${keys.length} secret key(s) from user secrets.`));
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Handle secret remove-all command.
|
|
204
|
+
* @param {Object} options - { shared?: boolean, yes?: boolean }
|
|
205
|
+
* @returns {Promise<void>}
|
|
206
|
+
*/
|
|
207
|
+
async function handleSecretsRemoveAll(options) {
|
|
208
|
+
const isShared = options.shared || options['shared'] || false;
|
|
209
|
+
if (!isShared) {
|
|
210
|
+
await removeAllUserSecrets(options);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const generalSecretsPath = await getAifabrixSecretsPath();
|
|
214
|
+
if (!generalSecretsPath) {
|
|
215
|
+
throw new Error('Shared secrets not configured. Set aifabrix-secrets in config.yaml.');
|
|
216
|
+
}
|
|
217
|
+
await removeAllSharedSecrets(generalSecretsPath, options);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
module.exports = { handleSecretsRemoveAll };
|
|
@@ -4,14 +4,14 @@
|
|
|
4
4
|
* @version 2.0.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
const { formatSuccessLine } = require('../utils/cli-test-layout-chalk');
|
|
7
8
|
const path = require('path');
|
|
8
9
|
const fs = require('fs');
|
|
9
10
|
const yaml = require('js-yaml');
|
|
10
|
-
const chalk = require('chalk');
|
|
11
11
|
const logger = require('../utils/logger');
|
|
12
12
|
const { getAifabrixSecretsPath } = require('../core/config');
|
|
13
13
|
const pathsUtil = require('../utils/paths');
|
|
14
|
-
const
|
|
14
|
+
const remoteDevAuth = require('../utils/remote-dev-auth');
|
|
15
15
|
const devApi = require('../api/dev.api');
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -33,7 +33,7 @@ function removeKeyFromFile(key, filePath) {
|
|
|
33
33
|
throw new Error(`Secret '${key}' not found.`);
|
|
34
34
|
}
|
|
35
35
|
delete data[key];
|
|
36
|
-
const yamlContent = yaml.dump(data, { indent: 2, lineWidth:
|
|
36
|
+
const yamlContent = yaml.dump(data, { indent: 2, lineWidth: -1, noRefs: true, sortKeys: false });
|
|
37
37
|
fs.writeFileSync(filePath, yamlContent, { mode: 0o600 });
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -44,27 +44,36 @@ function removeKeyFromFile(key, filePath) {
|
|
|
44
44
|
* @returns {Promise<void>}
|
|
45
45
|
*/
|
|
46
46
|
async function removeSharedSecret(key, generalSecretsPath) {
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
const target = await remoteDevAuth.resolveSharedSecretsEndpoint(generalSecretsPath);
|
|
48
|
+
if (remoteDevAuth.isRemoteSecretsUrl(target)) {
|
|
49
|
+
const auth = await remoteDevAuth.getRemoteDevAuth();
|
|
49
50
|
if (!auth) {
|
|
50
51
|
throw new Error('Remote server not configured or certificate missing. Run "aifabrix dev init" first.');
|
|
51
52
|
}
|
|
52
53
|
try {
|
|
53
|
-
await devApi.deleteSecret(
|
|
54
|
+
await devApi.deleteSecret(
|
|
55
|
+
auth.serverUrl,
|
|
56
|
+
auth.clientCertPem,
|
|
57
|
+
key,
|
|
58
|
+
auth.serverCaPem || undefined,
|
|
59
|
+
target
|
|
60
|
+
);
|
|
54
61
|
} catch (err) {
|
|
55
62
|
if (err.status === 404) {
|
|
56
63
|
throw new Error(`Secret '${key}' not found.`);
|
|
57
64
|
}
|
|
58
65
|
throw err;
|
|
59
66
|
}
|
|
60
|
-
|
|
67
|
+
const host = remoteDevAuth.getSharedSecretsRemoteHostname(target);
|
|
68
|
+
const where = host ? `shared secrets (remote - ${host})` : 'shared secrets (remote)';
|
|
69
|
+
logger.log(formatSuccessLine(`Secret '${key}' removed from ${where}.`));
|
|
61
70
|
return;
|
|
62
71
|
}
|
|
63
|
-
const resolvedPath = path.isAbsolute(
|
|
64
|
-
?
|
|
65
|
-
: path.resolve(process.cwd(),
|
|
72
|
+
const resolvedPath = path.isAbsolute(target)
|
|
73
|
+
? target
|
|
74
|
+
: path.resolve(process.cwd(), target);
|
|
66
75
|
removeKeyFromFile(key, resolvedPath);
|
|
67
|
-
logger.log(
|
|
76
|
+
logger.log(formatSuccessLine(`Secret '${key}' removed from shared secrets file.`));
|
|
68
77
|
}
|
|
69
78
|
|
|
70
79
|
/**
|
|
@@ -88,9 +97,9 @@ async function handleSecretsRemove(key, options) {
|
|
|
88
97
|
}
|
|
89
98
|
await removeSharedSecret(key, generalSecretsPath);
|
|
90
99
|
} else {
|
|
91
|
-
const userSecretsPath =
|
|
100
|
+
const userSecretsPath = pathsUtil.getPrimaryUserSecretsLocalPath();
|
|
92
101
|
removeKeyFromFile(key, userSecretsPath);
|
|
93
|
-
logger.log(
|
|
102
|
+
logger.log(formatSuccessLine(`Secret '${key}' removed from user secrets.`));
|
|
94
103
|
}
|
|
95
104
|
}
|
|
96
105
|
|