App-CPAN-SBOM

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

Change history for App-CPAN-SBOM

1.03 2025-08-11
    - Added "DTRACK_*" env variables for CI/CD
    - Improved BOM generation

1.02 2025-06-05
    - Added support for projects that use "cpanfile.snapshot" or "cpanfile"
    - Added support for uploading BOM files to OWASP Dependency Track

1.01 2025-03-14
    - Added CPAN::Audit for populate vulnerabilities

1.00 2025-03-10
    - First release of App::CPAN::SBOM

INSTALL.md  view on Meta::CPAN

# App::CPAN::SBOM - Utility for generate SBOM file

The INSTALL is used to introduce the module and provide instructions on
how to install the module, any machine dependencies it may have (for
example C compilers and installed libraries) and any other information
that should be provided before the module is installed.

## INSTALLATION

Using Makefile.PL:

To install this module, run the following commands.

    perl Makefile.PL
    make
    make test
    make install

Using App::cpanminus:

    cpanm App::CPAN::SBOM

## SUPPORT AND DOCUMENTATION

After installing, you can find documentation for this module with the
perldoc command.

    perldoc App::CPAN::SBOM


You can also look for information at:

  * GitHub issues (report bugs here) https://github.com/giterlizzi/perl-App-CPAN-SBOM/issues


## LICENSE AND COPYRIGHT

Copyright (C) 2025 Giuseppe Di Terlizzi

This program is free software; you can redistribute it and/or modify it
under the terms of the the Artistic License (2.0). You may obtain a
copy of the full license at:

MANIFEST  view on Meta::CPAN

bin/cpan-sbom
Changes
INSTALL.md
lib/App/CPAN/SBOM.pm
LICENSE
Makefile.PL
MANIFEST
README.md
t/00-load.t
xt/kwalitee.t
xt/manifest.t
xt/pod-coverage.t
xt/pod.t
META.yml                                 Module YAML meta-data (added by MakeMaker)

META.json  view on Meta::CPAN

   ],
   "dynamic_config" : 1,
   "generated_by" : "ExtUtils::MakeMaker version 7.76, CPAN::Meta::Converter version 2.150010",
   "license" : [
      "artistic_2"
   ],
   "meta-spec" : {
      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
      "version" : 2
   },
   "name" : "App-CPAN-SBOM",
   "no_index" : {
      "directory" : [
         "t",
         "inc"
      ]
   },
   "prereqs" : {
      "build" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"

META.json  view on Meta::CPAN

            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "CPAN::Audit" : "0",
            "Cpanel::JSON::XS" : "0",
            "HTTP::Tiny" : "0",
            "MIME::Base64" : "0",
            "MetaCPAN::Client" : "0",
            "SBOM::CycloneDX" : "0",
            "URI::PackageURL" : "2.22",
            "perl" : "5.016"
         }
      },
      "test" : {
         "requires" : {
            "Test::More" : "0"
         }
      }
   },
   "release_status" : "stable",
   "resources" : {
      "bugtracker" : {
         "web" : "https://github.com/giterlizzi/perl-App-CPAN-SBOM/issues"
      },
      "repository" : {
         "type" : "git",
         "url" : "git://github.com/giterlizzi/perl-App-CPAN-SBOM",
         "web" : "https://github.com/giterlizzi/perl-App-CPAN-SBOM"
      }
   },
   "version" : "1.03",
   "x_purl" : "pkg:cpan/GDT/App-CPAN-SBOM",
   "x_serialization_backend" : "JSON::PP version 4.16"
}

META.yml  view on Meta::CPAN

  ExtUtils::MakeMaker: '0'
  Test::More: '0'
configure_requires:
  ExtUtils::MakeMaker: '0'
dynamic_config: 1
generated_by: 'ExtUtils::MakeMaker version 7.76, CPAN::Meta::Converter version 2.150010'
license: artistic_2
meta-spec:
  url: http://module-build.sourceforge.net/META-spec-v1.4.html
  version: '1.4'
name: App-CPAN-SBOM
no_index:
  directory:
    - t
    - inc
