mirror of
https://github.com/AikidoSec/safe-chain.git
synced 2026-05-26 12:10:49 +00:00
Add minimum package age check for pypi
This commit is contained in:
parent
2c8a1b4972
commit
fd6fb456b4
22 changed files with 516 additions and 273 deletions
|
|
@ -174,10 +174,18 @@ describe("newPackagesDatabase", async () => {
|
|||
assert.strictEqual(db.isNewlyReleasedPackage("foo", "1.0.0"), true);
|
||||
});
|
||||
|
||||
it("returns false for all packages when ecosystem is not JS", async () => {
|
||||
it("supports package checks for the python ecosystem", async () => {
|
||||
ecosystem = "py";
|
||||
fetchedList = [
|
||||
{
|
||||
source: "pypi",
|
||||
package_name: "foo",
|
||||
version: "1.0.0",
|
||||
released_on: hoursAgo(1),
|
||||
},
|
||||
];
|
||||
const db = await openNewPackagesDatabase();
|
||||
assert.strictEqual(db.isNewlyReleasedPackage("foo", "1.0.0"), false);
|
||||
assert.strictEqual(db.isNewlyReleasedPackage("foo", "1.0.0"), true);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ import {
|
|||
ECOSYSTEM_JS,
|
||||
ECOSYSTEM_PY,
|
||||
} from "../config/settings.js";
|
||||
import { getEquivalentPackageNames } from "./packageNameVariants.js";
|
||||
|
||||
/**
|
||||
* @typedef {Object} NewPackagesDatabase
|
||||
* @property {function(string, string): boolean} isNewlyReleasedPackage
|
||||
* @property {function(string | undefined, string | undefined): boolean} isNewlyReleasedPackage
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
@ -33,21 +34,28 @@ function getCurrentFeedSource() {
|
|||
* @returns {NewPackagesDatabase}
|
||||
*/
|
||||
export function buildNewPackagesDatabase(newPackagesList) {
|
||||
const ecosystem = getEcoSystem();
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {string} version
|
||||
* @param {string | undefined} name
|
||||
* @param {string | undefined} version
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isNewlyReleasedPackage(name, version) {
|
||||
if (!name || !version) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const cutOff = new Date(
|
||||
new Date().getTime() - getMinimumPackageAgeHours() * 3600 * 1000
|
||||
);
|
||||
const expectedSource = getCurrentFeedSource();
|
||||
const candidateNames = getEquivalentPackageNames(name, ecosystem);
|
||||
|
||||
const entry = newPackagesList.find(
|
||||
(pkg) =>
|
||||
(!pkg.source || pkg.source.toLowerCase() === expectedSource) &&
|
||||
pkg.package_name === name &&
|
||||
candidateNames.includes(pkg.package_name) &&
|
||||
pkg.version === version
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,15 @@ describe("buildNewPackagesDatabase", () => {
|
|||
assert.strictEqual(db.isNewlyReleasedPackage("not-there", "1.0.0"), false);
|
||||
});
|
||||
|
||||
it("returns false when name or version is undefined", () => {
|
||||
const db = buildNewPackagesDatabase([
|
||||
{ package_name: "foo", version: "1.0.0", released_on: hoursAgo(1) },
|
||||
]);
|
||||
|
||||
assert.strictEqual(db.isNewlyReleasedPackage(undefined, "1.0.0"), false);
|
||||
assert.strictEqual(db.isNewlyReleasedPackage("foo", undefined), false);
|
||||
});
|
||||
|
||||
it("returns false for a known package but different version", () => {
|
||||
const db = buildNewPackagesDatabase([
|
||||
{ package_name: "foo", version: "2.0.0", released_on: hoursAgo(1) },
|
||||
|
|
@ -96,5 +105,54 @@ describe("buildNewPackagesDatabase", () => {
|
|||
|
||||
minimumPackageAgeHours = 24; // reset
|
||||
});
|
||||
|
||||
it("matches underscore request names against hyphen feed names for python", () => {
|
||||
ecosystem = "py";
|
||||
|
||||
const db = buildNewPackagesDatabase([
|
||||
{ source: "pypi", package_name: "foo-bar", version: "1.0.0", released_on: hoursAgo(1) },
|
||||
]);
|
||||
|
||||
assert.strictEqual(db.isNewlyReleasedPackage("foo_bar", "1.0.0"), true);
|
||||
|
||||
ecosystem = "js";
|
||||
});
|
||||
|
||||
it("matches hyphen request names against underscore feed names for python", () => {
|
||||
ecosystem = "py";
|
||||
|
||||
const db = buildNewPackagesDatabase([
|
||||
{ source: "pypi", package_name: "foo_bar", version: "1.0.0", released_on: hoursAgo(1) },
|
||||
]);
|
||||
|
||||
assert.strictEqual(db.isNewlyReleasedPackage("foo-bar", "1.0.0"), true);
|
||||
|
||||
ecosystem = "js";
|
||||
});
|
||||
|
||||
it("matches dot request names against hyphen feed names for python", () => {
|
||||
ecosystem = "py";
|
||||
|
||||
const db = buildNewPackagesDatabase([
|
||||
{ source: "pypi", package_name: "foo-bar", version: "1.0.0", released_on: hoursAgo(1) },
|
||||
]);
|
||||
|
||||
assert.strictEqual(db.isNewlyReleasedPackage("foo.bar", "1.0.0"), true);
|
||||
|
||||
ecosystem = "js";
|
||||
});
|
||||
|
||||
it("matches underscore request names against dot feed names for python", () => {
|
||||
ecosystem = "py";
|
||||
|
||||
const db = buildNewPackagesDatabase([
|
||||
{ source: "pypi", package_name: "foo.bar", version: "1.0.0", released_on: hoursAgo(1) },
|
||||
]);
|
||||
|
||||
assert.strictEqual(db.isNewlyReleasedPackage("foo_bar", "1.0.0"), true);
|
||||
|
||||
ecosystem = "js";
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ import {
|
|||
getNewPackagesListVersionPath,
|
||||
} from "../config/configFile.js";
|
||||
import { ui } from "../environment/userInteraction.js";
|
||||
import { getEcoSystem, ECOSYSTEM_JS } from "../config/settings.js";
|
||||
import { buildNewPackagesDatabase } from "./newPackagesDatabaseBuilder.js";
|
||||
import { warnOnceAboutUnavailableDatabase } from "./newPackagesDatabaseWarnings.js";
|
||||
|
||||
|
|
@ -28,11 +27,6 @@ export async function openNewPackagesDatabase() {
|
|||
return cachedNewPackagesDatabase;
|
||||
}
|
||||
|
||||
if (getEcoSystem() !== ECOSYSTEM_JS) {
|
||||
cachedNewPackagesDatabase = { isNewlyReleasedPackage: () => false };
|
||||
return cachedNewPackagesDatabase;
|
||||
}
|
||||
|
||||
/** @type {import("../api/aikido.js").NewPackageEntry[]} */
|
||||
let newPackagesList;
|
||||
|
||||
|
|
|
|||
18
packages/safe-chain/src/scanning/packageNameVariants.js
Normal file
18
packages/safe-chain/src/scanning/packageNameVariants.js
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
import { ECOSYSTEM_PY } from "../config/settings.js";
|
||||
|
||||
/**
|
||||
* @param {string} packageName
|
||||
* @param {string} ecosystem
|
||||
* @returns {string[]}
|
||||
*/
|
||||
export function getEquivalentPackageNames(packageName, ecosystem) {
|
||||
if (ecosystem !== ECOSYSTEM_PY) {
|
||||
return [packageName];
|
||||
}
|
||||
|
||||
const hyphenName = packageName.replaceAll(/[_.-]/g, "-");
|
||||
const underscoreName = packageName.replaceAll(/[._-]/g, "_");
|
||||
const dotName = packageName.replaceAll(/[_.-]/g, ".");
|
||||
|
||||
return [...new Set([packageName, hyphenName, underscoreName, dotName])];
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue