Skip to content

Commit

Permalink
Re-pushing the snyk-artifactory-upload tool
Browse files Browse the repository at this point in the history
  • Loading branch information
rhicksiii91 committed Apr 13, 2024
0 parents commit a257418
Show file tree
Hide file tree
Showing 23 changed files with 2,355 additions and 0 deletions.
28 changes: 28 additions & 0 deletions .github/workflows/publish.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
name: Example workflow using Snyk
on:
push:
branches: main

env:
PUBLISHER_ID: ${{ secrets.PUBLISHER_ID }}
AZURE_TOKEN: ${{ secrets.AZURE_TOKEN }}

jobs:
develop:

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
name: Extract Version number
- id: set_version
run: |
content=`cat ./vss-extension.json`
content="${content//'%'/'%25'}"
content="${content//$'\n'/'%0A'}"
content="${content//$'\r'/'%0D'}"
echo "::set-output name=vssextensionjson::$content"
name: Publish Visual Studio extension
- run : |
npm install -g tfx-cli
npx tfx extension create --output-path --manifest-globs vss-extension.json
npx tfx extension publish --auth-type pat -t $AZURE_TOKEN --publisher $PUBLISHER_ID --vsix ./SnykProfessionalServices.snyk-artifactory-upload-${{fromJson(steps.set_version.outputs.vssextensionjson).version}}.vsix
16 changes: 16 additions & 0 deletions .github/workflows/publishmanifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"$schema": "http://json.schemastore.org/vsix-publish",
"categories": [
"build",
"coding"
],
"identity": {
"internalName": "snyk-artifactory-upload-test"
},
"overview": "overview.md",
"priceCategory": "free",
"publisher": "SnykProfessionalServices",
"private": true,
"qna": true,
"repo": "https://github.com/snyk-labs/snyk-artifactory-upload"
}
13 changes: 13 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright 2024 Snyk Ltd.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
101 changes: 101 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# Snyk Artifactory Upload

## Overview

This Azure DevOps task provides functionality to take Snyk vulnerability report details and upload them as properties onto Artifactory artifacts. It supports three main operations: `copy`, `process`, and `copyandprocess`. The task interacts with a Snyk vulnerability report file generated by a preceding task (Snyk Vulnerability Scan Task).

## Features

- **Copy Operation:**
- Uploads the Snyk vulnerability report file to a user-specified directory (`snykFilePath` input).

- **Process Operation:**
- Retrieves the Snyk report from the specified directory (`snykFilePath` input).
- Sets properties from the report file onto designated Artifactory artifacts.
- Artifacts can be specified either by providing a list of artifact URLs or build details (build name, number, and project name).
- When using the url list option you can call multiple URL's seperated by a delimter (which can be configured to be a custom in the task, by default it is <,>)
- Url's can be specific artifacts or folders, the task will set properties as long as the path is valid.
- Do not include initial slash in URL list, example of a valid list > "path/to/some/artifact, path/to/some/folder"

## Usage

### Parameters

- **Operation:**
- Choose one of the following operations: `copy`, `process`, `copyandprocess`.

- **Snyk File Path (`snykFilePath`):**
- The directory path where the Snyk vulnerability report file will be stored or retrieved.

- **Artifact Specification:**
- Specify artifacts either by providing a list of URLs or build details.

### Example

```yaml
- task: snyk-artifactory-azure-upload@1
inputs:
Operation: 'CopyAndProcess'
SnykDirectory: '$(Pipeline.Workspace)'
artifactoryServiceConnection: 'someserviceconnection'
InputType: 'Build'
BuildName: 'somebuild'
BuildNumber: 'somebuildNumber'
ProjectName: 'someProjectName'
```
### Snyk Scan Data Properties
Upon successfully retrieving scan data, the following properties are set on the artifact:
- **Scan Status (`snyk_sast_scan_status`):**
- Indicates the status of the Snyk Static Application Security Testing (SAST) scan.