requires:
  CPAN::Audit: '0'
  Cpanel::JSON::XS: '0'
  HTTP::Tiny: '0'
  MIME::Base64: '0'
  MetaCPAN::Client: '0'
  SBOM::CycloneDX: '0'
  URI::PackageURL: '2.22'
  perl: '5.016'
resources:
  bugtracker: https://github.com/giterlizzi/perl-App-CPAN-SBOM/issues
  repository: git://github.com/giterlizzi/perl-App-CPAN-SBOM
version: '1.03'
x_purl: pkg:cpan/GDT/App-CPAN-SBOM
x_serialization_backend: 'CPAN::Meta::YAML version 0.020'

Makefile.PL  view on Meta::CPAN

#!perl

use strict;
use warnings;
use ExtUtils::MakeMaker;

WriteMakefile(
    NAME               => 'App-CPAN-SBOM',
    AUTHOR             => q{Giuseppe Di Terlizzi <gdt@cpan.org>},
    VERSION_FROM       => 'lib/App/CPAN/SBOM.pm',
    LICENSE            => 'artistic_2',
    MIN_PERL_VERSION   => 5.016,
    PL_FILES           => {},
    EXE_FILES          => ['bin/cpan-sbom'],
    CONFIGURE_REQUIRES => {'ExtUtils::MakeMaker' => '0'},
    TEST_REQUIRES      => {'Test::More'          => '0'},
    PREREQ_PM          => {
        'SBOM::CycloneDX'  => 0,
        'CPAN::Audit'      => 0,
        'MetaCPAN::Client' => 0,
        'URI::PackageURL'  => '2.22',
        'MIME::Base64'     => 0,
        'HTTP::Tiny'       => 0,
        'Cpanel::JSON::XS' => 0,
    },
    META_MERGE => {
        'meta-spec' => {version => 2},
        'resources' => {
            bugtracker => {web => 'https://github.com/giterlizzi/perl-App-CPAN-SBOM/issues'},
            repository => {
                type => 'git',
                url  => 'git://github.com/giterlizzi/perl-App-CPAN-SBOM',
                web  => 'https://github.com/giterlizzi/perl-App-CPAN-SBOM'
            },
        },
        x_purl => 'pkg:cpan/GDT/App-CPAN-SBOM'
    },
    dist  => {COMPRESS => 'gzip -9f', SUFFIX => 'gz'},
    clean => {FILES    => 'App-CPAN-SBOM-*'},
);

README.md  view on Meta::CPAN

