Skip to content
80 changes: 76 additions & 4 deletions .github/workflows/reusable_sign-artifacts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
workflow_call:
inputs:
artifact-glob:
description: Glob pattern to match artifacts to sign (e.g. dist/**/*.{jar,deb,rpm})
description: Glob pattern to match artifacts to sign (e.g. dist/**/*.{jar,deb,rpm,nupkg})
required: true
type: string
artifact-name:
Expand All @@ -16,7 +16,22 @@ on:
description: Retention days for the artifacts
required: false
type: number
default: 1
default: 7
enable-nuget-signing:
description: Enable SSL.com signing for NuGet packages
required: false
type: boolean
default: false
nuget-environment:
description: SSL.com environment name for NuGet signing
required: false
type: string
default: PROD
jvm-max-memory:
description: Maximum JVM memory for NuGet signing process
required: false
type: string
default: 1024M
artifactory-url:
required: false
description: JFrog Artifactory URL
Expand All @@ -37,17 +52,30 @@ on:
required: false
type: string
default: ubuntu-22.04

secrets:
gpg-private-key:
required: true
gpg-public-key:
required: true
gpg-key-pass:
required: true
es-username:
description: SSL.com username for NuGet signing
required: false
es-password:
description: SSL.com password for NuGet signing
required: false
credential-id:
description: SSL.com credential ID for NuGet signing
required: false
es-totp-secret:
description: SSL.com TOTP secret for NuGet signing
required: false

permissions:
contents: read
packages: read

jobs:
sign:
runs-on: ${{ inputs.runs-on }}
Expand All @@ -65,10 +93,54 @@ jobs:
run: |
sudo apt-get update && sudo apt-get install dpkg-sig dpkg-dev -y

- name: Sign Artifacts
- name: Sign Artifacts with GPG
run: |
chmod +x ${{ github.workspace }}/.github/workflows/sign-artifacts/entrypoint.sh
${{ github.workspace }}/.github/workflows/sign-artifacts/entrypoint.sh "${{ inputs.artifact-glob }}" "${{ inputs.artifact-name }}"

- name: Check for NuGet packages and sign if enabled
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the step after this not actually list out the files that it signs? this seems like a weird step? Just here to print information out?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The previous commit had an all in one workflow that built the packages then signed them, the build step was removed.

if: inputs.enable-nuget-signing
run: |
echo "Checking for NuGet packages..."
NUGET_PACKAGES=$(find "${{ inputs.artifact-name }}" -name "*.nupkg" -type f)
if [ -n "$NUGET_PACKAGES" ]; then
echo "Found NuGet packages, signing with SSL.com..."
echo "$NUGET_PACKAGES" | while read -r file; do
echo "Signing: $file"
done
else
echo "No NuGet packages found"
fi

- name: Sign NuGet Packages with SSL.com
if: inputs.enable-nuget-signing
uses: sslcom/esigner-codesign@a272724cb13abe0abc579c6c40f7899969b6942b
with:
command: sign
username: ${{secrets.es-username}}
password: ${{secrets.es-password}}
credential_id: ${{secrets.credential-id}}
totp_secret: ${{secrets.es-totp-secret}}
file_path: ${{ inputs.artifact-name }}/**/*.nupkg
output_path: ${{github.workspace}}/${{ inputs.artifact-name }}
malware_block: false
override: false
environment_name: ${{ inputs.nuget-environment }}
clean_logs: true
jvm_max_memory: ${{ inputs.jvm-max-memory }}
signing_method: v1

- name: Verify NuGet Packages (if NuGet signing was performed)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want to capture the names of the signed package from the previous step? this is probably fine... but feels odd to run a find on something you should know.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as prior

if: inputs.enable-nuget-signing
run: |
echo "Verifying signed NuGet packages..."
if [ -d "${{ inputs.artifact-name }}" ]; then
find "${{ inputs.artifact-name }}" -name "*.nupkg" -type f | while read -r file; do
echo "Verifying: $file"
dotnet nuget verify "$file" --all || echo "Warning: Could not verify $file"
done
fi

- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/sign-artifacts/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ echo "Processing all files in target directory: $TARGET_DIR"
find "$TARGET_DIR" -type f | while read -r file; do
echo "Processing: $file"


# Skip signature and checksum files to prevent infinite loops
if [[ "$file" =~ \.(asc|sha256)$ ]]; then
continue
Expand Down Expand Up @@ -80,8 +79,13 @@ find "$TARGET_DIR" -type f | while read -r file; do
# SHA256 checksum for signature file
shasum -a 256 "$file.asc" > "$file.asc.sha256"

echo "Signed: $file"
echo "GPG Signed: $file"
echo " Signature: $file.asc"
echo " Checksum: $file.sha256"
echo " Sig Checksum: $file.asc.sha256"

# Note about NuGet packages
if [[ "$ext" == "nupkg" ]]; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be better to change the logic of the script to only pick up files it could sign, aka, this bash script only signs rpms, and debs right? Or is this echo important?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i added the nuget signing to the reusable-sign artifacts file. so this just confirms if theres a nupkg to be signed if not it skips the signing

echo " Note: NuGet package detected - will be signed by SSL.com if enabled in workflow"
fi
done
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"yaml.schemas": {},
"cSpell.words": ["aerospike", "kennylong", "kennylong's"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like there is a war between formatters but please use the default trunk from this repository.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

updated

"cSpell.words": ["aerospike", "kennylong", "kennylong's"],
"postman.settings.dotenv-detection-notification-visibility": false
}
155 changes: 151 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,151 @@
# shared-workflows
# Shared Workflows

This repository contains reusable GitHub Actions workflows for common CI/CD tasks.

## Available Workflows

### Sign Packages

