Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,23 @@ jobs:
run: sudo apt-get install -y lld
- run: make validate-elf-symbols

validate-keyring:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- run: make validate-keyring

validate-dist-release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: dtolnay/rust-toolchain@stable
- run: make dist-release
- name: check release artefacts
run: |-
ls -la release/*/
cat release/*/libpathrs.sha256sum

build:
runs-on: ubuntu-latest
strategy:
Expand Down Expand Up @@ -521,6 +538,8 @@ jobs:
- check-lint-nohack
- validate-cbindgen
- validate-elf-symbols
- validate-keyring
- validate-dist-release
- build
- rustdoc
- doctest
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
/target
**/*.rs.bk

# Releases directory.
/release

# pkg-config generated by install.sh.
/pathrs.pc

Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- `install.sh` now accepts `--rust-target` and `--rust-buildmode` as parameters
to make cross-compilation workflows easier to write (in particular, this is
needed for runc's release scripts).
- We now produce signed release artefacts for our releases (though currently
only in the form of signed source and `cargo vendor` tarballs). The accepted
set of signing keys are available in [`libpathrs.keyring`](./libpathrs.keyring).

### Changed ###
- The `O_PATH` resolver for `procfs` now has an additional bit of hardening
Expand Down
1 change: 1 addition & 0 deletions MAINTAINERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Aleksa Sarai <cyphar@cyphar.com> (@cyphar)
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,10 @@ validate-cbindgen:
validate-elf-symbols: release
./hack/check-elf-symbols.sh ./target/release/libpathrs.so

.PHONY: validate-keyring
validate-keyring:
./hack/keyring-validate.sh

.PHONY: test-rust-doctest
test-rust-doctest:
$(CARGO_LLVM_COV) --no-report --branch --doc
Expand Down Expand Up @@ -176,3 +180,9 @@ install: release
@echo "[Sleeping for 3 seconds.]"
@sleep 3s
./install.sh

GPG_KEYID ?= cyphar@cyphar.com

.PHONY: dist-release
dist-release:
./hack/release.sh -S $(GPG_KEYID)
40 changes: 40 additions & 0 deletions hack/keyring-addkey.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/bash
# SPDX-License-Identifier: Apache-2.0
# Copyright (C) 2023-2025 SUSE LLC.
# Copyright (C) 2023 Open Containers Authors
# Copyright (C) 2026 Aleksa Sarai <cyphar@cyphar.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -Eeuxo pipefail

project="libpathrs"
root="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/..")"
keyring_file="$root/$project.keyring"

function bail() {
echo "$@" >&2
exit 1
}

[[ "$#" -eq 2 ]] || bail "usage: $0 <github-handle> <keyid>"

github_handle="${1}"
gpg_keyid="${2}"

cat >>"$keyring_file" <<EOF
$(gpg --list-keys "$gpg_keyid")

$(gpg --armor --comment="github=$github_handle" --export --export-options=export-minimal,export-clean "$gpg_keyid")

EOF
112 changes: 112 additions & 0 deletions hack/keyring-validate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
#!/bin/bash
# SPDX-License-Identifier: Apache-2.0
# Copyright (C) 2023-2025 SUSE LLC.
# Copyright (C) 2023 Open Containers Authors
# Copyright (C) 2026 Aleksa Sarai <cyphar@cyphar.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -Eeuo pipefail

project="libpathrs"
root="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")/..")"

function log() {
echo "[*]" "$@" >&2
}

function bail() {
log "$@"
exit 1
}

# Temporary GPG keyring for messing around with.
tmp_gpgdir="$(mktemp -d --tmpdir "$project-validate-tmpkeyring.XXXXXX")"
trap 'rm -r "$tmp_gpgdir"' EXIT

function gpg_user() {
local user=$1
shift
gpg --homedir="$tmp_gpgdir" --no-default-keyring --keyring="$user.keyring" "$@"
}

# Get the set of MAINTAINERS.
readarray -t maintainers < <(sed -E 's|.* <.*> \(@?(.*)\)$|\1|' <"$root/MAINTAINERS")
echo "------------------------------------------------------------"
echo "$project maintainers:"
printf " * %s\n" "${maintainers[@]}"
echo "------------------------------------------------------------"

# Create a dummy gpg keyring from the set of MAINTAINERS.
while IFS="" read -r username || [ -n "$username" ]; do
curl -sSL "https://github.com/$username.gpg" | gpg_user "$username" --import
done < <(printf '%s\n' "${maintainers[@]}")

# Make sure all of the keys in the keyring have a github=... comment.
awk <"$root/$project.keyring" '
/^-----BEGIN PGP PUBLIC KEY BLOCK-----$/ { key_idx++; in_pgp=1; has_comment=0; }

# PGP comments are never broken up over several lines, and we only have one
# comment entry in our keyring file anyway.
in_pgp && /^Comment:.* github=\w+.*/ { has_comment=1 }

