Thanks to visit codestin.com
Credit goes to github.com

Skip to content
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
1 change: 1 addition & 0 deletions GrypeVersion.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
exports.GRYPE_VERSION = "v0.34.4";
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,33 @@ You may add a `.grype.yaml` file at your repository root
for more [Grype configuration](https://github.com/anchore/grype#configuration)
such as [ignoring certain matches](https://github.com/anchore/grype#specifying-matches-to-ignore).

## anchore/scan-action/download-grype

A sub-action to [download Grype](download-grype/action.yml).

Input parameters:

| Parameter | Description | Default |
| --------------- | ------------------------------------------------------------------------------------------------------------ | ------- |
| `grype-version` | An optional Grype version to download, defaults to the pinned version in [GrypeVersion.js](GrypeVersion.js). | |

Output parameters:

| Parameter | Description |
| --------- | -------------------------------------------------------------------- |
| `cmd` | a reference to the [Grype](https://github.com/anchore/grype) binary. |

`cmd` can be referenced in a workflow like other output parameters:
`${{ steps.<step-id>.outputs.cmd }}`

Example usage:

```yaml
- uses: anchore/scan-action/download-grype@v3
id: grype
- run: ${{steps.grype.outputs.cmd}} dir:.
```

## Contributing

We love contributions, feedback, and bug reports. For issues with the invocation of this action, file [issues](https://github.com/anchore/scan-action/issues) in this repository.
Expand Down
66 changes: 25 additions & 41 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ module.exports =
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({

/***/ 244:
/***/ ((__unused_webpack_module, exports) => {

exports.GRYPE_VERSION = "v0.34.4";


/***/ }),

/***/ 932:
/***/ ((module, __unused_webpack_exports, __webpack_require__) => {

Expand All @@ -10,42 +18,10 @@ const core = __webpack_require__(186);
const { exec } = __webpack_require__(514);
const fs = __webpack_require__(747);
const stream = __webpack_require__(413);
const { GRYPE_VERSION } = __webpack_require__(244);

const grypeBinary = "grype";
const grypeVersion = "0.34.4";

// Find all 'content-*.json' files in the directory. dirname should include the full path
function findContent(searchDir) {
let contentFiles = [];
let match = /content-.*\.json/;
var dirItems = fs.readdirSync(searchDir);
if (dirItems) {
for (let i = 0; i < dirItems.length; i++) {
if (match.test(dirItems[i])) {
contentFiles.push(`${searchDir}/${dirItems[i]}`);
}
}
} else {
core.debug("no dir content found");
}

core.debug(contentFiles.toString());
return contentFiles;
}

// Load the json content of each file in a list and return them as a list
function loadContent(files) {
let contents = [];
if (files) {
files.forEach((item) => contents.push(JSON.parse(fs.readFileSync(item))));
}
return contents;
}

// Merge the multiple content output types into a single array
function mergeResults(contentArray) {
return contentArray.reduce((merged, n) => merged.concat(n.content), []);
}
const grypeVersion = core.getInput("grype-version") || GRYPE_VERSION;

async function downloadGrype(version) {
let url = `https://raw.githubusercontent.com/anchore/grype/main/install.sh`;
Expand All @@ -58,7 +34,7 @@ async function downloadGrype(version) {
// Make sure the tool's executable bit is set
await exec(`chmod +x ${installPath}`);

let cmd = `${installPath} -b ${installPath}_grype v${version}`;
let cmd = `${installPath} -b ${installPath}_grype ${version}`;
await exec(cmd);
let grypePath = `${installPath}_grype/grype`;

Expand All @@ -75,6 +51,7 @@ async function installGrype(version) {

// Add tool to path for this and future actions to use
core.addPath(grypePath);
return `${grypePath}/${grypeBinary}`;
}

function sourceInput() {
Expand Down Expand Up @@ -255,15 +232,22 @@ module.exports = {
run,
runScan,
installGrype,
mergeResults,
findContent,
loadContent,
};

if (require.main === require.cache[eval('__filename')]) {
run().catch((err) => {
throw new Error(err);
});
const entrypoint = core.getInput("run");
switch (entrypoint) {
case "download-grype": {
installGrype(grypeVersion).then((path) => {
core.info(`Downloaded Grype to: ${path}`);
core.setOutput("cmd", path);
});
break;
}
default: {
run().then();
}
}
}


Expand Down
20 changes: 20 additions & 0 deletions download-grype/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: "Download Grype"
author: "Anchore"
description: "Downloads the Grype binary and provides a path to execute it"
branding:
color: blue
icon: check-circle
inputs:
grype-version:
description: "A specific version of Grype to install"
required: false
run:
description: "Flag to indicate which sub-action to run"
required: false
default: "download-grype"
outputs:
cmd:
description: "An absolute path to the Grype executable"
runs:
using: "node12"
main: "../dist/index.js"
58 changes: 17 additions & 41 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,10 @@ const core = require("@actions/core");
const { exec } = require("@actions/exec");
const fs = require("fs");
const stream = require("stream");
const { GRYPE_VERSION } = require("./GrypeVersion");

const grypeBinary = "grype";
const grypeVersion = "0.34.4";

// Find all 'content-*.json' files in the directory. dirname should include the full path
function findContent(searchDir) {
let contentFiles = [];
let match = /content-.*\.json/;
var dirItems = fs.readdirSync(searchDir);
if (dirItems) {
for (let i = 0; i < dirItems.length; i++) {
if (match.test(dirItems[i])) {
contentFiles.push(`${searchDir}/${dirItems[i]}`);
}
}
} else {
core.debug("no dir content found");
}

core.debug(contentFiles.toString());
return contentFiles;
}

// Load the json content of each file in a list and return them as a list
function loadContent(files) {
let contents = [];
if (files) {
files.forEach((item) => contents.push(JSON.parse(fs.readFileSync(item))));
}
return contents;
}

// Merge the multiple content output types into a single array
function mergeResults(contentArray) {
return contentArray.reduce((merged, n) => merged.concat(n.content), []);
}
const grypeVersion = core.getInput("grype-version") || GRYPE_VERSION;

async function downloadGrype(version) {
let url = `https://raw.githubusercontent.com/anchore/grype/main/install.sh`;
Expand All @@ -51,7 +19,7 @@ async function downloadGrype(version) {
// Make sure the tool's executable bit is set
await exec(`chmod +x ${installPath}`);

let cmd = `${installPath} -b ${installPath}_grype v${version}`;
let cmd = `${installPath} -b ${installPath}_grype ${version}`;
await exec(cmd);
let grypePath = `${installPath}_grype/grype`;

Expand All @@ -68,6 +36,7 @@ async function installGrype(version) {

// Add tool to path for this and future actions to use
core.addPath(grypePath);
return `${grypePath}/${grypeBinary}`;
}

function sourceInput() {
Expand Down Expand Up @@ -248,13 +217,20 @@ module.exports = {
run,
runScan,
installGrype,
mergeResults,
findContent,
loadContent,
};

if (require.main === module) {
run().catch((err) => {
throw new Error(err);
});
const entrypoint = core.getInput("run");
Copy link
Contributor Author

@kzantow kzantow Mar 29, 2022

Choose a reason for hiding this comment

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

I decided to use a parameter to switch functionality here instead of compiling multiple different files; there are some limitations to the ncc tool used to build the actual dist/index.js and limitations in github actions that mean you either need to do this or compile multiple distinct scripts, all of which have duplicated code. I did the latter approach in sbom-action but I'm probably going to swap to this method to simplify things and speed up the commit/build cycle.

switch (entrypoint) {
case "download-grype": {
installGrype(grypeVersion).then((path) => {
core.info(`Downloaded Grype to: ${path}`);
core.setOutput("cmd", path);
});
break;
}
default: {
run().then();
}
}
}
1 change: 0 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
module.exports = {
setupFiles: ["<rootDir>/.jest/setEnvVars.js"],
verbose: true,
testPathIgnorePatterns: ["action.test.js"],
};
48 changes: 38 additions & 10 deletions tests/action.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
const child_process = require('child_process');
const path = require('path');
const process = require('process');
const child_process = require("child_process");
const os = require("os");
const path = require("path");
const process = require("process");

// shows how the runner will run a javascript action with env / stdout protocol
test('test runs', () => {
process.env['INPUT_DEBUG'] = 'true';
process.env['INPUT_IMAGE-REFERENCE'] = 'docker.io/alpine:latest';
const index_path = path.join(__dirname, '../index.js');
console.log(child_process.execSync(`node ${index_path}`, {env: process.env}).toString());
});
const actionPath = path.join(__dirname, "../index.js");

// Execute the action, and return any outputs
function runAction(inputs) {
// reverse core.js: const val = process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || '';
for (const k in inputs) {
process.env[`INPUT_${k}`.toUpperCase()] = inputs[k];
}
// capture stdout
const stdout = child_process
.execSync(`node ${actionPath}`, {
env: process.env,
})
.toString("utf8");
const outputs = {};
// reverse setOutput command calls like:
// ::set-output name=cmd::/tmp/actions/cache/grype/0.34.4/x64/grype
for (const line of stdout.split(os.EOL)) {
const groups = line.match(/::set-output name=(\w+)::(.*)$/);
if (groups && groups.length > 2) {
outputs[groups[1]] = groups[2];
}
}
return outputs;
}

describe("sbom-action", () => {
it("runs download-grype", () => {
const outputs = runAction({
run: "download-grype",
});
expect(outputs.cmd).toBeDefined();

Choose a reason for hiding this comment

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

Is this comparing to blank? output === undefined? Because a successful execution doesn't output anything?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is comparing to undefined, which means this output is any sort of string.

});
});
Loading