From de98902a85982351c7539672391de014252edde5 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Fri, 8 Mar 2024 18:33:47 -0800 Subject: Add 'showjson' command to output an advisory in OSV JSON Open Source Vulnerability format is a standard for publishing vulnerabilities in Open Source projects and is defined at https://ossf.github.io/osv-schema/ --- NEWS | 1 + lib/MGA/Advisories.pm | 23 +++++++++++++ mgaadv | 17 ++++++++++ tmpl/advisory.json | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 tmpl/advisory.json diff --git a/NEWS b/NEWS index 61c5377..8a16eb6 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,7 @@ Version X - template: change default CVE year to 2024 - use https: links where possible +- add 'showjson' command to output an advisory in OSV JSON format Version 0.27 diff --git a/lib/MGA/Advisories.pm b/lib/MGA/Advisories.pm index cbabd68..c8514fa 100644 --- a/lib/MGA/Advisories.pm +++ b/lib/MGA/Advisories.pm @@ -821,4 +821,27 @@ sub showadv { print $advtxt; } +sub showadvjson { + my ($advdb, $adv) = @_; + if (!$advdb->{advisories}{$adv}) { + print STDERR "Cannot find advisory $adv\n"; + return undef; + } + my $template = Template->new( + ENCODING => 'utf8', + INCLUDE_PATH => $config->{tmpl_dir}, + EVAL_PERL => 1, + ); + my $vars = { + config => $config, + advisory => $adv, + advdb => $advdb, + basename => \%basename, + tools => \%tools, + }; + my $advtxt; + process_template($template, 'advisory', $vars, \$advtxt, 'json'); + print $advtxt; +} + 1; diff --git a/mgaadv b/mgaadv index ca519b0..78b1cf3 100755 --- a/mgaadv +++ b/mgaadv @@ -109,6 +109,15 @@ END $0 show [ID] Show an advisory. +END + }, + showjson => { + run => \&showadvjson, + descr => 'Show an advisory in JSON format', + usage => < { @@ -219,6 +228,14 @@ sub showadv { MGA::Advisories::showadv(\%advdb, $adv); } +sub showadvjson { + usageexit('usage', $_[0]) unless @_ == 2; + my $adv = $_[1]; + my %advdb; + $advdb{advisories} = MGA::Advisories::get_advisories(); + MGA::Advisories::showadvjson(\%advdb, $adv); +} + sub updateadv { usageexit('usage', $_[0]) unless @_ == 1; MGA::Advisories::download_advisories; diff --git a/tmpl/advisory.json b/tmpl/advisory.json new file mode 100644 index 0000000..475012f --- /dev/null +++ b/tmpl/advisory.json @@ -0,0 +1,94 @@ +[% USE date -%] +[% PERL -%] +use JSON; +[% END -%] +[% MACRO jsonvar(var) PERL -%] +# JSON-encode the given variable, including quotes +print JSON::encode_json($stash->get($stash->get('var'))); +[% END %] +[%- SET adv = advdb.advisories.$advisory -%] +{ + "schema_version": "1.6.2", + "id": [% jsonvar('advisory') %], + "published": "[% date.format(adv.status.published, format => '%Y-%m-%dT%H:%M:%SZ', gmt => 1) %]", + "summary": [% jsonvar('adv.subject') %], + "details": [% jsonvar('adv.description') %], +[% IF adv.CVE && adv.CVE.list.size != 0 -%] + "related": [ +[% FOREACH cve IN adv.CVE -%] + [% jsonvar('cve') -%] +[% "," IF ! loop.last %] +[% END -%] + ], +[% END -%] + "references": [ + { + "type": "ADVISORY", + "url": "[% config.site_url %]/[% basename.ID(advisory) %].html" + } +[%- "," IF adv.references && adv.references.list.size != 0 %] +[% FOREACH ref IN adv.references -%] + { + "type": "REPORT", + "url": [% jsonvar('ref') %] + } +[%- "," IF ! loop.last %] +[% END -%] + ], + "affected": [ +[% USE srciter = iterator(adv.src.keys) -%] +[% FOREACH rel IN srciter -%] +[% USE mediaiter = iterator(adv.src.$rel.keys) -%] +[% FOREACH media IN mediaiter -%] +[% FOREACH srpm IN adv.src.$rel.$media -%] + { + "package": { + "ecosystem": "Mageia:[% rel %]", +[% USE pkg = String(srpm) -%] +[% FOREACH part IN pkg.split('-[\w\.+~^]+-[\w\.]+\.mga\d+') -%] +[% SET pkgname = part -%] +[% LAST -%] +[% END -%] + "name": [% jsonvar('pkgname') %], +[% CALL pkg.shift(pkgname) -%] +[% CALL pkg.shift('-') -%] +[% SET pkgver = pkg.text -%] +[% USE purl = String('pkg:rpm/mageia/') -%] +[% CALL purl.push(pkgname) -%] +[% CALL purl.push('?distro=mageia-') -%] +[% CALL purl.push(rel) -%] +[% SET purltext = purl.text -%] + "purl": [% jsonvar('purltext') %] + }, + "ranges": [ + { + "type": "ECOSYSTEM", + "events": [ + { + "introduced": "0" + }, + { + "fixed": [% jsonvar('pkgver') %] + } + ] + } + ], + "ecosystem_specific": { + "section": [% jsonvar('media') %] + } + } +[%- "," IF ! loop.last || ! mediaiter.last || ! srciter.last %] +[% END %] +[%- END -%] +[%- END -%] + ], + "credits": [ + { + "name": "Mageia", + "type": "COORDINATOR", + "contact": [ + "https://wiki.mageia.org/en/Packages_Security_Team" + ] + } + ] +} -- cgit v1.2.1