+
Skip to content

feat: update Scan action to use grype db v6 #462

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Apr 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ jobs:
done
- run: npm ci
- run: npm run audit
- run: npm test
- run: npm run test-ci

test-download-action:
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ typings/

# grype db for tests
/grype-db
/grype

# Action temporary files
/results.*
2 changes: 1 addition & 1 deletion GrypeVersion.js
Original file line number Diff line number Diff line change
@@ -1 +1 @@
exports.GRYPE_VERSION = "v0.87.0";
exports.GRYPE_VERSION = "v0.91.1";
4 changes: 2 additions & 2 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/***/ 4739:
/***/ ((__unused_webpack_module, exports) => {

exports.GRYPE_VERSION = "v0.87.0";
exports.GRYPE_VERSION = "v0.91.1";


/***/ }),
Expand Down Expand Up @@ -404,6 +404,7 @@ async function runScan({
core.debug("Add Missing CPEs: " + addCpesIfNone);
core.debug("Orient by CVE: " + byCve);
core.debug("Output Format: " + outputFormat);
core.debug("Cache DB: " + cacheDb);

core.debug("Creating options for GRYPE analyzer");

Expand Down Expand Up @@ -458,7 +459,6 @@ async function runScan({
);
}
}

return out;
}

Expand Down
2 changes: 1 addition & 1 deletion index.js
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,7 @@ async function runScan({
core.debug("Add Missing CPEs: " + addCpesIfNone);
core.debug("Orient by CVE: " + byCve);
core.debug("Output Format: " + outputFormat);
core.debug("Cache DB: " + cacheDb);

core.debug("Creating options for GRYPE analyzer");

Expand Down Expand Up @@ -444,7 +445,6 @@ async function runScan({
);
}
}

return out;
}

