Dist-Zilla-Plugin-CycloneDX

 view release on metacpan or  search on metacpan

CPAN-META/Dist-Zilla-Plugin-CycloneDX-0.001.cdx.json  view on Meta::CPAN

                  {
                     "type": "vcs",
                     "url": "https://github.com/Leont/dist-zilla-plugin-cyclonedx"
                  }
               ],
               "group": "CPAN",
               "name": "Dist-Zilla-Plugin-CycloneDX",
               "type": "library"
            },
            {
               "bom-ref": "SBOM-CycloneDX@1.09",
               "description": "Perl distribution for CycloneDX",
               "externalReferences": [
                  {
                     "type": "website",
                     "url": "https://metacpan.org/pod/SBOM::CycloneDX"
                  },
                  {
                     "type": "documentation",
                     "url": "https://metacpan.org/dist/SBOM-CycloneDX"
                  },
                  {
                     "type": "vcs",
                     "url": "https://github.com/giterlizzi/perl-SBOM-CycloneDX"
                  },
                  {
                     "type": "issue-tracker",
                     "url": "https://github.com/giterlizzi/perl-SBOM-CycloneDX/issues"
                  },
                  {
                     "type": "license",
                     "url": "https://github.com/giterlizzi/perl-SBOM-CycloneDX/blob/main/LICENSE"
                  },
                  {
                     "type": "release-notes",
                     "url": "https://github.com/giterlizzi/perl-SBOM-CycloneDX/blob/main/Changes"
                  },
                  {
                     "type": "distribution",
                     "url": "https://metacpan.org/dist/SBOM-CycloneDX"
                  }
               ],
               "group": "CPAN",
               "licenses": [
                  {
                     "license": {
                        "id": "Artistic-2.0"
                     }
                  }
               ],
               "name": "SBOM-CycloneDX",
               "type": "library",
               "version": "1.09"
            }
         ]
      }
   },
   "serialNumber": "urn:uuid:a489e437-c1e7-4f3e-847c-6fb7ce1a0ee5",
   "specVersion": "1.7",
   "version": 1
}

