diff --git a/src/index.d.ts b/src/index.d.ts index a56bcc5f..77490c90 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -20,6 +20,7 @@ export interface Env { // shared secret used as authorization when invoking the collab service (eg for syncadmin) COLLAB_SHARED_SECRET: string; DA_OPS_IMS_ORG: string; + DA_OPS_IMS_BOT_EMAIL: string; DA_AUTH: KVNamespace, DA_CONFIG: KVNamespace, diff --git a/src/utils/auth.js b/src/utils/auth.js index fffc3d14..9d20a15d 100644 --- a/src/utils/auth.js +++ b/src/utils/auth.js @@ -272,6 +272,19 @@ export async function getAclCtx(env, org, users, key, api) { }); } + if (env.DA_OPS_IMS_BOT_EMAIL) { + props.permissions.data.push({ + path: 'CONFIG', + groups: env.DA_OPS_IMS_BOT_EMAIL, + actions: 'write', + }); + props.permissions.data.push({ + path: '/ + **', + groups: env.DA_OPS_IMS_BOT_EMAIL, + actions: 'write', + }); + } + const aclTrace = []; props.permissions.data.forEach(({ path, groups, actions }) => { if (!path || !groups) return; diff --git a/test/utils/auth.test.js b/test/utils/auth.test.js index c95da531..fb1c0c05 100644 --- a/test/utils/auth.test.js +++ b/test/utils/auth.test.js @@ -558,6 +558,45 @@ describe('DA auth', () => { }, '/some/deep/path', 'write')); }); + it('test DA_OPS_IMS_BOT_EMAIL permissions', async () => { + const botEmail = 'da-ops-bot@adobe.com'; + const envBot = { + ...env2, + DA_OPS_IMS_BOT_EMAIL: botEmail, + }; + + // Bot user identified solely by email — no orgs membership at all. + // This is the substantive difference from the DA_OPS_IMS_ORG test: + // the bearer is matched on email, independent of IMS org membership. + const users = [{ email: botEmail, orgs: [] }]; + const aclCtx = await getAclCtx(envBot, 'test', users, '/', 'config'); + + // Should have write permission on CONFIG because of DA_OPS_IMS_BOT_EMAIL injection + assert(hasPermission({ + users, org: 'test', aclCtx, key: '', + }, 'CONFIG', 'write', true)); + + // Should have write permission on / because of DA_OPS_IMS_BOT_EMAIL injection + // (path: '/ + **') + assert(hasPermission({ + users, org: 'test', aclCtx, key: '', + }, '/', 'write')); + + // Should have write permission on path because of DA_OPS_IMS_BOT_EMAIL injection + // (path: '/ + **') + assert(hasPermission({ + users, org: 'test', aclCtx, key: '', + }, '/some/deep/path', 'write')); + + // A different email must NOT inherit bot permissions — the rule matches + // on the specific email, not on "any user when DA_OPS_IMS_BOT_EMAIL is set". + const otherUsers = [{ email: 'not-the-bot@adobe.com', orgs: [] }]; + const otherCtx = await getAclCtx(envBot, 'test', otherUsers, '/', 'config'); + assert(!hasPermission({ + users: otherUsers, org: 'test', aclCtx: otherCtx, key: '', + }, '/', 'write')); + }); + it('returns empty action set when DA_CONFIG KV GET throws 414 key-too-long error', async () => { // IMS auth redirect fragments (access_token=..., ld_hash=...) leak into the URL path, // producing an org segment >512 bytes. KV rejects the lookup with a 414 error;