mirror of
https://github.com/ben-grande/qusal.git
synced 2024-12-13 01:44:34 -05:00
feat: verify commit signature before push
Check commit signature and if it fails, check if any signed tags associated with commit exist from a keyring that can be found only locally. For: https://github.com/ben-grande/qusal/issues/105
This commit is contained in:
parent
efe0fa6ac7
commit
8fbd9a063c
@ -5,5 +5,5 @@
|
|||||||
|
|
||||||
[codespell]
|
[codespell]
|
||||||
skip = LICENSES,.git,*.asc,./rpm_spec/*-*.spec,*.muttrc,./salt/sys-cacher/files/server/conf/*_mirrors_*,./salt/dotfiles/files/vim/.config/vim/after/plugin/update-time.vim
|
skip = LICENSES,.git,*.asc,./rpm_spec/*-*.spec,*.muttrc,./salt/sys-cacher/files/server/conf/*_mirrors_*,./salt/dotfiles/files/vim/.config/vim/after/plugin/update-time.vim
|
||||||
ignore-words-list = uptodate,iterm,doas
|
ignore-words-list = uptodate,iterm,doas,fpr
|
||||||
ignore-regex = (nnoremap|bind)\b.*
|
ignore-regex = (nnoremap|bind)\b.*
|
||||||
|
14
.github/workflows/main.yaml
vendored
14
.github/workflows/main.yaml
vendored
@ -70,3 +70,17 @@ jobs:
|
|||||||
else
|
else
|
||||||
gitlint --debug --commits "${base}..${head}"
|
gitlint --debug --commits "${base}..${head}"
|
||||||
fi
|
fi
|
||||||
|
- name: Verify that commits have associated signatures
|
||||||
|
run: |
|
||||||
|
if test "${{ github.event_name}}" = "pull_request"
|
||||||
|
then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
base="${{ github.event.before }}"
|
||||||
|
head="${{ github.event.after }}"
|
||||||
|
if test "${base}" = "${head}" || test -z "${base}"
|
||||||
|
then
|
||||||
|
scripts/commit-verify.sh "${head}"
|
||||||
|
else
|
||||||
|
scripts/commit-verify.sh $(git rev-list --reverse ${base}..${head})
|
||||||
|
fi
|
||||||
|
@ -19,6 +19,7 @@ repos:
|
|||||||
language: script
|
language: script
|
||||||
pass_filenames: true
|
pass_filenames: true
|
||||||
description: Prohibit Unicode
|
description: Prohibit Unicode
|
||||||
|
stages: [commit]
|
||||||
|
|
||||||
- id: spell-lint
|
- id: spell-lint
|
||||||
name: spell-lint
|
name: spell-lint
|
||||||
@ -26,6 +27,7 @@ repos:
|
|||||||
language: script
|
language: script
|
||||||
pass_filenames: true
|
pass_filenames: true
|
||||||
description: Spellcheck files
|
description: Spellcheck files
|
||||||
|
stages: [commit]
|
||||||
|
|
||||||
- id: shell-lint
|
- id: shell-lint
|
||||||
name: shell-lint
|
name: shell-lint
|
||||||
@ -43,6 +45,7 @@ repos:
|
|||||||
\.(policy|asc|txt|top|sls|jinja|toml|vim|py|muttrc|nft|md|spec|
|
\.(policy|asc|txt|top|sls|jinja|toml|vim|py|muttrc|nft|md|spec|
|
||||||
list|sources|repo|socket|timer|service|y(a)?ml)$
|
list|sources|repo|socket|timer|service|y(a)?ml)$
|
||||||
description: Lint Shellscripts
|
description: Lint Shellscripts
|
||||||
|
stages: [commit]
|
||||||
|
|
||||||
- id: markdown-lint
|
- id: markdown-lint
|
||||||
name: markdown-lint
|
name: markdown-lint
|
||||||
@ -51,6 +54,7 @@ repos:
|
|||||||
pass_filenames: true
|
pass_filenames: true
|
||||||
files: \.md$
|
files: \.md$
|
||||||
description: Lint Markdown files
|
description: Lint Markdown files
|
||||||
|
stages: [commit]
|
||||||
|
|
||||||
- id: python-lint
|
- id: python-lint
|
||||||
name: python-lint
|
name: python-lint
|
||||||
@ -59,6 +63,7 @@ repos:
|
|||||||
pass_filenames: true
|
pass_filenames: true
|
||||||
files: \.py$
|
files: \.py$
|
||||||
description: Lint Python files
|
description: Lint Python files
|
||||||
|
stages: [commit]
|
||||||
|
|
||||||
- id: salt-lint
|
- id: salt-lint
|
||||||
name: salt-lint
|
name: salt-lint
|
||||||
@ -67,6 +72,7 @@ repos:
|
|||||||
pass_filenames: true
|
pass_filenames: true
|
||||||
files: (^minion.d/.*.conf|\.(sls|top|jinja|j2|tmpl|tst))$
|
files: (^minion.d/.*.conf|\.(sls|top|jinja|j2|tmpl|tst))$
|
||||||
description: Lint Salt files
|
description: Lint Salt files
|
||||||
|
stages: [commit]
|
||||||
|
|
||||||
- id: yaml-lint
|
- id: yaml-lint
|
||||||
name: yaml-lint
|
name: yaml-lint
|
||||||
@ -75,6 +81,7 @@ repos:
|
|||||||
pass_filenames: true
|
pass_filenames: true
|
||||||
files: \.(yaml|yml)$
|
files: \.(yaml|yml)$
|
||||||
description: Lint YAML files
|
description: Lint YAML files
|
||||||
|
stages: [commit]
|
||||||
|
|
||||||
- id: qubesbuilder-gen
|
- id: qubesbuilder-gen
|
||||||
name: qubesbuilder-gen
|
name: qubesbuilder-gen
|
||||||
@ -84,6 +91,7 @@ repos:
|
|||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
files: salt/\S+/README.md
|
files: salt/\S+/README.md
|
||||||
description: Check if .qubesbuilder is up to date
|
description: Check if .qubesbuilder is up to date
|
||||||
|
stages: [commit]
|
||||||
|
|
||||||
# - id: spec-gen
|
# - id: spec-gen
|
||||||
# name: spec-gen
|
# name: spec-gen
|
||||||
@ -96,6 +104,7 @@ repos:
|
|||||||
# ^(rpm_spec/template/template.spec|salt/.*|
|
# ^(rpm_spec/template/template.spec|salt/.*|
|
||||||
# scripts/spec-(get|gen)\.sh)$
|
# scripts/spec-(get|gen)\.sh)$
|
||||||
# description: Check if RPM SPEC files are up to date
|
# description: Check if RPM SPEC files are up to date
|
||||||
|
# stages: [commit]
|
||||||
|
|
||||||
- id: license-lint
|
- id: license-lint
|
||||||
name: license-lint
|
name: license-lint
|
||||||
@ -104,3 +113,12 @@ repos:
|
|||||||
language: python
|
language: python
|
||||||
pass_filenames: false
|
pass_filenames: false
|
||||||
description: Lint files to comply with the REUSE Specification
|
description: Lint files to comply with the REUSE Specification
|
||||||
|
stages: [commit]
|
||||||
|
|
||||||
|
- id: commit-verify
|
||||||
|
name: commit-verify
|
||||||
|
entry: scripts/commit-verify.sh
|
||||||
|
language: script
|
||||||
|
pass_filenames: false
|
||||||
|
description: Verify if there is a valid signature associated with the revisions
|
||||||
|
stages: [push]
|
||||||
|
@ -89,3 +89,13 @@ To run pre-commit linters:
|
|||||||
```sh
|
```sh
|
||||||
pre-commit run
|
pre-commit run
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Maintainer's lint
|
||||||
|
|
||||||
|
Note this is only required for maintainers.
|
||||||
|
|
||||||
|
Install the `pre-push` hooks:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
pre-commit install -t pre-push
|
||||||
|
```
|
||||||
|
93
scripts/commit-verify.sh
Executable file
93
scripts/commit-verify.sh
Executable file
@ -0,0 +1,93 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
## SPDX-FileCopyrightText: 2024 Benjamin Grande M. S. <ben.grande.b@gmail.com>
|
||||||
|
##
|
||||||
|
## SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
key_dir="${KEY_DIR:-"salt/qubes-builder/files/client/qusal/keys"}"
|
||||||
|
key_suffix="${KEY_SUFFIX:-".asc"}"
|
||||||
|
|
||||||
|
usage(){
|
||||||
|
printf '%s\n' "Usage: ${0##*/} [REV...]
|
||||||
|
Info:
|
||||||
|
Default key directory (KEY_DIR): '${key_dir}'
|
||||||
|
Default key suffix (KEY_SUFFIX): '${key_suffix}'
|
||||||
|
Example:
|
||||||
|
${0##*/} # HEAD
|
||||||
|
${0##*/} HEAD # HEAD
|
||||||
|
${0##*/} a # revision 'a'
|
||||||
|
${0##*/} \$(git rev-list HEAD~5..) # 5 revs before and until HEAD
|
||||||
|
${0##*/} \$(git rev-list a^..) # from rev 'a' until HEAD
|
||||||
|
${0##*/} \$(git rev-list a^..b) # from rev 'a' until revision 'b'
|
||||||
|
${0##*/} \$(git rev-list a..) # from child of rev 'a' until HEAD
|
||||||
|
${0##*/} \$(git rev-list HEAD) # all revs until HEAD
|
||||||
|
KEY_DIR=/path KEY_SUFFIX=.gpg ${0##*/} # custom key path and suffix"
|
||||||
|
}
|
||||||
|
|
||||||
|
case "${1-}" in
|
||||||
|
-h|--?help) usage; exit 1;;
|
||||||
|
*) ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
command -v git >/dev/null ||
|
||||||
|
{ printf '%s\n' "Missing program: git" >&2; exit 1; }
|
||||||
|
command -v gpg >/dev/null ||
|
||||||
|
{ printf '%s\n' "Missing program: gpg" >&2; exit 1; }
|
||||||
|
command -v gpgconf >/dev/null ||
|
||||||
|
{ printf '%s\n' "Missing program: gpgconf" >&2; exit 1; }
|
||||||
|
repo_toplevel="$(git rev-parse --show-toplevel)"
|
||||||
|
test -d "${repo_toplevel}" || exit 1
|
||||||
|
cd "${repo_toplevel}"
|
||||||
|
unset repo_toplevel
|
||||||
|
|
||||||
|
gpg_homedir="$(mktemp -d)"
|
||||||
|
trap 'rm -rf -- "${gpg_homedir}"' EXIT INT HUP QUIT ABRT
|
||||||
|
export GNUPGHOME="${gpg_homedir}"
|
||||||
|
otrust="${gpg_homedir}/otrust.txt"
|
||||||
|
gpg_agent="$(gpgconf --list-components | awk -F: '/^gpg-agent:/{print $3}')"
|
||||||
|
gpg_cmd="gpg --status-fd=2"
|
||||||
|
|
||||||
|
${gpg_cmd} --agent-program "${gpg_agent}" \
|
||||||
|
--import "${key_dir}"/*"${key_suffix}" >/dev/null 2>&1
|
||||||
|
|
||||||
|
${gpg_cmd} --with-colons --list-public-keys | awk -F ':' '{
|
||||||
|
if (prev_line ~ /^pub$/ && $1 ~ /^fpr$/) {
|
||||||
|
print $10 ":6:"
|
||||||
|
}
|
||||||
|
prev_line = $1
|
||||||
|
}' | tee -- "${otrust}" >/dev/null
|
||||||
|
|
||||||
|
${gpg_cmd} --import-ownertrust "${otrust}" >/dev/null 2>&1
|
||||||
|
|
||||||
|
fail="0"
|
||||||
|
|
||||||
|
for rev in "${@:-"HEAD"}"; do
|
||||||
|
tag_success="0"
|
||||||
|
rev="$(git rev-parse --verify "${rev}")"
|
||||||
|
|
||||||
|
if git verify-commit -- "${rev}" >/dev/null 2>&1; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
tag_list="$(git tag --points-at="${rev}")"
|
||||||
|
if test -n "${tag_list}"; then
|
||||||
|
for tag in ${tag_list}; do
|
||||||
|
if git verify-tag -- "${tag}" >/dev/null 2>&1; then
|
||||||
|
tag_success="1"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if test "${tag_success}" = "1"; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
fail=1
|
||||||
|
printf '%s\n' "error: no valid signature associated with rev: ${rev}" >&2
|
||||||
|
done
|
||||||
|
|
||||||
|
if test "${fail}" = "1"; then
|
||||||
|
exit 1
|
||||||
|
fi
|
@ -22,7 +22,7 @@ block_max_chars(){
|
|||||||
char_value="${2}"
|
char_value="${2}"
|
||||||
less_than="${3}"
|
less_than="${3}"
|
||||||
if test "${#char_value}" -ge "${less_than}"; then
|
if test "${#char_value}" -ge "${less_than}"; then
|
||||||
err_msg="Error: ${char_key} is too long. Must be <${less_than} chars."
|
err_msg="error: ${char_key} is too long. Must be <${less_than} chars."
|
||||||
printf '%s\n' "${err_msg}" >&2
|
printf '%s\n' "${err_msg}" >&2
|
||||||
printf '%s\n' "Key contents: ${char_value}" >&2
|
printf '%s\n' "Key contents: ${char_value}" >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
@ -21,7 +21,7 @@ esac
|
|||||||
## update on save.
|
## update on save.
|
||||||
if ! vim -e -c 'setf markdown' -c 'if !exists(":GenTocGFM") | cq | endif' -c q
|
if ! vim -e -c 'setf markdown' -c 'if !exists(":GenTocGFM") | cq | endif' -c q
|
||||||
then
|
then
|
||||||
err_msg="Error: Vim Plugin mzlogin/vim-markdown-toc isn't installed."
|
err_msg="error: Vim Plugin mzlogin/vim-markdown-toc isn't installed."
|
||||||
printf '%s\n' "${err_msg}" >&2
|
printf '%s\n' "${err_msg}" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@ -29,7 +29,7 @@ fi
|
|||||||
|
|
||||||
for f in "${@}"; do
|
for f in "${@}"; do
|
||||||
if ! test -f "${f}"; then
|
if ! test -f "${f}"; then
|
||||||
printf '%s\n' "Error: Not a regular file: ${f}" >&2
|
printf '%s\n' "error: Not a regular file: ${f}" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if ! grep -q -e "^## Table of Contents$" -- "${f}"; then
|
if ! grep -q -e "^## Table of Contents$" -- "${f}"; then
|
||||||
|
Loading…
Reference in New Issue
Block a user