From 9c7cf6aa5026886065208a9dbb7edc2278a0f45d Mon Sep 17 00:00:00 2001 From: Andrei Enascut Date: Mon, 20 Jul 2026 11:18:17 +0300 Subject: [PATCH] fix: allow S2S consumers with site:readAll to submit authenticated scrape jobs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit POST /tools/scrape/jobs checked hasAccess(site) only — an org-membership check that always fails for cross-tenant S2S principals (their token carries their own org, not the customer's). Every other cross-tenant route (sites, organizations, configuration) already has the hasS2SCapability(CAP_SITE_READ_ALL) fallback; scrapeJob was missed. Fixes SITES-47964 (DRS 403 on twilio.com authenticated scrape path). Co-Authored-By: Claude Opus 4.8 (1M context) --- src/controllers/scrapeJob.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/controllers/scrapeJob.js b/src/controllers/scrapeJob.js index cd5ebb85db..33f04268a1 100644 --- a/src/controllers/scrapeJob.js +++ b/src/controllers/scrapeJob.js @@ -30,6 +30,7 @@ import { import { retrievePageAuthentication } from '@adobe/spacecat-shared-ims-client'; import { cleanupHeaderValue } from '@adobe/helix-shared-utils'; import AccessControlUtil from '../support/access-control-util.js'; +import { CAP_SITE_READ_ALL } from '../routes/capability-constants.js'; import { getCookieValue, getIMSPromiseToken, ErrorWithStatusCode } from '../support/utils.js'; import { PROMISE_BASED_AUTHORING_TYPES } from '../utils/constants.js'; @@ -203,7 +204,11 @@ function ScrapeJobController(context) { } const accessControlUtil = AccessControlUtil.fromContext(requestContext); - if (!await accessControlUtil.hasAccess(site)) { + const isAdmin = accessControlUtil.hasAdminReadAccess(); + const s2sResult = isAdmin + ? { allowed: false, reason: 'admin-bypass' } + : await accessControlUtil.hasS2SCapability(CAP_SITE_READ_ALL); + if (!isAdmin && !s2sResult.allowed && !await accessControlUtil.hasAccess(site)) { return forbidden('User does not have access to this site'); }