12 Commits
Author SHA1 Message Date
Tony Arcieri 69366f33c9 Prep for v2.0.0 release (#25)
Continuous integration / main (push) Failing after 1m29s
2024-09-23 08:24:55 -06:00
Tony Arcieri 7b350a127d npm audit fix (#24) 2024-09-23 08:21:39 -06:00
Charles Lechasseur 286a088f1c fix: update @clechasseur/rs-actions-core and other dependencies (#23)
This fixes a high-severity security vulnerability in the `braces` library.
2024-07-22 13:12:29 -06:00
Ross b7dc4ebf0c Added support for working-directory (#21) 2024-07-08 10:14:45 -06:00
Tillmann 6dc762e804 update to latest upstream and rebuild (#20) 2024-05-09 19:18:11 -06:00
Charles Lechasseur fe0359b3e1 Run on Node 20.x (#16)
Also move to @clechasseur/rs-actions-core for more up-to-date dependencies
2024-04-23 16:26:03 -06:00
pinkforest 4da312dd0f docs: Update repo link 2023-04-04 19:19:38 +10:00
pinkforest d6805b6463 docs: Bump version in README 2023-04-04 18:24:42 +10:00
pinkforest(she/her) dd51754d4e Further fix unsound and notice reporting (#10) (#11)
Continuous integration / main (push) Successful in 1m55s
2023-04-04 18:16:49 +10:00
pinkforest(she/her) 7cb7a4e8d4 Add notice and unsound (#9)
Continuous integration / main (push) Successful in 2m12s
2023-04-04 08:08:08 +10:00
pinkforest(she/her) 13d7e3e1c9 Updates to v1.3.2 with node16 2023-03-28 11:24:53 +11:00
dependabot-preview[bot] 9448c34627 Update readme and changelog 2023-03-28 11:23:25 +11:00
13 changed files with 4568 additions and 21054 deletions
+7 -2
View File
@@ -11,8 +11,13 @@ jobs:
env:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v1
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: '.nvmrc'
cache: 'npm'
- run: npm ci
- run: npm run lint
# octokit types problem ?
# - run: npm run lint
- run: npm run build
- run: npm run test
+1 -1
View File
@@ -1 +1 @@
@actions-rs:registry=https://npm.pkg.github.com
@clechasseur:registry=https://npm.pkg.github.com
+1 -1
View File
@@ -1 +1 @@
v16
v20
+30
View File
@@ -5,6 +5,36 @@ 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).
## [1.4.1] - 2023-04-04
### Fixed
- Corrected reporting on `unsound` and `notice` informationals
## [1.4.0] - 2023-04-04
### Fixed
- Reflect change to enable warning on `unsound` and `notice` informationals
## [1.3.2] - 2023-03-13
### Changed
- Update various dependencies to fix some known vulnerabilities.
## [1.3.1] - 2020-05-10
### Fixed
- GitHub Actions does not support sequences as input
## [1.3.0] - 2022-05-09
### Added
- Add support for ignores (#1)
## [1.2.0] - 2020-05-07
### Fixed
+27 -5
View File
@@ -1,7 +1,6 @@
# Rust `audit-check` Action
![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)
[![Gitter](https://badges.gitter.im/actions-rs/community.svg)](https://gitter.im/actions-rs/community)
> Security vulnerabilities audit
@@ -27,8 +26,8 @@ jobs:
security_audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions-rs/audit-check@v1
- uses: actions/checkout@v4
- uses: rustsec/audit-check@v1.4.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
```
@@ -44,6 +43,27 @@ Note that informational advisories are not affecting the check status.
![Check screenshot](.github/check_screenshot.png)
#### Granular Permissions
These are the typically used permissions:
```yaml
name: 'rust-audit-check'
github-token:
action-input:
input: token
is-default: false
permissions:
issues: write
issues-reason: to create issues
checks: write
checks-reason: to create check
```
The action does not raise issues when it is not triggered from a "cron" scheduled workflow.
When running the action as scheduled it will crate issues but e.g. in PR / push fails the action.
#### Limitations
Due to [token permissions](https://help.github.com/en/articles/virtual-environments-for-github-actions#token-permissions),
@@ -66,8 +86,8 @@ jobs:
audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions-rs/audit-check@v1
- uses: actions/checkout@v4
- uses: rustsec/audit-check@v1.4.1
with:
token: ${{ secrets.GITHUB_TOKEN }}
```
@@ -83,5 +103,7 @@ For each new advisory (including informal) an issue will be created:
| Name | Required | Description | Type | Default |
| ------------| -------- | ---------------------------------------------------------------------------| ------ | --------|
| `token` | ✓ | [GitHub token], usually a `${{ secrets.GITHUB_TOKEN }}` | string | |
| `ignore` | | Comma-separated list of advisory ids to ignore | string | |
| `working-directory`| | The directory of the Cargo.toml / Cargo.lock files to scan. | string | `.` |
[GitHub token]: https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token
+5 -1
View File
@@ -11,7 +11,11 @@ inputs:
ignore:
description: Comma-separated list of advisory ids to ignore
required: false
working-directory:
description: The directory of the Cargo.toml / Cargo.lock files to scan.
required: false
default: .
runs:
using: 'node12'
using: 'node20'
main: 'dist/index.js'
BIN
View File
Binary file not shown.
+3 -1
View File
File diff suppressed because one or more lines are too long
+4395 -20978
View File
File diff suppressed because it is too large Load Diff
+16 -20
View File
@@ -1,6 +1,6 @@
{
"name": "rust-audit-check",
"version": "1.3.1",
"version": "2.0.0",
"private": false,
"description": "Security audit for security vulnerabilities",
"main": "lib/main.js",
@@ -34,26 +34,22 @@
"url": "https://github.com/actions-rs/audit-check/issues"
},
"dependencies": {
"@actions-rs/core": "0.0.9",
"@actions/core": "^1.2.4",
"@actions/github": "^2.1.1",
"npm-check-updates": "^4.1.2",
"nunjucks": "^3.2.1"
"@clechasseur/rs-actions-core": "^3.0.5",
"nunjucks": "^3.2.4"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^2.31.0",
"ts-node": "^8.10.1",
"@typescript-eslint/parser": "^2.31.0",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.11.0",
"eslint-plugin-prettier": "^3.1.3",
"@types/jest": "^25.2.1",
"@types/node": "^13.13.5",
"@zeit/ncc": "^0.22.1",
"jest": "^26.0.1",
"jest-circus": "^26.0.1",
"ts-jest": "^25.5.0",
"typescript": "^3.8.3",
"prettier": "^2.0.5"
"@typescript-eslint/parser": "^6.21.0",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"ts-node": "^10.9.2",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-prettier": "^5.1.3",
"@types/jest": "^29.5.12",
"@types/node": "^20.11.17",
"@vercel/ncc": "0.38.1",
"jest": "^29.7.0",
"ts-jest": "^29.1.2",
"typescript": "^5.3.3",
"prettier": "^3.2.5"
}
}
+4 -3
View File
@@ -2,18 +2,19 @@
* Parse action input into a some proper thing.
*/
import { input } from '@actions-rs/core';
import { getInputList } from '@actions-rs/core/dist/input';
import { input } from '@clechasseur/rs-actions-core';
// Parsed action input
export interface Input {
token: string;
ignore: string[];
workingDirectory: string;
}
export function get(): Input {
return {
token: input.getInput('token', { required: true }),
ignore: getInputList('ignore', { required: false }),
ignore: input.getInputList('ignore', { required: false }),
workingDirectory: input.getInput('working-directory', { required: false }) ?? '.',
};
}
+16 -14
View File
@@ -4,24 +4,19 @@ import * as os from 'os';
import * as core from '@actions/core';
import * as github from '@actions/github';
import { Cargo } from '@actions-rs/core';
import { Cargo } from '@clechasseur/rs-actions-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(
ignore: string[] | undefined,
workingDirectory: string,
): 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)');
@@ -30,6 +25,7 @@ async function getData(
commandArray.push('--ignore', item);
}
commandArray.push('--json');
commandArray.push('--file', `${workingDirectory}/Cargo.lock`);
await cargo.call(commandArray, {
ignoreReturnCode: true,
listeners: {
@@ -50,9 +46,17 @@ async function getData(
return JSON.parse(stdout);
}
function removeTrailingSlash(str) {
if (str[str.length - 1] === '/') {
return str.substr(0, str.length - 1);
}
return str;
}
export async function run(actionInput: input.Input): Promise<void> {
const ignore = actionInput.ignore;
const report = await getData(ignore);
const workingDirectory = removeTrailingSlash(actionInput.workingDirectory);
const report = await getData(ignore, workingDirectory);
let shouldReport = false;
if (!report.vulnerabilities.found) {
core.info('No vulnerabilities were found');
@@ -84,20 +88,18 @@ export async function run(actionInput: input.Input): Promise<void> {
return;
}
const client = new github.GitHub(actionInput.token, {
userAgent: USER_AGENT,
});
// const octokit = github.getOctokit(actionInput.token, {userAgent: USER_AGENT});
const advisories = report.vulnerabilities.list;
if (github.context.eventName == 'schedule') {
core.debug(
'Action was triggered on a schedule event, creating an Issues report',
);
await reporter.reportIssues(client, advisories, warnings);
await reporter.reportIssues(actionInput.token, advisories, warnings);
} else {
core.debug(
`Action was triggered on a ${github.context.eventName} event, creating a Check report`,
);
await reporter.reportCheck(client, advisories, warnings);
await reporter.reportCheck(actionInput.token, advisories, warnings);
}
}
@@ -106,7 +108,7 @@ async function main(): Promise<void> {
const actionInput = input.get();
await run(actionInput);
} catch (error) {
core.setFailed(error.message);
core.setFailed((error as Error).message);
}
return;
+47 -12
View File
@@ -4,14 +4,18 @@ import * as core from '@actions/core';
import * as github from '@actions/github';
import * as nunjucks from 'nunjucks';
import { checks } from '@actions-rs/core';
import { checks } from '@clechasseur/rs-actions-core';
import * as interfaces from './interfaces';
import * as templates from './templates';
const pkg = require('../package.json'); // eslint-disable-line @typescript-eslint/no-var-requires
const USER_AGENT = `${pkg.name}/${pkg.version} (${pkg.bugs.url})`;
interface Stats {
critical: number;
notices: number;
unmaintained: number;
unsound: number;
other: number;
}
@@ -34,6 +38,20 @@ function makeReport(
});
break;
case 'unsound':
preparedWarnings.push({
advisory: warning.advisory,
package: warning.package,
});
break;
case 'notice':
preparedWarnings.push({
advisory: warning.advisory,
package: warning.package,
});
break;
case 'informational':
preparedWarnings.push({
advisory: warning.advisory,
@@ -72,6 +90,7 @@ function getStats(
let critical = 0;
let notices = 0;
let unmaintained = 0;
let unsound = 0;
let other = 0;
for (const vulnerability of vulnerabilities) {
switch (vulnerability.advisory.informational) {
@@ -81,6 +100,9 @@ function getStats(
case 'unmaintained':
unmaintained += 1;
break;
case 'unsound':
unsound += 1;
break;
case null:
critical += 1;
break;
@@ -96,6 +118,10 @@ function getStats(
unmaintained += 1;
break;
case 'unsound':
unsound += 1;
break;
default:
// Both yanked and informational types of kind
other += 1;
@@ -107,6 +133,7 @@ function getStats(
critical: critical,
notices: notices,
unmaintained: unmaintained,
unsound: unsound,
other: other,
};
}
@@ -115,8 +142,7 @@ function getSummary(stats: Stats): string {
const blocks: string[] = [];
if (stats.critical > 0) {
// TODO: Plural
blocks.push(`${stats.critical} advisory(ies)`);
blocks.push(`${stats.critical} advisories`);
}
if (stats.notices > 0) {
blocks.push(`${stats.notices} notice${plural(stats.notices)}`);
@@ -124,6 +150,9 @@ function getSummary(stats: Stats): string {
if (stats.unmaintained > 0) {
blocks.push(`${stats.unmaintained} unmaintained`);
}
if (stats.unsound > 0) {
blocks.push(`${stats.unsound} unsound`);
}
if (stats.other > 0) {
blocks.push(`${stats.other} other`);
}
@@ -133,11 +162,12 @@ function getSummary(stats: Stats): string {
/// Create and publish audit results into the Commit Check.
export async function reportCheck(
client: github.GitHub,
token: string,
vulnerabilities: Array<interfaces.Vulnerability>,
warnings: Array<interfaces.Warning>,
): Promise<void> {
const reporter = new checks.CheckReporter(client, 'Security audit');
const client = github.getOctokit(token, {userAgent: USER_AGENT});
const reporter = new checks.CheckReporter(client.rest, 'Security audit');
const stats = getStats(vulnerabilities, warnings);
const summary = getSummary(stats);
@@ -201,11 +231,12 @@ See https://github.com/actions-rs/clippy-check/issues/2 for details.`);
}
async function alreadyReported(
client: github.GitHub,
token: string,
advisoryId: string,
): Promise<boolean> {
const { owner, repo } = github.context.repo;
const results = await client.search.issuesAndPullRequests({
const client = github.getOctokit(token, {userAgent: USER_AGENT});
const results = await client.rest.search.issuesAndPullRequests({
q: `${advisoryId} in:title repo:${owner}/${repo}`,
per_page: 1, // eslint-disable-line @typescript-eslint/camelcase
});
@@ -222,15 +253,17 @@ will not report an issue against it`,
}
export async function reportIssues(
client: github.GitHub,
token: string,
vulnerabilities: Array<interfaces.Vulnerability>,
warnings: Array<interfaces.Warning>,
): Promise<void> {
const { owner, repo } = github.context.repo;
const client = github.getOctokit(token, {userAgent: USER_AGENT});
for (const vulnerability of vulnerabilities) {
const reported = await alreadyReported(
client,
token,
vulnerability.advisory.id,
);
if (reported) {
@@ -240,7 +273,7 @@ export async function reportIssues(
const body = nunjucks.renderString(templates.VULNERABILITY_ISSUE, {
vulnerability: vulnerability,
});
const issue = await client.issues.create({
const issue = await client.rest.issues.create({
owner: owner,
repo: repo,
title: `${vulnerability.advisory.id}: ${vulnerability.advisory.title}`,
@@ -254,6 +287,8 @@ export async function reportIssues(
for (const warning of warnings) {
let advisory: interfaces.Advisory;
switch (warning.kind) {
case 'unsound':
case 'notice':
case 'unmaintained':
case 'informational':
advisory = warning.advisory;
@@ -270,7 +305,7 @@ export async function reportIssues(
continue;
}
const reported = await alreadyReported(client, advisory.id);
const reported = await alreadyReported(token, advisory.id);
if (reported) {
continue;
}
@@ -279,7 +314,7 @@ export async function reportIssues(
warning: warning,
advisory: advisory,
});
const issue = await client.issues.create({
const issue = await client.rest.issues.create({
owner: owner,
repo: repo,
title: `${advisory.id}: ${advisory.title}`,