Public Access
Release v1.0.0
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
max_line_length = 80
|
||||
indent_size = 4
|
||||
|
||||
[*.yml]
|
||||
indent_size = 2
|
||||
@@ -0,0 +1 @@
|
||||
dist
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true
|
||||
},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"project": "./tsconfig.json"
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended-requiring-type-checking",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:prettier/recommended",
|
||||
"prettier",
|
||||
"prettier/@typescript-eslint"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/explicit-function-return-type": 0
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
custom: https://svartalf.info/donate/
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
@@ -0,0 +1,18 @@
|
||||
name: Continuous integration
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
main:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create npm configuration
|
||||
run: echo "//npm.pkg.github.com/:_authToken=${token}" >> ~/.npmrc
|
||||
env:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: actions/checkout@v1
|
||||
- run: npm ci
|
||||
- run: npm run lint
|
||||
- run: npm run build
|
||||
- run: npm run test
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
__tests__/runner/*
|
||||
|
||||
# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
*.lcov
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# TypeScript cache
|
||||
*.tsbuildinfo
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
.env.test
|
||||
|
||||
# parcel-bundler cache (https://parceljs.org/)
|
||||
.cache
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# nuxt.js build output
|
||||
.nuxt
|
||||
|
||||
# vuepress build output
|
||||
.vuepress/dist
|
||||
|
||||
# Serverless directories
|
||||
.serverless/
|
||||
|
||||
# FuseBox cache
|
||||
.fusebox/
|
||||
|
||||
# DynamoDB Local files
|
||||
.dynamodb/
|
||||
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 4,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- Problem matcher which will highlight warnings and errors in the cargo output
|
||||
|
||||
### Changed
|
||||
|
||||
- Use `@action-rs/core` package for cargo/cross execution
|
||||
|
||||
## [1.0.1] - 2019-09-15
|
||||
|
||||
### Added
|
||||
|
||||
- First public version
|
||||
@@ -0,0 +1,22 @@
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 actions-rs team and contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
@@ -1 +1,77 @@
|
||||
[WIP]
|
||||
# Rust `audit-check` Action
|
||||
|
||||

|
||||
[](https://gitter.im/actions-rs/community)
|
||||
|
||||
> Security vulnerabilities audit
|
||||
|
||||
This GitHub Action is using [cargo-audit](https://github.com/RustSec/cargo-audit)
|
||||
to perform an audit for crates with security vulnerabilities.
|
||||
|
||||
## Usage
|
||||
|
||||
### Audit changes
|
||||
|
||||
We can utilize the GitHub Actions ability to execute workflow
|
||||
only if [specific files were changed](https://help.github.com/en/articles/workflow-syntax-for-github-actions#onpushpull_requestpaths)
|
||||
and execute this Action to check the changed dependencies only:
|
||||
|
||||
```yaml
|
||||
name: Security audit
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- '**/Cargo.toml'
|
||||
- '**/Cargo.lock'
|
||||
jobs:
|
||||
security_audit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions-rs/audit-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
```
|
||||
|
||||
In that case this Action will create a Check with the advisories found:
|
||||
|
||||

|
||||
|
||||
#### Limitations
|
||||
|
||||
Due to [token permissions](https://help.github.com/en/articles/virtual-environments-for-github-actions#token-permissions),
|
||||
this Action **WILL NOT** be able to create Checks for Pull Requests from the forked repositories,
|
||||
see [actions-rs/clippy-check#2](https://github.com/actions-rs/clippy-check/issues/2) for details.\
|
||||
As a fallback this Action will output all advisories found to the stdout.
|
||||
|
||||
## Scheduled audit
|
||||
|
||||
Another option is to use [`schedule`](https://help.github.com/en/articles/events-that-trigger-workflows#scheduled-events-schedule) event
|
||||
and execute this Action periodically against the repository default branch `HEAD`.
|
||||
|
||||
```yaml
|
||||
name: Security audit
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
jobs:
|
||||
audit:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions-rs/audit-check@alpha
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
```
|
||||
|
||||
With this workflow Action will be executed at midnight on each day
|
||||
and check if there any new advisories appear for crate dependencies.\
|
||||
For each such advisory an issue will be created:
|
||||
|
||||

|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Required | Description | Type | Default |
|
||||
| ------------| -------- | -------------------------------------------------------------------------| ------ | --------|
|
||||
| `token` | ✓ | GitHub token, `${{ secrets.GITHUB_TOKEN }}` | string | |
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
describe('actions-rs/audit', () => {
|
||||
beforeEach(() => {
|
||||
})
|
||||
|
||||
it('Should do something', async () => {
|
||||
});
|
||||
});
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
name: 'rust-audit-check'
|
||||
description: 'Run cargo audit and check for security advisories'
|
||||
author: 'actions-rs team'
|
||||
branding:
|
||||
icon: play-circle
|
||||
color: black
|
||||
inputs:
|
||||
token:
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: 'node12'
|
||||
main: 'dist/index.js'
|
||||
Vendored
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
clearMocks: true,
|
||||
moduleFileExtensions: ['js', 'ts'],
|
||||
testEnvironment: 'node',
|
||||
testMatch: ['**/*.test.ts'],
|
||||
testRunner: 'jest-circus/runner',
|
||||
transform: {
|
||||
'^.+\\.ts$': 'ts-jest'
|
||||
},
|
||||
verbose: true
|
||||
}
|
||||
Generated
+5885
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "rust-audit-check",
|
||||
"version": "1.0.0",
|
||||
"private": false,
|
||||
"description": "Security audit for security vulnerabilities",
|
||||
"main": "lib/main.js",
|
||||
"directories": {
|
||||
"lib": "lib",
|
||||
"test": "__tests__"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "ncc build src/main.ts --minify",
|
||||
"watch": "ncc build src/main.ts --watch --minify",
|
||||
"test": "jest",
|
||||
"format": "prettier --write 'src/**/*.{js,ts,tsx}'",
|
||||
"refresh": "rm -rf ./lib/* && npm run-script build",
|
||||
"lint": "tsc --noEmit && eslint 'src/**/*.{js,ts,tsx}'"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/actions-rs/audit.git"
|
||||
},
|
||||
"keywords": [
|
||||
"actions",
|
||||
"rust",
|
||||
"cargo",
|
||||
"audit",
|
||||
"security",
|
||||
"advisory"
|
||||
],
|
||||
"author": "actions-rs",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/actions-rs/audit-check/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@actions-rs/core": "0.0.5",
|
||||
"@actions/core": "^1.1.1",
|
||||
"@actions/github": "^1.1.0",
|
||||
"handlebars": "^4.4.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^2.3.2",
|
||||
"ts-node": "^8.4.1",
|
||||
"@typescript-eslint/parser": "^2.3.2",
|
||||
"eslint": "^6.5.1",
|
||||
"eslint-config-prettier": "^6.3.0",
|
||||
"eslint-plugin-prettier": "^3.1.1",
|
||||
"@types/jest": "^24.0.13",
|
||||
"@types/node": "^12.7.8",
|
||||
"@zeit/ncc": "^0.20.5",
|
||||
"jest": "^24.9.0",
|
||||
"jest-circus": "^24.9.0",
|
||||
"ts-jest": "^24.1.0",
|
||||
"typescript": "^3.5.1",
|
||||
"prettier": "^1.18.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Parse action input into a some proper thing.
|
||||
*/
|
||||
|
||||
import { input } from '@actions-rs/core';
|
||||
|
||||
// Parsed action input
|
||||
export interface Input {
|
||||
token: string;
|
||||
}
|
||||
|
||||
export function get(): Input {
|
||||
return {
|
||||
token: input.getInput('token', { required: true }),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
export interface Report {
|
||||
database: DatabaseInfo;
|
||||
lockfile: LockfileInfo;
|
||||
vulnerabilities: VulnerabilitiesInfo;
|
||||
warnings: Vulnerability[];
|
||||
}
|
||||
|
||||
export interface DatabaseInfo {
|
||||
'advisory-count': number;
|
||||
'last-commit': string;
|
||||
'last-updated': string;
|
||||
}
|
||||
|
||||
export interface LockfileInfo {
|
||||
'dependency-count': number;
|
||||
}
|
||||
|
||||
export interface VulnerabilitiesInfo {
|
||||
found: boolean;
|
||||
count: number;
|
||||
list: Vulnerability[];
|
||||
}
|
||||
|
||||
export interface Vulnerability {
|
||||
advisory: Advisory;
|
||||
package: Package;
|
||||
}
|
||||
|
||||
export interface Advisory {
|
||||
id: string;
|
||||
package: string;
|
||||
title: string;
|
||||
description: string;
|
||||
informational: undefined | string | 'notice' | 'unmaintained';
|
||||
url: string;
|
||||
}
|
||||
|
||||
export interface Package {
|
||||
name: string;
|
||||
version: string;
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
import * as process from 'process';
|
||||
import * as os from 'os';
|
||||
|
||||
import * as core from '@actions/core';
|
||||
import * as github from '@actions/github';
|
||||
|
||||
import { Cargo } from '@actions-rs/core';
|
||||
|
||||
import * as input from './input';
|
||||
import * as interfaces from './interfaces';
|
||||
import * as reporter from './reporter';
|
||||
|
||||
const pkg = require('../package.json'); // eslint-disable-line @typescript-eslint/no-var-requires
|
||||
|
||||
const USER_AGENT = `${pkg.name}/${pkg.version} (${pkg.bugs.url})`;
|
||||
|
||||
async function getData(): Promise<interfaces.Report> {
|
||||
const cargo = await Cargo.get();
|
||||
await cargo.findOrInstall('cargo-audit');
|
||||
|
||||
await cargo.call(['generate-lockfile']);
|
||||
|
||||
let stdout = '';
|
||||
try {
|
||||
core.startGroup('Calling cargo-audit (JSON output)');
|
||||
await cargo.call(['audit', '--json'], {
|
||||
ignoreReturnCode: true,
|
||||
listeners: {
|
||||
stdout: buffer => {
|
||||
stdout += buffer.toString();
|
||||
},
|
||||
},
|
||||
});
|
||||
} finally {
|
||||
// Cool story: `cargo-audit` JSON output is missing the trailing `\n`,
|
||||
// so the `::endgroup::` annotation from the line below is being
|
||||
// eaten by it.
|
||||
// Manually writing the `\n` to denote the `cargo-audit` end
|
||||
process.stdout.write(os.EOL);
|
||||
core.endGroup();
|
||||
}
|
||||
|
||||
return JSON.parse(stdout);
|
||||
}
|
||||
|
||||
export async function run(actionInput: input.Input): Promise<void> {
|
||||
const report = await getData();
|
||||
let shouldReport = false;
|
||||
if (!report.vulnerabilities.found) {
|
||||
core.info('No vulnerabilities were found');
|
||||
} else {
|
||||
core.warning(`${report.vulnerabilities.count} vulnerabilities found!`);
|
||||
shouldReport = true;
|
||||
}
|
||||
|
||||
if (report.warnings.length === 0) {
|
||||
core.info('No warnings were found');
|
||||
} else {
|
||||
core.warning(`${report.warnings.length} warnings found!`);
|
||||
shouldReport = true;
|
||||
}
|
||||
|
||||
if (!shouldReport) {
|
||||
return;
|
||||
}
|
||||
|
||||
const client = new github.GitHub(actionInput.token, {
|
||||
userAgent: USER_AGENT,
|
||||
});
|
||||
const advisories = report.vulnerabilities.list.concat(report.warnings);
|
||||
if (github.context.eventName == 'schedule') {
|
||||
core.debug(
|
||||
'Action was triggered on a schedule event, creating an Issues report',
|
||||
);
|
||||
await reporter.reportIssues(client, advisories);
|
||||
} else {
|
||||
core.debug(
|
||||
`Action was triggered on a ${github.context.eventName} event, creating a Check report`,
|
||||
);
|
||||
await reporter.reportCheck(client, advisories);
|
||||
}
|
||||
}
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const actionInput = input.get();
|
||||
|
||||
try {
|
||||
await run(actionInput);
|
||||
} catch (error) {
|
||||
core.setFailed(error.message);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
main();
|
||||
+171
@@ -0,0 +1,171 @@
|
||||
import * as process from 'process';
|
||||
|
||||
import * as core from '@actions/core';
|
||||
import * as github from '@actions/github';
|
||||
|
||||
import { checks } from '@actions-rs/core';
|
||||
import * as interfaces from './interfaces';
|
||||
import * as templates from './templates';
|
||||
|
||||
interface Stats {
|
||||
critical: number;
|
||||
notices: number;
|
||||
unmaintained: number;
|
||||
other: number;
|
||||
}
|
||||
|
||||
function dumpVulnerabilities(
|
||||
vulnerabilities: Array<interfaces.Vulnerability>,
|
||||
): void {
|
||||
const render = templates.CHECK_TEXT({
|
||||
vulnerabilities: vulnerabilities,
|
||||
});
|
||||
|
||||
core.info(render);
|
||||
}
|
||||
|
||||
export function plural(value: number, suffix = 's'): string {
|
||||
return value == 1 ? '' : suffix;
|
||||
}
|
||||
|
||||
function getStats(vulnerabilities: Array<interfaces.Vulnerability>): Stats {
|
||||
let critical = 0;
|
||||
let notices = 0;
|
||||
let unmaintained = 0;
|
||||
let other = 0;
|
||||
for (const vulnerability of vulnerabilities) {
|
||||
switch (vulnerability.advisory.informational) {
|
||||
case 'notice':
|
||||
notices += 1;
|
||||
break;
|
||||
case 'unmaintained':
|
||||
unmaintained += 1;
|
||||
break;
|
||||
case null:
|
||||
critical += 1;
|
||||
break;
|
||||
default:
|
||||
other += 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
critical: critical,
|
||||
notices: notices,
|
||||
unmaintained: unmaintained,
|
||||
other: other,
|
||||
};
|
||||
}
|
||||
|
||||
function getSummary(stats: Stats): string {
|
||||
const blocks: string[] = [];
|
||||
|
||||
if (stats.critical > 0) {
|
||||
// TODO: Plural
|
||||
blocks.push(`${stats.critical} advisory(ies)`);
|
||||
}
|
||||
if (stats.notices > 0) {
|
||||
blocks.push(`${stats.notices} notice${plural(stats.notices)}`);
|
||||
}
|
||||
if (stats.unmaintained > 0) {
|
||||
blocks.push(`${stats.unmaintained} unmaintained`);
|
||||
}
|
||||
if (stats.other > 0) {
|
||||
blocks.push(`${stats.other} other`);
|
||||
}
|
||||
|
||||
return blocks.join(', ');
|
||||
}
|
||||
|
||||
/// Create and publish audit results into the Commit Check.
|
||||
export async function reportCheck(
|
||||
client: github.GitHub,
|
||||
vulnerabilities: Array<interfaces.Vulnerability>,
|
||||
): Promise<void> {
|
||||
const reporter = new checks.CheckReporter(client, 'Security audit');
|
||||
const stats = getStats(vulnerabilities);
|
||||
const summary = getSummary(stats);
|
||||
|
||||
core.info(`Found ${summary}`);
|
||||
|
||||
try {
|
||||
await reporter.startCheck('queued');
|
||||
} catch (error) {
|
||||
// `GITHUB_HEAD_REF` is set only for forked repos,
|
||||
// so we can check if it is a fork and not a base repo.
|
||||
if (process.env.GITHUB_HEAD_REF) {
|
||||
core.error(`Unable to publish audit check! Reason: ${error}`);
|
||||
core.warning(
|
||||
'It seems that this Action is executed from the forked repository.',
|
||||
);
|
||||
core.warning(`GitHub Actions are not allowed to use Check API, \
|
||||
when executed for a forked repos. \
|
||||
See https://github.com/actions-rs/clippy-check/issues/2 for details.`);
|
||||
core.info('Posting audit report here instead.');
|
||||
|
||||
dumpVulnerabilities(vulnerabilities);
|
||||
if (stats.critical > 0) {
|
||||
throw new Error(
|
||||
'Critical vulnerabilities were found, marking check as failed',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
|
||||
try {
|
||||
const output = {
|
||||
title: 'Security advisories found',
|
||||
summary: summary,
|
||||
text: templates.CHECK_TEXT({
|
||||
vulnerabilities: vulnerabilities,
|
||||
}),
|
||||
};
|
||||
const status = stats.critical > 0 ? 'failure' : 'success';
|
||||
await reporter.finishCheck(status, output);
|
||||
} catch (error) {
|
||||
await reporter.cancelCheck();
|
||||
throw error;
|
||||
}
|
||||
|
||||
if (stats.critical > 0) {
|
||||
throw new Error(
|
||||
'Critical vulnerabilities were found, marking check as failed',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function reportIssues(
|
||||
client: github.GitHub,
|
||||
vulnerabilities: Array<interfaces.Vulnerability>,
|
||||
): Promise<void> {
|
||||
const { owner, repo } = github.context.repo;
|
||||
for (const vulnerability of vulnerabilities) {
|
||||
const results = await client.search.issuesAndPullRequests({
|
||||
q: `${vulnerability.advisory.id} in:title repo:${owner}/${repo}`,
|
||||
per_page: 1, // eslint-disable-line @typescript-eslint/camelcase
|
||||
});
|
||||
|
||||
if (results.data.total_count > 0) {
|
||||
core.info(
|
||||
`Seems like ${vulnerability.advisory.id} is mentioned already in the issues/PRs, \
|
||||
will not report an issue against it`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
const issue = await client.issues.create({
|
||||
owner: owner,
|
||||
repo: repo,
|
||||
title: `${vulnerability.advisory.id}: ${vulnerability.advisory.title}`,
|
||||
body: templates.ISSUE_BODY({
|
||||
vulnerability: vulnerability,
|
||||
}),
|
||||
});
|
||||
core.info(
|
||||
`Created an issue for ${vulnerability.advisory.id}: ${issue.data.html_url}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import * as Handlebars from 'handlebars';
|
||||
|
||||
export const CHECK_TEXT = Handlebars.compile(
|
||||
`
|
||||
{{#each vulnerabilities}}
|
||||
## [{{this.advisory.id}}](https://rustsec.org/advisories/{{this.advisory.id}}.html)
|
||||
|
||||
> {{this.advisory.title}}
|
||||
|
||||
| Details | |
|
||||
| ------------------- | ---------------------------------------------- |
|
||||
{{#if this.advisory.informational}}
|
||||
| Status | {{this.advisory.informational}} |
|
||||
{{/if}}
|
||||
| Package | \`{{this.package.name}}\` |
|
||||
| Version | \`{{this.package.version}}\` |
|
||||
| URL | [{{this.advisory.url}}]({{this.advisory.url}}) |
|
||||
| Date | {{this.advisory.date}} |
|
||||
{{#if this.versions.patched.length}}
|
||||
| Patched versions | \`{{this.versions.patched}}\` |
|
||||
{{/if}}
|
||||
{{#if this.versions.unaffected.length}}
|
||||
| Unaffected versions | \`{{this.versions.unaffected}}\` |
|
||||
{{/if}}
|
||||
{{this.advisory.description}}
|
||||
{{/each}}
|
||||
`,
|
||||
{
|
||||
knownHelpersOnly: true,
|
||||
noEscape: true,
|
||||
strict: true,
|
||||
},
|
||||
);
|
||||
|
||||
export const ISSUE_BODY = Handlebars.compile(
|
||||
`
|
||||
> {{vulnerability.advisory.title}}
|
||||
|
||||
| Details | |
|
||||
| ------------------- | ---------------------------------------------- |
|
||||
{{#if vulnerability.advisory.informational}}
|
||||
| Status | {{vulnerability.advisory.informational}} |
|
||||
{{/if}}
|
||||
| Package | \`{{vulnerability.package.name}}\` |
|
||||
| Version | \`{{vulnerability.package.version}}\` |
|
||||
| URL | [{{vulnerability.advisory.url}}]({{vulnerability.advisory.url}}) |
|
||||
| Date | {{vulnerability.advisory.date}} |
|
||||
{{#if vulnerability.versions.patched}}
|
||||
| Patched versions | \`{{vulnerability.versions.patched}}\` |
|
||||
{{/if}}
|
||||
{{#if vulnerability.versions.unaffected}}
|
||||
| Unaffected versions | \`{{vulnerability.versions.unaffected}}\` |
|
||||
{{/if}}
|
||||
|
||||
{{vulnerability.advisory.description}}
|
||||
|
||||
See [advisory page](https://rustsec.org/advisories/{{vulnerability.advisory.id}}.html) for additional details.
|
||||
`,
|
||||
{
|
||||
knownHelpersOnly: true,
|
||||
noEscape: true,
|
||||
strict: true,
|
||||
},
|
||||
);
|
||||
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"newLine": "LF",
|
||||
"noEmitOnError": true,
|
||||
"noErrorTruncation": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
// TODO: enabling it breaks the `@actions/github` package somehow
|
||||
"noImplicitAny": false,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"outDir": "dist",
|
||||
"pretty": true,
|
||||
"removeComments": true,
|
||||
"resolveJsonModule": true,
|
||||
"rootDir": "src",
|
||||
"strict": true,
|
||||
"suppressImplicitAnyIndexErrors": false,
|
||||
"target": "es2018"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user