META.json  view on Meta::CPAN

      },
      "runtime" : {
         "requires" : {
            "Carp" : "0",
            "Dist::Zilla::File::InMemory" : "0",
            "Dist::Zilla::Role::FileGatherer" : "0",
            "Dist::Zilla::Role::Plugin" : "0",
            "Moose" : "0",
            "Moose::Role" : "0",
            "MooseX::Types::Moose" : "0",
            "SBOM::CycloneDX" : "1.08",
            "SBOM::CycloneDX::Component" : "0",
            "SBOM::CycloneDX::ExternalReference" : "0",
            "SBOM::CycloneDX::License" : "0",
            "SBOM::CycloneDX::Metadata" : "0",
            "SBOM::CycloneDX::Metadata::Lifecycle" : "0",
            "SBOM::CycloneDX::OrganizationalContact" : "0",
            "SBOM::CycloneDX::Tools" : "0",
            "SBOM::CycloneDX::Util" : "0",
            "Time::Piece" : "0",
            "URI::PackageURL" : "0",
            "autovivification" : "0",
            "experimental" : "0",
            "namespace::autoclean" : "0",
            "perl" : "5.020"
         }
      },
      "test" : {
         "requires" : {

META.yml  view on Meta::CPAN

    file: lib/Dist/Zilla/Role/CycloneDXSource.pm
    version: '0.001'
requires:
  Carp: '0'
  Dist::Zilla::File::InMemory: '0'
  Dist::Zilla::Role::FileGatherer: '0'
  Dist::Zilla::Role::Plugin: '0'
  Moose: '0'
  Moose::Role: '0'
  MooseX::Types::Moose: '0'
  SBOM::CycloneDX: '1.08'
  SBOM::CycloneDX::Component: '0'
  SBOM::CycloneDX::ExternalReference: '0'
  SBOM::CycloneDX::License: '0'
  SBOM::CycloneDX::Metadata: '0'
  SBOM::CycloneDX::Metadata::Lifecycle: '0'
  SBOM::CycloneDX::OrganizationalContact: '0'
  SBOM::CycloneDX::Tools: '0'
  SBOM::CycloneDX::Util: '0'
  Time::Piece: '0'
  URI::PackageURL: '0'
  autovivification: '0'
  experimental: '0'
  namespace::autoclean: '0'
  perl: '5.020'
resources:
  IRC:
    url: irc://irc.perl.org/#distzilla
  bugtracker: https://github.com/Leont/dist-zilla-plugin-cyclonedx/issues

lib/Dist/Zilla/Plugin/CycloneDX.pm  view on Meta::CPAN

use MooseX::Types::Moose 'Str';
use namespace::autoclean;
use experimental qw/signatures postderef lexical_subs/;
no autovivification;

use Carp;
use Dist::Zilla::File::InMemory;
use Time::Piece;
use URI::PackageURL;

use SBOM::CycloneDX 1.08;
use SBOM::CycloneDX::Component;
use SBOM::CycloneDX::ExternalReference;
use SBOM::CycloneDX::License;
use SBOM::CycloneDX::Metadata;
use SBOM::CycloneDX::Metadata::Lifecycle;
use SBOM::CycloneDX::OrganizationalContact;
use SBOM::CycloneDX::Tools;
use SBOM::CycloneDX::Util qw/cpan_meta_to_spdx_license cyclonedx_component/;

has filename => (
	is      => 'ro',
	isa     => Str,
	lazy    => 1,
	default => sub($self) {
		my $name    = $self->zilla->name;
		my $version = $self->zilla->version;
		return "CPAN-META/$name-$version.cdx.json";
	}

lib/Dist/Zilla/Plugin/CycloneDX.pm  view on Meta::CPAN

	homepage       => 'website',
	x_mailing_list => 'mailing-list',
	x_MailingList  => 'mailing-list',
	x_mailinglist  => 'mailing-list',
	x_mastodon     => 'social',
	x_twitter      => 'social',
	x_wiki         => 'documentation',
);

my sub make_externs($module, $resources) {
	my @externs = SBOM::CycloneDX::ExternalReference->new(type => 'documentation', url => "https://metacpan.org/pod/$module");
	if (my $tracker = $resources->{bugtracker}{web}) {
		push @externs, SBOM::CycloneDX::ExternalReference->new(type => 'issue-tracker', url => $tracker);
	}
	if (my $repo = $resources->{repository}{web}) {
		push @externs, SBOM::CycloneDX::ExternalReference->new(type => 'vcs', url => $repo);
	}
	if (my $irc = $resources->{x_IRC}) {
		my $url = ref $irc ? $irc->{url} : $irc;
		push @externs, SBOM::CycloneDX::ExternalReference->new(type => 'chat', url => $url);
	}
	for my $key (keys %simple_resource) {
		if (my $url = $resources->{$key}) {
			push @externs, SBOM::CycloneDX::ExternalReference->new(type => $simple_resource{$key}, url => $url);
		}
	}
	return sort { $a->type cmp $b->type } @externs;
}

sub make_purl($name, $version) {
	return URI::PackageURL->new(
		type      => 'cpan',
		namespace => '',
		name      => $name,
		version   => $version,
	);
}

my sub make_root_component($meta) {
	my $purl    = make_purl($meta->{name}, $meta->{version});
	my $bom_ref = sprintf '%s@%s', $meta->{name}, $meta->{version};
	my $module  = $meta->{name} =~ s/-/::/gr;
	my @externs = make_externs($module, $meta->{resources});

	return SBOM::CycloneDX::Component->new(
		type                => 'library',
		group               => 'CPAN',
		name                => $meta->{name},
		version             => $meta->{version},
		description         => $meta->{abstract},
		bom_ref             => $bom_ref,
		purl                => $purl,
		external_references => \@externs,
	);
}

my sub to_organization($author) {
	my ($name, $email) = $author =~ /([^<]+?)\s+<([^>]+)>/ or croak "Could not parse author '$author'";
	return SBOM::CycloneDX::OrganizationalContact->new(name => $name, email => $email);
}

my sub make_licenses($meta) {
	if (my $spdx_expr = $meta->{x_spdx_expression}) {
		return SBOM::CycloneDX::License->new($spdx_expr);
	} else {
		my @raw = map { cpan_meta_to_spdx_license($_) } $meta->{license}->@*;
		return map { SBOM::CycloneDX::License->new($_) } @raw;
	}
}

my %self_resources = (
	bugtracker => {
		web    => 'https://github.com/Leont/dist-zilla-plugin-cyclonedx/issues',
	},
	repository => {
		web    => 'https://github.com/Leont/dist-zilla-plugin-cyclonedx',
	},

lib/Dist/Zilla/Plugin/CycloneDX.pm  view on Meta::CPAN

	my %args = (
		type                => 'library',
		group               => 'CPAN',
		name                => $dist,
		external_references => \@externs,
	);
	if ($version) {
		$args{version} = $version;
		$args{purl}    = make_purl($dist, $version);
	}
	return SBOM::CycloneDX::Component->new(%args);
}

my sub make_tools($plugins) {
	my $distname = __PACKAGE__ =~ s/::/-/gr;
	my @tools = make_tool_component(__PACKAGE__, $distname, \%self_resources);
	push @tools, map { make_tool_component(ref($_), $_->cyclonedx_dist, $_->cyclonedx_resources) } $plugins->@*;
	push @tools, cyclonedx_component;

	return SBOM::CycloneDX::Tools->new(components => \@tools);
}

my sub make_metadata($meta, $plugins) {
	my $component = make_root_component($meta);
	my @authors   = map { to_organization($_) } $meta->{author}->@*;
	my $timestamp = SBOM::CycloneDX::Timestamp->new($ENV{TIMESTAMP} // scalar gmtime);
	my @licenses  = make_licenses($meta);
	my @lifecycle = SBOM::CycloneDX::Metadata::Lifecycle->new(phase => 'pre-build');
	my $tools     = make_tools($plugins);

	return SBOM::CycloneDX::Metadata->new(
		component  => $component,
		authors    => \@authors,
		timestamp  => $timestamp,
		licenses   => \@licenses,
		lifecycles => \@lifecycle,
		tools      => $tools,
	);
}

sub gather_files($self) {
	my @plugins  = $self->zilla->plugins_with(-CycloneDXSource)->@*;
	my $metadata = make_metadata($self->zilla->distmeta, \@plugins);
	my $bom      = SBOM::CycloneDX->new(metadata => $metadata);

	for my $plugin (@plugins) {
		$plugin->add_to_bom($bom);
	}

	local $SIG{__WARN__} = sub { warn $_[0] unless $_[0] =~ /Net::IDN::Encode/ };
	if (my @errors = $bom->validate) {
		croak "Errors found in BOM: @errors";
	}

	$self->add_file(Dist::Zilla::File::InMemory->new(
		name            => $self->filename,
		encoded_content => $bom->to_string,
	));

	return;
}

lib/Dist/Zilla/Plugin/CycloneDX.pm  view on Meta::CPAN

=head1 NAME

Dist::Zilla::Plugin::CycloneDX - CycloneDX files in dzil generated dists

=head1 VERSION

version 0.001

=head1 DESCRIPTION

This module adds a CycloneDX SBOM file to your distribution. By default this will only contain information that's already contained in the META files, but this can be extended by other plugins that implement the L<CycloneDXSource|Dist::Zilla::Role::C...

=head1 AUTHOR

Leon Timmermans <fawaka@gmail.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Leon Timmermans.

This is free software; you can redistribute it and/or modify it under

lib/Dist/Zilla/Role/CycloneDXSource.pm  view on Meta::CPAN

sub cyclonedx_dist($self) {
	return ref($self) =~ s/::/-/gr;
}

sub cyclonedx_resources($self) {
	return {};
}

1;

# ABSTRACT: A role for plugins that adds information to the CycloneDX SBOM

__END__

=pod

=encoding UTF-8

=head1 NAME

Dist::Zilla::Role::CycloneDXSource - A role for plugins that adds information to the CycloneDX SBOM

=head1 VERSION

version 0.001

=head1 DESCRIPTION

=head1 METHODS

=head2 add_to_bom

This method, taking a single L<SBOM::CycloneDX|SBOM::CycloneDX> object as argument. This can be manipulated, typically to add information to it.

=head1 AUTHOR

Leon Timmermans <fawaka@gmail.com>

=head1 COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Leon Timmermans.

This is free software; you can redistribute it and/or modify it under



( run in 1.814 second using v1.01-cache-2.11-cpan-9581c071862 )