Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"@adobe/aio-lib-core-config": "^5",
"@adobe/aio-lib-core-logging": "^3",
"@adobe/aio-lib-env": "^3",
"@adobe/aio-lib-runtime": "^7.0.0",
"@adobe/aio-lib-runtime": "next",
Comment thread
moritzraho marked this conversation as resolved.
Outdated
"@adobe/aio-lib-web": "^7",
"@oclif/core": "^3",
"chalk": "^4",
Expand Down
13 changes: 13 additions & 0 deletions src/lib/run-dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ const utils = require('./app-helper')
const { SERVER_HOST, SERVER_DEFAULT_PORT, BUNDLER_DEFAULT_PORT, DEV_API_PREFIX, DEV_API_WEB_PREFIX, BUNDLE_OPTIONS, CHANGED_ASSETS_PRINT_LIMIT } = require('./constants')
const RAW_CONTENT_TYPES = ['application/octet-stream', 'multipart/form-data']

// for the include-ims-credentials annotation
let imsAuthObject = null

/* global Request, Response */

/**
Expand Down Expand Up @@ -86,6 +89,9 @@ async function runDev (runOptions, config, _inprocHookRunner) {
// ex. console.log('AIO_DEV ', process.env.AIO_DEV ? 'dev' : 'prod')
process.env.AIO_DEV = 'true'

// include ims credentials inputs __ims_oauth_s2s and __ims_env
imsAuthObject = rtLib.utils.loadIMSCredentialsFromEnv()

const serverPortToUse = parseInt(process.env.PORT) || SERVER_DEFAULT_PORT
const serverPort = await getPort({ port: serverPortToUse })

Expand Down Expand Up @@ -346,6 +352,13 @@ async function invokeAction ({ actionRequestContext, logger }) {
}
}

// process the include-ims-credentials annotation
const newInputs = rtLib.utils.getIncludeIMSCredentialsAnnotationInputs(action, imsAuthObject)
if (newInputs) {
Object.entries(newInputs).forEach(([k, v]) => { params[k] = v })
logger.debug(`Added IMS credentials to action params for action '${actionName}'.`)
}

// if we run an action, we will restore the process.env after the call
// we must do this before we load the action because code can execute on require/import
const preCallEnv = { ...process.env }
Expand Down
3 changes: 2 additions & 1 deletion test/__mocks__/@adobe/aio-lib-runtime.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ const mockRtLibInstance = {

const mockRtUtils = {
getActionUrls: jest.fn(),
checkOpenWhiskCredentials: jest.fn()
checkOpenWhiskCredentials: jest.fn(),
getIncludeIMSCredentialsAnnotationInputs: jest.fn()
}

const init = jest.fn().mockReturnValue(mockRtLibInstance)
Expand Down
127 changes: 127 additions & 0 deletions test/lib/run-dev.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -1231,6 +1231,12 @@ describe('invokeSequence', () => {
})

describe('runDev', () => {
const originalEnv = process.env

afterEach(() => {
process.env = { ...originalEnv }
})

test('no front end, no back end', async () => {
const actionPath = fixturePath('actions/successNoReturnAction.js')
const config = createConfig({
Expand All @@ -1253,6 +1259,32 @@ describe('runDev', () => {
expect(Object.keys(actionUrls).length).toEqual(0)
})

test('calls loadIMSCredentialsFromEnv for include-ims-credentials support', async () => {
const rtLib = jest.requireActual('@adobe/aio-lib-runtime')
const loadIMSCredentialsFromEnvSpy = jest.spyOn(rtLib.utils, 'loadIMSCredentialsFromEnv')

const actionPath = fixturePath('actions/successNoReturnAction.js')
const config = createConfig({
hasFrontend: false,
hasBackend: true,
packageName: 'mypackage',
actions: {
myaction: {
function: actionPath
}
}
})
const runOptions = createRunOptions({ cert: 'my-cert', key: 'my-key' })
const hookRunner = () => {}
const { actionUrls, serverCleanup } = await runDev(runOptions, config, hookRunner)

await serverCleanup()

expect(loadIMSCredentialsFromEnvSpy).toHaveBeenCalled()
expect(Object.keys(actionUrls).length).toBeGreaterThan(0)
loadIMSCredentialsFromEnvSpy.mockRestore()
})

test('no front end, has back end', async () => {
const actionPath = fixturePath('actions/successNoReturnAction.js')
const config = createConfig({
Expand Down Expand Up @@ -1706,6 +1738,101 @@ describe('invokeAction', () => {
statusCode: 400
})
})

describe('include-ims-credentials annotation', () => {
const rtLib = jest.requireActual('@adobe/aio-lib-runtime')
let getIncludeIMSCredentialsAnnotationInputsSpy

beforeEach(() => {
getIncludeIMSCredentialsAnnotationInputsSpy = jest.spyOn(rtLib.utils, 'getIncludeIMSCredentialsAnnotationInputs')
})

afterEach(() => {
getIncludeIMSCredentialsAnnotationInputsSpy.mockRestore()
})

test('adds IMS credentials to params when getIncludeIMSCredentialsAnnotationInputs returns inputs', async () => {
const packageName = 'foo'
const actionPath = fixturePath('actions/successReturnAction.js')
const actionLoader = createActionLoader(actionPath)

const action = {
function: actionPath,
annotations: {
'include-ims-credentials': true
}
}
const actionParams = { existingParam: 'value' }
const actionName = 'a'
const actionConfig = {
[packageName]: {
actions: {
[actionName]: action
}
}
}

// Mock the function to return IMS credentials
const mockImsInputs = {
__ims_oauth_s2s: { client_id: 'mock-access-token', org_id: 'mock-org-id' },
__ims_env: 'stage'
}
getIncludeIMSCredentialsAnnotationInputsSpy.mockReturnValue(mockImsInputs)

const actionRequestContext = {
contextActionLoader: actionLoader,
contextItem: action,
contextItemParams: actionParams,
contextItemName: actionName,
packageName,
actionConfig
}
const response = await invokeAction({ actionRequestContext, logger: mockLogger })

expect(getIncludeIMSCredentialsAnnotationInputsSpy).toHaveBeenCalledWith(action, expect.anything())
expect(actionParams.__ims_oauth_s2s).toEqual({ client_id: 'mock-access-token', org_id: 'mock-org-id' })
expect(actionParams.__ims_env).toEqual('stage')
expect(actionParams.existingParam).toEqual('value')
expect(mockLogger.debug).toHaveBeenCalledWith(`Added IMS credentials to action params for action '${actionName}'.`)
expect(response.statusCode).toEqual(200)
})

test('does not add IMS credentials when getIncludeIMSCredentialsAnnotationInputs returns null', async () => {
const packageName = 'foo'
const actionPath = fixturePath('actions/successReturnAction.js')
const actionLoader = createActionLoader(actionPath)

const action = { function: actionPath }
const actionParams = { existingParam: 'value' }
const actionName = 'a'
const actionConfig = {
[packageName]: {
actions: {
[actionName]: action
}
}
}

// Mock the function to return null (no annotation or no IMS auth object)
getIncludeIMSCredentialsAnnotationInputsSpy.mockReturnValue(null)

const actionRequestContext = {
contextActionLoader: actionLoader,
contextItem: action,
contextItemParams: actionParams,
contextItemName: actionName,
packageName,
actionConfig
}
const response = await invokeAction({ actionRequestContext, logger: mockLogger })

expect(getIncludeIMSCredentialsAnnotationInputsSpy).toHaveBeenCalledWith(action, expect.anything())
expect(actionParams.__ims_oauth_s2s).toBeUndefined()
expect(actionParams.__ims_env).toBeUndefined()
expect(actionParams.existingParam).toEqual('value')
expect(response.statusCode).toEqual(200)
})
})
})

describe('defaultActionLoader', () => {
Expand Down
Loading