diff --git a/.talismanrc b/.talismanrc index 7fa0724..9eae385 100644 --- a/.talismanrc +++ b/.talismanrc @@ -345,13 +345,13 @@ fileignoreconfig: - filename: src/environments/environment.errors.test.ts checksum: 33ae71db0a46173c903659438a77d1d441797a8296e0591dbaa48512f32a4cab - filename: src/stacks/stacks.api.test.ts - checksum: db0c613f10361fa6aafa71cc09d217a3c5a7f924523901469b174807b7b9b237 + checksum: 67e00bd82b3c3a96c05585f36a3c3ace7f06eff535bc347fe9937033775cf5cc - filename: src/stacks/stacks.api.ts checksum: 7241b9c2c6e946c11849bb5fb21842c03eca09f9ed6c901be198fd544ce8f769 - filename: src/variables/variable.chooser.ts checksum: 15a6b8a1a974c8d0396ac18d8c9d39c8bc9f70efbf41ce0eef79180ce16b2f04 - filename: src/variables/variable.create.test.ts - checksum: 48b9864639a01e05b8c6de9ce5ef1abad7ba990ecfbe7f47d0df3d3e759344b8 + checksum: 71dbed4ca09e86e761026955c7865f12e4f168e3afcf4c4ef664d3de319a2697 - filename: src/variables/variable.dotenv.test.ts checksum: c3d5e33189736bb42b7c4fac7375cf0307681b34feca4830b49331f55a130f78 - filename: src/variables/variable.dotenv.ts @@ -377,13 +377,13 @@ fileignoreconfig: - filename: src/variables/variable.presenter.ts checksum: ee8e4dcf75ad7e849d1e8e64ce6a6549d13fc62dc9aa322d96eb2e725d629db5 - filename: src/variables/variable.set.test.ts - checksum: f6a59e15775ea4247ec3860d4d3fad495b1624ed8a9d834c79a3fcc3033df58e + checksum: 68bd428a7f0a26e495cd9f79779cbc9fb5017cdee684594e90a983ea14303a62 - filename: src/variables/variable.sources.test.ts checksum: 63ad95e998cbc6d33fabe4ce76797e8788b17abec3833b4fed2360eab01a6f79 - filename: src/variables/variable.sources.ts checksum: c2c7e442c6fed29b11843850ad86c8603540fcc174e1fac79993c8e26d95e8dc - filename: src/variables/variable.stack.test.ts - checksum: 75db498059c80145ed72ef4ec4c3e787cca31ab1e7e41ad563ec90fa6dfc035d + checksum: d221484c0709aeb6de9359f533ee79d73513a878cace0a6247439917d658ce4f - filename: src/variables/variable.stack.ts checksum: 0c5116d39bacccdb6e813357dd091e90274383761832f19d3a9b5433a21d99ae - filename: src/variables/variable.summary.test.ts diff --git a/src/stacks/stacks.api.test.ts b/src/stacks/stacks.api.test.ts index ce6a043..88de253 100644 --- a/src/stacks/stacks.api.test.ts +++ b/src/stacks/stacks.api.test.ts @@ -1,8 +1,13 @@ +import { randomUUID } from 'node:crypto'; import { EXIT_RUNTIME } from '../core/constants'; import type { CmaCollection, CmaSession } from '../transport/cma-client'; import { StackLookupError } from './stack.errors'; import { StacksApi } from './stacks.api'; +const TOKEN_A = `cs-${randomUUID()}`; +const TOKEN_B = `cs-${randomUUID()}`; +const TOKEN_C = `cs-${randomUUID()}`; + function session(stacks: CmaCollection | Error, tokens: CmaCollection | Error) { const asked: { stacks: string[]; tokens: string[] } = { stacks: [], tokens: [] }; const cma = { @@ -63,15 +68,15 @@ describe('stacks api', () => { {}, { items: [ - { name: 'prod-token', token: 'cs-aaa', scope: [{ module: 'environment', environments: [{ name: 'production' }, { name: 'staging' }] }] }, - { name: 'dev-token', token: 'cs-bbb', scope: [{ module: 'environment', environments: [{ name: 'development' }] }] }, + { name: 'prod-token', token: TOKEN_A, scope: [{ module: 'environment', environments: [{ name: 'production' }, { name: 'staging' }] }] }, + { name: 'dev-token', token: TOKEN_B, scope: [{ module: 'environment', environments: [{ name: 'development' }] }] }, ], }, ); await expect(api.deliveryTokens('blt1')).resolves.toEqual([ - { name: 'prod-token', token: 'cs-aaa', environment: 'production' }, - { name: 'dev-token', token: 'cs-bbb', environment: 'development' }, + { name: 'prod-token', token: TOKEN_A, environment: 'production' }, + { name: 'dev-token', token: TOKEN_B, environment: 'development' }, ]); expect(asked.tokens).toEqual(['blt1']); }); @@ -85,20 +90,20 @@ describe('stacks api', () => { [[{ module: 'environment', environments: [{}] }]], [[null, 'text']], ])('leaves the environment unset when the token scope names none (%p)', async (scope) => { - const { api } = session({}, { items: [{ name: 'prod-token', token: 'cs-aaa', scope }] }); + const { api } = session({}, { items: [{ name: 'prod-token', token: TOKEN_A, scope }] }); - await expect(api.deliveryTokens('blt1')).resolves.toEqual([{ name: 'prod-token', token: 'cs-aaa', environment: undefined }]); + await expect(api.deliveryTokens('blt1')).resolves.toEqual([{ name: 'prod-token', token: TOKEN_A, environment: undefined }]); }); it('skips a token with no value and names one by its position when it has no name', async () => { const { api } = session( {}, - { items: [{ name: 'no-value' }, { token: 'cs-bbb' }, { name: 'blank', token: ' ' }, null, { name: 'ok', token: 'cs-ccc' }] }, + { items: [{ name: 'no-value' }, { token: TOKEN_B }, { name: 'blank', token: ' ' }, null, { name: 'ok', token: TOKEN_C }] }, ); await expect(api.deliveryTokens('blt1')).resolves.toEqual([ - { name: 'Delivery token 2', token: 'cs-bbb', environment: undefined }, - { name: 'ok', token: 'cs-ccc', environment: undefined }, + { name: 'Delivery token 2', token: TOKEN_B, environment: undefined }, + { name: 'ok', token: TOKEN_C, environment: undefined }, ]); }); diff --git a/src/variables/variable.create.test.ts b/src/variables/variable.create.test.ts index a4e372a..a9d59d8 100644 --- a/src/variables/variable.create.test.ts +++ b/src/variables/variable.create.test.ts @@ -1,8 +1,12 @@ +import { randomUUID } from 'node:crypto'; import { CancelledError, UsageError } from '../core/errors'; import type { UxLike } from '../core/prompt'; import type { ServiceContext } from '../core/service-context'; import { variablesForCreate } from './variable.create'; +const PICKED_TOKEN = `cs-${randomUUID()}`; +const SAVED_TOKEN = `cs-${randomUUID()}`; + const STACK = 'Import variables from a stack'; const SKIP = 'Skip adding environment variables'; const FILE = 'Import variables from a dotenv file'; @@ -42,7 +46,7 @@ function fakes(options: { isTTY?: boolean; answers?: Record; fi api: { stacks: { list: async () => [{ name: 'Shop', apiKey: 'blt1' }], - deliveryTokens: async () => [{ name: 'prod-token', token: 'cs-picked-value', environment: 'production' }], + deliveryTokens: async () => [{ name: 'prod-token', token: PICKED_TOKEN, environment: 'production' }], }, variables: { stackTemplate: async () => [{ key: 'CONTENTSTACK_API_HOST', value: 'api.example.test' }] }, }, @@ -249,7 +253,7 @@ describe('variable create', () => { it('imports through --from-stack and --alias without asking, merging it before a typed --var', async () => { const { services, io, asked, printed } = fakes(); const savedToken = (alias: string) => - alias === 'my-prod' ? { token: 'cs-saved-value', apiKey: 'blt9', environment: 'staging' } : undefined; + alias === 'my-prod' ? { token: SAVED_TOKEN, apiKey: 'blt9', environment: 'staging' } : undefined; const variables = await variablesForCreate( { vars: ['CONTENTSTACK_ENVIRONMENT=override'], envFiles: undefined, dataDir: '/work', org: 'org1', fromStack: true, alias: 'my-prod' }, @@ -261,7 +265,7 @@ describe('variable create', () => { expect(variables).toEqual([ { key: 'CONTENTSTACK_API_HOST', value: 'api.example.test' }, { key: 'CONTENTSTACK_API_KEY', value: 'blt9' }, - { key: 'CONTENTSTACK_DELIVERY_TOKEN', value: 'cs-saved-value' }, + { key: 'CONTENTSTACK_DELIVERY_TOKEN', value: SAVED_TOKEN }, { key: 'CONTENTSTACK_ENVIRONMENT', value: 'override' }, ]); expect(asked).toEqual([]); @@ -270,7 +274,7 @@ describe('variable create', () => { 'No value was available for CONTENTSTACK_CDN, so it was not imported.', '\u2714 4 variables ready to set \u2014 4 from stack, CONTENTSTACK_ENVIRONMENT overridden by --var', ]); - expect(printed.join('\n')).not.toContain('cs-saved-value'); + expect(printed.join('\n')).not.toContain(SAVED_TOKEN); }); it('refuses --from-stack without --alias when there is no terminal, asking nothing', async () => { @@ -308,7 +312,7 @@ describe('variable create', () => { 'EXTRA', ]); expect(printed.join('\n')).toContain('4 from stack'); - expect(printed.join('\n')).not.toContain('cs-picked-value'); + expect(printed.join('\n')).not.toContain(PICKED_TOKEN); }); it('refuses Skip combined with the stack choice', async () => { diff --git a/src/variables/variable.set.test.ts b/src/variables/variable.set.test.ts index 975fb3f..9b2aec8 100644 --- a/src/variables/variable.set.test.ts +++ b/src/variables/variable.set.test.ts @@ -1,3 +1,4 @@ +import { randomUUID } from 'node:crypto'; import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; @@ -10,6 +11,8 @@ import { DEFAULT_VARIABLE_IO } from './variable.io'; import { VariableSetter } from './variable.set'; import type { SavedToken } from './variable.stack'; +const SECRET_TOKEN = `cs-${randomUUID()}`; + const SCOPE = { org: 'org1', project: 'proj1', environment: 'env1' }; function fakes( @@ -195,7 +198,7 @@ describe('variable setter with --from-stack', () => { it('imports through the saved token under the alias for the same organization, merges it in and names the stack', async () => { const { setter, printed, templateAsked, aliasAsked, updates } = stackSetter({ - token: 'cs-secret-token', + token: SECRET_TOKEN, apiKey: 'blt9', environment: 'staging', }); @@ -208,7 +211,7 @@ describe('variable setter with --from-stack', () => { { key: 'KEEP', value: 'k' }, { key: 'CONTENTSTACK_API_HOST', value: 'api.example.test' }, { key: 'CONTENTSTACK_API_KEY', value: 'blt9' }, - { key: 'CONTENTSTACK_DELIVERY_TOKEN', value: 'cs-secret-token' }, + { key: 'CONTENTSTACK_DELIVERY_TOKEN', value: SECRET_TOKEN }, { key: 'CONTENTSTACK_ENVIRONMENT', value: 'staging' }, ]); expect(printed).toEqual([ @@ -216,7 +219,7 @@ describe('variable setter with --from-stack', () => { 'No value was available for CONTENTSTACK_CDN, so it was not imported.', '\u2714 4 variables set \u2014 4 from stack', ]); - expect(printed.join('\n')).not.toContain('cs-secret-token'); + expect(printed.join('\n')).not.toContain(SECRET_TOKEN); }); it('writes nothing when the alias has no saved token', async () => { diff --git a/src/variables/variable.stack.test.ts b/src/variables/variable.stack.test.ts index ff1b2d2..ae99da4 100644 --- a/src/variables/variable.stack.test.ts +++ b/src/variables/variable.stack.test.ts @@ -1,3 +1,4 @@ +import { randomUUID } from 'node:crypto'; import { configHandler } from '@contentstack/cli-utilities'; import { CancelledError, UsageError } from '../core/errors'; @@ -9,6 +10,12 @@ import type { StackTemplateEntry } from './variables.api'; import { importFromStack, readSavedToken } from './variable.stack'; import type { SavedToken } from './variable.stack'; +const PROD_TOKEN = `cs-${randomUUID()}`; +const DEV_TOKEN = `cs-${randomUUID()}`; +const SAVED_TOKEN = `cs-${randomUUID()}`; +const LOOSE_TOKEN = `cs-${randomUUID()}`; +const OTHER_TOKEN = `cs-${randomUUID()}`; + const TEMPLATE: StackTemplateEntry[] = [ { key: 'CONTENTSTACK_API_HOST', value: 'https://api.example.test' }, { key: 'CONTENTSTACK_CDN', value: 'cdn.example.test' }, @@ -23,8 +30,8 @@ const STACKS: Stack[] = [ ]; const TOKENS: DeliveryToken[] = [ - { name: 'prod-token', token: 'cs-prod-value', environment: 'production' }, - { name: 'dev-token', token: 'cs-dev-value', environment: 'development' }, + { name: 'prod-token', token: PROD_TOKEN, environment: 'production' }, + { name: 'dev-token', token: DEV_TOKEN, environment: 'development' }, ]; interface Scenario { @@ -88,7 +95,7 @@ function fakes(scenario: Scenario = {}) { return { services, calls, printed, prompts }; } -const SAVED: SavedToken = { token: 'cs-saved-value', apiKey: 'blt9', environment: 'staging' }; +const SAVED: SavedToken = { token: SAVED_TOKEN, apiKey: 'blt9', environment: 'staging' }; function saved(entries: Record) { const asked: string[] = []; @@ -115,13 +122,13 @@ describe('variable stack import with --alias', () => { { key: 'CONTENTSTACK_API_HOST', value: 'api.example.test' }, { key: 'CONTENTSTACK_CDN', value: 'cdn.example.test' }, { key: 'CONTENTSTACK_API_KEY', value: 'blt9' }, - { key: 'CONTENTSTACK_DELIVERY_TOKEN', value: 'cs-saved-value' }, + { key: 'CONTENTSTACK_DELIVERY_TOKEN', value: SAVED_TOKEN }, { key: 'CONTENTSTACK_ENVIRONMENT', value: 'staging' }, ]); expect(asked).toEqual(['my-prod']); expect(calls).toEqual(['template:org1']); expect(printed).toEqual(['Using the saved delivery token "my-prod" (environment staging).']); - expect(printed.join('\n')).not.toContain('cs-saved-value'); + expect(printed.join('\n')).not.toContain(SAVED_TOKEN); }); it('omits the host and CDN when the template carries no value for them', async () => { @@ -144,7 +151,7 @@ describe('variable stack import with --alias', () => { await importFromStack({ org: 'org1', alias: 'a' }, { services, savedToken }); expect(printed).toContain('No value was available for CONTENTSTACK_CDN, so it was not imported.'); - expect(printed.join('\n')).not.toContain('cs-saved-value'); + expect(printed.join('\n')).not.toContain(SAVED_TOKEN); }); it('keeps a host that is not a url as it is and reduces a url to its host and port', async () => { @@ -245,7 +252,7 @@ describe('variable stack import without --alias', () => { { key: 'CONTENTSTACK_API_HOST', value: 'api.example.test' }, { key: 'CONTENTSTACK_CDN', value: 'cdn.example.test' }, { key: 'CONTENTSTACK_API_KEY', value: 'blt2' }, - { key: 'CONTENTSTACK_DELIVERY_TOKEN', value: 'cs-prod-value' }, + { key: 'CONTENTSTACK_DELIVERY_TOKEN', value: PROD_TOKEN }, { key: 'CONTENTSTACK_ENVIRONMENT', value: 'production' }, ]); expect(prompts[0].payload).toMatchObject({ @@ -262,13 +269,13 @@ describe('variable stack import without --alias', () => { ], }); expect(printed).toEqual(['Using delivery token "prod-token" of stack "Blog" (environment production).']); - expect(JSON.stringify({ printed, prompts })).not.toContain('cs-prod-value'); + expect(JSON.stringify({ printed, prompts })).not.toContain(PROD_TOKEN); }); it('offers a token with no environment without the parenthesis and then refuses it', async () => { const { services, prompts } = fakes({ answers: { Stack: '0', 'Delivery token': '0' }, - tokens: [{ name: 'loose', token: 'cs-loose', environment: undefined }], + tokens: [{ name: 'loose', token: LOOSE_TOKEN, environment: undefined }], }); await expect(importFromStack({ org: 'org1' }, { services, savedToken: NOTHING_SAVED })).rejects.toThrow( @@ -341,16 +348,16 @@ describe('readSavedToken', () => { } it('reads the token csdx auth:tokens:add saved under the alias', () => { - const asked = configHolding({ 'my-prod': { token: 'cs-x', apiKey: 'blt1', environment: 'production', type: 'delivery' } }); + const asked = configHolding({ 'my-prod': { token: OTHER_TOKEN, apiKey: 'blt1', environment: 'production', type: 'delivery' } }); - expect(readSavedToken('my-prod')).toEqual({ token: 'cs-x', apiKey: 'blt1', environment: 'production', type: 'delivery' }); + expect(readSavedToken('my-prod')).toEqual({ token: OTHER_TOKEN, apiKey: 'blt1', environment: 'production', type: 'delivery' }); expect(asked).toEqual(['tokens']); }); it('leaves the environment and type unset when the entry has none', () => { - configHolding({ a: { token: 'cs-x', apiKey: 'blt1' } }); + configHolding({ a: { token: OTHER_TOKEN, apiKey: 'blt1' } }); - expect(readSavedToken('a')).toEqual({ token: 'cs-x', apiKey: 'blt1', environment: undefined, type: undefined }); + expect(readSavedToken('a')).toEqual({ token: OTHER_TOKEN, apiKey: 'blt1', environment: undefined, type: undefined }); }); it.each([ @@ -358,10 +365,10 @@ describe('readSavedToken', () => { [null], ['text'], [{}], - [{ token: 'cs-x' }], + [{ token: OTHER_TOKEN }], [{ apiKey: 'blt1' }], [{ token: '', apiKey: 'blt1' }], - [{ token: 'cs-x', apiKey: ' ' }], + [{ token: OTHER_TOKEN, apiKey: ' ' }], ])('reports no saved token for an entry of %p', (entry) => { configHolding({ a: entry }); @@ -369,12 +376,12 @@ describe('readSavedToken', () => { }); it('finds an alias that contains a dot', () => { - configHolding({ 'prod.eu': { token: 'cs-x', apiKey: 'blt1' } }); + configHolding({ 'prod.eu': { token: OTHER_TOKEN, apiKey: 'blt1' } }); - expect(readSavedToken('prod.eu')).toEqual({ token: 'cs-x', apiKey: 'blt1', environment: undefined, type: undefined }); + expect(readSavedToken('prod.eu')).toEqual({ token: OTHER_TOKEN, apiKey: 'blt1', environment: undefined, type: undefined }); }); - it.each([[undefined], [null], ['text'], [{}], [{ other: { token: 'cs-x', apiKey: 'blt1' } }]])( + it.each([[undefined], [null], ['text'], [{}], [{ other: { token: OTHER_TOKEN, apiKey: 'blt1' } }]])( 'reports no saved token when the tokens config holds %p', (tokens) => { configHolding(tokens);