From 865853a10c8298c2e6b70ad4bedd07a18cae3dba Mon Sep 17 00:00:00 2001 From: Tobias Brox Date: Wed, 31 Dec 2025 09:49:53 +0100 Subject: [PATCH 1/4] Add GPG signature verification for AWS CLI installer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Verify the GPG signature of downloaded AWS CLI packages using the official AWS CLI public key, as recommended in the AWS documentation. - Add AWS CLI public key (files/aws-cli-public-key.asc) - Add verify_signature parameter (defaults to true) - Download signature file and verify before extraction - Use isolated gpg keyring to avoid affecting user's keyring - Requires gpg and unzip packages when verification is enabled - Fall back to direct extraction when verification is disabled See: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- README.md | 20 ++++-- files/aws-cli-public-key.asc | 29 ++++++++ manifests/init.pp | 8 ++- manifests/install.pp | 135 ++++++++++++++++++++++++++++------- 4 files changed, 160 insertions(+), 32 deletions(-) create mode 100644 files/aws-cli-public-key.asc diff --git a/README.md b/README.md index 96ece95..c776486 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,7 @@ 2. [Module Description - What the module does and why it is useful](#module-description) 3. [Setup - The basics of getting started with awscli2](#setup) * [What awscli2 affects](#what-awscli2-affects) + * [Requirements](#requirements) 4. [Usage - Configuration options and additional functionality](#usage) * [Required Parameters](#required-parameters) * [Optional Parameters](#optional-parameters) @@ -12,7 +13,7 @@ ## Overview -This module installs (or upgrades, or un-installs) the AWS CLI v2. Redhat has dropped the AWS CLI v1 from its repositories, and AWS has packaged up v2 of the CLI with all dependencies included (but not packaged it as an RPM). +This module installs (or upgrades, or un-installs) the AWS CLI v2. AWS has packaged up v2 of the CLI with all dependencies included (but not packaged it as a deb or RPM). ## Module Description @@ -27,6 +28,11 @@ install. This was done to prevent having to download the `latest` zip file from AWS on every puppet run just to see if it has been updated. This module will remove older versions after a successful upgrade to keep disk space down. +By default, this module verifies the GPG signature of the downloaded package +using the official AWS CLI public key, as recommended by AWS. This ensures +the integrity and authenticity of the installer. See: +https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html + This module delivers a custom fact (`umd_awscliv2_version`) which is used to determine if an upgrade or clean install is needed (it will do nothing if the requested version is already installed). @@ -35,7 +41,7 @@ This module is not a complete replacement for a package management system, and it is possible for it to fail to un-install older versions on upgrade or `absent`. In particular, the currently installed version fact is based on the current value of `$bin_path`, and changing this parameter after an install -has happened will leave the previous installation abandoned. +has happened will leave the previous installation abandoned. ## Setup @@ -44,19 +50,25 @@ has happened will leave the previous installation abandoned. * By default, it will install the CLI into `/usr/local/aws-cli`. * By default, it will symlink binaries (`aws`, `aws_completer`) into `/usr/bin`. +### Requirements + +* `gpg` - Required for signature verification (enabled by default). +* `unzip` - Required for extracting the installer when signature verification is enabled. + ## Usage Include the `awscli2` class and define the following parameters as required: ### Required Parameters -* `version`: The version of the CLI to install +* `version`: The version of the CLI to install, e.g. `'2.15.0'` ### Optional Parameters * `ensure`: Set to `absent` to un-install the AWS CLI. * `install_dir`: Path to install the CLI into. Defaults to `/usr/local/aws-cli`. * `bin_dir`: Path to create symlinks to binaries. Defaults to `/usr/bin`. +* `verify_signature`: Whether to verify the GPG signature of the downloaded package. Defaults to `true`. ### Example @@ -64,6 +76,6 @@ Include the `awscli2` class and define the following parameters as required: --- classes: - awscli2 -awscli2::version: '2.0.28' +awscli2::version: '2.15.0' ``` diff --git a/files/aws-cli-public-key.asc b/files/aws-cli-public-key.asc new file mode 100644 index 0000000..805491c --- /dev/null +++ b/files/aws-cli-public-key.asc @@ -0,0 +1,29 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBF2Cr7UBEADJZHcgusOJl7ENSyumXh85z0TRV0xJorM2B/JL0kHOyigQluUG +ZMLhENaG0bYatdrKP+3H91lvK050pXwnO/R7fB/FSTouki4ciIx5OuLlnJZIxSzx +PqGl0mkxImLNbGWoi6Lto0LYxqHN2iQtzlwTVmq9733zd3XfcXrZ3+LblHAgEt5G +TfNxEKJ8soPLyWmwDH6HWCnjZ/aIQRBTIQ05uVeEoYxSh6wOai7ss/KveoSNBbYz +gbdzoqI2Y8cgH2nbfgp3DSasaLZEdCSsIsK1u05CinE7k2qZ7KgKAUIcT/cR/grk +C6VwsnDU0OUCideXcQ8WeHutqvgZH1JgKDbznoIzeQHJD238GEu+eKhRHcz8/jeG +94zkcgJOz3KbZGYMiTh277Fvj9zzvZsbMBCedV1BTg3TqgvdX4bdkhf5cH+7NtWO +lrFj6UwAsGukBTAOxC0l/dnSmZhJ7Z1KmEWilro/gOrjtOxqRQutlIqG22TaqoPG +fYVN+en3Zwbt97kcgZDwqbuykNt64oZWc4XKCa3mprEGC3IbJTBFqglXmZ7l9ywG +EEUJYOlb2XrSuPWml39beWdKM8kzr1OjnlOm6+lpTRCBfo0wa9F8YZRhHPAkwKkX +XDeOGpWRj4ohOx0d2GWkyV5xyN14p2tQOCdOODmz80yUTgRpPVQUtOEhXQARAQAB +tCFBV1MgQ0xJIFRlYW0gPGF3cy1jbGlAYW1hem9uLmNvbT6JAlQEEwEIAD4CGwMF +CwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQT7Xbd/1cEYuAURraimMQrMRnJHXAUC +aGveYQUJDMpiLAAKCRCmMQrMRnJHXKBYD/9Ab0qQdGiO5hObchG8xh8Rpb4Mjyf6 +0JrVo6m8GNjNj6BHkSc8fuTQJ/FaEhaQxj3pjZ3GXPrXjIIVChmICLlFuRXYzrXc +Pw0lniybypsZEVai5kO0tCNBCCFuMN9RsmmRG8mf7lC4FSTbUDmxG/QlYK+0IV/l +uJkzxWa+rySkdpm0JdqumjegNRgObdXHAQDWlubWQHWyZyIQ2B4U7AxqSpcdJp6I +S4Zds4wVLd1WE5pquYQ8vS2cNlDm4QNg8wTj58e3lKN47hXHMIb6CHxRnb947oJa +pg189LLPR5koh+EorNkA1wu5mAJtJvy5YMsppy2y/kIjp3lyY6AmPT1posgGk70Z +CmToEZ5rbd7ARExtlh76A0cabMDFlEHDIK8RNUOSRr7L64+KxOUegKBfQHb9dADY +qqiKqpCbKgvtWlds909Ms74JBgr2KwZCSY1HaOxnIr4CY43QRqAq5YHOay/mU+6w +hhmdF18vpyK0vfkvvGresWtSXbag7Hkt3XjaEw76BzxQH21EBDqU8WJVjHgU6ru+ +DJTs+SxgJbaT3hb/vyjlw0lK+hFfhWKRwgOXH8vqducF95NRSUxtS4fpqxWVaw3Q +V2OWSjbne99A5EPEySzryFTKbMGwaTlAwMCwYevt4YT6eb7NmFhTx0Fis4TalUs+ +j+c7Kg92pDx2uQ== +=OBAt +-----END PGP PUBLIC KEY BLOCK----- diff --git a/manifests/init.pp b/manifests/init.pp index eae87cd..4a6d4cb 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -17,14 +17,20 @@ # Path to install the AWS CLI into. Defaults to `/usr/local/aws-cli`. # # @param bin_dir -# The directory to store symlinks to eecutables for the AWS CLI. +# The directory to store symlinks to executables for the AWS CLI. # Defaults to `/usr/bin`. # +# @param verify_signature +# Whether to verify the GPG signature of the downloaded package. +# Defaults to `true`. Requires `gpg` and `unzip` to be installed. +# See: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html +# class awscli2 ( String[1] $version, Enum['absent', 'present'] $ensure = 'present', String[1] $install_dir = '/usr/local/aws-cli', String[1] $bin_dir = '/usr/bin', + Boolean $verify_signature = true, ) { if $ensure == 'absent' { contain awscli2::uninstall diff --git a/manifests/install.pp b/manifests/install.pp index 8ea8630..6e0e9f9 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -31,21 +31,28 @@ # Figure out if we need to do a new install (nothing installed), # an upgrade (existing install version differs to requested version) # or nothing (existing install version matches requested version) - if $facts['umd_awscli2_version'] { - if $facts['umd_awscli2_version'] == $awscli2::version { - # Nothing to do, installed matches requested. - } else { - # Installed differs from requested, need to do an upgrade install. - $need_upgrade = true - } - } else { - # nothing currently installed. + $is_installed = $facts['umd_awscli2_version'] != undef + $version_matches = $is_installed and ($facts['umd_awscli2_version'] == $awscli2::version) + + # Determine action needed + if $is_installed and !$version_matches { + # Installed version differs from requested + $need_install = false + $need_upgrade = true + } elsif !$is_installed { + # Nothing installed yet $need_install = true + $need_upgrade = false + } else { + # Version matches, nothing to do + $need_install = false + $need_upgrade = false } if $need_install or $need_upgrade { # If we need to install/upgrade, we need to pull down the package. $package_url = "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-${awscli2::version}.zip" + $signature_url = "${package_url}.sig" $default_args = [ '--install-dir', @@ -62,24 +69,90 @@ $args = shellquote($default_args+$extra_args); - # download and extract the package. + # Create temp directory for installation file { '/tmp/umd_awscli2_install': ensure => directory, } - -> archive { '/tmp/umd_awscli2.zip': - ensure => present, - source => $package_url, - extract => true, - extract_path => '/tmp/umd_awscli2_install', - creates => '/tmp/umd_awscli2_install/aws/install', - cleanup => true, - } - # run the installer - -> exec { 'awscliv2-installer': - command => "/tmp/umd_awscli2_install/aws/install ${args}", - cwd => '/tmp/umd_awscli2_install', - logoutput => true, + + if $awscli2::verify_signature { + # Deploy the AWS CLI public key for signature verification + file { '/tmp/umd_awscli2_install/aws-cli-public-key.asc': + ensure => file, + source => 'puppet:///modules/awscli2/aws-cli-public-key.asc', + mode => '0444', + require => File['/tmp/umd_awscli2_install'], + } + + # Download the signature file + archive { '/tmp/umd_awscli2_install/awscli2.zip.sig': + ensure => present, + source => $signature_url, + extract => false, + require => File['/tmp/umd_awscli2_install'], + } + + # Download the zip file (without extracting yet) + archive { '/tmp/umd_awscli2.zip': + ensure => present, + source => $package_url, + extract => false, + require => File['/tmp/umd_awscli2_install'], + } + + # Verify the GPG signature + exec { 'awscli2-verify-signature': + command => '/usr/bin/gpg --no-default-keyring --keyring /tmp/umd_awscli2_install/aws-cli-keyring.gpg --import /tmp/umd_awscli2_install/aws-cli-public-key.asc && /usr/bin/gpg --no-default-keyring --keyring /tmp/umd_awscli2_install/aws-cli-keyring.gpg --verify /tmp/umd_awscli2_install/awscli2.zip.sig /tmp/umd_awscli2.zip', + cwd => '/tmp/umd_awscli2_install', + logoutput => true, + require => [ + File['/tmp/umd_awscli2_install/aws-cli-public-key.asc'], + Archive['/tmp/umd_awscli2_install/awscli2.zip.sig'], + Archive['/tmp/umd_awscli2.zip'], + ], + } + + # Extract the zip file after verification + exec { 'awscli2-extract': + command => '/usr/bin/unzip -o /tmp/umd_awscli2.zip -d /tmp/umd_awscli2_install', + creates => '/tmp/umd_awscli2_install/aws/install', + require => Exec['awscli2-verify-signature'], + } + + # Clean up the zip file + exec { 'awscli2-cleanup-zip': + command => '/usr/bin/rm -f /tmp/umd_awscli2.zip', + refreshonly => true, + subscribe => Exec['awscli2-extract'], + } + + # Run the installer + exec { 'awscliv2-installer': + command => "/tmp/umd_awscli2_install/aws/install ${args}", + cwd => '/tmp/umd_awscli2_install', + logoutput => true, + require => Exec['awscli2-extract'], + } + } else { + # Skip signature verification - download and extract directly + archive { '/tmp/umd_awscli2.zip': + ensure => present, + source => $package_url, + extract => true, + extract_path => '/tmp/umd_awscli2_install', + creates => '/tmp/umd_awscli2_install/aws/install', + cleanup => true, + require => File['/tmp/umd_awscli2_install'], + } + + # Run the installer + exec { 'awscliv2-installer': + command => "/tmp/umd_awscli2_install/aws/install ${args}", + cwd => '/tmp/umd_awscli2_install', + logoutput => true, + require => Archive['/tmp/umd_awscli2.zip'], + } } + # These next 3 (v2/latest+version) are created by the installer # but declaring them as resources (after the installer runs) # allows us to have puppet purge old installs while @@ -87,19 +160,27 @@ # This model (upgrade first, then remove old) also allows # other things on the system using the aws cli to not fail # if they happen to run while we are upgrading. - -> file { "${awscli2::install_dir}/v2": + file { "${awscli2::install_dir}/v2": ensure => directory, force => true, purge => true, recurse => true, + require => Exec['awscliv2-installer'], } - -> file { "${$awscli2::install_dir}/v2/current": + + file { "${awscli2::install_dir}/v2/current": ensure => link, + require => File["${awscli2::install_dir}/v2"], } - -> file { "${$awscli2::install_dir}/v2/${awscli2::version}": + + file { "${awscli2::install_dir}/v2/${awscli2::version}": ensure => directory, + require => File["${awscli2::install_dir}/v2/current"], } + # clean up the install temp dir. - -> exec { '/usr/bin/rm -rf /tmp/umd_awscli2_install': } + exec { '/usr/bin/rm -rf /tmp/umd_awscli2_install': + require => File["${awscli2::install_dir}/v2/${awscli2::version}"], + } } } From 5a4f25a56595d305240f332b4015328ec58bf52e Mon Sep 17 00:00:00 2001 From: Tobias Brox Date: Wed, 31 Dec 2025 09:51:56 +0100 Subject: [PATCH 2/4] Default version to 'latest' for automatic updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change version parameter from required to optional, defaulting to 'latest' which always installs/upgrades to the latest available AWS CLI version. - Use non-versioned download URL when version is 'latest' - Always attempt upgrade when version is 'latest' (installer handles idempotency) - Skip old version cleanup when using 'latest' (version unknown at compile time) - Update documentation with new default behavior and examples 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- README.md | 29 +++++++++------- manifests/init.pp | 7 ++-- manifests/install.pp | 78 +++++++++++++++++++++++++++++--------------- 3 files changed, 74 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index c776486..48ca9e3 100644 --- a/README.md +++ b/README.md @@ -6,9 +6,8 @@ * [What awscli2 affects](#what-awscli2-affects) * [Requirements](#requirements) 4. [Usage - Configuration options and additional functionality](#usage) - * [Required Parameters](#required-parameters) * [Optional Parameters](#optional-parameters) - * [Example](#example) + * [Examples](#examples) 5. [Limitations - OS compatibility, etc.](#limitations) ## Overview @@ -23,10 +22,11 @@ command (provided by redhat) was installed into that location, and we do not want to break any scripts that do not have `/usr/local/bin` in their path or may have hard-coded `/usr/bin/aws`. -This module requires the manual specification of the version of the CLI to -install. This was done to prevent having to download the `latest` zip file -from AWS on every puppet run just to see if it has been updated. This module -will remove older versions after a successful upgrade to keep disk space down. +By default, this module installs the latest available version of the CLI. +When using a specific version, this module will remove older versions after +a successful upgrade to keep disk space down. When using `'latest'`, old +version cleanup is skipped since the version directory name is not known +at Puppet compile time. By default, this module verifies the GPG signature of the downloaded package using the official AWS CLI public key, as recommended by AWS. This ensures @@ -59,18 +59,25 @@ has happened will leave the previous installation abandoned. Include the `awscli2` class and define the following parameters as required: -### Required Parameters - -* `version`: The version of the CLI to install, e.g. `'2.15.0'` - ### Optional Parameters +* `version`: The version of the CLI to install, e.g. `'2.15.0'`. Defaults to `'latest'`, which always installs/upgrades to the latest available version. Note: Using `'latest'` will attempt to download and run the installer on every Puppet run (the installer handles idempotency). * `ensure`: Set to `absent` to un-install the AWS CLI. * `install_dir`: Path to install the CLI into. Defaults to `/usr/local/aws-cli`. * `bin_dir`: Path to create symlinks to binaries. Defaults to `/usr/bin`. * `verify_signature`: Whether to verify the GPG signature of the downloaded package. Defaults to `true`. -### Example +### Examples + +Install the latest version (default): + +```yaml +--- +classes: + - awscli2 +``` + +Install a specific version: ```yaml --- diff --git a/manifests/init.pp b/manifests/init.pp index 4a6d4cb..5d85891 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -7,7 +7,10 @@ # ---------- # # @param version -# Version of the AWS CLI to install. E.g. "2.0.28" +# Version of the AWS CLI to install. E.g. "2.0.28", or "latest" to always +# install/upgrade to the latest available version. Defaults to "latest". +# Note: Using "latest" will attempt to download and run the installer on +# every Puppet run (the installer handles idempotency). # # @param ensure # Set to `absent` to un-install the AWS CLI. Set to `present` to @@ -26,7 +29,7 @@ # See: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html # class awscli2 ( - String[1] $version, + String[1] $version = 'latest', Enum['absent', 'present'] $ensure = 'present', String[1] $install_dir = '/usr/local/aws-cli', String[1] $bin_dir = '/usr/bin', diff --git a/manifests/install.pp b/manifests/install.pp index 6e0e9f9..a8baa65 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -31,11 +31,18 @@ # Figure out if we need to do a new install (nothing installed), # an upgrade (existing install version differs to requested version) # or nothing (existing install version matches requested version) + # + # When version is 'latest', always attempt an upgrade - the installer + # handles idempotency and will skip if already up-to-date. $is_installed = $facts['umd_awscli2_version'] != undef $version_matches = $is_installed and ($facts['umd_awscli2_version'] == $awscli2::version) # Determine action needed - if $is_installed and !$version_matches { + if $awscli2::version == 'latest' { + # For 'latest', always run installer (it handles idempotency) + $need_install = !$is_installed + $need_upgrade = $is_installed + } elsif $is_installed and !$version_matches { # Installed version differs from requested $need_install = false $need_upgrade = true @@ -51,7 +58,12 @@ if $need_install or $need_upgrade { # If we need to install/upgrade, we need to pull down the package. - $package_url = "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-${awscli2::version}.zip" + # When version is 'latest', use the non-versioned URL. + if $awscli2::version == 'latest' { + $package_url = 'https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip' + } else { + $package_url = "https://awscli.amazonaws.com/awscli-exe-linux-x86_64-${awscli2::version}.zip" + } $signature_url = "${package_url}.sig" $default_args = [ @@ -153,34 +165,46 @@ } } - # These next 3 (v2/latest+version) are created by the installer - # but declaring them as resources (after the installer runs) - # allows us to have puppet purge old installs while - # still preserving the 'current' install we just did. - # This model (upgrade first, then remove old) also allows - # other things on the system using the aws cli to not fail - # if they happen to run while we are upgrading. - file { "${awscli2::install_dir}/v2": - ensure => directory, - force => true, - purge => true, - recurse => true, - require => Exec['awscliv2-installer'], - } + # When using a specific version, we can purge old versions from the + # install directory while preserving the current install. This is done + # by declaring the version directory as a resource after the installer runs. + # When using 'latest', we skip purging since we don't know the version + # directory name at Puppet compile time. + if $awscli2::version != 'latest' { + # These next 3 (v2/latest+version) are created by the installer + # but declaring them as resources (after the installer runs) + # allows us to have puppet purge old installs while + # still preserving the 'current' install we just did. + # This model (upgrade first, then remove old) also allows + # other things on the system using the aws cli to not fail + # if they happen to run while we are upgrading. + file { "${awscli2::install_dir}/v2": + ensure => directory, + force => true, + purge => true, + recurse => true, + require => Exec['awscliv2-installer'], + } - file { "${awscli2::install_dir}/v2/current": - ensure => link, - require => File["${awscli2::install_dir}/v2"], - } + file { "${awscli2::install_dir}/v2/current": + ensure => link, + require => File["${awscli2::install_dir}/v2"], + } - file { "${awscli2::install_dir}/v2/${awscli2::version}": - ensure => directory, - require => File["${awscli2::install_dir}/v2/current"], - } + file { "${awscli2::install_dir}/v2/${awscli2::version}": + ensure => directory, + require => File["${awscli2::install_dir}/v2/current"], + } - # clean up the install temp dir. - exec { '/usr/bin/rm -rf /tmp/umd_awscli2_install': - require => File["${awscli2::install_dir}/v2/${awscli2::version}"], + # clean up the install temp dir. + exec { '/usr/bin/rm -rf /tmp/umd_awscli2_install': + require => File["${awscli2::install_dir}/v2/${awscli2::version}"], + } + } else { + # When using 'latest', just clean up the temp dir after install + exec { '/usr/bin/rm -rf /tmp/umd_awscli2_install': + require => Exec['awscliv2-installer'], + } } } } From d82e592e6d991a6f8b4da02fc09017212c14354d Mon Sep 17 00:00:00 2001 From: Tobias Brox Date: Wed, 31 Dec 2025 11:11:49 +0100 Subject: [PATCH 3/4] Fork attribution and metadata updates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Rename module to tobixen-awscli2 - Update author, source, project_page, and issues_url - Add Ubuntu 20.04 and 24.04 to supported operating systems - Expand RedHat support to versions 7, 8, 9 - Bump Puppet requirement to support Puppet 8 - Add fork attribution with link to original umd/awscli2 module - Document fork changes in README 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- README.md | 12 ++++++++++++ metadata.json | 27 ++++++++++++++++++--------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 48ca9e3..e67277f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,15 @@ +# puppet-awscli2 + +This is a fork of [umd/awscli2](https://forge.puppet.com/modules/umd/awscli2) from the University of Maryland. + +The original source repository is at https://gitlab.umd.edu/it-platform/puppet-awscli2 - but I can't access it, probably it's behind a firewall. + +## Fork Changes + +- **GPG signature verification**: Downloads are verified using the official AWS CLI public key before installation +- **Default to latest version**: The `version` parameter now defaults to `'latest'` for automatic updates +- **Ubuntu support**: Added explicit support for Ubuntu 20.04 and 24.04 + #### Table of Contents 1. [Overview](#overview) diff --git a/metadata.json b/metadata.json index e5e4d49..7725fe8 100644 --- a/metadata.json +++ b/metadata.json @@ -1,12 +1,12 @@ { - "name": "umd-awscli2", - "version": "0.3.0", - "author": "umd", - "summary": "Installs the AWS CLI version 2", + "name": "tobixen-awscli2", + "version": "0.4.0", + "author": "tobixen", + "summary": "Installs the AWS CLI version 2 with GPG signature verification", "license": "Apache-2.0", - "source": "https://gitlab.umd.edu/it-platform/puppet-awscli2", - "project_page": "https://gitlab.umd.edu/it-platform/puppet-awscli2", - "issues_url": "https://gitlab.umd.edu/it-platform/puppet-awscli2", + "source": "https://github.com/tobixen/puppet-awscli2", + "project_page": "https://github.com/tobixen/puppet-awscli2", + "issues_url": "https://github.com/tobixen/puppet-awscli2/issues", "dependencies": [ { "name": "puppetlabs-stdlib", @@ -21,14 +21,23 @@ { "operatingsystem": "RedHat", "operatingsystemrelease": [ - "7" + "7", + "8", + "9" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "20.04", + "24.04" ] } ], "requirements": [ { "name": "puppet", - "version_requirement": ">= 4.10.0 < 7.0.0" + "version_requirement": ">= 4.10.0 < 9.0.0" } ], "pdk-version": "3.0.1", From 36d8cf0cc77f9a39252e120e3ee3c6c090ead906 Mon Sep 17 00:00:00 2001 From: Tobias Brox Date: Wed, 31 Dec 2025 11:16:07 +0100 Subject: [PATCH 4/4] Add rspec-puppet tests and GitHub Actions CI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add comprehensive spec tests for the awscli2 module: - Test default parameters with 'latest' version - Test GPG signature verification (enabled by default) - Test verify_signature => false option - Test specific version installation - Test custom install_dir and bin_dir parameters - Test ensure => absent for uninstall CI configuration: - Run puppet-lint for code style checking - Run rspec-puppet tests on Puppet 7 and 8 - Use appropriate Ruby versions for each Puppet version 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .fixtures.yml | 10 +++++ .github/workflows/test.yml | 52 ++++++++++++++++++++++ .rspec | 2 + Gemfile | 11 +++++ Rakefile | 9 ++++ manifests/install.pp | 6 ++- spec/classes/awscli2_spec.rb | 85 ++++++++++++++++++++++++++++++++++++ spec/spec_helper.rb | 14 ++++++ 8 files changed, 187 insertions(+), 2 deletions(-) create mode 100644 .fixtures.yml create mode 100644 .github/workflows/test.yml create mode 100644 .rspec create mode 100644 Gemfile create mode 100644 Rakefile create mode 100644 spec/classes/awscli2_spec.rb create mode 100644 spec/spec_helper.rb diff --git a/.fixtures.yml b/.fixtures.yml new file mode 100644 index 0000000..7623cfc --- /dev/null +++ b/.fixtures.yml @@ -0,0 +1,10 @@ +fixtures: + forge_modules: + stdlib: + repo: puppetlabs/stdlib + ref: 9.0.0 + archive: + repo: puppet/archive + ref: 7.0.0 + symlinks: + awscli2: "#{source_dir}" diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..345287f --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,52 @@ +name: CI + +on: + push: + branches: [main, feature/*] + pull_request: + branches: [main] + +jobs: + lint: + name: Puppet Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' + bundler-cache: true + + - name: Run puppet-lint + run: bundle exec rake lint + + spec: + name: RSpec Tests (Puppet ${{ matrix.puppet }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + puppet: ['7', '8'] + include: + - puppet: '7' + ruby: '3.1' + - puppet: '8' + ruby: '3.2' + + steps: + - uses: actions/checkout@v4 + + - name: Set up Ruby ${{ matrix.ruby }} + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + bundler-cache: true + env: + PUPPET_GEM_VERSION: "~> ${{ matrix.puppet }}.0" + + - name: Run spec tests + run: bundle exec rake spec + env: + PUPPET_GEM_VERSION: "~> ${{ matrix.puppet }}.0" diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..16f9cdb --- /dev/null +++ b/.rspec @@ -0,0 +1,2 @@ +--color +--format documentation diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..c74de1d --- /dev/null +++ b/Gemfile @@ -0,0 +1,11 @@ +source 'https://rubygems.org' + +gem 'puppet', ENV['PUPPET_GEM_VERSION'] || '>= 7.0' +gem 'rake' + +group :test do + gem 'rspec-puppet', '~> 4.0' + gem 'rspec-puppet-facts', '~> 4.0' + gem 'puppetlabs_spec_helper', '~> 7.0' + gem 'puppet-lint', '~> 4.0' +end diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..8be06cf --- /dev/null +++ b/Rakefile @@ -0,0 +1,9 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_140chars') +PuppetLint.configuration.ignore_paths = ['spec/**/*.pp', 'vendor/**/*.pp'] + +desc 'Run all tests' +task :test => [:lint, :spec] diff --git a/manifests/install.pp b/manifests/install.pp index a8baa65..ae7e5f3 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -197,12 +197,14 @@ } # clean up the install temp dir. - exec { '/usr/bin/rm -rf /tmp/umd_awscli2_install': + exec { 'awscli2-cleanup-tmpdir': + command => '/usr/bin/rm -rf /tmp/umd_awscli2_install', require => File["${awscli2::install_dir}/v2/${awscli2::version}"], } } else { # When using 'latest', just clean up the temp dir after install - exec { '/usr/bin/rm -rf /tmp/umd_awscli2_install': + exec { 'awscli2-cleanup-tmpdir': + command => '/usr/bin/rm -rf /tmp/umd_awscli2_install', require => Exec['awscliv2-installer'], } } diff --git a/spec/classes/awscli2_spec.rb b/spec/classes/awscli2_spec.rb new file mode 100644 index 0000000..0f1c383 --- /dev/null +++ b/spec/classes/awscli2_spec.rb @@ -0,0 +1,85 @@ +require 'spec_helper' + +describe 'awscli2' do + on_supported_os.each do |os, os_facts| + context "on #{os}" do + let(:facts) { os_facts } + + context 'with default parameters' do + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_class('awscli2') } + it { is_expected.to contain_class('awscli2::install') } + end + + context 'with ensure => absent' do + let(:params) { { 'ensure' => 'absent' } } + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_class('awscli2::uninstall') } + end + end + end + + context 'on Ubuntu 24.04' do + let(:facts) do + { + :osfamily => 'Debian', + :operatingsystem => 'Ubuntu', + :operatingsystemrelease => '24.04', + :kernel => 'Linux', + :architecture => 'x86_64', + } + end + + context 'with default parameters (latest version)' do + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_class('awscli2::install') } + + it { is_expected.to contain_file('/tmp/umd_awscli2_install').with_ensure('directory') } + + # With verify_signature => true (default), should have GPG verification resources + it { is_expected.to contain_file('/tmp/umd_awscli2_install/aws-cli-public-key.asc') } + it { is_expected.to contain_archive('/tmp/umd_awscli2_install/awscli2.zip.sig') } + it { is_expected.to contain_archive('/tmp/umd_awscli2.zip').with_extract(false) } + it { is_expected.to contain_exec('awscli2-verify-signature') } + it { is_expected.to contain_exec('awscli2-extract') } + it { is_expected.to contain_exec('awscliv2-installer') } + it { is_expected.to contain_exec('awscli2-cleanup-tmpdir') } + end + + context 'with verify_signature => false' do + let(:params) { { 'verify_signature' => false } } + + it { is_expected.to compile.with_all_deps } + + # Without signature verification, should use archive with extract + it { is_expected.to contain_archive('/tmp/umd_awscli2.zip').with_extract(true) } + it { is_expected.not_to contain_exec('awscli2-verify-signature') } + it { is_expected.not_to contain_file('/tmp/umd_awscli2_install/aws-cli-public-key.asc') } + end + + context 'with specific version' do + let(:params) { { 'version' => '2.15.0' } } + + it { is_expected.to compile.with_all_deps } + + # With specific version, should have version cleanup resources + it { is_expected.to contain_file('/usr/local/aws-cli/v2') } + it { is_expected.to contain_file('/usr/local/aws-cli/v2/current') } + it { is_expected.to contain_file('/usr/local/aws-cli/v2/2.15.0') } + end + + context 'with custom install_dir and bin_dir' do + let(:params) do + { + 'version' => '2.15.0', + 'install_dir' => '/opt/aws-cli', + 'bin_dir' => '/usr/local/bin', + } + end + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_file('/opt/aws-cli/v2') } + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..e176275 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,14 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'rspec-puppet-facts' + +include RspecPuppetFacts + +RSpec.configure do |c| + c.default_facts = { + :osfamily => 'Debian', + :operatingsystem => 'Ubuntu', + :operatingsystemrelease => '24.04', + :kernel => 'Linux', + :architecture => 'x86_64', + } +end