mirror of
https://github.com/AikidoSec/safe-chain.git
synced 2026-05-26 20:20:49 +00:00
Allow trailing * for wildcard matching
This commit is contained in:
parent
d7a9884ff6
commit
2d609066c8
3 changed files with 99 additions and 4 deletions
|
|
@ -214,16 +214,16 @@ You can set the minimum package age through multiple sources (in order of priori
|
|||
|
||||
### Excluding Packages
|
||||
|
||||
Exclude trusted packages from minimum age filtering via environment variable or config file (both are merged):
|
||||
Exclude trusted packages from minimum age filtering via environment variable or config file (both are merged). Supports wildcard patterns with trailing `*`:
|
||||
|
||||
```shell
|
||||
export SAFE_CHAIN_NPM_MINIMUM_PACKAGE_AGE_EXCLUSIONS="react,@aikidosec/safe-chain"
|
||||
export SAFE_CHAIN_NPM_MINIMUM_PACKAGE_AGE_EXCLUSIONS="@aikidosec/*,react-*,lodash"
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"npm": {
|
||||
"minimumPackageAgeExclusions": ["react", "@aikidosec/safe-chain"]
|
||||
"minimumPackageAgeExclusions": ["@aikidosec/*", "react-*", "lodash"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ export function modifyNpmInfoResponse(body, headers) {
|
|||
// Check if this package is excluded from minimum age filtering
|
||||
const packageName = bodyJson.name;
|
||||
const exclusions = getNpmMinimumPackageAgeExclusions();
|
||||
if (packageName && exclusions.includes(packageName)) {
|
||||
if (packageName && exclusions.some((pattern) => matchesExclusionPattern(packageName, pattern))) {
|
||||
ui.writeVerbose(
|
||||
`Safe-chain: ${packageName} is excluded from minimum package age filtering (minimumPackageAgeExclusions setting).`
|
||||
);
|
||||
|
|
@ -187,3 +187,17 @@ function getMostRecentTag(tagList) {
|
|||
export function getHasSuppressedVersions() {
|
||||
return state.hasSuppressedVersions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a package name matches an exclusion pattern.
|
||||
* Supports trailing wildcard (*) for prefix matching.
|
||||
* @param {string} packageName
|
||||
* @param {string} pattern
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function matchesExclusionPattern(packageName, pattern) {
|
||||
if (pattern.endsWith("*")) {
|
||||
return packageName.startsWith(pattern.slice(0, -1));
|
||||
}
|
||||
return packageName === pattern;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -481,6 +481,87 @@ describe("npmInterceptor minimum package age", async () => {
|
|||
assert.equal(Object.keys(modifiedJson.versions).length, 2);
|
||||
});
|
||||
|
||||
it("Should exclude packages matching wildcard pattern @scope/*", async () => {
|
||||
minimumPackageAgeSettings = 5;
|
||||
skipMinimumPackageAgeSetting = false;
|
||||
minimumPackageAgeExclusionsSetting = ["@aikidosec/*"];
|
||||
|
||||
const packageUrl = "https://registry.npmjs.org/@aikidosec/safe-chain";
|
||||
|
||||
const originalBody = JSON.stringify({
|
||||
name: "@aikidosec/safe-chain",
|
||||
["dist-tags"]: { latest: "2.0.0" },
|
||||
versions: { ["1.0.0"]: {}, ["2.0.0"]: {} },
|
||||
time: {
|
||||
created: getDate(-365 * 24),
|
||||
modified: getDate(-1),
|
||||
["1.0.0"]: getDate(-100),
|
||||
["2.0.0"]: getDate(-1), // Would normally be filtered
|
||||
},
|
||||
});
|
||||
|
||||
const modifiedBody = await runModifyNpmInfoRequest(packageUrl, originalBody);
|
||||
const modifiedJson = JSON.parse(modifiedBody);
|
||||
|
||||
// All versions should remain since @aikidosec/* matches @aikidosec/safe-chain
|
||||
assert.equal(Object.keys(modifiedJson.versions).length, 2);
|
||||
assert.ok(Object.keys(modifiedJson.versions).includes("1.0.0"));
|
||||
assert.ok(Object.keys(modifiedJson.versions).includes("2.0.0"));
|
||||
});
|
||||
|
||||
it("Should exclude packages matching wildcard pattern prefix-*", async () => {
|
||||
minimumPackageAgeSettings = 5;
|
||||
skipMinimumPackageAgeSetting = false;
|
||||
minimumPackageAgeExclusionsSetting = ["react-*"];
|
||||
|
||||
const packageUrl = "https://registry.npmjs.org/react-dom";
|
||||
|
||||
const originalBody = JSON.stringify({
|
||||
name: "react-dom",
|
||||
["dist-tags"]: { latest: "18.0.0" },
|
||||
versions: { ["17.0.0"]: {}, ["18.0.0"]: {} },
|
||||
time: {
|
||||
created: getDate(-365 * 24),
|
||||
modified: getDate(-1),
|
||||
["17.0.0"]: getDate(-100),
|
||||
["18.0.0"]: getDate(-1), // Would normally be filtered
|
||||
},
|
||||
});
|
||||
|
||||
const modifiedBody = await runModifyNpmInfoRequest(packageUrl, originalBody);
|
||||
const modifiedJson = JSON.parse(modifiedBody);
|
||||
|
||||
// All versions should remain since react-* matches react-dom
|
||||
assert.equal(Object.keys(modifiedJson.versions).length, 2);
|
||||
});
|
||||
|
||||
it("Should NOT exclude packages that don't match wildcard pattern", async () => {
|
||||
minimumPackageAgeSettings = 5;
|
||||
skipMinimumPackageAgeSetting = false;
|
||||
minimumPackageAgeExclusionsSetting = ["@aikidosec/*"];
|
||||
|
||||
const packageUrl = "https://registry.npmjs.org/@other/package";
|
||||
|
||||
const originalBody = JSON.stringify({
|
||||
name: "@other/package",
|
||||
["dist-tags"]: { latest: "2.0.0" },
|
||||
versions: { ["1.0.0"]: {}, ["2.0.0"]: {} },
|
||||
time: {
|
||||
created: getDate(-365 * 24),
|
||||
modified: getDate(-1),
|
||||
["1.0.0"]: getDate(-100),
|
||||
["2.0.0"]: getDate(-1),
|
||||
},
|
||||
});
|
||||
|
||||
const modifiedBody = await runModifyNpmInfoRequest(packageUrl, originalBody);
|
||||
const modifiedJson = JSON.parse(modifiedBody);
|
||||
|
||||
// Version 2.0.0 should be filtered since @other/package doesn't match @aikidosec/*
|
||||
assert.equal(Object.keys(modifiedJson.versions).length, 1);
|
||||
assert.ok(Object.keys(modifiedJson.versions).includes("1.0.0"));
|
||||
});
|
||||
|
||||
it("Should reset exclusions between tests", async () => {
|
||||
minimumPackageAgeSettings = 5;
|
||||
skipMinimumPackageAgeSetting = false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue