Compare commits

..

2 commits

4 changed files with 90 additions and 16 deletions

View file

@ -1,4 +1,4 @@
FROM docker:20.10.23-dind
FROM docker:28.3.1-dind-alpine3.22
# Cannot use a rootless container due to permissions errors writing to the
# workspace
@ -6,7 +6,7 @@ FROM docker:20.10.23-dind
# This is an alpine-based image
RUN true && \
apk add --no-cache curl && \
apk add --no-cache curl uhubctl && \
apkArch="$(arch)" && \
if [ $apkArch = "x86_64" ]; then apkArch=amd64; fi && \
curl -sLO https://github.com/sigstore/rekor/releases/download/v1.0.1/rekor-cli-linux-${apkArch} && \

View file

@ -1,16 +1,56 @@
Notifies using ntfy
===================
Signs files using an HSM
========================
Usage:
Basic Usage
-----------
```yaml
- name: Notify
uses: https://git.lerch.org/lobo/action-notify-ntfy@v1
if: always()
- name: Sign
id: sign
uses: https://git.lerch.org/lobo/action-hsm-sign@v1
with:
# Can use ** glob syntax for all files
files: output/**
user_pin: ${{ secrets.HSM_USER_PIN }}
# if specified, public key will be used to upload artifacts to the sigstore server
public_key: https://lerch.org/server_public_key.pem
pin: ${{ secrets.HSM_USER_PIN }}
files: ???
public_key: 'https://emil.lerch.org/serverpublic.pem'
```
If a public key is specified, [rekor](https://github.com/sigstore/rekor) will
be invoked, sending the signature to the [sigstore public transparency
log](https://sigstore.dev).
The action provides the following outputs:
* Source: Source file used for the signature
* Signature: Signature
* URL: If a public key is specified, the URL output provides the sigstore log url
Because multiple files can be signed, these outputs have numerical suffixes.
In the above example, the output `${{ steps.sign.outputs.URL_1 }}` would be the
url for the first file signed with this action
Usage with Smart USB Hubs
-------------------------
Many consumer HSMs will "hang" after prolonged usage. To alleviate problems
associated with this, this action can integrate with smart USB hubs to turn
on the hub's port and wait for the OS to recognize the attached HSM before
performing the signing action.
**NOTE: The action will turn off the port on the USB hub when it is done processing**
To enable this feature, use inputs uhub_location **and** uhub_port. To
determine the proper values for these, it is best to consult [uhubctl
documentation](https://github.com/mvp/uhubctl?tab=readme-ov-file#usage) and
run some command line tests. Updating the previous example:
```yaml
- name: Sign
id: sign
uses: https://git.lerch.org/lobo/action-hsm-sign@v1
with:
pin: ${{ secrets.HSM_USER_PIN }}
files: ???
public_key: 'https://emil.lerch.org/serverpublic.pem'
uhub_location: "1-1.3"
uhub_port: "4"
```

View file

@ -15,6 +15,12 @@ inputs:
public_key:
description: 'URL to PEM format public key. Specify only if uploading to sigstore'
required: false
uhub_location:
description: 'If HSM is attached to software controlled power hub, location of hub (-l parameter of uhubctl)'
required: false
uhub_port:
description: 'If HSM is attached to software controlled power hub, port to power on, then off (-p parameter of uhubctl)'
required: false
runs:
using: 'docker'
image: 'Dockerfile'

View file

@ -1,5 +1,28 @@
#!/bin/sh
if [ -n "${INPUT_UHUB_LOCATION}" ] && [ -n "${INPUT_UHUB_PORT}" ]; then
uhubctl -a off -p "${INPUT_UHUB_PORT}" -l "${INPUT_UHUB_LOCATION}" # Off seems to be reflected immediately
# Capture the number of hidraw devices with the port off
devs="$(find /dev -maxdepth 1 -name 'hi*' |wc -l)"
uhubctl -a on -p "${INPUT_UHUB_PORT}" -l "${INPUT_UHUB_LOCATION}"
retries=0
while [ "$(find /dev -maxdepth 1 -name 'hi*' |wc -l)" = "$devs" ] && [ $retries -lt 10 ]; do
# Generally takes a few seconds to settle in
echo "waiting for device connection ($retries / 10)"
sleep 1
retries=$((i+1))
done
if [ $retries -ge 10 ]; then
echo "device is not available. Aborting"
exit 1
fi
else
if [ -n "${INPUT_UHUB_LOCATION}" ] || [ -n "${INPUT_UHUB_PORT}" ]; then
echo "if UHUB functionality is desired, both uhub_location and uhub_port must be specified"
exit 1
fi
fi
dir="$(dirname "${INPUT_FILES}")"
glob="$(basename "${INPUT_FILES}")"
# Pass these through sort so we can have deterministic output indexing
@ -43,10 +66,15 @@ while IFS= read -r f; do
# echo "INDEX_${i}=$(echo "$output"|cut -d, -f1|cut -d\ -f5)" >> "${GITHUB_OUTPUT}"
# The parsing, though, is identical
echo "URL_${i}=$(echo "$output"|cut -d: -f2-|cut -d\ -f2)" >> "${GITHUB_OUTPUT}"
echo "SOURCE_${i}=${f}" >> "${GITHUB_OUTPUT}"
echo "SIG_${i}=${dest_sig}" >> "${GITHUB_OUTPUT}"
i=$((i+1))
fi
echo "SOURCE_${i}=${f}" >> "${GITHUB_OUTPUT}"
echo "SIG_${i}=${dest_sig}" >> "${GITHUB_OUTPUT}"
i=$((i+1))
done <<ALLFILES_INPUT
$all_files
ALLFILES_INPUT
if [ -n "${INPUT_UHUB_LOCATION}" ] && [ -n "${INPUT_UHUB_PORT}" ]; then
# Turn off the port when we're done
uhubctl -a off -p "${INPUT_UHUB_PORT}" -l "${INPUT_UHUB_LOCATION}"
fi