- **File**: `.github/workflows/reusable_sign-artifacts.yaml`
- **Purpose**: Sign RPM, DEB, and NuGet packages with GPG and SSL.com certificates
- **Usage**: See [Sign Artifacts Documentation](#sign-artifacts)

### Upload Artifacts

- **File**: `.github/workflows/reusable_upload-artifacts.yaml`
- **Purpose**: Upload artifacts to various destinations
- **Usage**: See [Upload Artifacts Documentation](#upload-artifacts)

## Sign Artifacts

The reusable sign artifacts workflow signs RPM, DEB, and NuGet packages using GPG and SSL.com certificates. This workflow is designed to be called after a build workflow that produces packages as artifacts.

### Features

- **Multi-format support**: Signs RPM and DEB packages with GPG, optionally signs NuGet packages with SSL.com certificates
- **Automatic detection**: Automatically detects NuGet packages and signs them when enabled
- **Flexible configuration**: Supports custom artifact patterns, paths, and signing settings
- **Secure signing**: Uses GPG for RPM/DEB and SSL.com certificates for NuGet packages
- **Verification**: Includes built-in package verification steps

### Basic Usage

```yaml
name: Build and Sign My Packages

on:
workflow_dispatch:
push:
branches: [main]

jobs:
build:
runs-on: ubuntu-latest
steps:
# Your build steps here that produce packages
- name: Build Packages
run: |
# Build RPM/DEB packages
# Build NuGet packages
dotnet pack --output artifacts

- name: Upload Packages
uses: actions/upload-artifact@v4
with:
name: packages
path: artifacts/

sign:
needs: build
uses: aerospike/shared-workflows/.github/workflows/reusable_sign-artifacts.yaml@main
with:
artifact-glob: artifacts/**/*.{deb,rpm,nupkg}
enable-nuget-signing: true
secrets:
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
gpg-public-key: ${{ secrets.GPG_PUBLIC_KEY }}
gpg-key-pass: ${{ secrets.GPG_KEY_PASS }}
es-username: ${{ secrets.ES_USERNAME }}
es-password: ${{ secrets.ES_PASSWORD }}
credential-id: ${{ secrets.CREDENTIAL_ID }}
es-totp-secret: ${{ secrets.ES_TOTP_SECRET }}
```

### Advanced Usage

```yaml
name: Build and Sign My Packages

on:
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
steps:
# Your build steps here
- name: Upload Packages
uses: actions/upload-artifact@v4
with:
name: my-custom-packages
path: dist/

sign:
needs: build
uses: aerospike/shared-workflows/.github/workflows/reusable_sign-artifacts.yaml@main
with:
artifact-glob: dist/**/*.{deb,rpm,nupkg}
output-dir: signed-packages
retention-days: 30
enable-nuget-signing: true
nuget-environment: PROD
jvm-max-memory: 2048M
secrets:
gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }}
gpg-public-key: ${{ secrets.GPG_PUBLIC_KEY }}
gpg-key-pass: ${{ secrets.GPG_KEY_PASS }}
es-username: ${{ secrets.ES_USERNAME }}
es-password: ${{ secrets.ES_PASSWORD }}
credential-id: ${{ secrets.CREDENTIAL_ID }}
es-totp-secret: ${{ secrets.ES_TOTP_SECRET }}
```

### Required Secrets

You need to set up the following secrets in your repository:

**For GPG signing (RPM/DEB packages):**

- `GPG_PRIVATE_KEY`: Your GPG private key
- `GPG_PUBLIC_KEY`: Your GPG public key
- `GPG_KEY_PASS`: Your GPG key passphrase

**For SSL.com signing (NuGet packages):**

- `ES_USERNAME`: Your SSL.com username
- `ES_PASSWORD`: Your SSL.com password
- `CREDENTIAL_ID`: Your SSL.com credential ID
- `ES_TOTP_SECRET`: Your SSL.com TOTP secret

### Input Parameters

| Parameter | Description | Required | Default |
| ---------------------- | ----------------------------------------- | -------- | ------------------ |
| `artifact-glob` | Glob pattern to match artifacts to sign | Yes | - |
| `output-dir` | Output directory for signed artifacts | No | `signed-artifacts` |
| `retention-days` | Number of days to retain artifacts | No | `7` |
| `enable-nuget-signing` | Enable SSL.com signing for NuGet packages | No | `false` |
| `nuget-environment` | SSL.com environment for NuGet signing | No | `PROD` |
| `jvm-max-memory` | Maximum JVM memory for NuGet signing | No | `1024M` |

### How It Works

1. **Download artifacts**: Downloads the specified artifacts containing packages
2. **GPG signing**: Signs RPM and DEB packages with GPG, creates detached signatures and checksums
3. **NuGet detection**: Automatically detects NuGet packages in the artifacts
4. **SSL.com signing**: Signs NuGet packages with SSL.com certificates (if enabled)
5. **Upload results**: Uploads all signed packages as artifacts
6. **Verify signatures**: Verifies signed packages and provides summaries

## Introduction

Expand Down Expand Up @@ -61,18 +208,18 @@ GitHub Actions and Workflows in the same repository necessarily share a version.
We suggest that you pin these actions/workflows to a specific sha with a comment of the semver tag. This way you can use dependabot to keep your workflows up to date. See [dependabot.yml](.github/dependabot.yml) for an example of this.

```yaml
# GOOD
# GOOD
uses: aerospike/shared-workflows/actions/setup-gpg@ed780e9928d56ef074532dbc6877166d5460587a # v0.1.0
# pro: reproducible builds, allows you to specify a known version of the action
# pro: dependabot can auto-PR updates to your repo, will also update version comment
# pro: official GitHub security hardening best practice

# BAD
# BAD
uses: aerospike/shared-workflows/actions/[email protected]
# pro: dependabot can auto-PR updates to your repo
# con: tags are not immutable. 'semver' hint not usable with semver niceties (pessimistic versioning, etc)

# BAD
# BAD
uses: aerospike/shared-workflows/actions/setup-gpg@main
# con: unsupported versioning usage: if this breaks for you, you will be told you should've pinned to a sha
# con: Requires that main is always backwards compatible and never breaks anything ever (not possible)
Expand Down