Expand Down
9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@
"test": "tests"
},
"scripts": {
"install-and-update-grype": "RUNNER_TOOL_CACHE='grype' RUNNER_TEMP='grype' node ./scripts/install-and-update-grype.js",
"audit": "better-npm-audit audit --production",
"lint": "eslint index.js",
"test": "eslint index.js && npm run download-pinned-grype-db && npm run build && GRYPE_DB_AUTO_UPDATE=false GRYPE_DB_CACHE_DIR=./grype-db GRYPE_DB_VALIDATE_AGE=false jest --runInBand",
"test:update-snapshots": "eslint index.js && npm run download-pinned-grype-db && GRYPE_DB_AUTO_UPDATE=false GRYPE_DB_CACHE_DIR=./grype-db GRYPE_DB_VALIDATE_AGE=false jest --runInBand --updateSnapshot",
"download-pinned-grype-db": "mkdir -p grype-db/5 && curl -sL https://toolbox-data.anchore.io/grype/databases/vulnerability-db_v5_2022-10-17T08:14:57Z_b50a86ce07d268101316.tar.gz | tar zxf - -C grype-db/5",
"test": "npm run lint && npm run start-registry && npm run install-and-update-grype && npm run build && npm run run-tests",
"test-ci": "npm run lint && npm run install-and-update-grype && npm run build && npm run run-tests",
"start-registry": "sh ./scripts/start_registry_and_push_images.sh",
"run-tests": "GRYPE_DB_AUTO_UPDATE=false GRYPE_DB_VALIDATE_AGE=false jest --runInBand",
"test:update-snapshots": "eslint index.js && npm run install-and-update-grype && GRYPE_DB_AUTO_UPDATE=false GRYPE_DB_VALIDATE_AGE=false jest --runInBand --updateSnapshot",
"build": "ncc build ./index.js && node dos2unix.js dist/index.js",
"precommit": "npm run prettier && npm run build && git add dist/",
"prepare": "husky install",
Expand Down
24 changes: 24 additions & 0 deletions scripts/install-and-update-grype.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const { execFile } = require("child_process");
const { installGrype } = require("../index");
const { GRYPE_VERSION } = require("../GrypeVersion");

(async () => {
try {
const pinnedDB =
"https://grype.anchore.io/databases/v6/vulnerability-db_v6.0.2_2025-04-01T01:31:39Z_1743480497.tar.zst";
const path = await installGrype(process.argv[2] || GRYPE_VERSION);
console.log("Installed to:", path);

execFile(path, ["db", "import", pinnedDB], (error, stdout, stderr) => {
console.log("Importing db from: ", pinnedDB);
if (error) {
console.error("Error running db update:", stderr);
process.exit(1);
}
console.log(stdout);
});
} catch (e) {
console.error("Failed to install or update Grype DB:", e);
process.exit(1);
}
})();
17 changes: 17 additions & 0 deletions scripts/start_registry_and_push_images.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/usr/bin/env bash
set -euo pipefail

# Remove existing container named 'registry' if it exists
if docker ps -a --format '{{.Names}}' | grep -Eq '^registry$'; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One other option is just uploading these prebuilt images to GHCR and getting rid of the build step altogether. It would make everyone's lives easier, probably.

echo "Removing existing 'registry' container..."
docker rm -f registry
fi

# Start a new registry container
docker run -d -p 5000:5000 --name registry registry:2

# Build and push images
for distro in alpine centos debian; do
docker build -t localhost:5000/match-coverage/$distro ./tests/fixtures/image-$distro-match-coverage
docker push localhost:5000/match-coverage/$distro:latest
done
92 changes: 0 additions & 92 deletions tests/action.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,6 @@ const githubActionsCore = require("@actions/core");
const githubActionsCache = require("@actions/cache");
const githubActionsExec = require("@actions/exec");
const { cleanup, mock, mockIO, setEnv, tmpdir, runAction } = require("./mocks");
const {
sha256,
tarGzDir,
dbServer,
listing,
writeMetadata,
} = require("./db_server");
const { run } = require("../index");

jest.setTimeout(90000); // 90 seconds; tests were timing out in CI. https://github.com/anchore/scan-action/pull/249
Expand Down Expand Up @@ -198,89 +191,4 @@ describe("Github action", () => {

expect(failure).toContain("Failed minimum severity level.");
});

it("uses db cache", async () => {
const dbCacheRoot = tmpdir();

mockIO({
image: "localhost:5000/match-coverage/debian:latest", // scan with vulns
path: "",
"fail-build": "true",
"output-format": "json",
"severity-cutoff": "medium",
"add-cpes-if-none": "true",
"cache-db": "true",
});

let restoreCacheDir;
let saveCacheDir;

mock(githubActionsCache, {
async isFeatureAvailable() {
return true;
},
async restoreCache(...args) {
restoreCacheDir = args[0][0];
},
async saveCache(...args) {
saveCacheDir = args[0][0];
},
});

const dbContents = await tarGzDir("grype-db/5");
const dbChecksum = sha256(dbContents);
const listings = [];

// mock a listings file
const listingResponse = {
available: {
5: listings,
},
};

// mock the db update server
const serverUrl = dbServer(listingResponse, dbContents);
const listingUrl = serverUrl + "/listings.json";

// set listing to have update
listings.push(listing(new Date(), serverUrl + "/db.tar.gz", dbChecksum));

setEnv({
GRYPE_DB_CACHE_DIR: dbCacheRoot,
GRYPE_DB_UPDATE_URL: listingUrl,
});
await run();

expect(restoreCacheDir).toBe(dbCacheRoot);
expect(saveCacheDir).toBe(dbCacheRoot);

// with a current, fresh db, we should not have saveCache called
restoreCacheDir = undefined;
saveCacheDir = undefined;

// update the db metadata to be fresh and not require an update
const fresh = new Date();
writeMetadata(dbCacheRoot, fresh);

// env is already set to the tmpdir, with a fresh db
await run();

expect(restoreCacheDir).toBe(dbCacheRoot);
expect(saveCacheDir).toBeUndefined();

// update the db metadata to be > 24 hours
const yesterday = new Date();
yesterday.setHours(yesterday.getHours() - 24);
writeMetadata(dbCacheRoot, yesterday);

// reset call tracking
restoreCacheDir = undefined;
saveCacheDir = undefined;

// env is already set to the tmpdir, but db is old and should be downloaded and cached
await run();

expect(restoreCacheDir).toBe(dbCacheRoot);
expect(saveCacheDir).toBe(dbCacheRoot);
});
});
68 changes: 0 additions & 68 deletions tests/db_server.js

This file was deleted.

1 change: 0 additions & 1 deletion tests/dist.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ function runDistBuild(inputs) {
RUNNER_TOOL_CACHE: process.env.RUNNER_TOOL_CACHE,
GRYPE_DB_AUTO_UPDATE: "false",
GRYPE_DB_VALIDATE_AGE: "false",
GRYPE_DB_CACHE_DIR: path.join(repoRootDir, "grype-db"),
};
// this is brittle and may need to be updated, but is currently how input are passed to the process:
// reverse core.js: const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || '';
Expand Down
1 change: 0 additions & 1 deletion tests/mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ module.exports = {
module.exports.setEnv({
GRYPE_DB_AUTO_UPDATE: "false",
GRYPE_DB_VALIDATE_AGE: "false",
GRYPE_DB_CACHE_DIR: path.join(path.dirname(__dirname), "grype-db"),
});

module.exports.mock(githubActionsCore, {
Expand Down
Loading
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载