Public Access
Compatibility with the latest cargo-audit output format
This commit is contained in:
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Invalid input properly terminates Action execution (#1)
|
- Invalid input properly terminates Action execution (#1)
|
||||||
|
- Compatibility with new `cargo-audit` JSON output (#70)
|
||||||
|
|
||||||
## [1.0.0] - 2019-10-09
|
## [1.0.0] - 2019-10-09
|
||||||
|
|
||||||
|
|||||||
BIN
Binary file not shown.
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Generated
+991
-194
File diff suppressed because it is too large
Load Diff
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "rust-audit-check",
|
"name": "rust-audit-check",
|
||||||
"version": "1.0.0",
|
"version": "1.0.1",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "Security audit for security vulnerabilities",
|
"description": "Security audit for security vulnerabilities",
|
||||||
"main": "lib/main.js",
|
"main": "lib/main.js",
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
"watch": "ncc build src/main.ts --watch --minify",
|
"watch": "ncc build src/main.ts --watch --minify",
|
||||||
"test": "jest --passWithNoTests",
|
"test": "jest --passWithNoTests",
|
||||||
"format": "prettier --write 'src/**/*.{js,ts,tsx}'",
|
"format": "prettier --write 'src/**/*.{js,ts,tsx}'",
|
||||||
"refresh": "rm -rf ./lib/* && npm run-script build",
|
"refresh": "rm -rf ./dist/* && npm run-script build",
|
||||||
"lint": "tsc --noEmit && eslint 'src/**/*.{js,ts,tsx}'"
|
"lint": "tsc --noEmit && eslint 'src/**/*.{js,ts,tsx}'"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -37,8 +37,8 @@
|
|||||||
"@actions-rs/core": "0.0.8",
|
"@actions-rs/core": "0.0.8",
|
||||||
"@actions/core": "^1.2.2",
|
"@actions/core": "^1.2.2",
|
||||||
"@actions/github": "^2.1.0",
|
"@actions/github": "^2.1.0",
|
||||||
"handlebars": "^4.7.2",
|
"npm-check-updates": "^4.0.1",
|
||||||
"npm-check-updates": "^4.0.1"
|
"nunjucks": "^3.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^2.17.0",
|
"@typescript-eslint/eslint-plugin": "^2.17.0",
|
||||||
|
|||||||
+29
-1
@@ -1,8 +1,14 @@
|
|||||||
|
/**
|
||||||
|
* These types should match to what `cargo-audit` outputs in a JSON format.
|
||||||
|
*
|
||||||
|
* See `rustsec` crate for structs used for serialization.
|
||||||
|
*/
|
||||||
|
|
||||||
export interface Report {
|
export interface Report {
|
||||||
database: DatabaseInfo;
|
database: DatabaseInfo;
|
||||||
lockfile: LockfileInfo;
|
lockfile: LockfileInfo;
|
||||||
vulnerabilities: VulnerabilitiesInfo;
|
vulnerabilities: VulnerabilitiesInfo;
|
||||||
warnings: Vulnerability[];
|
warnings: Warning[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DatabaseInfo {
|
export interface DatabaseInfo {
|
||||||
@@ -39,3 +45,25 @@ export interface Package {
|
|||||||
name: string;
|
name: string;
|
||||||
version: string;
|
version: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Warning {
|
||||||
|
kind: Kind;
|
||||||
|
package: Package;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TypeScript types system is weird :(
|
||||||
|
export interface Kind {
|
||||||
|
unmaintained?: KindUnmaintained;
|
||||||
|
informational?: KindInformational;
|
||||||
|
yanked?: KindYanked;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface KindUnmaintained {
|
||||||
|
advisory: Advisory;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface KindInformational {
|
||||||
|
advisory: Advisory;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface KindYanked {} // eslint-disable-line @typescript-eslint/no-empty-interface
|
||||||
|
|||||||
+3
-3
@@ -67,17 +67,17 @@ export async function run(actionInput: input.Input): Promise<void> {
|
|||||||
const client = new github.GitHub(actionInput.token, {
|
const client = new github.GitHub(actionInput.token, {
|
||||||
userAgent: USER_AGENT,
|
userAgent: USER_AGENT,
|
||||||
});
|
});
|
||||||
const advisories = report.vulnerabilities.list.concat(report.warnings);
|
const advisories = report.vulnerabilities.list;
|
||||||
if (github.context.eventName == 'schedule') {
|
if (github.context.eventName == 'schedule') {
|
||||||
core.debug(
|
core.debug(
|
||||||
'Action was triggered on a schedule event, creating an Issues report',
|
'Action was triggered on a schedule event, creating an Issues report',
|
||||||
);
|
);
|
||||||
await reporter.reportIssues(client, advisories);
|
await reporter.reportIssues(client, advisories, report.warnings);
|
||||||
} else {
|
} else {
|
||||||
core.debug(
|
core.debug(
|
||||||
`Action was triggered on a ${github.context.eventName} event, creating a Check report`,
|
`Action was triggered on a ${github.context.eventName} event, creating a Check report`,
|
||||||
);
|
);
|
||||||
await reporter.reportCheck(client, advisories);
|
await reporter.reportCheck(client, advisories, report.warnings);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+121
-21
@@ -2,6 +2,7 @@ import * as process from 'process';
|
|||||||
|
|
||||||
import * as core from '@actions/core';
|
import * as core from '@actions/core';
|
||||||
import * as github from '@actions/github';
|
import * as github from '@actions/github';
|
||||||
|
import * as nunjucks from 'nunjucks';
|
||||||
|
|
||||||
import { checks } from '@actions-rs/core';
|
import { checks } from '@actions-rs/core';
|
||||||
import * as interfaces from './interfaces';
|
import * as interfaces from './interfaces';
|
||||||
@@ -14,21 +15,54 @@ interface Stats {
|
|||||||
other: number;
|
other: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function dumpVulnerabilities(
|
nunjucks.configure({
|
||||||
vulnerabilities: Array<interfaces.Vulnerability>,
|
trimBlocks: true,
|
||||||
): void {
|
lstripBlocks: true,
|
||||||
const render = templates.CHECK_TEXT({
|
|
||||||
vulnerabilities: vulnerabilities,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
core.info(render);
|
function makeReport(
|
||||||
|
vulnerabilities: Array<interfaces.Vulnerability>,
|
||||||
|
warnings: Array<interfaces.Warning>,
|
||||||
|
): string {
|
||||||
|
const preparedWarnings: Array<templates.ReportWarning> = [];
|
||||||
|
for (const warning of warnings) {
|
||||||
|
// TODO: Is there any better way?
|
||||||
|
if ('unmaintained' in warning.kind) {
|
||||||
|
preparedWarnings.push({
|
||||||
|
advisory: warning.kind.unmaintained!.advisory, // eslint-disable-line @typescript-eslint/no-non-null-assertion
|
||||||
|
package: warning.package,
|
||||||
|
});
|
||||||
|
} else if ('informational' in warning.kind) {
|
||||||
|
preparedWarnings.push({
|
||||||
|
advisory: warning.kind.informational!.advisory, // eslint-disable-line @typescript-eslint/no-non-null-assertion
|
||||||
|
package: warning.package,
|
||||||
|
});
|
||||||
|
} else if ('yanked' in warning.kind) {
|
||||||
|
preparedWarnings.push({
|
||||||
|
package: warning.package,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
core.warning(
|
||||||
|
`Unknown warning kind ${warning.kind} found, please, file a bug`,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nunjucks.renderString(templates.REPORT, {
|
||||||
|
vulnerabilities: vulnerabilities,
|
||||||
|
warnings: preparedWarnings,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function plural(value: number, suffix = 's'): string {
|
export function plural(value: number, suffix = 's'): string {
|
||||||
return value == 1 ? '' : suffix;
|
return value == 1 ? '' : suffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStats(vulnerabilities: Array<interfaces.Vulnerability>): Stats {
|
function getStats(
|
||||||
|
vulnerabilities: Array<interfaces.Vulnerability>,
|
||||||
|
warnings: Array<interfaces.Warning>,
|
||||||
|
): Stats {
|
||||||
let critical = 0;
|
let critical = 0;
|
||||||
let notices = 0;
|
let notices = 0;
|
||||||
let unmaintained = 0;
|
let unmaintained = 0;
|
||||||
@@ -50,6 +84,15 @@ function getStats(vulnerabilities: Array<interfaces.Vulnerability>): Stats {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const warning of warnings) {
|
||||||
|
if (warning.kind.unmaintained) {
|
||||||
|
unmaintained += 1;
|
||||||
|
} else {
|
||||||
|
// Both yanked and informational types of kind
|
||||||
|
other += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
critical: critical,
|
critical: critical,
|
||||||
notices: notices,
|
notices: notices,
|
||||||
@@ -82,9 +125,10 @@ function getSummary(stats: Stats): string {
|
|||||||
export async function reportCheck(
|
export async function reportCheck(
|
||||||
client: github.GitHub,
|
client: github.GitHub,
|
||||||
vulnerabilities: Array<interfaces.Vulnerability>,
|
vulnerabilities: Array<interfaces.Vulnerability>,
|
||||||
|
warnings: Array<interfaces.Warning>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const reporter = new checks.CheckReporter(client, 'Security audit');
|
const reporter = new checks.CheckReporter(client, 'Security audit');
|
||||||
const stats = getStats(vulnerabilities);
|
const stats = getStats(vulnerabilities, warnings);
|
||||||
const summary = getSummary(stats);
|
const summary = getSummary(stats);
|
||||||
|
|
||||||
core.info(`Found ${summary}`);
|
core.info(`Found ${summary}`);
|
||||||
@@ -104,7 +148,7 @@ when executed for a forked repos. \
|
|||||||
See https://github.com/actions-rs/clippy-check/issues/2 for details.`);
|
See https://github.com/actions-rs/clippy-check/issues/2 for details.`);
|
||||||
core.info('Posting audit report here instead.');
|
core.info('Posting audit report here instead.');
|
||||||
|
|
||||||
dumpVulnerabilities(vulnerabilities);
|
core.info(makeReport(vulnerabilities, warnings));
|
||||||
if (stats.critical > 0) {
|
if (stats.critical > 0) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
'Critical vulnerabilities were found, marking check as failed',
|
'Critical vulnerabilities were found, marking check as failed',
|
||||||
@@ -116,12 +160,11 @@ See https://github.com/actions-rs/clippy-check/issues/2 for details.`);
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const body = makeReport(vulnerabilities, warnings);
|
||||||
const output = {
|
const output = {
|
||||||
title: 'Security advisories found',
|
title: 'Security advisories found',
|
||||||
summary: summary,
|
summary: summary,
|
||||||
text: templates.CHECK_TEXT({
|
text: body,
|
||||||
vulnerabilities: vulnerabilities,
|
|
||||||
}),
|
|
||||||
};
|
};
|
||||||
const status = stats.critical > 0 ? 'failure' : 'success';
|
const status = stats.critical > 0 ? 'failure' : 'success';
|
||||||
await reporter.finishCheck(status, output);
|
await reporter.finishCheck(status, output);
|
||||||
@@ -137,35 +180,92 @@ See https://github.com/actions-rs/clippy-check/issues/2 for details.`);
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function reportIssues(
|
async function alreadyReported(
|
||||||
client: github.GitHub,
|
client: github.GitHub,
|
||||||
vulnerabilities: Array<interfaces.Vulnerability>,
|
advisoryId: string,
|
||||||
): Promise<void> {
|
): Promise<boolean> {
|
||||||
const { owner, repo } = github.context.repo;
|
const { owner, repo } = github.context.repo;
|
||||||
for (const vulnerability of vulnerabilities) {
|
|
||||||
const results = await client.search.issuesAndPullRequests({
|
const results = await client.search.issuesAndPullRequests({
|
||||||
q: `${vulnerability.advisory.id} in:title repo:${owner}/${repo}`,
|
q: `${advisoryId} in:title repo:${owner}/${repo}`,
|
||||||
per_page: 1, // eslint-disable-line @typescript-eslint/camelcase
|
per_page: 1, // eslint-disable-line @typescript-eslint/camelcase
|
||||||
});
|
});
|
||||||
|
|
||||||
if (results.data.total_count > 0) {
|
if (results.data.total_count > 0) {
|
||||||
core.info(
|
core.info(
|
||||||
`Seems like ${vulnerability.advisory.id} is mentioned already in the issues/PRs, \
|
`Seems like ${advisoryId} is mentioned already in the issues/PRs, \
|
||||||
will not report an issue against it`,
|
will not report an issue against it`,
|
||||||
);
|
);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function reportIssues(
|
||||||
|
client: github.GitHub,
|
||||||
|
vulnerabilities: Array<interfaces.Vulnerability>,
|
||||||
|
warnings: Array<interfaces.Warning>,
|
||||||
|
): Promise<void> {
|
||||||
|
const { owner, repo } = github.context.repo;
|
||||||
|
|
||||||
|
for (const vulnerability of vulnerabilities) {
|
||||||
|
const reported = await alreadyReported(
|
||||||
|
client,
|
||||||
|
vulnerability.advisory.id,
|
||||||
|
);
|
||||||
|
if (reported) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const body = nunjucks.renderString(templates.VULNERABILITY_ISSUE, {
|
||||||
|
vulnerability: vulnerability,
|
||||||
|
});
|
||||||
const issue = await client.issues.create({
|
const issue = await client.issues.create({
|
||||||
owner: owner,
|
owner: owner,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
title: `${vulnerability.advisory.id}: ${vulnerability.advisory.title}`,
|
title: `${vulnerability.advisory.id}: ${vulnerability.advisory.title}`,
|
||||||
body: templates.ISSUE_BODY({
|
body: body,
|
||||||
vulnerability: vulnerability,
|
|
||||||
}),
|
|
||||||
});
|
});
|
||||||
core.info(
|
core.info(
|
||||||
`Created an issue for ${vulnerability.advisory.id}: ${issue.data.html_url}`,
|
`Created an issue for ${vulnerability.advisory.id}: ${issue.data.html_url}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const warning of warnings) {
|
||||||
|
let advisory: interfaces.Advisory;
|
||||||
|
if ('unmaintained' in warning.kind) {
|
||||||
|
advisory = warning.kind.unmaintained!.advisory; // eslint-disable-line @typescript-eslint/no-non-null-assertion
|
||||||
|
} else if ('informational' in warning.kind) {
|
||||||
|
advisory = warning.kind.informational!.advisory; // eslint-disable-line @typescript-eslint/no-non-null-assertion
|
||||||
|
} else if ('yanked' in warning.kind) {
|
||||||
|
core.warning(
|
||||||
|
`Crate ${warning.package.name} was yanked, but no issue will be reported about it`,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
core.warning(
|
||||||
|
`Unknown warning kind ${warning.kind} found, please, file a bug`,
|
||||||
|
);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const reported = await alreadyReported(client, advisory.id);
|
||||||
|
if (reported) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = nunjucks.renderString(templates.WARNING_ISSUE, {
|
||||||
|
warning: warning,
|
||||||
|
advisory: advisory,
|
||||||
|
});
|
||||||
|
const issue = await client.issues.create({
|
||||||
|
owner: owner,
|
||||||
|
repo: repo,
|
||||||
|
title: `${advisory.id}: ${advisory.title}`,
|
||||||
|
body: body,
|
||||||
|
});
|
||||||
|
core.info(
|
||||||
|
`Created an issue for ${advisory.id}: ${issue.data.html_url}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+105
-46
@@ -1,64 +1,123 @@
|
|||||||
import * as Handlebars from 'handlebars';
|
/**
|
||||||
|
* Naive way to bundle the templates in order to skip any build/watch pre-processing steps.
|
||||||
|
*/
|
||||||
|
|
||||||
export const CHECK_TEXT = Handlebars.compile(
|
import * as interfaces from './interfaces';
|
||||||
`
|
|
||||||
{{#each vulnerabilities}}
|
|
||||||
## [{{this.advisory.id}}](https://rustsec.org/advisories/{{this.advisory.id}}.html)
|
|
||||||
|
|
||||||
> {{this.advisory.title}}
|
export interface ReportWarning {
|
||||||
|
advisory?: interfaces.Advisory;
|
||||||
|
package: interfaces.Package;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const REPORT = `
|
||||||
|
{% if vulnerabilities.length > 0 %}
|
||||||
|
## Vulnerabilities
|
||||||
|
|
||||||
|
{% for v in vulnerabilities %}
|
||||||
|
### [{{ v.advisory.id }}](https://rustsec.org/advisories/{{ v.advisory.id }}.html)
|
||||||
|
|
||||||
|
> {{ v.advisory.title }}
|
||||||
|
|
||||||
| Details | |
|
| Details | |
|
||||||
| ------------------- | ---------------------------------------------- |
|
| ------------------- | ---------------------------------------------- |
|
||||||
{{#if this.advisory.informational}}
|
{% if v.advisory.informational %}
|
||||||
| Status | {{this.advisory.informational}} |
|
| Status | {{ v.advisory.informational }} |
|
||||||
{{/if}}
|
{% endif %}
|
||||||
| Package | \`{{this.package.name}}\` |
|
| Package | \`{{ v.package.name }}\` |
|
||||||
| Version | \`{{this.package.version}}\` |
|
| Version | \`{{ v.package.version }}\` |
|
||||||
| URL | [{{this.advisory.url}}]({{this.advisory.url}}) |
|
{% if v.advisory.url %}
|
||||||
| Date | {{this.advisory.date}} |
|
| URL | [{{ v.advisory.url }}]({{ v.advisory.url }}) |
|
||||||
{{#if this.versions.patched.length}}
|
{% endif %}
|
||||||
| Patched versions | \`{{this.versions.patched}}\` |
|
| Date | {{ v.advisory.date }} |
|
||||||
{{/if}}
|
{% if v.versions.patched.length > 0 %}
|
||||||
{{#if this.versions.unaffected.length}}
|
| Patched versions | \`{{ v.versions.patched | safe }}\` |
|
||||||
| Unaffected versions | \`{{this.versions.unaffected}}\` |
|
{% endif %}
|
||||||
{{/if}}
|
{% if v.versions.unaffected.length > 0 %}
|
||||||
{{this.advisory.description}}
|
| Unaffected versions | \`{{ v.versions.unaffected | safe }}\` |
|
||||||
{{/each}}
|
{% endif %}
|
||||||
`,
|
|
||||||
{
|
|
||||||
knownHelpersOnly: true,
|
|
||||||
noEscape: true,
|
|
||||||
strict: true,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
export const ISSUE_BODY = Handlebars.compile(
|
{{ v.advisory.description }}
|
||||||
`
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if warnings.length > 0 %}
|
||||||
|
## Warnings
|
||||||
|
|
||||||
|
{% for w in warnings %}
|
||||||
|
{% if w.advisory %}
|
||||||
|
### [{{ w.advisory.id }}](https://rustsec.org/advisories/{{ w.advisory.id }}.html)
|
||||||
|
|
||||||
|
> {{ w.advisory.title }}
|
||||||
|
|
||||||
|
| Details | |
|
||||||
|
| ------------------- | ---------------------------------------------- |
|
||||||
|
{% if w.advisory.informational %}
|
||||||
|
| Status | {{ w.advisory.informational }} |
|
||||||
|
{% endif %}
|
||||||
|
| Package | \`{{ w.package.name }}\` |
|
||||||
|
| Version | \`{{ w.package.version | safe }}\` |
|
||||||
|
{% if w.advisory.url %}
|
||||||
|
| URL | [{{ w.advisory.url }}]({{ w.advisory.url }}) |
|
||||||
|
{% endif %}
|
||||||
|
| Date | {{ w.advisory.date }} |
|
||||||
|
{% if w.versions.patched.length > 0 %}
|
||||||
|
| Patched versions | \`{{ w.versions.patched | safe }}\` |
|
||||||
|
{% endif %}
|
||||||
|
{% if w.versions.unaffected.length > 0 %}
|
||||||
|
| Unaffected versions | \`{{ w.versions.unaffected | safe }}\` |
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ w.advisory.description }}
|
||||||
|
{% else %}
|
||||||
|
### Crate \`{{ w.package.name }}\` is yanked
|
||||||
|
|
||||||
|
No extra details provided.
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const VULNERABILITY_ISSUE = `
|
||||||
> {{ vulnerability.advisory.title }}
|
> {{ vulnerability.advisory.title }}
|
||||||
|
|
||||||
| Details | |
|
| Details | |
|
||||||
| ------------------- | ---------------------------------------------- |
|
| ------------------- | ---------------------------------------------- |
|
||||||
{{#if vulnerability.advisory.informational}}
|
{% if vulnerability.advisory.informational %}
|
||||||
| Status | {{ vulnerability.advisory.informational }} |
|
| Status | {{ vulnerability.advisory.informational }} |
|
||||||
{{/if}}
|
{% endif %}
|
||||||
| Package | \`{{ vulnerability.package.name }}\` |
|
| Package | \`{{ vulnerability.package.name }}\` |
|
||||||
| Version | \`{{vulnerability.package.version}}\` |
|
| Version | \`{{ vulnerability.package.version | safe }}\` |
|
||||||
|
{% if vulnerability.advisory.url %}
|
||||||
| URL | [{{ vulnerability.advisory.url }}]({{ vulnerability.advisory.url }}) |
|
| URL | [{{ vulnerability.advisory.url }}]({{ vulnerability.advisory.url }}) |
|
||||||
|
{% endif %}
|
||||||
| Date | {{ vulnerability.advisory.date }} |
|
| Date | {{ vulnerability.advisory.date }} |
|
||||||
{{#if vulnerability.versions.patched}}
|
{% if vulnerability.versions.patched.length > 0 %}
|
||||||
| Patched versions | \`{{vulnerability.versions.patched}}\` |
|
| Patched versions | \`{{ vulnerability.versions.patched | safe }}\` |
|
||||||
{{/if}}
|
{% endif %}
|
||||||
{{#if vulnerability.versions.unaffected}}
|
{% if vulnerability.versions.unaffected.length > 0 %}
|
||||||
| Unaffected versions | \`{{vulnerability.versions.unaffected}}\` |
|
| Unaffected versions | \`{{ vulnerability.versions.unaffected | safe }}\` |
|
||||||
{{/if}}
|
{% endif %}
|
||||||
|
|
||||||
{{ vulnerability.advisory.description }}
|
{{ vulnerability.advisory.description }}
|
||||||
|
|
||||||
See [advisory page](https://rustsec.org/advisories/{{ vulnerability.advisory.id }}.html) for additional details.
|
See [advisory page](https://rustsec.org/advisories/{{ vulnerability.advisory.id }}.html) for additional details.
|
||||||
`,
|
`;
|
||||||
{
|
|
||||||
knownHelpersOnly: true,
|
export const WARNING_ISSUE = `
|
||||||
noEscape: true,
|
> {{ advisory.title }}
|
||||||
strict: true,
|
|
||||||
},
|
| Details | |
|
||||||
);
|
| ------------------- | ---------------------------------------------- |
|
||||||
|
{% if advisory.informational %}
|
||||||
|
| Status | {{ advisory.informational }} |
|
||||||
|
{% endif %}
|
||||||
|
| Package | \`{{ warning.package.name }}\` |
|
||||||
|
| Version | \`{{ warning.package.version | safe }}\` |
|
||||||
|
| URL | [{{ advisory.url }}]({{ advisory.url }}) |
|
||||||
|
| Date | {{ advisory.date }} |
|
||||||
|
|
||||||
|
{{ advisory.description }}
|
||||||
|
|
||||||
|
See [advisory page](https://rustsec.org/advisories/{{ advisory.id }}.html) for additional details.
|
||||||
|
`;
|
||||||
|
|||||||
Reference in New Issue
Block a user