[![Release](https://img.shields.io/github/release/giterlizzi/perl-App-CPAN-SBOM.svg)](https://github.com/giterlizzi/perl-App-CPAN-SBOM/releases) [![Actions Status](https://github.com/giterlizzi/perl-App-CPAN-SBOM/workflows/linux/badge.svg)](https://g...

# App-CPAN-SBOM - CPAN SBOM (Software Bill of Materials) generator

## Synopsis

```.bash
cpan-sbom --distribution NAME@VERSION
cpan-sbom --meta (META|MYMETA).(json|yml)

cpan-sbom --project-directory DIRECTORY [ --project-name NAME --project-version VERSION --project-description TEXT
                                          --project-license SPDX-LICENSE --project-type BOM-TYPE
                                          --project-author STRING [--project-author STRING] ]

cpan-sbom [--help|--man|-v]

Options:
  -o, --output                          Output file. Default bom.json 

      --distribution NAME@VERSION       Distribution name and version
      --meta                            META or MYMETA file

      --project-directory NAME          Project directory
      --project-meta                    Project META or MYMETA file (alias of --meta)
      --project-type BOM-TYPE           Project type (default: library)
      --project-name NAME               Project name (default: project directory name)
      --project-version VERSION         Project version
      --project-author STRING           Project author(s)
      --project-license SPDX-LICENSE    Project SPDX license
      --project-description TEXT        Project description                  

      --maxdepth=NUM                    Max depth (default: 1)
      --vulnerabilities                 Include Module/Distribution vulnerabilities
      --no-vulnerabilities

      --validate                        Validate the generated SBOM using JSON Schema (default: true)
      --no-validate

      --list-spdx-licenses              List SPDX licenses

      --debug                           Enable debug messages

      --help                            Brief help message
      --man                             Full documentation
  -v, --version                         Print version

README.md  view on Meta::CPAN

      --skip-tls-check                  Disable SSL/TLS check (Env: $DTRACK_SKIP_TLS_CHECK)
      --project-id STRING               Project ID (Env: $DTRACK_PROJECT_ID)
      --project-name NAME               Project name (Env: DTRACK_PROJECT_NAME)
      --project-version VERSION         Project version (Env: $DTRACK_PROJECT_VERSION)
      --parent-project-id STRING        Parent project ID (Env: $DTRACK_PARENT_PROJECT_ID)
```

## Examples

```.bash
Create SBOM of specific distribution:

$ cpan-sbom --distribution libwww-perl@6.78

Create SBOM from META file:

$ cpan-sbom --meta META.json

Create SBOM from your project directory:

$ cpan-sbom \
    --project-directory . \
    --project-name "My Cool Application" \
    --project-type application \
    --project-version 1.337 \
    --project-license Artistic-2.0
    --project-author "Larry Wall <larry@wall.org>"

Create SBOM file and upload to OWASP Dependency Track:

$ cpan-sbom \
  --meta META.json \
  --server-url https://dtrack.example.com \
  --api-key DTRAC-API-KEY \
  --project-id DTRACK-PROJECT-ID
```

## Install

Using Makefile.PL:

To install `App-CPAN-SBOM` distribution, run the following commands.

    perl Makefile.PL
    make
    make test
    make install

Using `App::cpanminus`:

    cpanm App::CPAN::SBOM


## Documentation

- `perldoc App::CPAN::SBOM`
- https://metacpan.org/release/App-CPAN-SBOM

## Copyright

- Copyright 2025 © Giuseppe Di Terlizzi

bin/cpan-sbom  view on Meta::CPAN

#!/usr/bin/perl

use strict;
use warnings;
use utf8;

use App::CPAN::SBOM;

exit App::CPAN::SBOM->run(@ARGV) unless caller();

__END__

=encoding utf-8

=head1 NAME

cpan-sbom - CPAN SBOM (Software Bill of Materials) generator

=head1 SYNOPSIS

    cpan-sbom --distribution NAME@VERSION
    cpan-sbom --meta (META|MYMETA).(json|yml)

    cpan-sbom --project-directory DIRECTORY [ --project-name NAME --project-version VERSION --project-description TEXT
                                              --project-license SPDX-LICENSE --project-type BOM-TYPE
                                              --project-author STRING [--project-author STRING] ]

    cpan-sbom [--help|--man|-v]

    Options:
      -o, --output                          Output file. Default bom.json 

          --distribution NAME@VERSION       Distribution name and version
          --meta                            META or MYMETA file

          --project-directory NAME          Project directory
          --project-meta                    Project META or MYMETA file (alias of --meta)
          --project-type BOM-TYPE           Project type (default: library)
          --project-name NAME               Project name (default: project directory name)
          --project-version VERSION         Project version
          --project-author STRING           Project author(s)
          --project-license SPDX-LICENSE    Project SPDX license
          --project-description TEXT        Project description                  

          --maxdepth=NUM                    Max depth (default: 1)
          --vulnerabilities                 Include Module/Distribution vulnerabilities
          --no-vulnerabilities

          --validate                        Validate the generated SBOM using JSON Schema (default: true)
          --no-validate

          --list-spdx-licenses              List SPDX licenses

          --debug                           Enable debug messages

          --help                            Brief help message
          --man                             Full documentation
      -v, --version                         Print version

bin/cpan-sbom  view on Meta::CPAN

          --server-url URL                  Dependency Track URL (Env: $DTRACK_URL)
          --api-key STRING                  API-Key (Env: $DTRACK_API_KEY)
          --skip-tls-check                  Disable SSL/TLS check (Env: $DTRACK_SKIP_TLS_CHECK)
          --project-id STRING               Project ID (Env: $DTRACK_PROJECT_ID)
          --project-name NAME               Project name (Env: DTRACK_PROJECT_NAME)
          --project-version VERSION         Project version (Env: $DTRACK_PROJECT_VERSION)
          --parent-project-id STRING        Parent project ID (Env: $DTRACK_PARENT_PROJECT_ID)

=head1 DESCRIPTION

C<cpan-sbom> CPAN SBOM (Software Bill of Materials) generator

=head1 EXAMPLES

    Create SBOM of specific distribution:

    $ cpan-sbom --distribution libwww-perl@6.78

    Create SBOM from META file:

    $ cpan-sbom --meta META.json

    Create SBOM from your project directory:

    $ cpan-sbom \
        --project-directory . \
        --project-name "My Cool Application" \
        --project-type application \
        --project-version 1.337 \
        --project-license Artistic-2.0
        --project-author "Larry Wall <larry@wall.org>"

    Create SBOM file and upload to OWASP Dependency Track:

    $ cpan-sbom \
      --meta META.json \
      --server-url https://dtrack.example.com \
      --api-key DTRAC-API-KEY \
      --project-id DTRACK-PROJECT-ID


=head1 SEE ALSO

L<SBOM::CycloneDX>

=head1 AUTHOR

L<Giuseppe Di Terlizzi|https://metacpan.org/author/gdt>

=head1 COPYRIGHT AND LICENSE

Copyright © 2025 L<Giuseppe Di Terlizzi|https://metacpan.org/author/gdt>

You may use and distribute this module according to the same terms

lib/App/CPAN/SBOM.pm  view on Meta::CPAN

package App::CPAN::SBOM;

use 5.010001;
use strict;
use warnings;
use utf8;

use CPAN::Audit;
use CPAN::Meta;
use Cpanel::JSON::XS qw(encode_json);
use Data::Dumper;
use File::Basename;
use File::Spec;
use Getopt::Long qw(GetOptionsFromArray :config gnu_compat);
use HTTP::Tiny;
use MetaCPAN::Client;
use MIME::Base64;
use Pod::Usage qw(pod2usage);
use URI::PackageURL;

use SBOM::CycloneDX::Component;
use SBOM::CycloneDX::ExternalReference;
use SBOM::CycloneDX::Hash;
use SBOM::CycloneDX::License;
use SBOM::CycloneDX::Metadata;
use SBOM::CycloneDX::OrganizationalContact;
use SBOM::CycloneDX::Util qw(cpan_meta_to_spdx_license cyclonedx_tool cyclonedx_component);
use SBOM::CycloneDX::Vulnerability::Affect;
use SBOM::CycloneDX::Vulnerability::Rating;
use SBOM::CycloneDX::Vulnerability::Source;
use SBOM::CycloneDX::Vulnerability;
use SBOM::CycloneDX;

our $VERSION = '1.03';


sub DEBUG { $ENV{SBOM_DEBUG} || 0 }

sub cli_error {
    my ($error, $code) = @_;
    $error =~ s/ at .* line \d+.*//;
    say STDERR "ERROR: $error";
    return $code || 1;
}

sub run {

lib/App/CPAN/SBOM.pm  view on Meta::CPAN

    pod2usage(-exitstatus => 0, -verbose => 2) if defined $options{man};
    pod2usage(-exitstatus => 0, -verbose => 0) if defined $options{help};

    $options{'project-meta'} //= $options{meta};

    if (defined $options{v}) {
        return show_version();
    }

    if ($options{'list-spdx-licenses'}) {
        say $_ for (sort @{SBOM::CycloneDX::Enum->SPDX_LICENSES});
        return 0;
    }

    unless ($options{distribution} || $options{'project-meta'} || $options{'project-directory'}) {
        pod2usage(-exitstatus => 0, -verbose => 0);
    }

    $options{maxdepth} //= 1;
    $options{validate} //= 1;

    if (defined $options{debug}) {
        $ENV{SBOM_DEBUG} = 1;
    }

    my $bom = SBOM::CycloneDX->new;

    if (defined $options{distribution}) {

        my ($distribution, $version) = split '@', $options{distribution};

        return cli_error('Missing distribution version') unless $version;

        make_sbom_from_dist(bom => $bom, distribution => $distribution, version => $version, options => \%options);
    }

    if (defined $options{'project-directory'} || defined $options{'project-meta'}) {
        make_sbom_from_project(bom => $bom, options => \%options);
    }

    $bom->metadata->tools->push(cyclonedx_tool());

    my $output_file = $options{output} // 'bom.json';

    say STDERR "Save SBOM to $output_file";

    open my $fh, '>', $output_file or Carp::croak "Failed to open file: $!";
    say $fh $bom->to_string;
    close $fh;

    if ($options{validate}) {
        my @errors = $bom->validate;
        say STDERR $_ foreach (@errors);
    }

lib/App/CPAN/SBOM.pm  view on Meta::CPAN


sub show_version {

    (my $progname = $0) =~ s/.*\///;

    say <<"VERSION";
$progname version $VERSION

Copyright 2025, Giuseppe Di Terlizzi <gdt\@cpan.org>

This program is part of the "App-CPAN-SBOM" distribution and is free software;
you can redistribute it and/or modify it under the same terms as Perl itself.

Complete documentation for $progname can be found using 'man $progname'
or on the internet at <https://metacpan.org/dist/App-CPAN-SBOM>.
VERSION

    return 0;

}

sub make_sbom_from_project {

    my (%params) = @_;

    my $audit_discover = CPAN::Audit::Discover->new;

    my $bom     = $params{bom};
    my $options = $params{options} || {};

    my @META_FILES = (qw[META.json META.yml MYMETA.json MYMETA.yml]);

    say STDERR 'Generate SBOM';

    my $project_type        = $options->{'project-type'} || 'library';
    my $project_directory   = File::Spec->rel2abs($options->{'project-directory'});
    my $project_meta        = $options->{'project-meta'}    || $options->{'meta'};
    my $project_name        = $options->{'project-name'}    || basename($project_directory);
    my $project_version     = $options->{'project-version'} || 0;
    my $project_description = $options->{'project-description'};
    my $project_license     = $options->{'project-license'};
    my $project_author      = $options->{'project-author'} || [];

lib/App/CPAN/SBOM.pm  view on Meta::CPAN


    if ($project_meta) {

        my $meta = CPAN::Meta->load_file($project_meta);

        $project_name    = $meta->name;
        $project_version = $meta->version;

        @authors             = make_authors([$meta->author]);
        @external_references = make_external_references($meta->{resources});
        @licenses            = (SBOM::CycloneDX::License->new(id => cpan_meta_to_spdx_license($meta->license)));

        # Detect distribution author dependencies
        # TODO get the author-defined dependency version

        my $prereqs = $meta->effective_prereqs;
        my $reqs    = $prereqs->requirements_for("runtime", "requires");

        for my $module (sort $reqs->required_modules) {
            next if $module eq 'perl';
            push @dependencies, {module => $module};
        }

    }

    if ($project_license) {
        @licenses = (SBOM::CycloneDX::License->new(id => $project_license));
    }

    if (@{$project_author}) {
        @authors = make_authors($project_author);
    }

    my $bom_ref = "$project_name\@$project_version";
    $bom_ref =~ s/\s+/-/g;

    # Build root BOM component
    my $root_component = SBOM::CycloneDX::Component->new(
        type                => $project_type,
        name                => $project_name,
        version             => $project_version,
        bom_ref             => $bom_ref,
        licenses            => \@licenses,
        authors             => \@authors,
        external_references => \@external_references,
    );

    if ($project_description) {
        $root_component->description($project_description);
    }

    # Add root BOM component in metadata
    $bom->metadata->component($root_component);

    # Find dependencies from "cpanfile.snapshot" or "cpanfile"
    if (my @audit_deps = $audit_discover->discover($project_directory)) {
        @dependencies = @audit_deps;
    }

    foreach my $dependency (@dependencies) {

        make_dep_compoment(

lib/App/CPAN/SBOM.pm  view on Meta::CPAN


sub make_sbom_from_dist {

    my (%params) = @_;

    my $distribution = $params{distribution};
    my $version      = $params{version};
    my $bom          = $params{bom};
    my $options      = $params{options} || {};

    say STDERR "Generate SBOM for $distribution\@$version";

    my $mcpan        = MetaCPAN::Client->new;
    my $release_data = $mcpan->release({all => [{distribution => $distribution}, {version => $version}]});

    my $dist_data = $release_data->next;

    unless ($dist_data) {
        Carp::carp("Unable to find release ($distribution\@$version) in Meta::CPAN");
        return;
    }

lib/App/CPAN/SBOM.pm  view on Meta::CPAN

        namespace => $dist_data->author,
        name      => $dist_data->distribution,
        version   => $dist_data->version
    );

    my @external_references = make_external_references($dist_data->metadata->{resources});

    my $license      = join ' AND ', @{$metadata->{license}};
    my $spdx_license = cpan_meta_to_spdx_license($license);

    my $bom_license = SBOM::CycloneDX::License->new(($spdx_license) ? {id => $spdx_license} : {name => $license});

    my $root_component = SBOM::CycloneDX::Component->new(
        type                => 'library',
        name                => $dist_data->name,
        version             => $dist_data->version,
        licenses            => [$bom_license],
        authors             => \@authors,
        bom_ref             => $purl->to_string,
        purl                => $purl,
        external_references => \@external_references
    );

lib/App/CPAN/SBOM.pm  view on Meta::CPAN

}

sub make_external_references {

    my $resources = shift;

    my @external_references = ();

    if (defined $resources->{repository} && $resources->{repository}->{url}) {
        my $external_reference
            = SBOM::CycloneDX::ExternalReference->new(type => 'vcs', url => $resources->{repository}->{url});
        push @external_references, $external_reference;
    }

    if (defined $resources->{bugtracker} && $resources->{bugtracker}->{web}) {
        my $external_reference
            = SBOM::CycloneDX::ExternalReference->new(type => 'issue-tracker', url => $resources->{bugtracker}->{web});
        push @external_references, $external_reference;
    }

    return @external_references;

}

sub make_authors {

    my $metadata_authors = shift;

    my @authors = ();

    foreach my $metadata_author (@{$metadata_authors}) {
        if ($metadata_author =~ /(.*) <(.*)>/) {
            my ($name, $email) = $metadata_author =~ /(.*) <(.*)>/;
            push @authors, SBOM::CycloneDX::OrganizationalContact->new(name => $name, email => _clean_email($email));
        }
        elsif ($metadata_author =~ /(.*), (.*)/) {
            my ($name, $email) = $metadata_author =~ /(.*), (.*)/;
            push @authors, SBOM::CycloneDX::OrganizationalContact->new(name => $name, email => _clean_email($email));
        }
        else {
            push @authors, SBOM::CycloneDX::OrganizationalContact->new(name => $metadata_author);
        }
    }

    return @authors;

}

sub _clean_email {

    my $email = shift;

lib/App/CPAN/SBOM.pm  view on Meta::CPAN


    my $metadata = $dist_data->metadata;

    $author //= $dist_data->author;

    my @authors = make_authors($metadata->{author});

    my $license      = join ' AND ', @{$dist_data->metadata->{license}};
    my $spdx_license = cpan_meta_to_spdx_license($license);

    my $bom_license = SBOM::CycloneDX::License->new(($spdx_license) ? {id => $spdx_license} : {name => $license});

    my $purl = URI::PackageURL->new(type => 'cpan', namespace => $author, name => $distribution, version => $version);

    my @ext_refs = make_external_references($dist_data->metadata->{resources});

    my $hashes = SBOM::CycloneDX::List->new;

    if (my $checksum = $dist_data->checksum_sha256) {
        $hashes->add(SBOM::CycloneDX::Hash->new(alg => 'sha-256', content => $checksum));
    }

    if (my $checksum = $dist_data->checksum_md5) {
        $hashes->add(SBOM::CycloneDX::Hash->new(alg => 'md5', content => $checksum));
    }

    my $component = SBOM::CycloneDX::Component->new(
        type                => 'library',
        name                => $distribution,
        version             => $version,
        licenses            => [$bom_license],
        authors             => \@authors,
        bom_ref             => $purl->to_string,
        purl                => $purl,
        hashes              => $hashes,
        external_references => \@ext_refs,
    );

lib/App/CPAN/SBOM.pm  view on Meta::CPAN

    foreach my $advisory (@{$result->{dists}->{$distribution}->{advisories}}) {

        my $description = $advisory->{description};
        my $severity    = $advisory->{severity} || 'unknown';
        my @cves        = @{$advisory->{cves}};
        my $cpansa      = $advisory->{id};
        my @references  = @{$advisory->{references}};

        foreach my $cve (@cves) {

            my $vulnerability = SBOM::CycloneDX::Vulnerability->new(
                id          => $cve,
                description => $description,
                source      => SBOM::CycloneDX::Vulnerability::Source->new(
                    name => 'NVD',
                    url  => "https://nvd.nist.gov/vuln/detail/$cve"
                ),
                affects => [SBOM::CycloneDX::Vulnerability::Affect->new(ref      => $bom_ref)],
                ratings => [SBOM::CycloneDX::Vulnerability::Rating->new(severity => $severity)]
            );

            $bom->vulnerabilities->add($vulnerability);
        }
    }

}

sub submit_bom {

lib/App/CPAN/SBOM.pm  view on Meta::CPAN

        $bom_payload->{parentUUID} = $options->{'parent-project-id'};
    }

    my $verify_ssl = (defined $options->{'skip-tls-check'}) ? 0 : 1;

    my $ua = HTTP::Tiny->new(
        verify_SSL      => $verify_ssl,
        default_headers => {'Content-Type' => 'application/json', 'X-Api-Key' => $options->{'api-key'}}
    );

    say STDERR "Upload BOM in OSWASP Dependency Track ($server_url)";

    my $response = $ua->put($server_url, {content => encode_json($bom_payload)});

    DEBUG and say STDERR "-- Response <-- " . Dumper($response);

    unless ($response->{success}) {
        return cli_error(sprintf(
            'Failed to upload BOM file to OWASP Dependency Track: (%s) %s - %s',
            $response->{status}, $response->{reason}, $response->{content}
        ));
    }

}

1;

__END__

=encoding utf-8

=head1 NAME

App::CPAN::SBOM - CPAN SBOM (Software Bill of Materials) generator

=head1 SYNOPSIS

    use App::CPAN::SBOM qw(run);

    run(\@ARGV);

=head1 DESCRIPTION

L<App::CPAN::SBOM> is a "Command Line Interface" helper module for C<cpan-sbom(1)> command.

=head2 METHODS

=over

=item App::CPAN::SBOM->run(@args)

=back

Execute the command

=head1 SUPPORT

=head2 Bugs / Feature Requests

Please report any bugs or feature requests through the issue tracker
at L<https://github.com/giterlizzi/perl-App-CPAN-SBOM/issues>.
You will be notified automatically of any progress on your issue.

=head2 Source Code

This is open source software.  The code repository is available for
public review and contribution under the terms of the license.

L<https://github.com/giterlizzi/perl-App-CPAN-SBOM>

    git clone https://github.com/giterlizzi/perl-App-CPAN-SBOM.git


=head1 AUTHOR

=over 4

=item * Giuseppe Di Terlizzi <gdt@cpan.org>

=back

t/00-load.t  view on Meta::CPAN

#!perl -T

use strict;
use warnings;

use Test::More;

use_ok('App::CPAN::SBOM');

done_testing();

diag("App::CPAN::SBOM $App::CPAN::SBOM::VERSION, Perl $], $^X");



( run in 0.567 second using v1.01-cache-2.11-cpan-f29a10751f0 )