Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
8da37c5
feat: guard edge deploy against out-of-scope suggestions for subpath …
dhavkuma Jun 11, 2026
a9013ff
Merge branch 'main' into feat/subpath-deploy-guards
dhavkuma Jun 11, 2026
6dc0a2c
test: cover isSuggestionInScope fallback paths for edge deploy guard
dhavkuma Jun 11, 2026
ae2ee15
fix: prevent path-prefix collision in subpath scope guard
dhavkuma Jun 11, 2026
1e7b0ef
Merge branch 'main' into feat/subpath-deploy-guards
dhavkuma Jun 16, 2026
607af71
Merge branch 'main' into feat/subpath-deploy-guards
dhavkuma Jul 1, 2026
d7cc3fc
fix: harden subpath scope guard against regex-alternation bypass and …
dhavkuma Jul 1, 2026
0951cea
Merge branch 'main' into feat/subpath-deploy-guards
dhavkuma Jul 1, 2026
af9859e
fix: enforce host/port match in subpath scope guard, not just pathname
dhavkuma Jul 1, 2026
183b46a
refactor: consume isPathPatternWithinSiteScope from spacecat-shared-u…
dhavkuma Jul 1, 2026
c586411
Merge remote-tracking branch 'origin/feat/subpath-deploy-guards' into…
dhavkuma Jul 1, 2026
313d111
chore: sync package-lock.json http-utils version pin
dhavkuma Jul 1, 2026
b9d9ca1
refactor: dedupe site.getBaseURL() call in deploySuggestionToEdge
dhavkuma Jul 2, 2026
3bf7d62
refactor: simplify edge-deploy scope guard, delegate to shared utils
dhavkuma Jul 2, 2026
fc70f06
Merge remote-tracking branch 'origin/main' into feat/subpath-deploy-g…
dhavkuma Jul 3, 2026
e392aa2
test: cover mixed domain-wide + path-level suggestions on subpath sites
dhavkuma Jul 3, 2026
dac37ff
Merge branch 'main' into feat/subpath-deploy-guards
dhavkuma Jul 3, 2026
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
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
"@adobe/spacecat-shared-tier-client": "1.5.1",
"@adobe/spacecat-shared-tokowaka-client": "1.20.0",
"@adobe/spacecat-shared-user-manager-client": "1.3.1",
"@adobe/spacecat-shared-utils": "1.123.0",
"@adobe/spacecat-shared-utils": "1.124.0",
"@adobe/spacecat-shared-vault-secrets": "1.3.5",
"@aws-sdk/client-cloudfront": "3.1045.0",
"@aws-sdk/client-iam": "3.1045.0",
Expand Down
30 changes: 29 additions & 1 deletion src/controllers/suggestions.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import {
isInteger,
isValidUUID,
isValidUrl,
isWithinSiteScope,
isPathPatternWithinSiteScope,
} from '@adobe/spacecat-shared-utils';

import {
Expand Down Expand Up @@ -1869,7 +1871,8 @@ function SuggestionsController(ctx, sqs, env) {
context.log.warn(`[edge-deploy-failed] site ${siteId} not found`);
return notFound('Site not found');
}
const apexBaseUrl = getHostName(site.getBaseURL()) || site.getBaseURL();
const siteBaseURL = site.getBaseURL();
const apexBaseUrl = getHostName(siteBaseURL) || siteBaseURL;

if (!isValidUUID(opportunityId)) {
context.log.warn(`[edge-deploy-failed] site: ${apexBaseUrl}, opportunityId ${opportunityId} is not a valid UUID`);
Expand Down Expand Up @@ -1926,6 +1929,23 @@ function SuggestionsController(ctx, sqs, env) {
const pathSuggestions = [];
const failedSuggestions = [];
let coveredSuggestionsCount = 0;

const isSuggestionInScope = (suggestion) => {
const data = suggestion.getData();
if (isDomainWideSuggestion(suggestion) || isPathSuggestion(suggestion)) {
const patterns = data?.allowedRegexPatterns;
if (!isNonEmptyArray(patterns)) {
return true;
}
return patterns.every((pattern) => isPathPatternWithinSiteScope(pattern, siteBaseURL));
}
const url = getSuggestionUrl(data, opportunity);
if (!url) {
return true;
}
return isWithinSiteScope(url, siteBaseURL);
};

// Check each requested suggestion (basic validation only)
suggestionIds.forEach((suggestionId, index) => {
const suggestion = allSuggestions.find((s) => s.getId() === suggestionId);
Expand All @@ -1938,6 +1958,14 @@ function SuggestionsController(ctx, sqs, env) {
message: 'Suggestion not found',
statusCode: 404,
});
} else if (!isSuggestionInScope(suggestion)) {
context.log.warn(`[edge-deploy-failed] site: ${apexBaseUrl}, suggestion ${suggestionId} URL is outside site scope`);
failedSuggestions.push({
uuid: suggestionId,
index,
message: 'Suggestion URL is outside the scope of the site base URL',
statusCode: 400,
});
} else if (isDomainWideSuggestion(suggestion)) {
context.log.info(`[edge-deploy] ${suggestionId} → DOMAIN-WIDE`);
const data = suggestion.getData();
Expand Down
Loading
Loading