Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/lib/defaults.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module.exports = {
defaultImageCacheDuration: '604800',
AIO_CONFIG_IMS_ORG_ID: 'project.org.ims_org_id',
SERVICE_API_KEY_ENV: 'SERVICE_API_KEY',
IMS_OAUTH_S2S_ENV: 'IMS_OAUTH_S2S',
ENTP_INT_CERTS_FOLDER: 'entp-int-certs',
CONSOLE_API_KEYS: {
prod: 'aio-cli-console-auth',
Expand Down
23 changes: 23 additions & 0 deletions src/lib/import-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -734,8 +734,31 @@ const getProjectCredentialType = (projectConfig, flags) => {
return LibConsoleCLI.OAUTH_SERVER_TO_SERVER_CREDENTIAL
}

/**
* Get the OAuth server_to_server credential in IMS API format, from the console config.
*
* @param {object} config Console config object
* @returns {{ client_id, client_secret, org_id, scopes } | undefined} OAuthS2S credential or undefined
*/
const getOAuthS2SCredential = (config) => {
const credential = config?.project?.workspace?.details?.credentials
?.find(c => c.integration_type === 'oauth_server_to_server')
?.oauth_server_to_server
const imsOrgId = config?.project?.org?.ims_org_id

if (credential) {
return {
client_id: credential.client_id,
client_secret: credential.client_secrets[0], // take the first secret
org_id: imsOrgId,
scopes: credential.scopes
}
}
}

module.exports = {
getServiceApiKey,
getOAuthS2SCredential,
writeFile,
loadConfigFile,
loadAndValidateConfigFile,
Expand Down
13 changes: 10 additions & 3 deletions src/lib/import.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { loadAndValidateConfigFile, importConfigJson, loadConfigFile, getServiceApiKey } = require('./import-helper')
const { SERVICE_API_KEY_ENV } = require('./defaults')
const { loadAndValidateConfigFile, importConfigJson, loadConfigFile, getServiceApiKey, getOAuthS2SCredential } = require('./import-helper')
const { SERVICE_API_KEY_ENV, IMS_OAUTH_S2S_ENV } = require('./defaults')

/**
* Imports the project's console config to the local environment.
Expand All @@ -23,7 +23,14 @@ async function importConsoleConfig (consoleConfigFileOrBuffer, flags) {
const config = loadFunc(consoleConfigFileOrBuffer).values

const serviceClientId = getServiceApiKey(config, useJwt)
const extraEnvVars = { [SERVICE_API_KEY_ENV]: serviceClientId }
const oauthS2SCredential = getOAuthS2SCredential(config)

let extraEnvVars
if (typeof oauthS2SCredential === 'object') {
extraEnvVars = { [SERVICE_API_KEY_ENV]: serviceClientId, [IMS_OAUTH_S2S_ENV]: JSON.stringify(oauthS2SCredential) }
} else {
extraEnvVars = { [SERVICE_API_KEY_ENV]: serviceClientId }
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: we should deprecate and delete that one eventually

}

await importConfigJson(consoleConfigFileOrBuffer, process.cwd(), { interactive, overwrite, merge, useJwt }, extraEnvVars)
return config
Expand Down
41 changes: 41 additions & 0 deletions test/commands/lib/import-helper.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ inquirer.createPromptModule.mockReturnValue(mockPrompt)

const {
getServiceApiKey,
getOAuthS2SCredential,
loadAndValidateConfigFile,
importConfigJson,
writeAio,
Expand All @@ -41,6 +42,9 @@ test('exports', () => {
expect(getServiceApiKey).toBeDefined()
expect(getServiceApiKey).toBeInstanceOf(Function)

expect(getOAuthS2SCredential).toBeDefined()
expect(getOAuthS2SCredential).toBeInstanceOf(Function)

expect(loadAndValidateConfigFile).toBeDefined()
expect(loadAndValidateConfigFile).toBeInstanceOf(Function)

Expand Down Expand Up @@ -446,3 +450,40 @@ describe('getServiceApiKey', () => {
expect(getServiceApiKey(config, true)).toEqual('XUXUXUXUXUXUXUX')
})
})

describe('getOAuthS2SCredential', () => {
test('bad config (undefined)', () => {
expect(getOAuthS2SCredential(undefined)).toBeUndefined()
})

test('bad config (empty object)', () => {
expect(getOAuthS2SCredential({})).toBeUndefined()
})

test('config file only has jwt (no OAuth S2S)', () => {
const config = fixtureHjson('valid.config.json')
expect(getOAuthS2SCredential(config)).toBeUndefined()
})

test('config file has no OAuth S2S credentials', () => {
const config = fixtureHjson('oauths2s/valid.config.no.creds.json')
expect(getOAuthS2SCredential(config)).toBeUndefined()
})

test('config file has OAuth S2S', () => {
const config = fixtureHjson('oauths2s/valid.config.json')
expect(getOAuthS2SCredential(config)).toEqual({
client_id: 'CXCXCXCXCXCXCXCXC',
client_secret: 'SFSFSFSFSFSFSFSFSFSFSFSFSFS',
org_id: 'XOXOXOXOXOXOX@AdobeOrg',
scopes: ['openid', 'AdobeID']
})
})

test('config file has OAuth S2S (migration, contains jwt)', () => {
// Note: migration configs have integration_type 'oauth_server_to_server_migrate', not 'oauth_server_to_server'
// so getOAuthS2SCredential should return undefined for migration configs
const config = fixtureHjson('oauths2s/valid.config.migrate.json')
expect(getOAuthS2SCredential(config)).toBeUndefined()
})
})
46 changes: 46 additions & 0 deletions test/commands/lib/import.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@ OF ANY KIND, either express or implied. See the License for the specific languag
governing permissions and limitations under the License.
*/
const inquirer = require('inquirer')
const fs = require('fs-extra')

// mock prompt before import
const mockPrompt = jest.fn()
inquirer.createPromptModule.mockReturnValue(mockPrompt)

const { importConsoleConfig, downloadConsoleConfigToBuffer } = require('../../../src/lib/import')
const { SERVICE_API_KEY_ENV, IMS_OAUTH_S2S_ENV } = require('../../../src/lib/defaults')

jest.mock('fs-extra')

beforeEach(() => {
jest.clearAllMocks()
Expand All @@ -29,4 +33,46 @@ test('exports', () => {
expect(downloadConsoleConfigToBuffer).toBeInstanceOf(Function)
})

describe('importConsoleConfig', () => {
test('with oauth_server_to_server credentials, adds IMS_OAUTH_S2S to env vars', async () => {
const configContent = fixtureFile('oauths2s/valid.config.json')
// The file is read twice: once by importConsoleConfig (loadFunc) and once by importConfigJson
fs.readFileSync.mockReturnValue(configContent)

const config = await importConsoleConfig('/some/config/path', { overwrite: true })

expect(config).toBeDefined()
expect(config.project.name).toEqual('TestProject123')

// Check that writeFile was called with the IMS_OAUTH_S2S_ENV variable
const envWriteCall = fs.writeFile.mock.calls.find(call => call[0].endsWith('.env'))
expect(envWriteCall).toBeDefined()
expect(envWriteCall[1]).toContain(SERVICE_API_KEY_ENV)
expect(envWriteCall[1]).toContain(IMS_OAUTH_S2S_ENV)

// Verify the IMS_OAUTH_S2S value contains expected credential data
const envContent = envWriteCall[1]
expect(envContent).toContain('"client_id":"CXCXCXCXCXCXCXCXC"')
expect(envContent).toContain('"client_secret":"SFSFSFSFSFSFSFSFSFSFSFSFSFS"')
expect(envContent).toContain('"org_id":"XOXOXOXOXOXOX@AdobeOrg"')
})

test('with jwt credentials only, does not add IMS_OAUTH_S2S to env vars', async () => {
const configContent = fixtureFile('valid.config.json')
// The file is read twice: once by importConsoleConfig (loadFunc) and once by importConfigJson
fs.readFileSync.mockReturnValue(configContent)

const config = await importConsoleConfig('/some/config/path', { overwrite: true })

expect(config).toBeDefined()
expect(config.project.name).toEqual('TestProject123')

// Check that writeFile was called without the IMS_OAUTH_S2S_ENV variable
const envWriteCall = fs.writeFile.mock.calls.find(call => call[0].endsWith('.env'))
expect(envWriteCall).toBeDefined()
expect(envWriteCall[1]).toContain(SERVICE_API_KEY_ENV)
expect(envWriteCall[1]).not.toContain(IMS_OAUTH_S2S_ENV)
})
})

// The functions in this module are largely tested by use.test.js