Skip to content

Commit

Permalink
Support uploading code scanning sarif
Browse files Browse the repository at this point in the history
  • Loading branch information
RobiNino committed Sep 4, 2024
1 parent 4ddfa9d commit 5f60d36
Show file tree
Hide file tree
Showing 302 changed files with 395,480 additions and 13 deletions.
34 changes: 33 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
- [Setting the JFrog Project Key](#setting-the-jfrog-project-key)
- [Downloading JFrog CLI from Artifactory](#downloading-jfrog-cli-from-artifactory)
- [JFrog Job Summary](#jfrog-job-summary)
- [Code Scanning Alerts](#code-scanning-alerts)
- [Example Projects](#example-projects)
- [Contributions](#contributions)
- [References](#references)
Expand Down Expand Up @@ -348,7 +349,38 @@ The final summary will include the summary of each CLI command that supports thi
To read more about the JFrog CLI supported commands, visit the following link:
[JFrog CLI Command Summaries Documentation](https://docs.jfrog-applications.jfrog.io/jfrog-applications/jfrog-cli/cli-command-summaries).

## Example projects
## Code Scanning Alerts
The action also supports the display of code scanning alerts in the GitHub Actions UI.

Code scanning alerts are generated following the execution of the `jf docker scan` and `jf scan` commands.

This feature is available for customers with an Artifactory Enterprise license or above.

### Preconditions
`JF_GIT_TOKEN` - GitHub token with `security-events: write` permission.

You can utilize [$\{{secrets.GITHUB\_TOKEN\}}](https://docs.github.com/en/actions/security-guides/automatic-token-authentication) for `JF_GIT_TOKEN`, which is an automatically generated token by GitHub.

```yaml
permissions:
id-token: write
contents: read
# Required for uploading code scanning.
security-events: write
```

``` yaml
- uses: jfrog/setup-jfrog-cli@v4
env:
# The GitHub token is automatically generated for the job
JF_GIT_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

### Code Scanning Alerts Example:

![Code-Scanning-Alerts](images/code-scanning.png)

## Example Projects

To help you get started, you can use [these](https://github.com/jfrog/project-examples/tree/master/github-action-examples) sample projects on GitHub.

Expand Down
Binary file added images/code-scanning.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions lib/cleanup.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ function generateJobSummary() {
core.startGroup('Generating Job Summary');
yield utils_1.Utils.runCli(['generate-summary-markdown']);
yield utils_1.Utils.setMarkdownAsJobSummary();
yield utils_1.Utils.populateCodeScanningTab();
// Clear files
yield utils_1.Utils.clearCommandSummaryDir();
}
catch (error) {
core.warning('Failed while attempting to generate job summary: ' + error);
Expand Down
96 changes: 91 additions & 5 deletions lib/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ const os_1 = require("os");
const path = __importStar(require("path"));
const path_1 = require("path");
const semver_1 = require("semver");
const core_1 = require("@octokit/core");
const github = __importStar(require("@actions/github"));
const zlib_1 = require("zlib");
const util_1 = require("util");
class Utils {
/**
* Retrieves server credentials for accessing JFrog's server
Expand Down Expand Up @@ -337,7 +341,7 @@ class Utils {
if (projectKey) {
Utils.exportVariableIfNotSet('JFROG_CLI_BUILD_PROJECT', projectKey);
}
// Enable Job summaries if needed
// Enable job summaries if disable was not requested.
if (!core.getBooleanInput(Utils.JOB_SUMMARY_DISABLE)) {
Utils.enableJobSummaries();
}
Expand Down Expand Up @@ -505,14 +509,74 @@ class Utils {
// Write to GitHub's job summary
core.summary.addRaw(markdownContent, true);
yield core.summary.write({ overwrite: true });
// Clear files
yield this.clearJobSummaryDir();
}
catch (error) {
core.warning(`Failed to generate Workflow summary: ${error}`);
}
});
}
/**
* Populates the code scanning SARIF (if generated by scan commands) to the code scanning tab in GitHub.
*/
static populateCodeScanningTab() {
return __awaiter(this, void 0, void 0, function* () {
try {
const encodedSarif = yield this.getCodeScanningEncodedSarif();
if (!encodedSarif) {
return;
}
const token = process.env.JF_GIT_TOKEN;
if (!token) {
console.info('No token provided for uploading code scanning sarif files.');
return;
}
yield this.uploadCodeScanningSarif(encodedSarif, token);
}
catch (error) {
core.warning(`Failed populating code scanning sarif: ${error}`);
}
});
}
/**
* Uploads the code scanning SARIF content to the code-scanning GitHub API.
* @param encodedSarif - The final compressed and encoded sarif content.
* @param token - GitHub token to use for the request. Has to have 'security-events: write' permission.
* @private
*/
static uploadCodeScanningSarif(encodedSarif, token) {
return __awaiter(this, void 0, void 0, function* () {
const octokit = new core_1.Octokit({ auth: token });
let response;
response = yield octokit.request('POST /repos/{owner}/{repo}/code-scanning/sarifs', {
owner: github.context.repo.owner,
repo: github.context.repo.repo,
commit_sha: github.context.sha,
ref: github.context.ref,
sarif: encodedSarif,
});
if (response.status < 200 || response.status >= 300) {
throw new Error(`Failed to upload SARIF file: ` + JSON.stringify(response));
}
core.info('SARIF file uploaded successfully');
});
}
/**
* Compresses the input sarif content using gzip and encodes it to base64. This is required by the code-scanning/sarif API.
* @param input - The sarif content to compress and encode.
* @returns The compressed and encoded string.
* @private
*/
static compressAndEncodeSarif(input) {
return __awaiter(this, void 0, void 0, function* () {
try {
const compressed = yield (0, util_1.promisify)(zlib_1.gzip)(input);
return compressed.toString('base64');
}
catch (error) {
throw new Error('Compression of sarif file failed: ' + error);
}
});
}
/**
* Each section should prepare a file called markdown.md.
* This function reads each section file and wraps it with a markdown header
Expand All @@ -530,6 +594,22 @@ class Utils {
return Utils.wrapContent(markdownContent);
});
}
/**
* Reads the combined SARIF file, compresses and encodes it to match the code-scanning/sarif API requirements.
* @returns <string[]> the paths of the code scanning sarif files.
*/
static getCodeScanningEncodedSarif() {
return __awaiter(this, void 0, void 0, function* () {
const finalSarifFile = path.join(Utils.getJobOutputDirectoryPath(), this.SECURITY_DIR_NAME, this.SARIF_REPORTS_DIR_NAME, this.CODE_SCANNING_FINAL_SARIF_FILE);
if (!(0, fs_1.existsSync)(finalSarifFile)) {
console.debug('No code scanning sarif file was found.');
return "";
}
// Read the SARIF file, compress and encode it to match the code-scanning/sarif API requirements.
const sarif = yield fs_1.promises.readFile(finalSarifFile, 'utf-8');
return yield this.compressAndEncodeSarif(sarif);
});
}
static readMarkdownContent() {
return __awaiter(this, void 0, void 0, function* () {
const markdownFilePath = path.join(Utils.getJobOutputDirectoryPath(), 'markdown.md');
Expand Down Expand Up @@ -585,10 +665,10 @@ class Utils {
}
return path.join(outputDir, Utils.JOB_SUMMARY_DIR_NAME);
}
static clearJobSummaryDir() {
static clearCommandSummaryDir() {
return __awaiter(this, void 0, void 0, function* () {
const outputDir = Utils.getJobOutputDirectoryPath();
core.debug('Removing Workflow summary directory: ' + outputDir);
core.debug('Removing command summary directory: ' + outputDir);
yield fs_1.promises.rm(outputDir, { recursive: true });
});
}
Expand Down Expand Up @@ -647,10 +727,16 @@ Utils.LATEST_SEMVER = '100.100.100';
Utils.SETUP_JFROG_CLI_SERVER_ID = 'setup-jfrog-cli-server';
// Directory name which holds markdown files for the Workflow summary
Utils.JOB_SUMMARY_DIR_NAME = 'jfrog-command-summary';
// Directory name which holds security command summary files
Utils.SECURITY_DIR_NAME = 'security';
// Directory name which holds sarifs files for the code scanning tab
Utils.SARIF_REPORTS_DIR_NAME = 'sarif-reports';
// JFrog CLI command summary output directory environment variable
Utils.JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR_ENV = 'JFROG_CLI_COMMAND_SUMMARY_OUTPUT_DIR';
// Minimum JFrog CLI version supported for job summary command
Utils.MIN_CLI_VERSION_JOB_SUMMARY = '2.66.0';
// Code scanning sarif expected file extension.
Utils.CODE_SCANNING_FINAL_SARIF_FILE = 'final.sarif';
// Inputs
// Version input
Utils.CLI_VERSION_ARG = 'version';
Expand Down
Loading

0 comments on commit 5f60d36

Please sign in to comment.