Skip to content
Merged
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
4 changes: 2 additions & 2 deletions src/BaseCommand.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const STAGE_LAUNCH_PREFIX = 'https://experience-stage.adobe.com/?devMode=true#/c
const appConfig = require('@adobe/aio-cli-lib-app-config')
const inquirer = require('inquirer')
const { CONSOLE_API_KEYS, APPLICATION_CONFIG_KEY, EXTENSIONS_CONFIG_KEY } = require('./lib/defaults')
const { getCliInfo } = require('./lib/app-helper')
const { getAccessToken } = require('./lib/auth-helper')
const LibConsoleCLI = require('@adobe/aio-cli-lib-console')
const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app', { provider: 'debug' })

Expand Down Expand Up @@ -54,7 +54,7 @@ class BaseCommand extends Command {
async getLibConsoleCLI () {
if (!this.consoleCLI) {
// requires valid login
const { accessToken, env } = await getCliInfo()
const { accessToken, env } = await getAccessToken()
// init console CLI sdk consoleCLI
this.consoleCLI = await LibConsoleCLI.init({ accessToken, env, apiKey: CONSOLE_API_KEYS[env] })
}
Expand Down
5 changes: 1 addition & 4 deletions src/commands/app/config/get/log-forwarding.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,7 @@ const { setRuntimeApiHostAndAuthHandler } = require('../../../../lib/auth-helper
class LogForwardingCommand extends BaseCommand {
async run () {
let aioConfig = (await this.getFullConfig()).aio
// TODO: remove this check once the deploy service is enabled by default
if (process.env.IS_DEPLOY_SERVICE_ENABLED === 'true') {
aioConfig = setRuntimeApiHostAndAuthHandler(aioConfig)
}
aioConfig = setRuntimeApiHostAndAuthHandler(aioConfig)
const lf = await LogForwarding.init(aioConfig)

const localConfig = lf.getLocalConfig()
Expand Down
5 changes: 1 addition & 4 deletions src/commands/app/config/get/log-forwarding/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,7 @@ class ErrorsCommand extends BaseCommand {

async getLogForwarding () {
let aioConfig = (await this.getFullConfig()).aio
// TODO: remove this check once the deploy service is enabled by default
if (process.env.IS_DEPLOY_SERVICE_ENABLED === 'true') {
aioConfig = setRuntimeApiHostAndAuthHandler(aioConfig)
}
aioConfig = setRuntimeApiHostAndAuthHandler(aioConfig)

const runtimeConfig = aioConfig.runtime
rtLib.utils.checkOpenWhiskCredentials({ ow: runtimeConfig })
Expand Down
5 changes: 1 addition & 4 deletions src/commands/app/config/set/log-forwarding.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@ const { setRuntimeApiHostAndAuthHandler } = require('../../../../lib/auth-helper
class LogForwardingCommand extends BaseCommand {
async run () {
let aioConfig = (await this.getFullConfig()).aio
// TODO: remove this check once the deploy service is enabled by default
if (process.env.IS_DEPLOY_SERVICE_ENABLED === 'true') {
aioConfig = setRuntimeApiHostAndAuthHandler(aioConfig)
}
aioConfig = setRuntimeApiHostAndAuthHandler(aioConfig)
const lf = await LogForwarding.init(aioConfig)

const destination = await this.promptDestination(lf.getSupportedDestinations())
Expand Down
13 changes: 5 additions & 8 deletions src/commands/app/deploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ const BaseCommand = require('../../BaseCommand')
const BuildCommand = require('./build')
const webLib = require('@adobe/aio-lib-web')
const { Flags } = require('@oclif/core')
const { runInProcess, buildExtensionPointPayloadWoMetadata, buildExcShellViewExtensionMetadata, getCliInfo, getFilesCountWithExtension } = require('../../lib/app-helper')
const { runInProcess, buildExtensionPointPayloadWoMetadata, buildExcShellViewExtensionMetadata, getFilesCountWithExtension } = require('../../lib/app-helper')
const rtLib = require('@adobe/aio-lib-runtime')
const LogForwarding = require('../../lib/log-forwarding')
const { sendAppAssetsDeployedAuditLog, sendAppDeployAuditLog } = require('../../lib/audit-logger')
const { setRuntimeApiHostAndAuthHandler } = require('../../lib/auth-helper')
const { setRuntimeApiHostAndAuthHandler, getAccessToken } = require('../../lib/auth-helper')
const logActions = require('../../lib/log-actions')

const PRE_DEPLOY_EVENT_REG = 'pre-deploy-event-reg'
Expand Down Expand Up @@ -54,7 +54,7 @@ class Deploy extends BuildCommand {

try {
const { aio: aioConfig, packagejson: packageJson } = await this.getFullConfig()
const cliDetails = await getCliInfo(flags.publish)
const cliDetails = await getAccessToken({ useCachedToken: flags.publish })
const appInfo = {
name: packageJson.name,
version: packageJson.version,
Expand Down Expand Up @@ -84,10 +84,7 @@ class Deploy extends BuildCommand {
if (aioConfig?.project?.workspace && flags['log-forwarding-update'] && flags.actions) {
spinner.start('Updating log forwarding configuration')
try {
let lfConfig = aioConfig
if (process.env.IS_DEPLOY_SERVICE_ENABLED === 'true') {
lfConfig = setRuntimeApiHostAndAuthHandler(aioConfig)
}
const lfConfig = setRuntimeApiHostAndAuthHandler(aioConfig)

const lf = await LogForwarding.init(lfConfig)
if (lf.isLocalConfigChanged()) {
Expand Down Expand Up @@ -129,7 +126,7 @@ class Deploy extends BuildCommand {
// - break into smaller pieces deploy, allowing to first deploy all actions then all web assets
for (let i = 0; i < keys.length; ++i) {
const k = keys[i]
const v = process.env.IS_DEPLOY_SERVICE_ENABLED === 'true' ? setRuntimeApiHostAndAuthHandler(values[i]) : values[i]
const v = setRuntimeApiHostAndAuthHandler(values[i])

await this.deploySingleConfig(k, v, flags, spinner)
if (cliDetails?.accessToken && v.app.hasFrontend && flags['web-assets']) {
Expand Down
8 changes: 4 additions & 4 deletions src/commands/app/undeploy.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ const { Flags } = require('@oclif/core')

const BaseCommand = require('../../BaseCommand')
const webLib = require('@adobe/aio-lib-web')
const { runInProcess, buildExtensionPointPayloadWoMetadata, getCliInfo } = require('../../lib/app-helper')
const { runInProcess, buildExtensionPointPayloadWoMetadata } = require('../../lib/app-helper')
const rtLib = require('@adobe/aio-lib-runtime')
const { sendAppAssetsUndeployedAuditLog, sendAppUndeployAuditLog } = require('../../lib/audit-logger')
const { setRuntimeApiHostAndAuthHandler } = require('../../lib/auth-helper')
const { setRuntimeApiHostAndAuthHandler, getAccessToken } = require('../../lib/auth-helper')

class Undeploy extends BaseCommand {
async run () {
Expand Down Expand Up @@ -52,7 +52,7 @@ class Undeploy extends BaseCommand {
const spinner = ora()
try {
const { aio: aioConfig, packagejson: packageJson } = await this.getFullConfig()
const cliDetails = await getCliInfo(flags.unpublish)
const cliDetails = await getAccessToken({ useCachedToken: flags.unpublish })
const appInfo = {
name: packageJson.name,
version: packageJson.version,
Expand Down Expand Up @@ -80,7 +80,7 @@ class Undeploy extends BaseCommand {
for (let i = 0; i < keys.length; ++i) {
const k = keys[i]
// TODO: remove this check once the deploy service is enabled by default
const v = process.env.IS_DEPLOY_SERVICE_ENABLED === 'true' ? setRuntimeApiHostAndAuthHandler(values[i]) : values[i]
const v = setRuntimeApiHostAndAuthHandler(values[i])

await this.undeployOneExt(k, v, flags, spinner)
if (cliDetails?.accessToken) {
Expand Down
31 changes: 0 additions & 31 deletions src/lib/app-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,10 @@ const fs = require('fs-extra')
const path = require('node:path')
const which = require('which')
const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app:lib-app-helper', { provider: 'debug' })
const { getToken, context } = require('@adobe/aio-lib-ims')
const { CLI } = require('@adobe/aio-lib-ims/src/context')
const chalk = require('chalk')
const aioConfig = require('@adobe/aio-lib-core-config')
const { AIO_CONFIG_WORKSPACE_SERVICES, AIO_CONFIG_ORG_SERVICES } = require('./defaults')
const { EOL } = require('os')
const { getCliEnv } = require('@adobe/aio-lib-env')
const yaml = require('js-yaml')
const RuntimeLib = require('@adobe/aio-lib-runtime')

Expand Down Expand Up @@ -179,33 +176,6 @@ function wrapError (err) {
return new Error(message)
}

/**
* getCliInfo
*
* @private
*
* @param {boolean} useForce - if true, user will be forced to login if not already logged in
* @returns {Promise<{accessToken: string, env: string}>} accessToken and env
*/
async function getCliInfo (useForce = true) {
const env = getCliEnv()
let accessToken
await context.setCli({ 'cli.bare-output': true }, false) // set this globally
if (useForce) {
aioLogger.debug('Retrieving CLI Token using force=true')
accessToken = await getToken(CLI)
} else {
aioLogger.debug('Retrieving CLI Token using force=false')
// in this case, the user might be logged in, but we don't want to force them
// we just check the config for the token ( we still use the cli context so we don't need to know
// the inner workings of ims-lib and where it stores access tokens)
// todo: this is a workaround, we should have a better way to check if the user is logged in (in ims-lib)
const contextConfig = await context.getCli()
accessToken = contextConfig?.access_token?.token
}
return { accessToken, env }
}

/**
* Joins url path parts
*
Expand Down Expand Up @@ -545,7 +515,6 @@ module.exports = {
runInProcess,
runPackageScript,
wrapError,
getCliInfo,
removeProtocolFromURL,
urlJoin,
checkFile,
Expand Down
44 changes: 13 additions & 31 deletions src/lib/audit-logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ const OPERATIONS = {
AB_APP_ASSETS_UNDEPLOYED: 'ab_app_assets_undeployed'
}

const AUDIT_SERVICE_ENDPOINT_ROUTE = '/audit-log-api/event-post'
const AUDIT_SERVICE_ENDPOINTS = {
stage: process.env.AUDIT_SERVICE_ENDPOINT_STAGE ?? 'https://deploy-service.stg.app-builder.corp.adp.adobe.io/audit-log-api/event-post',
prod: process.env.AUDIT_SERVICE_ENDPOINT_PROD ?? 'https://deploy-service.app-builder.adp.adobe.io/audit-log-api/event-post'
stage: 'https://deploy-service.stg.app-builder.corp.adp.adobe.io',
prod: 'https://deploy-service.app-builder.adp.adobe.io'
}

/**
Expand Down Expand Up @@ -52,31 +53,6 @@ const AUDIT_SERVICE_ENDPOINTS = {
* @property {string} operation - Operation type: 'ab_app_deploy', 'ab_app_undeploy', 'ab_app_assets_deployed', or 'ab_app_assets_undeployed'
*/

/**
* Checks for environment variable overrides of audit service endpoints and logs warnings if found.
*
* This function checks for the following environment variables:
* - AUDIT_SERVICE_ENDPOINT_STAGE: Override for the stage environment endpoint
* - AUDIT_SERVICE_ENDPOINT_PROD: Override for the production environment endpoint
*
* If any of these variables are set, a warning will be logged to the console indicating
* which variables are being overridden and their values.
*
* @function checkOverrides
* @returns {void}
*/
function checkOverrides () {
const toCheck = ['AUDIT_SERVICE_ENDPOINT_STAGE', 'AUDIT_SERVICE_ENDPOINT_PROD']
const overrides = toCheck.filter((toCheck) => process.env[toCheck])

if (overrides.length > 0) {
console.warn('Audit Service overrides detected:')
overrides.forEach((override) => {
console.warn(` ${override}: ${process.env[override]}`)
})
}
}

/**
* Publish audit log events to audit service
*
Expand All @@ -85,9 +61,14 @@ function checkOverrides () {
* @throws {Error} If the audit log request fails
*/
async function publishAuditLogs ({ accessToken, logEvent, env = 'prod' }) {
checkOverrides()
let url = AUDIT_SERVICE_ENDPOINTS[env] ?? AUDIT_SERVICE_ENDPOINTS.prod
if (process.env.AIO_DEPLOY_SERVICE_URL) {
url = process.env.AIO_DEPLOY_SERVICE_URL
}

// add the route to the endpoint
url += AUDIT_SERVICE_ENDPOINT_ROUTE

const url = AUDIT_SERVICE_ENDPOINTS[env] ?? AUDIT_SERVICE_ENDPOINTS.prod
const payload = {
event: logEvent
}
Expand Down Expand Up @@ -208,11 +189,12 @@ async function sendAppAssetsUndeployedAuditLog ({ accessToken, cliCommandFlags,

module.exports = {
OPERATIONS,
AUDIT_SERVICE_ENDPOINT_ROUTE,
AUDIT_SERVICE_ENDPOINTS,
publishAuditLogs,
getAuditLogEvent,
sendAppDeployAuditLog,
sendAppUndeployAuditLog,
sendAppAssetsDeployedAuditLog,
sendAppAssetsUndeployedAuditLog,
checkOverrides
sendAppAssetsUndeployedAuditLog
}
83 changes: 54 additions & 29 deletions src/lib/auth-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,52 +12,77 @@ governing permissions and limitations under the License.
const { getToken, context } = require('@adobe/aio-lib-ims')
const { CLI } = require('@adobe/aio-lib-ims/src/context')
const { getCliEnv } = require('@adobe/aio-lib-env')
const defaultRuntimeUrl = 'https://adobeioruntime.net'
const defaultDeployServiceUrl = 'https://deploy-service.app-builder.adp.adobe.io'
const aioLogger = require('@adobe/aio-lib-core-logging')('@adobe/aio-cli-plugin-app:auth-helper', { provider: 'debug' })

/**
* Retrieves an access token for Adobe I/O CLI authentication.
* This function handles both CLI and custom contexts, setting up the appropriate
* authentication context and retrieving the corresponding access token.
*
* @async
* @function getAccessToken
* @param {object} [options] - Options for token retrieval
* @param {boolean} [options.useCachedToken=false] - Whether to use a cached token instead of requesting a new one
* @returns {Promise<{accessToken: string|null, env: string}>} An object containing:
* - accessToken: The retrieved access token for authentication, or null if token retrieval failed
* - env: The current CLI environment (e.g. 'prod', 'stage')
* @throws {Error} If token retrieval fails or context setup fails
*/
async function getAccessToken ({ useCachedToken = false } = {}) {
const env = getCliEnv()
aioLogger.debug(`Retrieving CLI Token using env=${env}`)

let contextName = CLI // default
const currentContext = await context.getCurrent() // potential override
if (currentContext !== CLI) {
contextName = currentContext
} else {
await context.setCli({ 'cli.bare-output': true }, false) // set this globally
}

let accessToken = null
if (useCachedToken) {
const contextConfig = await context.get(contextName)
accessToken = contextConfig?.access_token?.token
} else {
accessToken = await getToken(contextName)
}

return { accessToken, env }
}

/**
* For use with the openwhisk client js library to send a bearer token instead of basic
* auth to the openwhisk service. Set this to the auth_handler option when initializing
*/
const bearerAuthHandler = {
getAuthHeader: async () => {
await context.setCli({ 'cli.bare-output': true }, false) // set this globally

const env = getCliEnv()

console.debug(`Retrieving CLI Token using env=${env}`)
const accessToken = await getToken(CLI)
const { accessToken } = await getAccessToken()

return `Bearer ${accessToken}`
}
}

const setRuntimeApiHostAndAuthHandler = (config) => {
// TODO: remove this check once the deploy service is enabled by default
if (process.env.IS_DEPLOY_SERVICE_ENABLED === 'true') {
const aioConfig = (config && 'runtime' in config) ? config : null
if (aioConfig) {
aioConfig.runtime.apihost = process.env.AIO_RUNTIME_APIHOST ?? defaultRuntimeUrl
aioConfig.runtime.auth_handler = bearerAuthHandler
return aioConfig
}
const owConfig = (config && 'ow' in config) ? config : null
if (owConfig) {
owConfig.ow.apihost = process.env.AIO_RUNTIME_APIHOST ?? defaultRuntimeUrl
owConfig.ow.auth_handler = bearerAuthHandler
return owConfig
}
} else {
if (config && config.runtime) {
config.runtime.apihost = process.env.AIO_RUNTIME_APIHOST ?? defaultRuntimeUrl
}
if (config && config.ow) {
config.ow.apihost = process.env.AIO_RUNTIME_APIHOST ?? defaultRuntimeUrl
}
const aioConfig = (config && 'runtime' in config) ? config : null
if (aioConfig) {
const apiEndpoint = process.env.AIO_DEPLOY_SERVICE_URL ?? defaultDeployServiceUrl
aioConfig.runtime.apihost = `${apiEndpoint}/runtime`
aioConfig.runtime.auth_handler = bearerAuthHandler
return aioConfig
}
const owConfig = (config && 'ow' in config) ? config : null
if (owConfig) {
const apiEndpoint = process.env.AIO_DEPLOY_SERVICE_URL ?? defaultDeployServiceUrl
owConfig.ow.apihost = `${apiEndpoint}/runtime`
owConfig.ow.auth_handler = bearerAuthHandler
return owConfig
}
return config
}

module.exports = {
getAccessToken,
bearerAuthHandler,
setRuntimeApiHostAndAuthHandler
}
4 changes: 3 additions & 1 deletion test/commands/app/add/service.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,12 @@ jest.mock('../../../../src/lib/import')
// mock login - mocks underlying methods behind getCliInfo
const mockAccessToken = 'some-access-token'
const mockSetCli = jest.fn()
const mockGetCurrent = jest.fn()
jest.mock('@adobe/aio-lib-ims', () => {
return {
context: {
setCli: () => mockSetCli()
setCli: () => mockSetCli(),
getCurrent: () => mockGetCurrent()
},
getToken: () => mockAccessToken
}
Expand Down
Loading