- **Findings Present (`snyk_sast_findings_present`):**
- A boolean flag indicating whether Snyk findings are present.
- `true` if findings are present, `false` otherwise.

- **Highest Severity Level (`snyk_sast_highest_severity_level`):**
- The highest severity level of vulnerabilities found in the scan.
- Possible values: `"high"`, `"medium"`, `"low"`, etc.

- **High Severity Count (`snyk_sast_high_severity_count`):**
- The count of vulnerabilities with high severity.

- **Medium Severity Count (`snyk_sast_medium_severity_count`):**
- The count of vulnerabilities with medium severity.

- **Low Severity Count (`snyk_sast_low_severity_count`):**
- The count of vulnerabilities with low severity.

- **Project Link (`snyk_sast_project_link`):**
- A link to the Snyk project providing detailed information about the scan results.




# Contributing to Azure DevOps Snyk Vulnerability Report Task

Thank you for considering contributing to this project! Please take a moment to review the following guidelines.

## Open Source Contributions

We currently do not accept open source contributions, including pull requests. The development of this project is primarily maintained by the project owners.

## Bug Reports and Feature Requests

For bug reports or feature requests, please follow these steps:

1. Check if the issue has already been reported in [GitHub Issues](https://github.com/snyk-labs/snyk-artifactory-upload/issues).
2. If not, open a new issue.
3. Provide detailed information about the problem or the requested feature.

## Pull Requests

As mentioned earlier, we do not accept open source contributions, including pull requests. However, we appreciate your interest in improving the project.

Thank you for your understanding and support!

## License

By contributing, you agree that your contributions will be licensed under the [Apache License 2.0](./LICENSE).
Binary file added images/extension-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 18 additions & 0 deletions overview.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Snyk Artifactory Upload

## Overview

This Azure DevOps task provides functionality to take Snyk vulnerability report details and upload them as properties onto Artifactory artifacts. It supports three main operations: `copy`, `process`, and `copyandprocess`. The task interacts with a Snyk vulnerability report file generated by a preceding task (Snyk Vulnerability Scan Task).

## Features

- **Copy Operation:**
- Uploads the Snyk vulnerability report file to a user-specified directory (`snykFilePath` input).

- **Process Operation:**
- Retrieves the Snyk report from the specified directory (`snykFilePath` input).
- Sets properties from the report file onto designated Artifactory artifacts.
- Artifacts can be specified either by providing a list of artifact URLs or build details (build name, number, and project name).
- When using the url list option you can call multiple URL's seperated by a delimter (which can be configured to be a custom in the task, by default it is <,>)
- Url's can be specific artifacts or folders, the task will set properties as long as the path is valid.
- Do not include initial slash in URL list, example of a valid list > "path/to/some/artifact, path/to/some/folder"
2 changes: 2 additions & 0 deletions task/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
.dccache
1 change: 1 addition & 0 deletions task/.taskkey
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
6aa09ff1-547d-437e-aa49-ea60f6b135e1
138 changes: 138 additions & 0 deletions task/artifactory-api-helpers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.setProperties = void 0;
const tl = require("azure-pipelines-task-lib/task");
const axios_1 = __importDefault(require("axios"));
const axios_retry_1 = __importDefault(require("axios-retry"));
const Utils = __importStar(require("./helpers"));
(0, axios_retry_1.default)(axios_1.default, {
retries: 10, // Number of retries
retryDelay: axios_retry_1.default.exponentialDelay, // Retry delay strategy
onRetry: (retryCount, error, Config) => { console.log("Axios request failed with " + error + " retrying now.."); }
});
function setProperties(properties) {
var _a, _b;
const inputType = (_a = tl.getInput("InputType", true)) === null || _a === void 0 ? void 0 : _a.toLowerCase();
// get username/password details from service connection
const serviceConnectionId = tl.getInput('artifactoryServiceConnection', true);
const auth = tl.getEndpointAuthorization(serviceConnectionId, false);
let authType = tl.getEndpointAuthorizationScheme(serviceConnectionId, false);
let authToken = '';
if (authType == 'UsernamePassword') {
const username = auth === null || auth === void 0 ? void 0 : auth.parameters['username'];
const password = auth === null || auth === void 0 ? void 0 : auth.parameters['password'];
authToken = Buffer.from(`${username}:${password}`).toString('base64');
authType = 'Basic';
}
else if (authType == 'Token') {
authToken = auth === null || auth === void 0 ? void 0 : auth.parameters['apitoken'];
authType = 'Bearer';
}
const baseUrl = tl.getEndpointUrl(serviceConnectionId, true);
//set API headers
const headers = {
Authorization: `${authType} ${authToken}`,
'Content-Type': 'application/json', // Set content type based on your requirements
};
//Retrieve artifact URLs
let artifactUrls = [];
if (inputType == "urllist") {
const delimiter = tl.getInput('delimiter', false) || ',';
artifactUrls = (_b = tl.getInput('artifactUrls', true)) === null || _b === void 0 ? void 0 : _b.split(delimiter);
//add properties to each artifact
for (let artifactUrlShort of artifactUrls) {
artifactUrlShort = Utils.encodeUrl(artifactUrlShort);
const artifactUrl = `${baseUrl}/api/storage/${artifactUrlShort}`; // Construct the complete URL
Object.keys(properties).forEach((prop) => {
const queryParams = {
"properties": [prop] + '=' + properties[prop], // Assuming 'prop' and 'properties' are defined elsewhere
};
axios_1.default.put(artifactUrl, null, {
params: queryParams,
headers: headers,
})
.then(response => {
console.log(`Successfully set property '${prop}' on Artifact ${artifactUrlShort}`);
})
.catch(error => {
//test
console.log('Error while attempting to add property to Artifact:' + error);
// Handle errors here
process.exit(1); // Exiting with a non-zero code indicating an error
});
});
}
}
else if (inputType == "build") {
const buildName = tl.getInput('BuildName', true);
const buildNumber = tl.getInput('BuildNumber', true);
const projectName = tl.getInput('ProjectKey', true);
const BuildStatus = tl.getInput('BuildStatus', false);
const searchBody = Object.assign({ "buildName": buildName, "buildNumber": buildNumber, "project": projectName }, (BuildStatus !== null && { myProperty: BuildStatus }));
const searchUrl = `${baseUrl}/api/search/buildArtifacts`;
axios_1.default.post(searchUrl, JSON.stringify(searchBody), {
headers: headers,
})
.then((response) => {
console.log("Data received from build search API: " + JSON.stringify(response.data));
artifactUrls = response.data.results.map((obj) => {
const { downloadUri } = obj;
const trimmedUrl = downloadUri.replace(`${baseUrl}/`, "");
return trimmedUrl;
});
for (let artifactUrlShort of artifactUrls) {
artifactUrlShort = Utils.encodeUrl(artifactUrlShort);
const artifactUrl = `${baseUrl}/api/storage/${artifactUrlShort}`; // Construct the complete URL
Object.keys(properties).forEach((prop) => {
const queryParams = {
"properties": [prop] + '=' + properties[prop], // Assuming 'prop' and 'properties' are defined elsewhere
};
setTimeout(() => axios_1.default.put(artifactUrl, null, {
params: queryParams,
headers: headers,
})
.then(response => {
console.log(`Successfully set property '${prop}' on Artifact ${artifactUrlShort}`);
// Adding a delay between each API call
})
.catch(error => {
console.log('Error while attempting to add property to Artifact: ' + error);
// Handle errors here
process.exit(1); // Exiting with a non-zero code indicating an error
}), 1000);
});
}
})
.catch((error) => {
console.error('Error from Artifactory search builds API:', error.response ? error.response.data : error.message);
process.exit(1);
});
}
}
exports.setProperties = setProperties;
Loading

0 comments on commit a257418

Please sign in to comment.