@credibledata/cred-cli 0.0.103 → 0.0.105
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/README.md +106 -1
- package/dist/agent-contract.spec.js +548 -0
- package/dist/agent-contract.spec.js.map +1 -0
- package/dist/browser.js +72 -0
- package/dist/browser.js.map +1 -0
- package/dist/browser.spec.js +125 -0
- package/dist/browser.spec.js.map +1 -0
- package/dist/client/api.js +4137 -1159
- package/dist/client/api.js.map +1 -1
- package/dist/client-codeassist/api.js +476 -0
- package/dist/client-codeassist/api.js.map +1 -0
- package/dist/client-codeassist/base.js +69 -0
- package/dist/client-codeassist/base.js.map +1 -0
- package/dist/client-codeassist/common.js +162 -0
- package/dist/client-codeassist/common.js.map +1 -0
- package/dist/client-codeassist/configuration.js +44 -0
- package/dist/client-codeassist/configuration.js.map +1 -0
- package/dist/client-codeassist/index.js +32 -0
- package/dist/client-codeassist/index.js.map +1 -0
- package/dist/clientconfiguration.js +17 -289
- package/dist/clientconfiguration.js.map +1 -1
- package/dist/clientconfiguration.spec.js +35 -96
- package/dist/clientconfiguration.spec.js.map +1 -1
- package/dist/commands/add.js +103 -3
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/add.spec.js +113 -0
- package/dist/commands/add.spec.js.map +1 -0
- package/dist/commands/connection/createconnections.js +104 -7
- package/dist/commands/connection/createconnections.js.map +1 -1
- package/dist/commands/connection/createconnections.spec.js +35 -1
- package/dist/commands/connection/createconnections.spec.js.map +1 -1
- package/dist/commands/connection/deleteconnection.js +4 -2
- package/dist/commands/connection/deleteconnection.js.map +1 -1
- package/dist/commands/connection/deleteconnection.spec.js +6 -1
- package/dist/commands/connection/deleteconnection.spec.js.map +1 -1
- package/dist/commands/connection/listconnections.js +2 -0
- package/dist/commands/connection/listconnections.js.map +1 -1
- package/dist/commands/connection/updateconnection.js +365 -0
- package/dist/commands/connection/updateconnection.js.map +1 -0
- package/dist/commands/connection/updateconnection.spec.js +625 -0
- package/dist/commands/connection/updateconnection.spec.js.map +1 -0
- package/dist/commands/database/createdatabase.js +52 -0
- package/dist/commands/database/createdatabase.js.map +1 -0
- package/dist/commands/database/database.spec.js +267 -0
- package/dist/commands/database/database.spec.js.map +1 -0
- package/dist/commands/database/deletedatabase.js +91 -0
- package/dist/commands/database/deletedatabase.js.map +1 -0
- package/dist/commands/database/getdatabase.js +97 -0
- package/dist/commands/database/getdatabase.js.map +1 -0
- package/dist/commands/database/listdatabases.js +36 -0
- package/dist/commands/database/listdatabases.js.map +1 -0
- package/dist/commands/database/shared.js +125 -0
- package/dist/commands/database/shared.js.map +1 -0
- package/dist/commands/database/shared.spec.js +109 -0
- package/dist/commands/database/shared.spec.js.map +1 -0
- package/dist/commands/database/updatedatabase.js +39 -0
- package/dist/commands/database/updatedatabase.js.map +1 -0
- package/dist/commands/environment/createenvironment.js +59 -28
- package/dist/commands/environment/createenvironment.js.map +1 -1
- package/dist/commands/environment/createenvironment.spec.js +29 -0
- package/dist/commands/environment/createenvironment.spec.js.map +1 -1
- package/dist/commands/environment/deleteenvironment.js +3 -2
- package/dist/commands/environment/deleteenvironment.js.map +1 -1
- package/dist/commands/environment/deleteenvironment.spec.js +5 -1
- package/dist/commands/environment/deleteenvironment.spec.js.map +1 -1
- package/dist/commands/environment/getenvironment.js +1 -0
- package/dist/commands/environment/getenvironment.js.map +1 -1
- package/dist/commands/environment/listenvironments.js +40 -8
- package/dist/commands/environment/listenvironments.js.map +1 -1
- package/dist/commands/environment/listenvironments.spec.js +41 -2
- package/dist/commands/environment/listenvironments.spec.js.map +1 -1
- package/dist/commands/environment/setenvironment.js +145 -6
- package/dist/commands/environment/setenvironment.js.map +1 -1
- package/dist/commands/environment/setenvironment.spec.js +256 -8
- package/dist/commands/environment/setenvironment.spec.js.map +1 -1
- package/dist/commands/environment/updateenvironment.js +12 -8
- package/dist/commands/environment/updateenvironment.js.map +1 -1
- package/dist/commands/environment/updateenvironment.spec.js +36 -2
- package/dist/commands/environment/updateenvironment.spec.js.map +1 -1
- package/dist/commands/get.js +64 -1
- package/dist/commands/get.js.map +1 -1
- package/dist/commands/group/addmember.js +3 -1
- package/dist/commands/group/addmember.js.map +1 -1
- package/dist/commands/group/addmember.spec.js +7 -2
- package/dist/commands/group/addmember.spec.js.map +1 -1
- package/dist/commands/group/creategroup.js +2 -0
- package/dist/commands/group/creategroup.js.map +1 -1
- package/dist/commands/group/deletegroup.js +3 -1
- package/dist/commands/group/deletegroup.js.map +1 -1
- package/dist/commands/group/deletegroup.spec.js +7 -1
- package/dist/commands/group/deletegroup.spec.js.map +1 -1
- package/dist/commands/group/getgroup.js +2 -0
- package/dist/commands/group/getgroup.js.map +1 -1
- package/dist/commands/group/listgroups.js +2 -0
- package/dist/commands/group/listgroups.js.map +1 -1
- package/dist/commands/group/removemember.js +3 -1
- package/dist/commands/group/removemember.js.map +1 -1
- package/dist/commands/group/removemember.spec.js +7 -2
- package/dist/commands/group/removemember.spec.js.map +1 -1
- package/dist/commands/groupaccesstoken/deleteToken.js +2 -1
- package/dist/commands/groupaccesstoken/deleteToken.js.map +1 -1
- package/dist/commands/groupaccesstoken/groupContainer.js +2 -0
- package/dist/commands/groupaccesstoken/groupContainer.js.map +1 -1
- package/dist/commands/list.js +24 -4
- package/dist/commands/list.js.map +1 -1
- package/dist/commands/materialization/cancelrun.js +3 -1
- package/dist/commands/materialization/cancelrun.js.map +1 -1
- package/dist/commands/materialization/getindex.js +2 -0
- package/dist/commands/materialization/getindex.js.map +1 -1
- package/dist/commands/materialization/getmaterialization.js +2 -0
- package/dist/commands/materialization/getmaterialization.js.map +1 -1
- package/dist/commands/materialization/getpreaggregate.js +2 -0
- package/dist/commands/materialization/getpreaggregate.js.map +1 -1
- package/dist/commands/materialization/getrun.js +2 -0
- package/dist/commands/materialization/getrun.js.map +1 -1
- package/dist/commands/materialization/listindexes.js +2 -0
- package/dist/commands/materialization/listindexes.js.map +1 -1
- package/dist/commands/materialization/listmaterializations.js +2 -0
- package/dist/commands/materialization/listmaterializations.js.map +1 -1
- package/dist/commands/materialization/listpreaggregates.js +2 -0
- package/dist/commands/materialization/listpreaggregates.js.map +1 -1
- package/dist/commands/materialization/listruns.js +3 -1
- package/dist/commands/materialization/listruns.js.map +1 -1
- package/dist/commands/materialization/rerun.js +3 -1
- package/dist/commands/materialization/rerun.js.map +1 -1
- package/dist/commands/misc/inquirerHost.js +87 -0
- package/dist/commands/misc/inquirerHost.js.map +1 -0
- package/dist/commands/misc/inquirerHost.spec.js +91 -0
- package/dist/commands/misc/inquirerHost.spec.js.map +1 -0
- package/dist/commands/misc/login.js +348 -58
- package/dist/commands/misc/login.js.map +1 -1
- package/dist/commands/misc/login.spec.js +525 -7
- package/dist/commands/misc/login.spec.js.map +1 -1
- package/dist/commands/misc/logout.js +26 -3
- package/dist/commands/misc/logout.js.map +1 -1
- package/dist/commands/misc/logout.spec.js +52 -12
- package/dist/commands/misc/logout.spec.js.map +1 -1
- package/dist/commands/misc/resolveLoginTarget.spec.js +90 -0
- package/dist/commands/misc/resolveLoginTarget.spec.js.map +1 -0
- package/dist/commands/misc/scope.spec.js +108 -0
- package/dist/commands/misc/scope.spec.js.map +1 -0
- package/dist/commands/misc/set-access-token.js +1 -1
- package/dist/commands/misc/set-access-token.js.map +1 -1
- package/dist/commands/misc/set-access-token.spec.js +13 -2
- package/dist/commands/misc/set-access-token.spec.js.map +1 -1
- package/dist/commands/misc/setup.js +819 -0
- package/dist/commands/misc/setup.js.map +1 -0
- package/dist/commands/misc/setup.spec.js +783 -0
- package/dist/commands/misc/setup.spec.js.map +1 -0
- package/dist/commands/misc/status.js +168 -0
- package/dist/commands/misc/status.js.map +1 -0
- package/dist/commands/misc/status.spec.js +301 -0
- package/dist/commands/misc/status.spec.js.map +1 -0
- package/dist/commands/misc/token.js +57 -0
- package/dist/commands/misc/token.js.map +1 -0
- package/dist/commands/misc/token.spec.js +92 -0
- package/dist/commands/misc/token.spec.js.map +1 -0
- package/dist/commands/package/deletepackage.js +4 -2
- package/dist/commands/package/deletepackage.js.map +1 -1
- package/dist/commands/package/deletepackage.spec.js +7 -1
- package/dist/commands/package/deletepackage.spec.js.map +1 -1
- package/dist/commands/package/getpackage.js +142 -0
- package/dist/commands/package/getpackage.js.map +1 -0
- package/dist/commands/package/getpackage.spec.js +246 -0
- package/dist/commands/package/getpackage.spec.js.map +1 -0
- package/dist/commands/package/listpackages.js +2 -0
- package/dist/commands/package/listpackages.js.map +1 -1
- package/dist/commands/package/publish.archive.spec.js +570 -0
- package/dist/commands/package/publish.archive.spec.js.map +1 -0
- package/dist/commands/package/publish.js +780 -49
- package/dist/commands/package/publish.js.map +1 -1
- package/dist/commands/package/publish.spec.js +451 -8
- package/dist/commands/package/publish.spec.js.map +1 -1
- package/dist/commands/package/updatepackage.js +22 -19
- package/dist/commands/package/updatepackage.js.map +1 -1
- package/dist/commands/package/updatepackage.spec.js +36 -1
- package/dist/commands/package/updatepackage.spec.js.map +1 -1
- package/dist/commands/permission/createpermission.js +3 -1
- package/dist/commands/permission/createpermission.js.map +1 -1
- package/dist/commands/permission/deletepermission.js +6 -3
- package/dist/commands/permission/deletepermission.js.map +1 -1
- package/dist/commands/permission/getpermission.js +2 -0
- package/dist/commands/permission/getpermission.js.map +1 -1
- package/dist/commands/permission/listpermissions.js +2 -0
- package/dist/commands/permission/listpermissions.js.map +1 -1
- package/dist/commands/rm.js +21 -0
- package/dist/commands/rm.js.map +1 -1
- package/dist/commands/set.js +40 -6
- package/dist/commands/set.js.map +1 -1
- package/dist/commands/set.spec.js +123 -0
- package/dist/commands/set.spec.js.map +1 -0
- package/dist/commands/table/addtable.js +155 -0
- package/dist/commands/table/addtable.js.map +1 -0
- package/dist/commands/table/deletetable.js +45 -0
- package/dist/commands/table/deletetable.js.map +1 -0
- package/dist/commands/table/gettable.js +32 -0
- package/dist/commands/table/gettable.js.map +1 -0
- package/dist/commands/table/listtables.js +36 -0
- package/dist/commands/table/listtables.js.map +1 -0
- package/dist/commands/table/table.spec.js +304 -0
- package/dist/commands/table/table.spec.js.map +1 -0
- package/dist/commands/table/tablefile.js +195 -0
- package/dist/commands/table/tablefile.js.map +1 -0
- package/dist/commands/table/tablefile.spec.js +158 -0
- package/dist/commands/table/tablefile.spec.js.map +1 -0
- package/dist/commands/update.js +21 -0
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/version/archive-unarchive-version.js +4 -2
- package/dist/commands/version/archive-unarchive-version.js.map +1 -1
- package/dist/commands/version/archive-unarchive-version.spec.js +6 -1
- package/dist/commands/version/archive-unarchive-version.spec.js.map +1 -1
- package/dist/commands/version/listversions.js +2 -0
- package/dist/commands/version/listversions.js.map +1 -1
- package/dist/common/UserGroupId.js +9 -4
- package/dist/common/UserGroupId.js.map +1 -1
- package/dist/common/UserGroupId.spec.js +5 -0
- package/dist/common/UserGroupId.spec.js.map +1 -1
- package/dist/constants.js +37 -143
- package/dist/constants.js.map +1 -1
- package/dist/index.js +487 -90
- package/dist/index.js.map +1 -1
- package/dist/logger.js +42 -9
- package/dist/logger.js.map +1 -1
- package/dist/session.js +56 -0
- package/dist/session.js.map +1 -0
- package/dist/session.spec.js +103 -0
- package/dist/session.spec.js.map +1 -0
- package/dist/setup-core/briefing.js +176 -0
- package/dist/setup-core/briefing.js.map +1 -0
- package/dist/setup-core/credstore.js +415 -0
- package/dist/setup-core/credstore.js.map +1 -0
- package/dist/setup-core/credstore.spec.js +238 -0
- package/dist/setup-core/credstore.spec.js.map +1 -0
- package/dist/setup-core/environments.js +267 -0
- package/dist/setup-core/environments.js.map +1 -0
- package/dist/setup-core/flow.e2e.js +165 -0
- package/dist/setup-core/flow.e2e.js.map +1 -0
- package/dist/setup-core/flow.js +765 -0
- package/dist/setup-core/flow.js.map +1 -0
- package/dist/setup-core/flow.spec.js +1348 -0
- package/dist/setup-core/flow.spec.js.map +1 -0
- package/dist/setup-core/folderconfig.js +283 -0
- package/dist/setup-core/folderconfig.js.map +1 -0
- package/dist/setup-core/git.js +97 -0
- package/dist/setup-core/git.js.map +1 -0
- package/dist/setup-core/host.js +77 -0
- package/dist/setup-core/host.js.map +1 -0
- package/dist/setup-core/importconnections.js +470 -0
- package/dist/setup-core/importconnections.js.map +1 -0
- package/dist/setup-core/importconnections.spec.js +594 -0
- package/dist/setup-core/importconnections.spec.js.map +1 -0
- package/dist/setup-core/liveness.js +94 -0
- package/dist/setup-core/liveness.js.map +1 -0
- package/dist/setup-core/liveness.spec.js +59 -0
- package/dist/setup-core/liveness.spec.js.map +1 -0
- package/dist/setup-core/localpublisherconfig.js +26 -0
- package/dist/setup-core/localpublisherconfig.js.map +1 -0
- package/dist/setup-core/localpublisherconfig.spec.js +29 -0
- package/dist/setup-core/localpublisherconfig.spec.js.map +1 -0
- package/dist/setup-core/mcpconfig.js +198 -0
- package/dist/setup-core/mcpconfig.js.map +1 -0
- package/dist/setup-core/mcpconfig.spec.js +205 -0
- package/dist/setup-core/mcpconfig.spec.js.map +1 -0
- package/dist/setup-core/packagemanifest.js +55 -0
- package/dist/setup-core/packagemanifest.js.map +1 -0
- package/dist/setup-core/ports.js +182 -0
- package/dist/setup-core/ports.js.map +1 -0
- package/dist/setup-core/ports.spec.js +173 -0
- package/dist/setup-core/ports.spec.js.map +1 -0
- package/dist/setup-core/publisherconfig.js +268 -0
- package/dist/setup-core/publisherconfig.js.map +1 -0
- package/dist/setup-core/publisherconfig.oracle.js +166 -0
- package/dist/setup-core/publisherconfig.oracle.js.map +1 -0
- package/dist/setup-core/publisherconfig.spec.js +277 -0
- package/dist/setup-core/publisherconfig.spec.js.map +1 -0
- package/dist/setup-core/publisherversion.js +26 -0
- package/dist/setup-core/publisherversion.js.map +1 -0
- package/dist/setup-core/readiness.spec.js +161 -0
- package/dist/setup-core/readiness.spec.js.map +1 -0
- package/dist/setup-core/readylines.js +169 -0
- package/dist/setup-core/readylines.js.map +1 -0
- package/dist/setup-core/readylines.spec.js +70 -0
- package/dist/setup-core/readylines.spec.js.map +1 -0
- package/dist/setup-core/refresh.js +348 -0
- package/dist/setup-core/refresh.js.map +1 -0
- package/dist/setup-core/refresh.spec.js +501 -0
- package/dist/setup-core/refresh.spec.js.map +1 -0
- package/dist/setup-core/skills.js +279 -0
- package/dist/setup-core/skills.js.map +1 -0
- package/dist/setup-core/skills.spec.js +334 -0
- package/dist/setup-core/skills.spec.js.map +1 -0
- package/dist/setup-core/supervisor.js +879 -0
- package/dist/setup-core/supervisor.js.map +1 -0
- package/dist/setup-core/supervisor.spec.js +833 -0
- package/dist/setup-core/supervisor.spec.js.map +1 -0
- package/dist/setup-core/writefile.js +61 -0
- package/dist/setup-core/writefile.js.map +1 -0
- package/dist/setup-core/writefile.spec.js +68 -0
- package/dist/setup-core/writefile.spec.js.map +1 -0
- package/dist/utils.js +409 -3
- package/dist/utils.js.map +1 -1
- package/dist/utils.spec.js +373 -2
- package/dist/utils.spec.js.map +1 -1
- package/dist/versioncheck-refresh.js +18 -0
- package/dist/versioncheck-refresh.js.map +1 -0
- package/dist/versioncheck.js +324 -0
- package/dist/versioncheck.js.map +1 -0
- package/dist/versioncheck.spec.js +587 -0
- package/dist/versioncheck.spec.js.map +1 -0
- package/node_modules/@credibledata/cli-auth/dist/index.d.ts +86 -0
- package/node_modules/@credibledata/cli-auth/dist/index.js +102 -0
- package/node_modules/@credibledata/cli-auth/package.json +19 -0
- package/package.json +18 -6
- package/.github/workflows/build.yml +0 -23
- package/.mocharc.json +0 -10
- package/.prettierignore +0 -2
- package/.prettierrc +0 -4
- package/README-DEV.md +0 -40
- package/coverage/coverage-summary.json +0 -40
- package/coverage/tmp/coverage-2152-1789496974457-0.json +0 -1
- package/coverage/tmp/coverage-2153-1789496954404-0.json +0 -1
- package/docker/Dockerfile.ci +0 -18
- package/docker-compose.yml +0 -18
- package/eslint.config.mjs +0 -45
- package/generate-client.sh +0 -27
- package/mocha.setup.ts +0 -4
- package/openapitools.json +0 -10
- package/src/client/.openapi-generator/FILES +0 -9
- package/src/client/.openapi-generator/VERSION +0 -1
- package/src/client/.openapi-generator-ignore +0 -23
- package/src/client/api.ts +0 -15999
- package/src/client/base.ts +0 -86
- package/src/client/common.ts +0 -150
- package/src/client/configuration.ts +0 -110
- package/src/client/git_push.sh +0 -57
- package/src/client/index.ts +0 -18
- package/src/clientconfiguration.spec.ts +0 -615
- package/src/clientconfiguration.ts +0 -364
- package/src/commands/add.ts +0 -191
- package/src/commands/connection/createconnections.spec.ts +0 -413
- package/src/commands/connection/createconnections.ts +0 -109
- package/src/commands/connection/deleteconnection.spec.ts +0 -189
- package/src/commands/connection/deleteconnection.ts +0 -57
- package/src/commands/connection/listconnections.spec.ts +0 -132
- package/src/commands/connection/listconnections.ts +0 -58
- package/src/commands/environment/createenvironment.spec.ts +0 -249
- package/src/commands/environment/createenvironment.ts +0 -73
- package/src/commands/environment/deleteenvironment.spec.ts +0 -152
- package/src/commands/environment/deleteenvironment.ts +0 -48
- package/src/commands/environment/getenvironment.spec.ts +0 -110
- package/src/commands/environment/getenvironment.ts +0 -43
- package/src/commands/environment/listenvironments.spec.ts +0 -123
- package/src/commands/environment/listenvironments.ts +0 -67
- package/src/commands/environment/setenvironment.spec.ts +0 -63
- package/src/commands/environment/setenvironment.ts +0 -14
- package/src/commands/environment/updateenvironment.spec.ts +0 -386
- package/src/commands/environment/updateenvironment.ts +0 -168
- package/src/commands/get.ts +0 -153
- package/src/commands/group/addmember.spec.ts +0 -257
- package/src/commands/group/addmember.ts +0 -85
- package/src/commands/group/creategroup.spec.ts +0 -146
- package/src/commands/group/creategroup.ts +0 -54
- package/src/commands/group/deletegroup.spec.ts +0 -120
- package/src/commands/group/deletegroup.ts +0 -45
- package/src/commands/group/getgroup.spec.ts +0 -129
- package/src/commands/group/getgroup.ts +0 -47
- package/src/commands/group/listgroups.spec.ts +0 -137
- package/src/commands/group/listgroups.ts +0 -45
- package/src/commands/group/removemember.spec.ts +0 -224
- package/src/commands/group/removemember.ts +0 -75
- package/src/commands/groupaccesstoken/createToken.spec.ts +0 -211
- package/src/commands/groupaccesstoken/createToken.ts +0 -72
- package/src/commands/groupaccesstoken/deleteToken.spec.ts +0 -147
- package/src/commands/groupaccesstoken/deleteToken.ts +0 -29
- package/src/commands/groupaccesstoken/groupContainer.ts +0 -83
- package/src/commands/groupaccesstoken/listTokens.spec.ts +0 -147
- package/src/commands/groupaccesstoken/listTokens.ts +0 -29
- package/src/commands/legacy.ts +0 -5
- package/src/commands/list.ts +0 -326
- package/src/commands/materialization/cancelrun.ts +0 -70
- package/src/commands/materialization/getindex.ts +0 -55
- package/src/commands/materialization/getmaterialization.ts +0 -57
- package/src/commands/materialization/getpreaggregate.ts +0 -58
- package/src/commands/materialization/getrun.ts +0 -55
- package/src/commands/materialization/listindexes.ts +0 -69
- package/src/commands/materialization/listmaterializations.ts +0 -53
- package/src/commands/materialization/listpreaggregates.ts +0 -74
- package/src/commands/materialization/listruns.ts +0 -77
- package/src/commands/materialization/rerun.ts +0 -123
- package/src/commands/misc/login.spec.ts +0 -371
- package/src/commands/misc/login.ts +0 -343
- package/src/commands/misc/logout.spec.ts +0 -32
- package/src/commands/misc/logout.ts +0 -9
- package/src/commands/misc/loopbackOAuth.ts +0 -127
- package/src/commands/misc/set-access-token.spec.ts +0 -95
- package/src/commands/misc/set-access-token.ts +0 -32
- package/src/commands/package/deletepackage.spec.ts +0 -164
- package/src/commands/package/deletepackage.ts +0 -58
- package/src/commands/package/listpackages.spec.ts +0 -163
- package/src/commands/package/listpackages.ts +0 -74
- package/src/commands/package/publish.spec.ts +0 -642
- package/src/commands/package/publish.ts +0 -236
- package/src/commands/package/updatepackage.spec.ts +0 -319
- package/src/commands/package/updatepackage.ts +0 -95
- package/src/commands/permission/createpermission.spec.ts +0 -507
- package/src/commands/permission/createpermission.ts +0 -181
- package/src/commands/permission/deletepermission.ts +0 -117
- package/src/commands/permission/getpermission.ts +0 -115
- package/src/commands/permission/listpermissions.ts +0 -101
- package/src/commands/permission/scope.ts +0 -180
- package/src/commands/rm.ts +0 -146
- package/src/commands/set.ts +0 -25
- package/src/commands/update.ts +0 -107
- package/src/commands/version/archive-unarchive-version.spec.ts +0 -456
- package/src/commands/version/archive-unarchive-version.ts +0 -108
- package/src/commands/version/listversions.spec.ts +0 -138
- package/src/commands/version/listversions.ts +0 -45
- package/src/common/UserGroupId.spec.ts +0 -115
- package/src/common/UserGroupId.ts +0 -137
- package/src/constants.spec.ts +0 -111
- package/src/constants.ts +0 -228
- package/src/index.ts +0 -378
- package/src/logger.spec.ts +0 -158
- package/src/logger.ts +0 -90
- package/src/polyfills/file.polyfill.ts +0 -6
- package/src/utils.spec.ts +0 -135
- package/src/utils.ts +0 -115
- package/src/validator.spec.ts +0 -51
- package/src/validator.ts +0 -44
- package/tsconfig.json +0 -17
|
@@ -45,6 +45,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
45
45
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
46
46
|
};
|
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
|
+
const environments_1 = require("../../setup-core/environments");
|
|
48
49
|
const child_process_1 = require("child_process");
|
|
49
50
|
const axios_1 = __importDefault(require("axios"));
|
|
50
51
|
const chai_1 = require("chai");
|
|
@@ -52,11 +53,15 @@ const fs_1 = __importDefault(require("fs"));
|
|
|
52
53
|
const os_1 = __importDefault(require("os"));
|
|
53
54
|
const path_1 = require("path");
|
|
54
55
|
const sinon_1 = __importDefault(require("sinon"));
|
|
55
|
-
const
|
|
56
|
+
const credEnvironments = __importStar(require("../../setup-core/environments"));
|
|
56
57
|
const clientconfiguration_1 = require("../../clientconfiguration");
|
|
58
|
+
const logger_1 = require("../../logger");
|
|
57
59
|
const login_1 = require("./login");
|
|
58
60
|
const api_1 = require("../../client/api");
|
|
59
61
|
const loopbackOAuth = __importStar(require("./loopbackOAuth"));
|
|
62
|
+
const utils = __importStar(require("../../utils"));
|
|
63
|
+
const browser = __importStar(require("../../browser"));
|
|
64
|
+
const refresh = __importStar(require("../../setup-core/refresh"));
|
|
60
65
|
function createFakeIdToken(payload) {
|
|
61
66
|
const header = Buffer.from(JSON.stringify({ alg: "none", typ: "JWT" })).toString("base64url");
|
|
62
67
|
const body = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
@@ -67,6 +72,8 @@ describe("login", () => {
|
|
|
67
72
|
let tmpConfigFilePath;
|
|
68
73
|
let axiosStub;
|
|
69
74
|
let orgPermissionsStub;
|
|
75
|
+
let openStub;
|
|
76
|
+
let shouldOpenStub;
|
|
70
77
|
const mockDeviceCodeResponse = {
|
|
71
78
|
data: {
|
|
72
79
|
verification_uri_complete: "https://example.com",
|
|
@@ -109,6 +116,9 @@ describe("login", () => {
|
|
|
109
116
|
activeEnvironment: "production",
|
|
110
117
|
}));
|
|
111
118
|
axiosStub = sinon_1.default.stub(axios_1.default, "request");
|
|
119
|
+
// Never a real browser from a test run, even one started at a terminal.
|
|
120
|
+
openStub = sinon_1.default.stub(browser, "openInBrowser").resolves(true);
|
|
121
|
+
shouldOpenStub = sinon_1.default.stub(browser, "shouldOpenBrowser").returns(false);
|
|
112
122
|
orgPermissionsStub = sinon_1.default
|
|
113
123
|
.stub(api_1.OrganizationsApi.prototype, "getOrganization")
|
|
114
124
|
.resolves(mockOrgPermissionsResponse);
|
|
@@ -134,6 +144,98 @@ describe("login", () => {
|
|
|
134
144
|
(0, chai_1.expect)(config.getProject()).to.equal("bar");
|
|
135
145
|
});
|
|
136
146
|
});
|
|
147
|
+
it("opens the sign-in page for a person at a terminal, after printing it", function () {
|
|
148
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
149
|
+
this.timeout(2000);
|
|
150
|
+
shouldOpenStub.returns(true);
|
|
151
|
+
const info = sinon_1.default.stub(logger_1.logger, "info");
|
|
152
|
+
axiosStub
|
|
153
|
+
.onFirstCall()
|
|
154
|
+
.resolves(mockDeviceCodeResponse)
|
|
155
|
+
.onSecondCall()
|
|
156
|
+
.resolves(mockedAccessTokenResponse);
|
|
157
|
+
yield (0, login_1.login)("foo", "http://localhost", tmpConfigFilePath);
|
|
158
|
+
(0, chai_1.expect)(openStub.calledOnceWith("https://example.com")).to.equal(true);
|
|
159
|
+
// Printed first, so the link is there when the browser does not open.
|
|
160
|
+
const printed = info
|
|
161
|
+
.getCalls()
|
|
162
|
+
.findIndex((call) => String(call.args[0]) ===
|
|
163
|
+
"Please visit the following URL to login https://example.com and verify user code 123456.");
|
|
164
|
+
(0, chai_1.expect)(printed).to.be.greaterThan(-1);
|
|
165
|
+
(0, chai_1.expect)(info.calledWith(sinon_1.default.match("Opened your browser to sign in."))).to.equal(true);
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
it("only prints the link when no one is at a terminal", function () {
|
|
169
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
170
|
+
this.timeout(2000);
|
|
171
|
+
shouldOpenStub.returns(false);
|
|
172
|
+
axiosStub
|
|
173
|
+
.onFirstCall()
|
|
174
|
+
.resolves(mockDeviceCodeResponse)
|
|
175
|
+
.onSecondCall()
|
|
176
|
+
.resolves(mockedAccessTokenResponse);
|
|
177
|
+
yield (0, login_1.login)("foo", "http://localhost", tmpConfigFilePath);
|
|
178
|
+
(0, chai_1.expect)(openStub.called).to.equal(false);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
it("stops polling on a final Auth0 answer instead of running out the clock", function () {
|
|
182
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
183
|
+
// `access_denied`, `expired_token`, `invalid_grant` are final for a
|
|
184
|
+
// device code; re-POSTing it can only fail again. The loop used to log
|
|
185
|
+
// and keep going for five minutes.
|
|
186
|
+
this.timeout(2000);
|
|
187
|
+
const exit = sinon_1.default.stub(process, "exit").callsFake(() => {
|
|
188
|
+
throw new Error("exited");
|
|
189
|
+
});
|
|
190
|
+
const errorLog = sinon_1.default.stub(logger_1.logger, "error");
|
|
191
|
+
axiosStub
|
|
192
|
+
.onFirstCall()
|
|
193
|
+
.resolves(mockDeviceCodeResponse)
|
|
194
|
+
.onSecondCall()
|
|
195
|
+
.rejects({
|
|
196
|
+
isAxiosError: true,
|
|
197
|
+
response: {
|
|
198
|
+
status: 403,
|
|
199
|
+
data: {
|
|
200
|
+
error: "access_denied",
|
|
201
|
+
error_description: "User denied the request",
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
yield (0, login_1.login)("foo", "http://localhost", tmpConfigFilePath).catch((error) => (0, chai_1.expect)(error.message).to.equal("exited"));
|
|
206
|
+
(0, chai_1.expect)(axiosStub.callCount, "no re-poll with a spent device code").to.equal(2);
|
|
207
|
+
(0, chai_1.expect)(exit.calledOnceWith(1)).to.equal(true);
|
|
208
|
+
(0, chai_1.expect)(errorLog.calledWith(sinon_1.default.match("User denied the request"))).to.equal(true);
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
it("keeps polling through a 5xx that carries no OAuth error code", function () {
|
|
212
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
213
|
+
// A proxy's 503 page says nothing about the device code, so it is a
|
|
214
|
+
// transport blip to retry, not a final answer to exit on.
|
|
215
|
+
this.timeout(4000);
|
|
216
|
+
const exit = sinon_1.default.stub(process, "exit").callsFake(() => {
|
|
217
|
+
throw new Error("exited");
|
|
218
|
+
});
|
|
219
|
+
sinon_1.default.stub(logger_1.logger, "error");
|
|
220
|
+
axiosStub
|
|
221
|
+
.onFirstCall()
|
|
222
|
+
.resolves(mockDeviceCodeResponse)
|
|
223
|
+
.onSecondCall()
|
|
224
|
+
.rejects({
|
|
225
|
+
isAxiosError: true,
|
|
226
|
+
message: "Request failed with status code 503",
|
|
227
|
+
response: { status: 503, data: "<html>Service Unavailable</html>" },
|
|
228
|
+
})
|
|
229
|
+
.onThirdCall()
|
|
230
|
+
.resolves(mockedAccessTokenResponse);
|
|
231
|
+
const config = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
232
|
+
config.setEnvironment("localhost");
|
|
233
|
+
yield (0, login_1.login)("test", "http://localhost", tmpConfigFilePath);
|
|
234
|
+
(0, chai_1.expect)(exit.called).to.equal(false);
|
|
235
|
+
(0, chai_1.expect)(axiosStub.callCount).to.equal(3);
|
|
236
|
+
(0, chai_1.expect)(config.getAccessToken()).to.equal(mockedAccessTokenResponse.data.access_token);
|
|
237
|
+
});
|
|
238
|
+
});
|
|
137
239
|
it("should change the active organization when login succeeds", function () {
|
|
138
240
|
return __awaiter(this, void 0, void 0, function* () {
|
|
139
241
|
this.timeout(2000);
|
|
@@ -150,6 +252,297 @@ describe("login", () => {
|
|
|
150
252
|
(0, chai_1.expect)(config.getOrganization()).to.equal("test");
|
|
151
253
|
});
|
|
152
254
|
});
|
|
255
|
+
/** An access token for localhost's API that expires `seconds` from now. */
|
|
256
|
+
function apiTokenExpiringIn(seconds) {
|
|
257
|
+
return createFakeIdToken({
|
|
258
|
+
aud: environments_1.auth0ConfigsByEnv.localhost.audience,
|
|
259
|
+
exp: Math.floor(Date.now() / 1000) + seconds,
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
function refreshResponse(body) {
|
|
263
|
+
return { status: 200, json: () => __awaiter(this, void 0, void 0, function* () { return body; }) };
|
|
264
|
+
}
|
|
265
|
+
// A live user session is not tied to an organization, so naming one is a
|
|
266
|
+
// switch. Signing in again asked for a second device code seconds after
|
|
267
|
+
// the first.
|
|
268
|
+
it("switches organization without signing in again when already signed in", function () {
|
|
269
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
270
|
+
const config = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
271
|
+
config.setEnvironment("localhost");
|
|
272
|
+
config.setOrganization("old-org");
|
|
273
|
+
config.setTokenPair({
|
|
274
|
+
accessToken: apiTokenExpiringIn(3600),
|
|
275
|
+
refreshToken: "refresh",
|
|
276
|
+
});
|
|
277
|
+
const fetchStub = sinon_1.default.stub(globalThis, "fetch");
|
|
278
|
+
yield (0, login_1.login)("new-org", "http://localhost", tmpConfigFilePath);
|
|
279
|
+
(0, chai_1.expect)(axiosStub.called, "no device-code request").to.equal(false);
|
|
280
|
+
(0, chai_1.expect)(orgPermissionsStub.firstCall.args[0]).to.equal("new-org");
|
|
281
|
+
(0, chai_1.expect)(new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath).getOrganization()).to.equal("new-org");
|
|
282
|
+
// The token had an hour left, so there was nothing to renew.
|
|
283
|
+
(0, chai_1.expect)(fetchStub.called, "no refresh request").to.equal(false);
|
|
284
|
+
});
|
|
285
|
+
});
|
|
286
|
+
it("renews an expired token before switching, instead of signing in again", function () {
|
|
287
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
288
|
+
const config = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
289
|
+
config.setEnvironment("localhost");
|
|
290
|
+
config.setOrganization("old-org");
|
|
291
|
+
config.setTokenPair({
|
|
292
|
+
accessToken: apiTokenExpiringIn(-60),
|
|
293
|
+
refreshToken: "refresh",
|
|
294
|
+
});
|
|
295
|
+
const renewed = apiTokenExpiringIn(7200);
|
|
296
|
+
sinon_1.default
|
|
297
|
+
.stub(globalThis, "fetch")
|
|
298
|
+
.resolves(refreshResponse({ access_token: renewed }));
|
|
299
|
+
yield (0, login_1.login)("new-org", "http://localhost", tmpConfigFilePath);
|
|
300
|
+
(0, chai_1.expect)(axiosStub.called, "no device-code request").to.equal(false);
|
|
301
|
+
const after = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
302
|
+
(0, chai_1.expect)(after.getOrganization()).to.equal("new-org");
|
|
303
|
+
(0, chai_1.expect)(after.getApiAccessToken()).to.equal(renewed);
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
// A refresh token Auth0 refuses means the saved session is over. The
|
|
307
|
+
// switch must not report "already signed in" over it, and the sign-in that
|
|
308
|
+
// replaces it keeps the organization and environment the user had chosen.
|
|
309
|
+
it("signs in again when the saved session cannot be renewed, keeping the organization and environment", function () {
|
|
310
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
311
|
+
this.timeout(4000);
|
|
312
|
+
const config = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
313
|
+
config.setEnvironment("localhost");
|
|
314
|
+
config.setOrganization("acme");
|
|
315
|
+
config.setProject("analytics");
|
|
316
|
+
config.setTokenPair({
|
|
317
|
+
accessToken: apiTokenExpiringIn(-60),
|
|
318
|
+
refreshToken: "dead",
|
|
319
|
+
});
|
|
320
|
+
sinon_1.default
|
|
321
|
+
.stub(globalThis, "fetch")
|
|
322
|
+
.resolves(refreshResponse({ error: "invalid_grant" }));
|
|
323
|
+
let storedAtSignIn;
|
|
324
|
+
axiosStub.onFirstCall().callsFake(() => __awaiter(this, void 0, void 0, function* () {
|
|
325
|
+
storedAtSignIn = JSON.parse(fs_1.default.readFileSync(tmpConfigFilePath, "utf-8")).configPerEnvironment.localhost;
|
|
326
|
+
return mockDeviceCodeResponse;
|
|
327
|
+
}));
|
|
328
|
+
axiosStub.onSecondCall().resolves(mockedAccessTokenResponse);
|
|
329
|
+
const warnStub = sinon_1.default.stub(logger_1.logger, "warn");
|
|
330
|
+
yield (0, login_1.login)("acme", "https://admin.example", tmpConfigFilePath);
|
|
331
|
+
(0, chai_1.expect)(axiosStub.called, "fell through to the device sign-in").to.equal(true);
|
|
332
|
+
// Not the refresh's own "Run `cred login`": that is what is running.
|
|
333
|
+
(0, chai_1.expect)(warnStub.firstCall.args[0]).to.equal("Your saved session can no longer be renewed, so signing in again.");
|
|
334
|
+
// When the device-code sign-in started, only the tokens were gone.
|
|
335
|
+
(0, chai_1.expect)(storedAtSignIn).to.deep.equal({
|
|
336
|
+
organization: "acme",
|
|
337
|
+
project: "analytics",
|
|
338
|
+
});
|
|
339
|
+
const after = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
340
|
+
(0, chai_1.expect)(after.getEnvironment()).to.equal("localhost");
|
|
341
|
+
(0, chai_1.expect)(after.getOrganization()).to.equal("acme");
|
|
342
|
+
(0, chai_1.expect)(after.getProject()).to.equal("analytics");
|
|
343
|
+
(0, chai_1.expect)(after.getRefreshToken()).to.equal("mock-refresh-token");
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
// Auth0 unreachable is not a dead session. The token on disk is still
|
|
347
|
+
// valid, and a device-code sign-in would need the same Auth0.
|
|
348
|
+
it("switches on the token on disk when Auth0 cannot be reached and it is still valid", function () {
|
|
349
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
350
|
+
const config = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
351
|
+
config.setEnvironment("localhost");
|
|
352
|
+
config.setOrganization("old-org");
|
|
353
|
+
// Inside the renewal window, so a refresh is attempted, but still valid.
|
|
354
|
+
const onDisk = apiTokenExpiringIn(60);
|
|
355
|
+
config.setTokenPair({ accessToken: onDisk, refreshToken: "refresh" });
|
|
356
|
+
sinon_1.default
|
|
357
|
+
.stub(globalThis, "fetch")
|
|
358
|
+
.rejects(Object.assign(new Error("fetch failed"), { code: "ECONNREFUSED" }));
|
|
359
|
+
const warnStub = sinon_1.default.stub(logger_1.logger, "warn");
|
|
360
|
+
yield (0, login_1.login)("new-org", "http://localhost", tmpConfigFilePath);
|
|
361
|
+
(0, chai_1.expect)(axiosStub.called, "no device-code request").to.equal(false);
|
|
362
|
+
(0, chai_1.expect)(warnStub.firstCall.args[0]).to.equal(`Could not reach ${environments_1.auth0ConfigsByEnv.localhost.domain} to refresh your session. Continuing with the token on disk, which is still valid.`);
|
|
363
|
+
const after = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
364
|
+
(0, chai_1.expect)(after.getOrganization()).to.equal("new-org");
|
|
365
|
+
(0, chai_1.expect)(after.getApiAccessToken()).to.equal(onDisk);
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
it("signs in again when Auth0 cannot be reached and the token on disk has expired", function () {
|
|
369
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
370
|
+
this.timeout(4000);
|
|
371
|
+
const config = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
372
|
+
config.setEnvironment("localhost");
|
|
373
|
+
config.setTokenPair({
|
|
374
|
+
accessToken: apiTokenExpiringIn(-60),
|
|
375
|
+
refreshToken: "refresh",
|
|
376
|
+
});
|
|
377
|
+
sinon_1.default
|
|
378
|
+
.stub(globalThis, "fetch")
|
|
379
|
+
.rejects(Object.assign(new Error("fetch failed"), { code: "ECONNREFUSED" }));
|
|
380
|
+
axiosStub
|
|
381
|
+
.onFirstCall()
|
|
382
|
+
.resolves(mockDeviceCodeResponse)
|
|
383
|
+
.onSecondCall()
|
|
384
|
+
.resolves(mockedAccessTokenResponse);
|
|
385
|
+
yield (0, login_1.login)("new-org", "https://admin.example", tmpConfigFilePath);
|
|
386
|
+
(0, chai_1.expect)(axiosStub.called, "fell through to the device sign-in").to.equal(true);
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
// Another `cred` process holds the refresh lock past the wait. A device-code
|
|
390
|
+
// sign-in would race it for the same `~/.cred`, so stop and say to rerun.
|
|
391
|
+
it("stops instead of signing in when the renewal says to retry and the token on disk has expired", function () {
|
|
392
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
393
|
+
const config = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
394
|
+
config.setEnvironment("localhost");
|
|
395
|
+
config.setTokenPair({
|
|
396
|
+
accessToken: apiTokenExpiringIn(-60),
|
|
397
|
+
refreshToken: "refresh",
|
|
398
|
+
});
|
|
399
|
+
sinon_1.default.stub(refresh, "ensureFreshTokens").resolves({
|
|
400
|
+
status: "offline",
|
|
401
|
+
reason: "Another cred process has been renewing your session for over 25s.",
|
|
402
|
+
retry: "Run the command again in a moment.",
|
|
403
|
+
});
|
|
404
|
+
const errorStub = sinon_1.default.stub(logger_1.logger, "error");
|
|
405
|
+
const exitStub = sinon_1.default.stub(process, "exit").callsFake(() => {
|
|
406
|
+
throw new Error("exit");
|
|
407
|
+
});
|
|
408
|
+
yield (0, login_1.login)("new-org", "https://admin.example", tmpConfigFilePath).catch((error) => (0, chai_1.expect)(error.message).to.equal("exit"));
|
|
409
|
+
(0, chai_1.expect)(exitStub.calledOnceWithExactly(1)).to.equal(true);
|
|
410
|
+
(0, chai_1.expect)(errorStub.firstCall.args[0]).to.equal("Another cred process has been renewing your session for over 25s. Run the command again in a moment.");
|
|
411
|
+
(0, chai_1.expect)(axiosStub.called, "no device-code request").to.equal(false);
|
|
412
|
+
});
|
|
413
|
+
});
|
|
414
|
+
describe("with a saved session on localhost", () => {
|
|
415
|
+
let logStub;
|
|
416
|
+
beforeEach(() => {
|
|
417
|
+
logStub = sinon_1.default.stub(console, "log");
|
|
418
|
+
const config = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
419
|
+
config.setEnvironment("localhost");
|
|
420
|
+
config.setOrganization("old-org");
|
|
421
|
+
const payload = Buffer.from(JSON.stringify({
|
|
422
|
+
aud: environments_1.auth0ConfigsByEnv.localhost.audience,
|
|
423
|
+
exp: Math.floor(Date.now() / 1000) + 3600,
|
|
424
|
+
})).toString("base64url");
|
|
425
|
+
config.setTokenPair({
|
|
426
|
+
accessToken: `e30.${payload}.sig`,
|
|
427
|
+
refreshToken: "refresh",
|
|
428
|
+
});
|
|
429
|
+
});
|
|
430
|
+
const said = () => logStub.getCalls().map((call) => String(call.args[0]));
|
|
431
|
+
it("names the cell and says it switched only when the organization changed", function () {
|
|
432
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
433
|
+
yield (0, login_1.login)("new-org", "http://localhost", tmpConfigFilePath);
|
|
434
|
+
(0, chai_1.expect)(said()).to.eql([
|
|
435
|
+
"Already signed in to localhost, so this switched to new-org without signing in again. To sign in as someone else, pass --force.",
|
|
436
|
+
]);
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
it("does not claim a switch when the organization was already selected", function () {
|
|
440
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
441
|
+
yield (0, login_1.login)("old-org", "http://localhost", tmpConfigFilePath);
|
|
442
|
+
(0, chai_1.expect)(said()).to.eql([
|
|
443
|
+
"Already signed in to localhost with old-org selected; nothing changed. To sign in as someone else, pass --force.",
|
|
444
|
+
]);
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
it("does not claim a switch when the unreachable-server path writes the same organization", function () {
|
|
448
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
449
|
+
orgPermissionsStub.rejects(new Error("connection refused"));
|
|
450
|
+
yield (0, login_1.login)("old-org", "http://localhost", tmpConfigFilePath);
|
|
451
|
+
(0, chai_1.expect)(said().join("\n")).to.not.contain("switched");
|
|
452
|
+
(0, chai_1.expect)(said().join("\n")).to.contain("nothing changed");
|
|
453
|
+
});
|
|
454
|
+
});
|
|
455
|
+
it("keeps the selected environment when the unreachable-server path sees the same organization", function () {
|
|
456
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
457
|
+
new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath).setProject("old-env");
|
|
458
|
+
orgPermissionsStub.rejects(new Error("connection refused"));
|
|
459
|
+
yield (0, login_1.login)("old-org", "http://localhost", tmpConfigFilePath);
|
|
460
|
+
(0, chai_1.expect)(new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath).getProject()).to.equal("old-env");
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
it("--force signs in again instead of reusing the saved session", function () {
|
|
464
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
465
|
+
this.timeout(2000);
|
|
466
|
+
axiosStub
|
|
467
|
+
.onFirstCall()
|
|
468
|
+
.resolves(mockDeviceCodeResponse)
|
|
469
|
+
.onSecondCall()
|
|
470
|
+
.resolves(mockedAccessTokenResponse);
|
|
471
|
+
yield (0, login_1.login)("new-org", "http://localhost", tmpConfigFilePath, undefined, undefined, { force: true });
|
|
472
|
+
(0, chai_1.expect)(axiosStub.called, "a device-code sign-in").to.equal(true);
|
|
473
|
+
const stored = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
474
|
+
(0, chai_1.expect)(stored.getAccessToken()).to.equal("mock-access-token");
|
|
475
|
+
(0, chai_1.expect)(stored.getOrganization()).to.equal("new-org");
|
|
476
|
+
(0, chai_1.expect)(said()).to.eql([
|
|
477
|
+
"Login successful. Signed in to new-org on localhost.",
|
|
478
|
+
]);
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
it("--force leaves the other cells' credentials alone", function () {
|
|
482
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
483
|
+
this.timeout(2000);
|
|
484
|
+
new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath, "staging").setTokenPair({
|
|
485
|
+
accessToken: "staging-token",
|
|
486
|
+
});
|
|
487
|
+
axiosStub
|
|
488
|
+
.onFirstCall()
|
|
489
|
+
.resolves(mockDeviceCodeResponse)
|
|
490
|
+
.onSecondCall()
|
|
491
|
+
.resolves(mockedAccessTokenResponse);
|
|
492
|
+
yield (0, login_1.login)("new-org", "http://localhost", tmpConfigFilePath, undefined, "localhost", { force: true });
|
|
493
|
+
(0, chai_1.expect)(new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath, "staging").getAccessToken()).to.equal("staging-token");
|
|
494
|
+
});
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
describe("bareCellWarning", () => {
|
|
498
|
+
it("names the global cell and both ways to stop depending on it", () => {
|
|
499
|
+
(0, chai_1.expect)((0, login_1.bareCellWarning)("staging", {
|
|
500
|
+
deployment: "videoamp",
|
|
501
|
+
from: "global",
|
|
502
|
+
})).to.equal("Your global cell is still videoamp; pass --cell staging on every command or run `cred set cell staging`.");
|
|
503
|
+
});
|
|
504
|
+
it("points at re-pinning, not `set cell`, in a pinned directory", () => {
|
|
505
|
+
(0, chai_1.expect)((0, login_1.bareCellWarning)("staging", {
|
|
506
|
+
deployment: "videoamp",
|
|
507
|
+
from: "folder",
|
|
508
|
+
})).to.equal("This directory is pinned to videoamp; pass --cell staging on every command here, or re-pin with `cred --cell staging init`.");
|
|
509
|
+
});
|
|
510
|
+
it("says nothing when bare commands already resolve to the cell logged in to", () => {
|
|
511
|
+
(0, chai_1.expect)((0, login_1.bareCellWarning)("staging", {
|
|
512
|
+
deployment: "staging",
|
|
513
|
+
from: "folder",
|
|
514
|
+
})).to.equal(undefined);
|
|
515
|
+
});
|
|
516
|
+
});
|
|
517
|
+
// The saved token passed its local checks but the server refused it: the
|
|
518
|
+
// switch must fall back to a real sign-in, or every retry fails the same way.
|
|
519
|
+
it("signs in again when the server rejects the saved session", function () {
|
|
520
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
521
|
+
this.timeout(4000);
|
|
522
|
+
const config = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
523
|
+
config.setEnvironment("localhost");
|
|
524
|
+
config.setTokenPair({
|
|
525
|
+
accessToken: apiTokenExpiringIn(3600),
|
|
526
|
+
refreshToken: "r",
|
|
527
|
+
});
|
|
528
|
+
orgPermissionsStub
|
|
529
|
+
.onFirstCall()
|
|
530
|
+
.rejects(Object.assign(new Error("Request failed with status code 401"), {
|
|
531
|
+
isAxiosError: true,
|
|
532
|
+
response: { status: 401 },
|
|
533
|
+
}))
|
|
534
|
+
.onSecondCall()
|
|
535
|
+
.resolves(mockOrgPermissionsResponse);
|
|
536
|
+
axiosStub
|
|
537
|
+
.onFirstCall()
|
|
538
|
+
.resolves(mockDeviceCodeResponse)
|
|
539
|
+
.onSecondCall()
|
|
540
|
+
.resolves(mockedAccessTokenResponse);
|
|
541
|
+
yield (0, login_1.login)("new-org", "https://admin.example", tmpConfigFilePath);
|
|
542
|
+
(0, chai_1.expect)(axiosStub.called, "fell through to the device sign-in").to.equal(true);
|
|
543
|
+
(0, chai_1.expect)(new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath).getOrganization()).to.equal("new-org");
|
|
544
|
+
});
|
|
545
|
+
});
|
|
153
546
|
it("should set an access token when login succeeds", function () {
|
|
154
547
|
return __awaiter(this, void 0, void 0, function* () {
|
|
155
548
|
this.timeout(2000);
|
|
@@ -200,7 +593,7 @@ describe("login", () => {
|
|
|
200
593
|
return __awaiter(this, void 0, void 0, function* () {
|
|
201
594
|
this.timeout(2000);
|
|
202
595
|
const orgIdStub = sinon_1.default
|
|
203
|
-
.stub(
|
|
596
|
+
.stub(credEnvironments, "getAuth0OrganizationIdForCliLogin")
|
|
204
597
|
.returns("org_nMRKafeSuxOiuJeG");
|
|
205
598
|
const loopbackStub = sinon_1.default
|
|
206
599
|
.stub(loopbackOAuth, "authorizationCodeViaLoopback")
|
|
@@ -223,7 +616,7 @@ describe("login", () => {
|
|
|
223
616
|
return __awaiter(this, void 0, void 0, function* () {
|
|
224
617
|
this.timeout(2000);
|
|
225
618
|
const orgIdStub = sinon_1.default
|
|
226
|
-
.stub(
|
|
619
|
+
.stub(credEnvironments, "getAuth0OrganizationIdForCliLogin")
|
|
227
620
|
.callsFake((name) => name.toLowerCase() === "videoamp"
|
|
228
621
|
? "org_nMRKafeSuxOiuJeG"
|
|
229
622
|
: undefined);
|
|
@@ -246,7 +639,7 @@ describe("login", () => {
|
|
|
246
639
|
return __awaiter(this, void 0, void 0, function* () {
|
|
247
640
|
this.timeout(2000);
|
|
248
641
|
const orgIdStub = sinon_1.default
|
|
249
|
-
.stub(
|
|
642
|
+
.stub(credEnvironments, "getAuth0OrganizationIdForCliLogin")
|
|
250
643
|
.returns("org_nMRKafeSuxOiuJeG");
|
|
251
644
|
sinon_1.default
|
|
252
645
|
.stub(loopbackOAuth, "authorizationCodeViaLoopback")
|
|
@@ -282,10 +675,23 @@ describe("isLoginInvocation", () => {
|
|
|
282
675
|
(0, chai_1.expect)((0, login_1.isLoginInvocation)(["node", "/x/index.js", "login", "myorg"])).to.be
|
|
283
676
|
.true;
|
|
284
677
|
});
|
|
678
|
+
// The global flag comes before the command, so it is argv[2].
|
|
679
|
+
it("is true when --non-interactive comes before login", () => {
|
|
680
|
+
(0, chai_1.expect)((0, login_1.isLoginInvocation)([
|
|
681
|
+
"node",
|
|
682
|
+
"/x/index.js",
|
|
683
|
+
"--non-interactive",
|
|
684
|
+
"login",
|
|
685
|
+
"myorg",
|
|
686
|
+
])).to.be.true;
|
|
687
|
+
});
|
|
285
688
|
it("is false for other commands (they stay fail-loud on a corrupt config)", () => {
|
|
286
689
|
(0, chai_1.expect)((0, login_1.isLoginInvocation)(["node", "/x/index.js", "status"])).to.be.false;
|
|
287
690
|
(0, chai_1.expect)((0, login_1.isLoginInvocation)(["node", "/x/index.js", "publish"])).to.be.false;
|
|
288
691
|
(0, chai_1.expect)((0, login_1.isLoginInvocation)(["node", "/x/index.js"])).to.be.false;
|
|
692
|
+
// An argument to another command is not the command.
|
|
693
|
+
(0, chai_1.expect)((0, login_1.isLoginInvocation)(["node", "/x/index.js", "get", "login"])).to.be
|
|
694
|
+
.false;
|
|
289
695
|
});
|
|
290
696
|
});
|
|
291
697
|
// Drives the real binary entrypoint (src/index.ts), not recoverIfCorrupt() in
|
|
@@ -324,18 +730,23 @@ describe("entrypoint recovery for a corrupt ~/.cred (real index.ts)", () => {
|
|
|
324
730
|
let output = "";
|
|
325
731
|
child.stdout.on("data", (d) => (output += d.toString()));
|
|
326
732
|
child.stderr.on("data", (d) => (output += d.toString()));
|
|
733
|
+
// Registered now so it cannot be missed if the child exits on its own.
|
|
734
|
+
const closed = new Promise((r) => child.on("close", () => r()));
|
|
327
735
|
// Recovery runs synchronously at module load, before login() touches the
|
|
328
736
|
// network. It renames the corrupt file aside (.cred.corrupt-*) and THEN
|
|
329
737
|
// rewrites .cred to a valid default. Gate on the rewrite, not the backup:
|
|
330
738
|
// the backup appears first, so killing the instant it shows can catch the
|
|
331
739
|
// child in the gap before .cred is rewritten — a flaky ENOENT on the read
|
|
332
740
|
// below. resetComplete() only goes true once .cred is the valid default
|
|
333
|
-
// (which implies the backup already happened).
|
|
334
|
-
//
|
|
741
|
+
// (which implies the backup already happened). The report is printed AFTER
|
|
742
|
+
// that rewrite, so also wait for it: a loaded CI runner can pause the child
|
|
743
|
+
// between the two, and killing it there leaves `output` empty. Then stop
|
|
744
|
+
// the process (login otherwise blocks on the device-code flow).
|
|
335
745
|
const resetComplete = () => {
|
|
336
746
|
try {
|
|
337
747
|
return (JSON.parse(fs_1.default.readFileSync(credPath, "utf8"))
|
|
338
|
-
.activeEnvironment === "production"
|
|
748
|
+
.activeEnvironment === "production" &&
|
|
749
|
+
/reset to defaults/.test(output));
|
|
339
750
|
}
|
|
340
751
|
catch (_a) {
|
|
341
752
|
return false; // .cred absent or mid-rewrite
|
|
@@ -355,6 +766,8 @@ describe("entrypoint recovery for a corrupt ~/.cred (real index.ts)", () => {
|
|
|
355
766
|
});
|
|
356
767
|
});
|
|
357
768
|
child.kill("SIGKILL");
|
|
769
|
+
// Let the stdio streams drain so everything the child wrote is in `output`.
|
|
770
|
+
yield closed;
|
|
358
771
|
const backup = findBackup();
|
|
359
772
|
(0, chai_1.expect)(backup, "corrupt config should be backed up aside").to.be.a("string");
|
|
360
773
|
// The bad contents are preserved in the backup, not destroyed.
|
|
@@ -365,6 +778,111 @@ describe("entrypoint recovery for a corrupt ~/.cred (real index.ts)", () => {
|
|
|
365
778
|
(0, chai_1.expect)(reset.configPerEnvironment).to.be.an("object");
|
|
366
779
|
// The startup read no longer dead-ends on the structure error.
|
|
367
780
|
(0, chai_1.expect)(output).to.not.match(/Invalid config structure/);
|
|
781
|
+
// And it SAYS so. `recoverIfCorrupt` returns the backup path instead of
|
|
782
|
+
// logging (setup-core owns no logger), which makes reporting the caller's
|
|
783
|
+
// job — and a caller that drops the return value resets a user's tokens
|
|
784
|
+
// and moves their file with no output at all. Asserting the absence of an
|
|
785
|
+
// error above cannot catch that; only asserting the presence of this can.
|
|
786
|
+
(0, chai_1.expect)(output, "the reset must be reported, not silent").to.match(/reset to defaults/);
|
|
787
|
+
(0, chai_1.expect)(output).to.contain(backup);
|
|
788
|
+
});
|
|
789
|
+
});
|
|
790
|
+
});
|
|
791
|
+
describe("login without an organization argument", () => {
|
|
792
|
+
let tmpConfigFilePath;
|
|
793
|
+
let axiosStub;
|
|
794
|
+
let listOrgsStub;
|
|
795
|
+
let selectStub;
|
|
796
|
+
const mockDeviceCode = {
|
|
797
|
+
data: {
|
|
798
|
+
verification_uri_complete: "https://example.com",
|
|
799
|
+
user_code: "123456",
|
|
800
|
+
device_code: "device-code-123",
|
|
801
|
+
interval: 1,
|
|
802
|
+
},
|
|
803
|
+
};
|
|
804
|
+
const mockTokens = {
|
|
805
|
+
data: {
|
|
806
|
+
id_token: createFakeIdToken({ name: "T", email: "t@example.com" }),
|
|
807
|
+
access_token: "mock-access-token",
|
|
808
|
+
refresh_token: "mock-refresh-token",
|
|
809
|
+
},
|
|
810
|
+
};
|
|
811
|
+
beforeEach(() => {
|
|
812
|
+
// Never a real browser from a test run, even one started at a terminal.
|
|
813
|
+
sinon_1.default.stub(browser, "shouldOpenBrowser").returns(false);
|
|
814
|
+
tmpConfigFilePath = (0, path_1.join)(fs_1.default.mkdtempSync((0, path_1.join)(os_1.default.tmpdir(), "cred-orgless-")), "cred.json");
|
|
815
|
+
fs_1.default.writeFileSync(tmpConfigFilePath, JSON.stringify({
|
|
816
|
+
configPerEnvironment: { localhost: {} },
|
|
817
|
+
activeEnvironment: "localhost",
|
|
818
|
+
}));
|
|
819
|
+
axiosStub = sinon_1.default
|
|
820
|
+
.stub(axios_1.default, "request")
|
|
821
|
+
.onFirstCall()
|
|
822
|
+
.resolves(mockDeviceCode)
|
|
823
|
+
.onSecondCall()
|
|
824
|
+
.resolves(mockTokens);
|
|
825
|
+
sinon_1.default
|
|
826
|
+
.stub(api_1.OrganizationsApi.prototype, "getOrganization")
|
|
827
|
+
.resolves({ status: 200, data: {} });
|
|
828
|
+
listOrgsStub = sinon_1.default.stub(api_1.OrganizationsApi.prototype, "listOrganizations");
|
|
829
|
+
selectStub = sinon_1.default.stub(utils, "selectFromList");
|
|
830
|
+
});
|
|
831
|
+
afterEach(() => {
|
|
832
|
+
sinon_1.default.restore();
|
|
833
|
+
fs_1.default.rmSync(tmpConfigFilePath, { force: true });
|
|
834
|
+
});
|
|
835
|
+
it("auto-selects when the user belongs to exactly one organization", function () {
|
|
836
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
837
|
+
this.timeout(2000);
|
|
838
|
+
listOrgsStub.resolves({ data: [{ name: "only-org" }] });
|
|
839
|
+
// selectFromList returns a single choice without prompting; assert the
|
|
840
|
+
// stored org rather than trusting the prompt was skipped by accident.
|
|
841
|
+
selectStub.callsFake((_msg, choices) => __awaiter(this, void 0, void 0, function* () { return choices.length === 1 ? choices[0].value : undefined; }));
|
|
842
|
+
yield (0, login_1.login)(undefined, "http://admin.ms2.localhost/api/v0", tmpConfigFilePath);
|
|
843
|
+
const config = new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath);
|
|
844
|
+
(0, chai_1.expect)(config.getOrganization()).to.equal("only-org");
|
|
845
|
+
});
|
|
846
|
+
});
|
|
847
|
+
it("prompts when the user belongs to several organizations, and shows display names", function () {
|
|
848
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
849
|
+
this.timeout(2000);
|
|
850
|
+
listOrgsStub.resolves({
|
|
851
|
+
data: [{ name: "alpha", displayName: "Alpha Inc" }, { name: "beta" }],
|
|
852
|
+
});
|
|
853
|
+
selectStub.resolves("beta");
|
|
854
|
+
yield (0, login_1.login)(undefined, "http://admin.ms2.localhost/api/v0", tmpConfigFilePath);
|
|
855
|
+
(0, chai_1.expect)(selectStub.calledOnce).to.equal(true);
|
|
856
|
+
(0, chai_1.expect)(selectStub.getCall(0).args[1]).to.eql([
|
|
857
|
+
{ name: "alpha (Alpha Inc)", value: "alpha" },
|
|
858
|
+
{ name: "beta", value: "beta" },
|
|
859
|
+
]);
|
|
860
|
+
(0, chai_1.expect)(new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath).getOrganization()).to.equal("beta");
|
|
861
|
+
});
|
|
862
|
+
});
|
|
863
|
+
it("skips entries the control plane returned without a name", function () {
|
|
864
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
865
|
+
this.timeout(2000);
|
|
866
|
+
listOrgsStub.resolves({
|
|
867
|
+
data: [{ displayName: "No name" }, { name: "real" }],
|
|
868
|
+
});
|
|
869
|
+
selectStub.callsFake((_msg, choices) => __awaiter(this, void 0, void 0, function* () { return choices.length === 1 ? choices[0].value : undefined; }));
|
|
870
|
+
yield (0, login_1.login)(undefined, "http://admin.ms2.localhost/api/v0", tmpConfigFilePath);
|
|
871
|
+
(0, chai_1.expect)(selectStub.getCall(0).args[1]).to.eql([
|
|
872
|
+
{ name: "real", value: "real" },
|
|
873
|
+
]);
|
|
874
|
+
});
|
|
875
|
+
});
|
|
876
|
+
it("does not list organizations when one was named (scripted use stays one call)", function () {
|
|
877
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
878
|
+
this.timeout(2000);
|
|
879
|
+
yield (0, login_1.login)("given-org", "http://admin.ms2.localhost/api/v0", tmpConfigFilePath);
|
|
880
|
+
(0, chai_1.expect)(listOrgsStub.called).to.equal(false);
|
|
881
|
+
(0, chai_1.expect)(selectStub.called).to.equal(false);
|
|
882
|
+
// Assert the login actually completed, so this test cannot pass by
|
|
883
|
+
// failing early before it would have listed organizations.
|
|
884
|
+
(0, chai_1.expect)(new clientconfiguration_1.ClientConfiguration(tmpConfigFilePath).getOrganization()).to.equal("given-org");
|
|
885
|
+
(0, chai_1.expect)(axiosStub.called).to.equal(true);
|
|
368
886
|
});
|
|
369
887
|
});
|
|
370
888
|
});
|