Skip to content

Commit 84ea46c

Browse files
authored
feat: support include-ims-credentials annotation (#224)
* feat: support include-ims-credentials annotation * chore: added tests * changes for multi env vars + throw on error * fix
1 parent e36fd4a commit 84ea46c

2 files changed

Lines changed: 496 additions & 3 deletions

File tree

src/utils.js

Lines changed: 110 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const archiver = require('archiver')
2323
const SupportedRuntimes = ['sequence', 'blackbox', 'nodejs:10', 'nodejs:12', 'nodejs:14', 'nodejs:16', 'nodejs:18', 'nodejs:20', 'nodejs:22', 'nodejs:24']
2424
const { HttpProxyAgent } = require('http-proxy-agent')
2525
const PatchedHttpsProxyAgent = require('./PatchedHttpsProxyAgent.js')
26+
const { getCliEnv, DEFAULT_ENV } = require('@adobe/aio-lib-env')
2627

2728
// must cover 'deploy-service[-region][.env].app-builder[.int|.corp].adp.adobe.io/runtime
2829
const SUPPORTED_ADOBE_ANNOTATION_ENDPOINT_REGEXES = [
@@ -41,6 +42,7 @@ const ANNOTATION_WEB_EXPORT = 'web-export'
4142
const ANNOTATION_RAW_HTTP = 'raw-http'
4243
const ANNOTATION_REQUIRE_ADOBE_AUTH = 'require-adobe-auth'
4344
const ANNOTATION_REQUIRE_WHISK_AUTH = 'require-whisk-auth'
45+
const ANNOTATION_INCLUDE_IMS_CREDENTIALS = 'include-ims-credentials'
4446
const VALUE_YES = 'yes'
4547
const VALUE_RAW = 'raw'
4648

@@ -1186,6 +1188,106 @@ function rewriteActionsWithAdobeAuthAnnotation (packages, deploymentPackages) {
11861188
}
11871189
}
11881190

1191+
/**
1192+
* This function implements the support for the `include-ims-credentials` annotation.
1193+
* It will expand the IMS_OAUTH_S2S environment variable into an input object stored under params.__ims_oauth_s2s and params.__ims_env
1194+
*
1195+
* @access private
1196+
* @param {ManifestPackages} packages the manifest packages
1197+
* @returns {ManifestPackages} newPackages, rewritten package with added inputs
1198+
*/
1199+
function rewriteActionsWithAdobeIncludeIMSCredentialsAnnotation (packages) {
1200+
// avoid side effects, do not modify input packages
1201+
const newPackages = cloneDeep(packages)
1202+
1203+
const imsAuthObject = loadIMSCredentialsFromEnv()
1204+
1205+
// traverse all actions in all packages
1206+
Object.keys(newPackages).forEach((key) => {
1207+
if (newPackages[key].actions) {
1208+
Object.keys(newPackages[key].actions).forEach((actionName) => {
1209+
const thisAction = newPackages[key].actions[actionName]
1210+
const newInputs = getIncludeIMSCredentialsAnnotationInputs(thisAction, imsAuthObject)
1211+
if (newInputs) {
1212+
if (!thisAction.inputs) {
1213+
thisAction.inputs = {}
1214+
}
1215+
Object.entries(newInputs).forEach(([k, v]) => { thisAction.inputs[k] = v })
1216+
aioLogger.debug(`processed annotation '${ANNOTATION_INCLUDE_IMS_CREDENTIALS}' for action '${key}/${actionName}'.`)
1217+
}
1218+
})
1219+
}
1220+
})
1221+
return newPackages
1222+
}
1223+
1224+
/**
1225+
* Load the IMS credentials from the environment variables.
1226+
*
1227+
* @returns {object} the IMS auth object
1228+
*/
1229+
function loadIMSCredentialsFromEnv () {
1230+
// constants
1231+
const IMS_OAUTH_S2S_ENV_KEY = 'IMS_OAUTH_S2S'
1232+
1233+
const imsAuthObject = {
1234+
client_id: process.env[`${IMS_OAUTH_S2S_ENV_KEY}_CLIENT_ID`],
1235+
client_secret: process.env[`${IMS_OAUTH_S2S_ENV_KEY}_CLIENT_SECRET`],
1236+
org_id: process.env[`${IMS_OAUTH_S2S_ENV_KEY}_ORG_ID`],
1237+
scopes: (() => {
1238+
try {
1239+
return JSON.parse(process.env[`${IMS_OAUTH_S2S_ENV_KEY}_SCOPES`])
1240+
} catch (e) {
1241+
return process.env[`${IMS_OAUTH_S2S_ENV_KEY}_SCOPES`] // pass in string as is
1242+
}
1243+
})()
1244+
}
1245+
return imsAuthObject
1246+
}
1247+
1248+
/**
1249+
* Get the inputs for the include-ims-credentials annotation.
1250+
* Throws an error if the imsAuthObject is incomplete.
1251+
*
1252+
* @param {object} thisAction the action to process
1253+
* @param {object} imsAuthObject the IMS auth object
1254+
* @returns {object|undefined} the inputs or undefined with a warning
1255+
*/
1256+
function getIncludeIMSCredentialsAnnotationInputs (thisAction, imsAuthObject) {
1257+
const env = getCliEnv() || DEFAULT_ENV
1258+
1259+
const IMS_OAUTH_S2S_INPUT = '__ims_oauth_s2s'
1260+
const IMS_ENV_INPUT = '__ims_env'
1261+
const IMS_OAUTH_S2S_ENV_KEY = 'IMS_OAUTH_S2S'
1262+
1263+
// check if the annotation is defined
1264+
if (thisAction.annotations?.[ANNOTATION_INCLUDE_IMS_CREDENTIALS]) {
1265+
// check if the IMS credentials are loaded properly, if not emit a warning
1266+
if (Object.keys(imsAuthObject).length === 0) {
1267+
throw new Error(`Credentials for the project are missing, please ensure the Console Workspace is configured with an OAuth server to server credential.
1268+
Unset the annotation '${ANNOTATION_INCLUDE_IMS_CREDENTIALS}' if you don't want to include credentials.`)
1269+
}
1270+
const missingEnvVars = []
1271+
if (!imsAuthObject.client_id) {
1272+
missingEnvVars.push(`${IMS_OAUTH_S2S_ENV_KEY}_CLIENT_ID`)
1273+
}
1274+
if (!imsAuthObject.client_secret) {
1275+
missingEnvVars.push(`${IMS_OAUTH_S2S_ENV_KEY}_CLIENT_SECRET`)
1276+
}
1277+
if (!imsAuthObject.org_id) {
1278+
missingEnvVars.push(`${IMS_OAUTH_S2S_ENV_KEY}_ORG_ID`)
1279+
}
1280+
if (!imsAuthObject.scopes) {
1281+
missingEnvVars.push(`${IMS_OAUTH_S2S_ENV_KEY}_SCOPES`)
1282+
}
1283+
if (missingEnvVars.length > 0) {
1284+
throw new Error(`Credentials for the project are incomplete. Missing '${missingEnvVars.join('|')}' env variables.
1285+
Unset the annotation '${ANNOTATION_INCLUDE_IMS_CREDENTIALS}' if you don't want to include credentials.`)
1286+
}
1287+
return { [IMS_OAUTH_S2S_INPUT]: { ...imsAuthObject }, [IMS_ENV_INPUT]: env }
1288+
}
1289+
}
1290+
11891291
/**
11901292
*
11911293
* Process the manifest and deployment content and returns deployment entities.
@@ -1210,11 +1312,14 @@ function processPackage (packages,
12101312

12111313
const isAdobeEndpoint = SUPPORTED_ADOBE_ANNOTATION_ENDPOINT_REGEXES.some(regex => regex.test(owOptions.apihost))
12121314
if (isAdobeEndpoint) {
1315+
// rewrite packages in case there are any `include-ims-credentials` annotations
1316+
const newPackages = rewriteActionsWithAdobeIncludeIMSCredentialsAnnotation(pkgs)
1317+
12131318
// rewrite packages in case there are any `require-adobe-auth` annotations
12141319
// this is a temporary feature and will be replaced by a native support in Adobe I/O Runtime
1215-
const { newPackages, newDeploymentPackages } = rewriteActionsWithAdobeAuthAnnotation(pkgs, deploymentPkgs)
1216-
pkgs = newPackages
1217-
deploymentPkgs = newDeploymentPackages
1320+
const ret = rewriteActionsWithAdobeAuthAnnotation(newPackages, deploymentPkgs)
1321+
pkgs = ret.newPackages
1322+
deploymentPkgs = ret.newDeploymentPackages
12181323
}
12191324

12201325
const pkgAndDeps = []
@@ -2185,5 +2290,7 @@ module.exports = {
21852290
dumpActionsBuiltInfo,
21862291
safeParse,
21872292
isSupportedActionKind,
2293+
getIncludeIMSCredentialsAnnotationInputs,
2294+
loadIMSCredentialsFromEnv,
21882295
DEFAULT_PACKAGE_RESERVED_NAME
21892296
}

0 commit comments

Comments
 (0)