/^-----END PGP PUBLIC KEY BLOCK-----$/ {
if (!has_comment) {
print "[!] Key", key_idx, "in '$project'.keyring is missing a github= comment."
exit 1
}
}
'

echo "------------------------------------------------------------"
echo "$project release managers:"
sed -En "s|^Comment:.* github=(\w+).*| * \1|p" <"$root/$project.keyring" | sort -u
echo "------------------------------------------------------------"
gpg --show-keys <"$root/$project.keyring"
echo "------------------------------------------------------------"

# Check that each entry in the keyring is actually a maintainer's key.
while IFS="" read -d $'\0' -r block || [ -n "$block" ]; do
username="$(sed -En "s|^Comment:.* github=(\w+).*|\1|p" <<<"$block")"

# FIXME: This is to work around codespell thinking that f-p-r is a
# misspelling of some other word, and the lack of support for inline
# ignores in codespell.
fprfield="f""p""r"

# Check the username is actually a maintainer. This is just a sanity check,
# since you can put whatever you like in the Comment field.
[ -f "$tmp_gpgdir/$username.keyring" ] || bail "User $username in $project.keyring is not a maintainer!"
grep "(@$username)$" "$root/MAINTAINERS" >/dev/null || bail "User $username in $project.keyring is not a maintainer!"

# Check that the key in the block actually matches a known key for that
# maintainer. Note that a block can contain multiple keys, so we need to
# check all of them. Since we have to handle multiple keys anyway, we'll
# also verify all of the subkeys (this is simpler to implement anyway since
# the --with-colons format outputs fingerprints for both primary and
# subkeys in the same way).
#
# Fingerprints have a field 1 of $fprfield and field 10 containing the
# fingerprint. See <https://github.com/gpg/gnupg/blob/master/doc/DETAILS>
# for more details.
while IFS="" read -r key || [ -n "$key" ]; do
gpg_user "$username" --list-keys --with-colons | grep "$fprfield:::::::::$key:" >/dev/null ||
bail "(Sub?)Key $key in $project.keyring is NOT actually one of $username's keys!"
log "Successfully verified $username's (sub?)key $key is legitimate."
done < <(gpg --show-keys --with-colons <<<"$block" |
grep "^$fprfield:" | cut -d: -f10)
done < <(awk <"$root/$project.keyring" '
/^-----BEGIN PGP PUBLIC KEY BLOCK-----$/ { in_block=1 }
in_block { print }
/^-----END PGP PUBLIC KEY BLOCK-----$/ { in_block=0; printf("\0"); }
')
44 changes: 44 additions & 0 deletions hack/readlinkf.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#!/bin/bash
# SPDX-License-Identifier: CC0-1.0
# readlinkf: POSIX-compliant implementation of readlink -f.
# Author: Koichi Nakashima <koichi@nksm.name>
# Licensed under the Creative Commons Zero v1.0 Universal license.
# <https://creativecommons.org/publicdomain/zero/1.0/>

# Copied verbatim from v1.1.0 of <https://github.com/ko1nksm/readlinkf>.

# POSIX compliant version
readlinkf_posix() {
[ "${1:-}" ] || return 1
max_symlinks=40
CDPATH='' # to avoid changing to an unexpected directory

target=$1
[ -e "${target%/}" ] || target=${1%"${1##*[!/]}"} # trim trailing slashes
[ -d "${target:-/}" ] && target="$target/"

cd -P . 2>/dev/null || return 1
while [ "$max_symlinks" -ge 0 ] && max_symlinks=$((max_symlinks - 1)); do
if [ ! "$target" = "${target%/*}" ]; then
case $target in
/*) cd -P "${target%/*}/" 2>/dev/null || break ;;
*) cd -P "./${target%/*}" 2>/dev/null || break ;;
esac
target=${target##*/}
fi

if [ ! -L "$target" ]; then
target="${PWD%/}${target:+/}${target}"
printf '%s\n' "${target:-/}"
return 0
fi

# `ls -dl` format: "%s %u %s %s %u %s %s -> %s\n",
# <file mode>, <number of links>, <owner name>, <group name>,
# <size>, <date and time>, <pathname of link>, <contents of link>
# https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html
link=$(ls -dl -- "$target" 2>/dev/null) || break
target=${link#*" $target -> "}
done
return 1
}
Loading
Loading