Skip to content

Commit

Permalink
Merge pull request #918 from snyk/fix/azure-repos-snippet-rule-overri…
Browse files Browse the repository at this point in the history
…den-issue

Fix/azure repos snippet rule overriden issue
  • Loading branch information
aarlaud authored Feb 11, 2025
2 parents 69aa18a + 85eee0c commit af8dea8
Show file tree
Hide file tree
Showing 7 changed files with 302 additions and 201 deletions.
6 changes: 3 additions & 3 deletions .snyk
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities.
version: v1.25.0
version: v1.25.1
# ignores vulnerabilities until expiry date; change duration by modifying expiry date
ignore:
SNYK-RHEL8-GLIBC-6656573:
Expand All @@ -15,8 +15,8 @@ ignore:
SNYK-JS-WS-7266574:
- '*':
reason: Mitigated in code
expires: 2025-02-10T21:59:20.738Z
created: 2024-06-26T21:59:20.744Z
expires: 2025-03-13T12:03:16.272Z
created: 2025-02-11T12:03:16.275Z
SNYK-JS-CROSSSPAWN-8303230:
- '*':
reason: No upstream fix available
Expand Down
2 changes: 1 addition & 1 deletion defaultFilters/azure-repos.json
Original file line number Diff line number Diff line change
Expand Up @@ -416,4 +416,4 @@
}
}
]
}
}
2 changes: 1 addition & 1 deletion defaultFilters/customPrTemplates/azure-repos.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[
{
"//": "get file content. restrict by file types",
"//": "get file existence. restrict by file types",
"method": "GET",
"path": "/:owner/_apis/git/repositories/:repo/items",
"origin": "https://${AZURE_REPOS_HOST}/${AZURE_REPOS_ORG}",
Expand Down
24 changes: 5 additions & 19 deletions lib/common/filter/filter-rules-loading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { log as logger } from '../../logs/logger';
import { findProjectRoot } from '../config/config';
import camelcase from 'camelcase';
import { FiltersType, Rule } from '../types/filter';
import { retrieveFilters, isValidURI } from './utils';
import { retrieveFilters, isValidURI, deepMergeRules } from './utils';
import { CONFIGURATION } from '../types/options';

const SUPPORTED_IAC_EXTENSIONS = ['tf', 'yaml', 'yml', 'tpl', 'json'];
Expand Down Expand Up @@ -276,14 +276,8 @@ function injectRulesAtRuntime(
findProjectRoot(__dirname) ?? process.cwd(),
`defaultFilters/apprisk/${type}.json`,
)) as Rule[];
// rm entry from filters.private if matching uri _and matching method_ in appRiskRules which takes precedence
const appRiskRulesPathMethodPattern = appRiskRules.map(
(x) => `${x.method}|${x.path}`,
);
filters.private = filters.private.filter((x) => {
return !appRiskRulesPathMethodPattern.includes(`${x.method}|${x.path}`);
});
filters.private.push(...appRiskRules);

filters.private = deepMergeRules(filters.private, appRiskRules);
}
}

Expand Down Expand Up @@ -314,16 +308,8 @@ function injectRulesAtRuntime(
findProjectRoot(__dirname) ?? process.cwd(),
`defaultFilters/customPrTemplates/${type}.json`,
)) as Rule[];
// rm entry from filters.private if matching uri _and matching method_ in customPRTemplatesRules which takes precedence
const customPRTemplatesRulesMethodPattern = customPRTemplatesRules.map(
(x) => `${x.method}|${x.path}`,
);
filters.private = filters.private.filter((x) => {
return !customPRTemplatesRulesMethodPattern.includes(
`${x.method}|${x.path}`,
);
});
filters.private.push(...customPRTemplatesRules);

filters.private = deepMergeRules(filters.private, customPRTemplatesRules);
}
}

Expand Down
63 changes: 63 additions & 0 deletions lib/common/filter/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { PostFilterPreparedRequest } from '../relay/prepareRequest';
import version from '../utils/version';
import { findProjectRoot } from '../config/config';
import { log as logger } from '../../logs/logger';
import { Rule } from '../types/filter';

export const validateHeaders = (headerFilters, requestHeaders = []) => {
for (const filter of headerFilters) {
Expand Down Expand Up @@ -70,3 +71,65 @@ export const retrieveFilters = async (locations: Map<string, string>) => {

return retrievedFiltersMap;
};

export function deepMergeRules(arr1: Rule[], arr2: Rule[]): Rule[] {
const isObject = (item: any): item is Record<string, any> =>
item && typeof item === 'object' && !Array.isArray(item);

const mergeArrays = (target: any[], source: any[]): any[] => {
const result = [...target];

for (const item of source) {
if (isObject(item) && item.queryParam) {
const existing = result.find(
(i) => isObject(i) && i.queryParam === item.queryParam,
);
if (existing) {
existing.values = [
...new Set([...(existing.values || []), ...(item.values || [])]),
];
} else {
result.push(item);
}
} else if (!result.includes(item)) {
result.push(item);
}
}

return result;
};

const mergeObjects = (
target: Record<string, any>,
source: Record<string, any>,
): Record<string, any> => {
for (const key of Object.keys(source)) {
if (isObject(target[key]) && isObject(source[key])) {
target[key] = mergeObjects(target[key], source[key]);
} else if (Array.isArray(target[key]) && Array.isArray(source[key])) {
target[key] = mergeArrays(target[key], source[key]);
} else {
target[key] = source[key];
}
}
return target;
};

const grouped: Record<string, Rule> = {};

for (const rule of [...arr1, ...arr2]) {
if (!rule || !isObject(rule)) continue;

if ('method' in rule && 'path' in rule && 'origin' in rule) {
const key = `${rule.method}:${rule.path}:${rule.origin}`;

if (grouped[key]) {
grouped[key] = mergeObjects(grouped[key], rule) as Rule;
} else {
grouped[key] = rule;
}
}
}

return Object.values(grouped);
}
1 change: 1 addition & 0 deletions package-lock.json

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

Loading

0 comments on commit af8dea8

Please sign in to comment.