Compare commits
10 Commits
c6d3a512e4
...
03bbbcc350
Author | SHA1 | Date |
---|---|---|
Lance Vick | 03bbbcc350 | |
Lance Vick | 7164bd6724 | |
Lance Vick | c18f9d36ea | |
Lance Vick | bcc863d5b1 | |
Lance Vick | eafc8c95d3 | |
Lance Vick | 72a7267a22 | |
Lance Vick | 170f49083b | |
Lance Vick | 8b5691dbc5 | |
Lance Vick | f8427ccf2d | |
Lance Vick | 20e73c7cec |
67
README.md
67
README.md
|
@ -1,6 +1,6 @@
|
||||||
# sig #
|
# git-sig #
|
||||||
|
|
||||||
The simple code signature toolchain for git repos.
|
The simple multisig toolchain for git repos.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ The simple code signature toolchain for git repos.
|
||||||
* Verify code changes made since last time minimum valid signatures were present
|
* Verify code changes made since last time minimum valid signatures were present
|
||||||
* Allow user to manually verify new keys and add to alias groups on the fly
|
* Allow user to manually verify new keys and add to alias groups on the fly
|
||||||
* Prompt user to install or upgrade any required tools as needed
|
* Prompt user to install or upgrade any required tools as needed
|
||||||
* Signs aginst git agnostic "tree hash" so signatures survive rebases
|
* Signs notes against git "tree hash" so signatures survive a rebase
|
||||||
* So long as the directory contents at a given ref do not change
|
* So long as the directory contents at a given ref do not change
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
@ -18,15 +18,17 @@ The simple code signature toolchain for git repos.
|
||||||
1. Clone
|
1. Clone
|
||||||
|
|
||||||
```
|
```
|
||||||
git clone git@gitlab.com/pchq/sig.git sig
|
git clone https://codeberg.org/distrust/git-sig.git
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Review source code and signatures manually
|
2. Review source code and signatures manually
|
||||||
|
|
||||||
Using `sig` to verify the signatures of `sig` itself is not recommended.
|
Using `git-sig` to verify the signatures of `git-sig` itself is not
|
||||||
|
recommended as it could simply lie to you.
|
||||||
|
|
||||||
Consider using the following one liner which is much faster to review:
|
Consider using the following one liner which is much faster to review:
|
||||||
```
|
```
|
||||||
|
git fetch origin refs/notes/signatures:refs/notes/signatures
|
||||||
while read -r line; do \
|
while read -r line; do \
|
||||||
gpg --verify \
|
gpg --verify \
|
||||||
<(printf "$line" | sed 's/.*pgp://g'| openssl base64 -d -A) \
|
<(printf "$line" | sed 's/.*pgp://g'| openssl base64 -d -A) \
|
||||||
|
@ -37,68 +39,75 @@ The simple code signature toolchain for git repos.
|
||||||
3. Copy to `$PATH`
|
3. Copy to `$PATH`
|
||||||
|
|
||||||
```
|
```
|
||||||
cp sig ~/.local/bin/
|
cp git-sig ~/.local/bin/
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
* sig verify [-g,--group=<group>] [-t,--threshold=<N>] [-r,--ref=<ref> ] [-d,--diff=<branch>]
|
```
|
||||||
* Verify m-of-n signatures by given group are present for a given git ref.
|
git sig add [-m,--method=<note|tag>] [-p,--push]
|
||||||
* sig add
|
Add signature for this repository
|
||||||
* Add signature to this git ref
|
git sig remove
|
||||||
* sig fetch [-g,--group=<group>]
|
Remove all signatures on current ref
|
||||||
* Fetch key by fingerprint. Optionally add to group.
|
git sig verify [-g,--group=<group>] [-t,--threshold=<N>] [d,--diff=<branch>]
|
||||||
* sig help
|
Verify m-of-n signatures by given group are present for directory.
|
||||||
* Show help text.
|
git sig push [-r,--remote=<remote>]
|
||||||
* sig version
|
Push all signatures on current ref
|
||||||
* Show version information.
|
git sig fetch [-g,--group=<group>]
|
||||||
|
Fetch key by fingerprint. Optionally add to group.
|
||||||
|
git sig help
|
||||||
|
Show this text.
|
||||||
|
git sig version
|
||||||
|
Show version information.
|
||||||
|
```
|
||||||
|
|
||||||
## Methods
|
## Methods
|
||||||
|
|
||||||
### Git
|
* Note
|
||||||
|
* Store/Verify signatures via Git Notes (default)
|
||||||
This method verifies the current HEAD was signed exactly as-is by one or more
|
* Can be exported and verified by external tools even without git history
|
||||||
keys.
|
* Tag
|
||||||
|
* Any git signed tags count towards total signatures
|
||||||
This counts the commit signature, and any number of signed tags pointing at
|
* Can optionally store new signatures as "sig-*" signed tag
|
||||||
this ref.
|
* Commit
|
||||||
|
* Signed commits count as one valid signature
|
||||||
|
|
||||||
### Assumptions
|
### Assumptions
|
||||||
- Single sig mode: Repo contents controlled by signer
|
- Single sig mode: Repo contents controlled by signer
|
||||||
- Multi-sig mode: Repo contents verified by multiple signers
|
- Multi-sig mode: Repo contents verified by multiple signers
|
||||||
- Multi-sig group mode: Repo contents approved by specified individuals
|
- Multi-sig group mode: Repo contents approved by specified individuals
|
||||||
- Hashing scheme for respective backend is not broken: (sha256)
|
- Hashing scheme is not broken: (SHA1, blame Torvalds)
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
#### Verify at least one signature is present with a known key
|
#### Verify at least one signature is present with a known key
|
||||||
|
|
||||||
```
|
```
|
||||||
sig verify
|
git sig verify
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Verify 2 unique signatures from known keys
|
#### Verify 2 unique signatures from known keys
|
||||||
|
|
||||||
```
|
```
|
||||||
sig verify --threshold 2
|
git sig verify --threshold 2
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Verify 3 unique signatures from specified signing group
|
#### Verify 3 unique signatures from specified signing group
|
||||||
|
|
||||||
```
|
```
|
||||||
sig verify --threshold 3 --group myteam
|
git sig verify --threshold 3 --group myteam
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Show diff between HEAD and last ref with 2 verified unique signatures
|
#### Show diff between HEAD and last ref with 2 verified unique signatures
|
||||||
|
|
||||||
```
|
```
|
||||||
sig verify --threshold 2 --diff
|
git sig verify --threshold 2 --diff
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Add signature
|
#### Add signature
|
||||||
|
|
||||||
```
|
```
|
||||||
sig add
|
git sig add
|
||||||
```
|
```
|
||||||
|
|
||||||
## Frequently Asked Questions
|
## Frequently Asked Questions
|
||||||
|
|
171
sig → git-sig
171
sig → git-sig
|
@ -6,6 +6,9 @@ readonly MIN_GPG_VERSION=2.2
|
||||||
readonly MIN_OPENSSL_VERSION=1.1
|
readonly MIN_OPENSSL_VERSION=1.1
|
||||||
readonly MIN_GETOPT_VERSION=2.33
|
readonly MIN_GETOPT_VERSION=2.33
|
||||||
|
|
||||||
|
GIT_SIG_GPG_VERIFY_COMMAND=${GIT_SIG_GPG_VERIFY_COMMAND:-gpg}
|
||||||
|
GIT_SIG_SIGN_COMMAND=${GIT_SIG_SIGN_COMMAND:-gpg}
|
||||||
|
|
||||||
## Private Functions
|
## Private Functions
|
||||||
|
|
||||||
### Exit with error message
|
### Exit with error message
|
||||||
|
@ -97,7 +100,7 @@ check_tools(){
|
||||||
for cmd in "$@"; do
|
for cmd in "$@"; do
|
||||||
command -v "$1" >/dev/null || die "Error: $cmd not found"
|
command -v "$1" >/dev/null || die "Error: $cmd not found"
|
||||||
case $cmd in
|
case $cmd in
|
||||||
gpg)
|
${GIT_SIG_VERIFY_COMMAND})
|
||||||
version=$(gpg --version | head -n1 | cut -d" " -f3)
|
version=$(gpg --version | head -n1 | cut -d" " -f3)
|
||||||
check_version "gnupg" "${version}" "${MIN_GPG_VERSION}"
|
check_version "gnupg" "${version}" "${MIN_GPG_VERSION}"
|
||||||
;;
|
;;
|
||||||
|
@ -116,7 +119,7 @@ check_tools(){
|
||||||
### Get primary UID for a given fingerprint
|
### Get primary UID for a given fingerprint
|
||||||
get_uid(){
|
get_uid(){
|
||||||
local -r fp="${1?}"
|
local -r fp="${1?}"
|
||||||
gpg --list-keys --with-colons "${fp}" 2>&1 \
|
${GIT_SIG_VERIFY_COMMAND} --list-keys --with-colons "${fp}" 2>&1 \
|
||||||
| awk -F: '$1 == "uid" {print $10}' \
|
| awk -F: '$1 == "uid" {print $10}' \
|
||||||
| head -n1
|
| head -n1
|
||||||
}
|
}
|
||||||
|
@ -124,7 +127,7 @@ get_uid(){
|
||||||
### Get primary fingerprint for given search
|
### Get primary fingerprint for given search
|
||||||
get_primary_fp(){
|
get_primary_fp(){
|
||||||
local -r search="${1?}"
|
local -r search="${1?}"
|
||||||
gpg --list-keys --with-colons "${search}" 2>&1 \
|
${GIT_SIG_VERIFY_COMMAND} --list-keys --with-colons "${search}" 2>&1 \
|
||||||
| awk -F: '$1 == "fpr" {print $10}' \
|
| awk -F: '$1 == "fpr" {print $10}' \
|
||||||
| head -n1
|
| head -n1
|
||||||
}
|
}
|
||||||
|
@ -132,7 +135,7 @@ get_primary_fp(){
|
||||||
### Get fingerprint for a given pgp file
|
### Get fingerprint for a given pgp file
|
||||||
get_file_fp(){
|
get_file_fp(){
|
||||||
local -r filename="${1?}"
|
local -r filename="${1?}"
|
||||||
gpg --list-packets "${filename}" \
|
${GIT_SIG_VERIFY_COMMAND} --list-packets "${filename}" \
|
||||||
| grep keyid \
|
| grep keyid \
|
||||||
| sed 's/.*keyid //g'
|
| sed 's/.*keyid //g'
|
||||||
}
|
}
|
||||||
|
@ -168,7 +171,7 @@ group_add_fp(){
|
||||||
done
|
done
|
||||||
|
|
||||||
echo "Adding key \"${fp}\" to group \"${group_name}\""
|
echo "Adding key \"${fp}\" to group \"${group_name}\""
|
||||||
gpg --list-keys >/dev/null 2>&1
|
${GIT_SIG_VERIFY_COMMAND} --list-keys >/dev/null 2>&1
|
||||||
printf 'group:0:%s' "${data%?}" \
|
printf 'group:0:%s' "${data%?}" \
|
||||||
| gpgconf --change-options gpg >/dev/null 2>&1
|
| gpgconf --change-options gpg >/dev/null 2>&1
|
||||||
}
|
}
|
||||||
|
@ -176,7 +179,7 @@ group_add_fp(){
|
||||||
### Get fingerprints for a given group
|
### Get fingerprints for a given group
|
||||||
group_get_fps(){
|
group_get_fps(){
|
||||||
local -r group_name=${1?}
|
local -r group_name=${1?}
|
||||||
gpg --with-colons --list-config group \
|
${GIT_SIG_VERIFY_COMMAND} --with-colons --list-config group \
|
||||||
| grep -i "^cfg:group:${group_name}:" \
|
| grep -i "^cfg:group:${group_name}:" \
|
||||||
| cut -d ':' -f4
|
| cut -d ':' -f4
|
||||||
}
|
}
|
||||||
|
@ -209,19 +212,7 @@ group_check_fp(){
|
||||||
|
|
||||||
tree_hash() {
|
tree_hash() {
|
||||||
local -r ref="${1:-HEAD}"
|
local -r ref="${1:-HEAD}"
|
||||||
local -r target=$(git rev-parse "$ref")
|
git rev-parse "${ref}^{tree}"
|
||||||
local -r current=$(git rev-parse HEAD)
|
|
||||||
[ "$target" == "$current" ] || git checkout "$target" >/dev/null 2>&1
|
|
||||||
mkdir -p ".${PROGRAM}"
|
|
||||||
printf "%s" "$( \
|
|
||||||
find . -type f -not -path "./.git/*" \
|
|
||||||
-exec openssl sha256 -r {} \;\
|
|
||||||
)" \
|
|
||||||
| sed -e 's/ \*/ /g' -e 's/ \.\// /g' \
|
|
||||||
| LC_ALL=C sort -k2 \
|
|
||||||
| openssl sha256 -r \
|
|
||||||
| sed -e 's/ .*//g'
|
|
||||||
[ "$target" == "$current" ] || git checkout "$current" >/dev/null 2>&1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sig_generate(){
|
sig_generate(){
|
||||||
|
@ -233,7 +224,7 @@ sig_generate(){
|
||||||
local -r body="sig:$version:$vcs_ref:$tree_hash:$review_hash:$sig_type"
|
local -r body="sig:$version:$vcs_ref:$tree_hash:$review_hash:$sig_type"
|
||||||
local -r signature=$(\
|
local -r signature=$(\
|
||||||
printf "%s" "$body" \
|
printf "%s" "$body" \
|
||||||
| gpg \
|
| ${GIT_SIG_SIGN_COMMAND} \
|
||||||
--detach-sign \
|
--detach-sign \
|
||||||
--local-user "$key" \
|
--local-user "$key" \
|
||||||
| openssl base64 -A \
|
| openssl base64 -A \
|
||||||
|
@ -298,7 +289,7 @@ verify_git_note(){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
gpg_sig_raw="$(
|
gpg_sig_raw="$(
|
||||||
gpg --verify --status-fd=1 \
|
${GIT_SIG_VERIFY_COMMAND} --verify --status-fd=1 \
|
||||||
<(printf '%s' "$sig" | openssl base64 -d -A) \
|
<(printf '%s' "$sig" | openssl base64 -d -A) \
|
||||||
<(printf '%s' "$body") 2>/dev/null \
|
<(printf '%s' "$body") 2>/dev/null \
|
||||||
)"
|
)"
|
||||||
|
@ -326,7 +317,13 @@ verify_git_notes(){
|
||||||
verify_git_commit(){
|
verify_git_commit(){
|
||||||
local -r ref="${1:-HEAD}"
|
local -r ref="${1:-HEAD}"
|
||||||
local gpg_sig_raw
|
local gpg_sig_raw
|
||||||
gpg_sig_raw=$(git verify-commit "$ref" --raw 2>&1)
|
gpg_sig_raw=$( \
|
||||||
|
git \
|
||||||
|
-c "gpg.program=$GIT_SIG_VERIFY_COMMAND" \
|
||||||
|
verify-commit "$ref" \
|
||||||
|
--raw \
|
||||||
|
2>&1 \
|
||||||
|
)
|
||||||
parse_gpg_status "$gpg_sig_raw"
|
parse_gpg_status "$gpg_sig_raw"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,9 +348,9 @@ verify(){
|
||||||
local -r group="${2}"
|
local -r group="${2}"
|
||||||
local -r ref=${3:-HEAD}
|
local -r ref=${3:-HEAD}
|
||||||
local sig_count=0 seen_fps fp commit_sig tag_sigs note_sigs
|
local sig_count=0 seen_fps fp commit_sig tag_sigs note_sigs
|
||||||
[ -d .git ] || [ -L .git ] || [ -f .git ] \
|
git rev-parse --git-dir >/dev/null 2>&1 \
|
||||||
|| die "Error: This folder is not a git repository"
|
|| die "Error: This folder is not a git repository"
|
||||||
if [[ $(git diff --stat) != '' ]]; then
|
if [[ $(git diff --stat) != '' ]]; then
|
||||||
die "Error: git tree is dirty"
|
die "Error: git tree is dirty"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -367,7 +364,7 @@ verify(){
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tag_sigs=$(verify_git_tags "$ref") && \
|
tag_sigs=$(verify_git_tags "$ref") && \
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
IFS=':' read -r -a sig <<< "$line"
|
IFS=':' read -r -a sig <<< "$line"
|
||||||
fp="${sig[1]}"
|
fp="${sig[1]}"
|
||||||
uid="${sig[5]}"
|
uid="${sig[5]}"
|
||||||
|
@ -378,7 +375,7 @@ verify(){
|
||||||
done <<< "$tag_sigs"
|
done <<< "$tag_sigs"
|
||||||
|
|
||||||
note_sigs=$(verify_git_notes "$ref") && \
|
note_sigs=$(verify_git_notes "$ref") && \
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
IFS=':' read -r -a sig <<< "$line"
|
IFS=':' read -r -a sig <<< "$line"
|
||||||
fp="${sig[1]}"
|
fp="${sig[1]}"
|
||||||
uid="${sig[5]}"
|
uid="${sig[5]}"
|
||||||
|
@ -387,7 +384,7 @@ verify(){
|
||||||
echo "Error: $error";
|
echo "Error: $error";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
echo "Verified signed git note commit by \"${uid}\""
|
echo "Verified signed git note by \"${uid}\""
|
||||||
if [[ "${seen_fps}" != *"${fp}"* ]]; then
|
if [[ "${seen_fps}" != *"${fp}"* ]]; then
|
||||||
seen_fps+=" ${fp}"
|
seen_fps+=" ${fp}"
|
||||||
fi
|
fi
|
||||||
|
@ -423,7 +420,7 @@ get_temp(){
|
||||||
## Add signed tag pointing at this commit.
|
## Add signed tag pointing at this commit.
|
||||||
## Optionally push to origin.
|
## Optionally push to origin.
|
||||||
sign_tag(){
|
sign_tag(){
|
||||||
[ -d '.git' ] \
|
git rev-parse --git-dir >/dev/null 2>&1 \
|
||||||
|| die "Not a git repository"
|
|| die "Not a git repository"
|
||||||
command -v git >/dev/null \
|
command -v git >/dev/null \
|
||||||
|| die "Git not installed"
|
|| die "Git not installed"
|
||||||
|
@ -443,7 +440,7 @@ sign_tag(){
|
||||||
## Add signed git note to this commit
|
## Add signed git note to this commit
|
||||||
## Optionally push to origin.
|
## Optionally push to origin.
|
||||||
sign_note() {
|
sign_note() {
|
||||||
[ -d '.git' ] \
|
git rev-parse --git-dir >/dev/null 2>&1 \
|
||||||
|| die "Not a git repository"
|
|| die "Not a git repository"
|
||||||
command -v git >/dev/null \
|
command -v git >/dev/null \
|
||||||
|| die "Git not installed"
|
|| die "Git not installed"
|
||||||
|
@ -461,17 +458,21 @@ sign_note() {
|
||||||
[[ "$push" -eq "0" ]] || $PROGRAM push
|
[[ "$push" -eq "0" ]] || $PROGRAM push
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
## Public Commands
|
## Public Commands
|
||||||
|
|
||||||
|
cmd_remove() {
|
||||||
|
git notes --ref signatures remove
|
||||||
|
}
|
||||||
|
|
||||||
cmd_verify() {
|
cmd_verify() {
|
||||||
local opts threshold=1 group="" method="" diff=""
|
local opts threshold=1 remote="origin" group="" method="" diff=""
|
||||||
opts="$(getopt -o t:g:m:d:: -l threshold:,group:,ref:,diff:: -n "$PROGRAM" -- "$@")"
|
opts="$(getopt -o t:g:m:o:d:: -l threshold:,group:,ref:,remote:,diff:: -n "$PROGRAM" -- "$@")"
|
||||||
eval set -- "$opts"
|
eval set -- "$opts"
|
||||||
while true; do case $1 in
|
while true; do case $1 in
|
||||||
-t|--threshold) threshold="$2"; shift 2 ;;
|
-t|--threshold) threshold="$2"; shift 2 ;;
|
||||||
-g|--group) group="$2"; shift 2 ;;
|
-g|--group) group="$2"; shift 2 ;;
|
||||||
-r|--ref) ref="$2"; shift 2 ;;
|
-r|--ref) ref="$2"; shift 2 ;;
|
||||||
|
-o|--remote) remote="$2"; shift 2 ;;
|
||||||
-d|--diff) diff="1"; shift 2 ;;
|
-d|--diff) diff="1"; shift 2 ;;
|
||||||
--) shift; break ;;
|
--) shift; break ;;
|
||||||
esac done
|
esac done
|
||||||
|
@ -498,48 +499,6 @@ cmd_verify() {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_fetch() {
|
|
||||||
local opts group="" group_fps=""
|
|
||||||
opts="$(getopt -o g: -l group: -n "$PROGRAM" -- "$@")"
|
|
||||||
eval set -- "$opts"
|
|
||||||
while true; do case $1 in
|
|
||||||
-g|--group) group="${2:-1}"; shift 2 ;;
|
|
||||||
--) shift; break ;;
|
|
||||||
esac done
|
|
||||||
[ $# -eq 1 ] || \
|
|
||||||
die "Usage: $PROGRAM fetch <fingerprint> [-g,--group=<group>]"
|
|
||||||
local -r fingerprint=${1}
|
|
||||||
|
|
||||||
if [ -n "$group" ]; then
|
|
||||||
group_fps=$(group_get_fps "${group_name}")
|
|
||||||
if [[ "${group_fps}" == *"${fingerprint}"* ]]; then
|
|
||||||
echo "Key \"${fingerprint}\" is already in group \"${group}\""
|
|
||||||
else
|
|
||||||
group_add_fp "${fingerprint}" "${group}"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
gpg --list-keys "${fingerprint}" > /dev/null 2>&1 \
|
|
||||||
&& echo "Key \"${fingerprint}\" is already in local keychain" \
|
|
||||||
&& return 0
|
|
||||||
|
|
||||||
echo "Requested key is not in keyring. Trying keyservers..."
|
|
||||||
for server in \
|
|
||||||
ha.pool.sks-keyservers.net \
|
|
||||||
hkp://keyserver.ubuntu.com:80 \
|
|
||||||
hkp://p80.pool.sks-keyservers.net:80 \
|
|
||||||
pgp.mit.edu \
|
|
||||||
; do
|
|
||||||
echo "Fetching key \"${fingerprint}\" from \"${server}\"";
|
|
||||||
gpg \
|
|
||||||
--recv-key \
|
|
||||||
--keyserver "$server" \
|
|
||||||
--keyserver-options timeout=10 \
|
|
||||||
--recv-keys "${fingerprint}" \
|
|
||||||
&& break
|
|
||||||
done
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd_add(){
|
cmd_add(){
|
||||||
local opts method="" push="0"
|
local opts method="" push="0"
|
||||||
opts="$(getopt -o m:p:: -l method:,push:: -n "$PROGRAM" -- "$@")"
|
opts="$(getopt -o m:p:: -l method:,push:: -n "$PROGRAM" -- "$@")"
|
||||||
|
@ -550,27 +509,44 @@ cmd_add(){
|
||||||
--) shift; break ;;
|
--) shift; break ;;
|
||||||
esac done
|
esac done
|
||||||
case $method in
|
case $method in
|
||||||
git) sign_note "$push" ;;
|
note) sign_note "$push" ;;
|
||||||
|
tag) sign_tag "$push" ;;
|
||||||
*) sign_note "$push" ;;
|
*) sign_note "$push" ;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_push() {
|
cmd_push() {
|
||||||
[ "$#" -eq 0 ] || { usage push; exit 1; }
|
local opts remote="origin" push="0"
|
||||||
git fetch origin refs/notes/signatures:refs/notes/origin/signatures
|
opts="$(getopt -o r: -l remote: -n "$PROGRAM" -- "$@")"
|
||||||
git notes --ref signatures merge -s cat_sort_uniq origin/signatures
|
eval set -- "$opts"
|
||||||
git push --tags origin refs/notes/signatures
|
while true; do case $1 in
|
||||||
|
-r|--remote) remote="$2"; shift 2 ;;
|
||||||
|
--) shift; break ;;
|
||||||
|
esac done
|
||||||
|
git push --tags "$remote" refs/notes/signatures
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd_pull() {
|
||||||
|
local opts remote="origin"
|
||||||
|
opts="$(getopt -o r: -l remote: -n "$PROGRAM" -- "$@")"
|
||||||
|
eval set -- "$opts"
|
||||||
|
while true; do case $1 in
|
||||||
|
-r|--remote) remote="$2"; shift 2 ;;
|
||||||
|
--) shift; break ;;
|
||||||
|
esac done
|
||||||
|
git fetch "$remote" refs/notes/signatures:refs/notes/${remote}/signatures
|
||||||
|
git notes --ref signatures merge -s cat_sort_uniq "${remote}"/signatures
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd_version() {
|
cmd_version() {
|
||||||
cat <<-_EOF
|
cat <<-_EOF
|
||||||
==============================================
|
==========================================
|
||||||
= sig: simple multisig trust toolchain =
|
= git-sig: multisig trust for git =
|
||||||
= =
|
= =
|
||||||
= v0.2 =
|
= v0.4 =
|
||||||
= =
|
= =
|
||||||
= https://github.com/distrust-foundation/sig =
|
= https://codeberg.org/distrust/git-sig =
|
||||||
==============================================
|
==========================================
|
||||||
_EOF
|
_EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -578,21 +554,25 @@ cmd_usage() {
|
||||||
cmd_version
|
cmd_version
|
||||||
cat <<-_EOF
|
cat <<-_EOF
|
||||||
Usage:
|
Usage:
|
||||||
$PROGRAM add [-m,--method=<note|tag>] [-p,--push]
|
git sig add [-m,--method=<note|tag>] [-p,--push]
|
||||||
Add signature for this repository
|
Add signature for this repository
|
||||||
$PROGRAM verify [-g,--group=<group>] [-t,--threshold=<N>] [d,--diff=<branch>]
|
git sig remove
|
||||||
|
Remove all signatures on current ref
|
||||||
|
git sig verify [-g,--group=<group>] [-t,--threshold=<N>] [d,--diff=<branch>]
|
||||||
Verify m-of-n signatures by given group are present for directory.
|
Verify m-of-n signatures by given group are present for directory.
|
||||||
$PROGRAM fetch [-g,--group=<group>]
|
git sig push [-r,--remote=<remote>]
|
||||||
Fetch key by fingerprint. Optionally add to group.
|
Push all signatures on current ref
|
||||||
$PROGRAM help
|
git sig pull [-r,--remote=<remote>]
|
||||||
|
Pull all signatures for current ref
|
||||||
|
git sig help
|
||||||
Show this text.
|
Show this text.
|
||||||
$PROGRAM version
|
git sig version
|
||||||
Show version information.
|
Show version information.
|
||||||
_EOF
|
_EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
# Verify all tools in this list are installed at needed versions
|
# Verify all tools in this list are installed at needed versions
|
||||||
check_tools git head cut find sort sed getopt gpg openssl
|
check_tools git head cut find sort sed getopt openssl ${GIT_SIG_VERIFY_COMMAND}
|
||||||
|
|
||||||
# Allow entire script to be namespaced based on filename
|
# Allow entire script to be namespaced based on filename
|
||||||
readonly PROGRAM="${0##*/}"
|
readonly PROGRAM="${0##*/}"
|
||||||
|
@ -601,8 +581,9 @@ readonly PROGRAM="${0##*/}"
|
||||||
case "$1" in
|
case "$1" in
|
||||||
verify) shift; cmd_verify "$@" ;;
|
verify) shift; cmd_verify "$@" ;;
|
||||||
add) shift; cmd_add "$@" ;;
|
add) shift; cmd_add "$@" ;;
|
||||||
fetch) shift; cmd_fetch "$@" ;;
|
remove) shift; cmd_remove "$@" ;;
|
||||||
push) shift; cmd_push "$@" ;;
|
push) shift; cmd_push "$@" ;;
|
||||||
|
pull) shift; cmd_pull "$@" ;;
|
||||||
version|--version) shift; cmd_version "$@" ;;
|
version|--version) shift; cmd_version "$@" ;;
|
||||||
help|--help) shift; cmd_usage "$@" ;;
|
help|--help) shift; cmd_usage "$@" ;;
|
||||||
*) cmd_usage "$@" ;;
|
*) cmd_usage "$@" ;;
|
|
@ -1,38 +1,38 @@
|
||||||
load test_helper
|
load test_helper
|
||||||
|
|
||||||
@test "Outputs help if run without arguments" {
|
@test "Outputs help if run without arguments" {
|
||||||
run sig
|
run git-sig
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
echo "${output}" | grep "simple multisig trust toolchain"
|
echo "${output}" | grep "multisig trust for git"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Outputs help if run with help" {
|
@test "Outputs help if run with help" {
|
||||||
run sig help
|
run git-sig help
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
echo "${output}" | grep "simple multisig trust toolchain"
|
echo "${output}" | grep "multisig trust for git"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Outputs version if run with version" {
|
@test "Outputs version if run with version" {
|
||||||
run sig version
|
run git-sig version
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
echo "${output}" | grep "v0.2"
|
echo "${output}" | grep "v0.3"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Outputs advice to install missing openssl" {
|
@test "Outputs advice to install missing openssl" {
|
||||||
sudo rm /usr/bin/openssl
|
sudo rm /usr/bin/openssl
|
||||||
run sig version
|
run git-sig version
|
||||||
echo "${output}" | grep "apt install openssl"
|
echo "${output}" | grep "apt install openssl"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Outputs advice to install missing gpg" {
|
@test "Outputs advice to install missing gpg" {
|
||||||
sudo rm /usr/bin/gpg
|
sudo rm /usr/bin/gpg
|
||||||
run sig version
|
run git-sig version
|
||||||
echo "${output}" | grep "apt install gnupg"
|
echo "${output}" | grep "apt install gnupg"
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Outputs advice to install missing getopt" {
|
@test "Outputs advice to install missing getopt" {
|
||||||
sudo rm /usr/bin/getopt
|
sudo rm /usr/bin/getopt
|
||||||
run sig version
|
run git-sig version
|
||||||
echo "${output}" | grep "apt install getopt"
|
echo "${output}" | grep "apt install getopt"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,26 +43,26 @@ load test_helper
|
||||||
git add .
|
git add .
|
||||||
git commit -m "initial commit"
|
git commit -m "initial commit"
|
||||||
echo "dirty" > somefile
|
echo "dirty" > somefile
|
||||||
run sig verify
|
run git-sig verify
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Exit 1 if git method requested but not a repo" {
|
@test "Exit 1 if git method requested but not a repo" {
|
||||||
run sig verify
|
run git-sig verify
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Verify succeeds when 1 unique git sig requirement is satisfied" {
|
@test "Verify succeeds when 1 unique git git-sig requirement is satisfied" {
|
||||||
set_identity "user1"
|
set_identity "user1"
|
||||||
echo "test string" > somefile
|
echo "test string" > somefile
|
||||||
git init
|
git init
|
||||||
git add .
|
git add .
|
||||||
git commit -m "initial commit"
|
git commit -m "initial commit"
|
||||||
run sig verify
|
run git-sig verify
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Verify succeeds when 3 unique git sig requirement is satisfied" {
|
@test "Verify succeeds when 3 unique git git-sig requirement is satisfied" {
|
||||||
git init
|
git init
|
||||||
set_identity "user1"
|
set_identity "user1"
|
||||||
echo "test string 1" > somefile1
|
echo "test string 1" > somefile1
|
||||||
|
@ -70,60 +70,60 @@ load test_helper
|
||||||
git commit -m "user1 commit"
|
git commit -m "user1 commit"
|
||||||
set_identity "user2"
|
set_identity "user2"
|
||||||
git log
|
git log
|
||||||
sig add
|
git-sig add
|
||||||
set_identity "user3"
|
set_identity "user3"
|
||||||
sig add
|
git-sig add
|
||||||
run sig verify --threshold 3
|
run git-sig verify --threshold 3
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Verify fails when 2 unique git sig requirement is not satisfied" {
|
@test "Verify fails when 2 unique git git-sig requirement is not satisfied" {
|
||||||
git init
|
git init
|
||||||
set_identity "user1"
|
set_identity "user1"
|
||||||
echo "test string 1" > somefile1
|
echo "test string 1" > somefile1
|
||||||
git add .
|
git add .
|
||||||
git commit -m "user1 commit"
|
git commit -m "user1 commit"
|
||||||
sig add
|
git-sig add
|
||||||
run sig verify --threshold 2
|
run git-sig verify --threshold 2
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Verify succeeds when 1 group git sig requirement is satisifed" {
|
@test "Verify succeeds when 1 group git git-sig requirement is satisifed" {
|
||||||
set_identity "user1"
|
set_identity "user1"
|
||||||
echo "test string" > somefile
|
echo "test string" > somefile
|
||||||
git init
|
git init
|
||||||
git add .
|
git add .
|
||||||
git commit -m "initial commit"
|
git commit -m "initial commit"
|
||||||
sig fetch --group maintainers AE08157232C35F04309FA478C5EBC4A7CF55A2D0
|
git-sig fetch --group maintainers AE08157232C35F04309FA478C5EBC4A7CF55A2D0
|
||||||
run sig verify --group maintainers
|
run git-sig verify --group maintainers
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Verify succeeds when 3 group git sig requirement is satisifed" {
|
@test "Verify succeeds when 3 group git git-sig requirement is satisifed" {
|
||||||
set_identity "user1"
|
set_identity "user1"
|
||||||
echo "test string" > somefile1
|
echo "test string" > somefile1
|
||||||
git init
|
git init
|
||||||
git add .
|
git add .
|
||||||
git commit -m "User 1 Commit"
|
git commit -m "User 1 Commit"
|
||||||
set_identity "user2"
|
set_identity "user2"
|
||||||
sig add
|
git-sig add
|
||||||
set_identity "user3"
|
set_identity "user3"
|
||||||
sig add
|
git-sig add
|
||||||
sig fetch --group maintainers AE08157232C35F04309FA478C5EBC4A7CF55A2D0
|
git-sig fetch --group maintainers AE08157232C35F04309FA478C5EBC4A7CF55A2D0
|
||||||
sig fetch --group maintainers BE4D60F6CFD2237A8AF978583C51CADD33BD0EE8
|
git-sig fetch --group maintainers BE4D60F6CFD2237A8AF978583C51CADD33BD0EE8
|
||||||
sig fetch --group maintainers 3E45AC9E190B4EE32BAE9F61A331AFB540761D69
|
git-sig fetch --group maintainers 3E45AC9E190B4EE32BAE9F61A331AFB540761D69
|
||||||
run sig verify --threshold 3 --group maintainers
|
run git-sig verify --threshold 3 --group maintainers
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
@test "Verify fails when 2 group git sig requirement is not satisifed" {
|
@test "Verify fails when 2 group git git-sig requirement is not satisifed" {
|
||||||
set_identity "user1"
|
set_identity "user1"
|
||||||
echo "test string" > somefile
|
echo "test string" > somefile
|
||||||
git init
|
git init
|
||||||
git add .
|
git add .
|
||||||
git commit -m "initial commit"
|
git commit -m "initial commit"
|
||||||
sig fetch --group maintainers AE08157232C35F04309FA478C5EBC4A7CF55A2D0
|
git-sig fetch --group maintainers AE08157232C35F04309FA478C5EBC4A7CF55A2D0
|
||||||
run sig verify --threshold 2 --group maintainers
|
run git-sig verify --threshold 2 --group maintainers
|
||||||
[ "$status" -eq 1 ]
|
[ "$status" -eq 1 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,14 +136,14 @@ load test_helper
|
||||||
git commit -m "User 1 Commit"
|
git commit -m "User 1 Commit"
|
||||||
|
|
||||||
set_identity "user2"
|
set_identity "user2"
|
||||||
sig add
|
git-sig add
|
||||||
|
|
||||||
set_identity "user1"
|
set_identity "user1"
|
||||||
echo "updated test string" > somefile1
|
echo "updated test string" > somefile1
|
||||||
git add .
|
git add .
|
||||||
git commit -m "User 1 Update Commit"
|
git commit -m "User 1 Update Commit"
|
||||||
|
|
||||||
run sig verify --threshold 2 --ref HEAD~1
|
run git-sig verify --threshold 2 --ref HEAD~1
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ load test_helper
|
||||||
git commit -m "User 1 Commit"
|
git commit -m "User 1 Commit"
|
||||||
|
|
||||||
set_identity "user2"
|
set_identity "user2"
|
||||||
sig add
|
git-sig add
|
||||||
|
|
||||||
set_identity "user1"
|
set_identity "user1"
|
||||||
git checkout -b feature_branch
|
git checkout -b feature_branch
|
||||||
|
@ -164,7 +164,7 @@ load test_helper
|
||||||
git add .
|
git add .
|
||||||
git commit -m "User 1 Update Commit"
|
git commit -m "User 1 Update Commit"
|
||||||
|
|
||||||
run sig verify --diff --ref master --threshold 2
|
run git-sig verify --diff --ref master --threshold 2
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
echo "${output}" | grep "updated test string"
|
echo "${output}" | grep "updated test string"
|
||||||
}
|
}
|
||||||
|
@ -178,10 +178,10 @@ load test_helper
|
||||||
git commit -m "User 1 Commit 1"
|
git commit -m "User 1 Commit 1"
|
||||||
|
|
||||||
set_identity "user2"
|
set_identity "user2"
|
||||||
sig add
|
git-sig add
|
||||||
|
|
||||||
set_identity "user3"
|
set_identity "user3"
|
||||||
sig add
|
git-sig add
|
||||||
|
|
||||||
set_identity "user1"
|
set_identity "user1"
|
||||||
echo "test string 2" > testfile
|
echo "test string 2" > testfile
|
||||||
|
@ -189,7 +189,7 @@ load test_helper
|
||||||
git commit -m "User 1 Commit 2"
|
git commit -m "User 1 Commit 2"
|
||||||
|
|
||||||
set_identity "user2"
|
set_identity "user2"
|
||||||
sig add
|
git-sig add
|
||||||
|
|
||||||
set_identity "user1"
|
set_identity "user1"
|
||||||
git checkout -b feature_branch
|
git checkout -b feature_branch
|
||||||
|
@ -197,7 +197,7 @@ load test_helper
|
||||||
git add .
|
git add .
|
||||||
git commit -m "User 1 Commit 3"
|
git commit -m "User 1 Commit 3"
|
||||||
|
|
||||||
run sig verify --diff --threshold 3
|
run git-sig verify --diff --threshold 3
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
echo "${output}" | grep "updated test string"
|
echo "${output}" | grep "updated test string"
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ setup(){
|
||||||
bin_dir=/tmp/bin
|
bin_dir=/tmp/bin
|
||||||
temp_dir=$(mktemp -d -t test-XXXXXXXXXX)
|
temp_dir=$(mktemp -d -t test-XXXXXXXXXX)
|
||||||
mkdir -p /tmp/bin
|
mkdir -p /tmp/bin
|
||||||
ln -sfn /home/test/sig/sig /tmp/bin/sig
|
ln -sfn /home/test/sig/git-sig /tmp/bin/git-sig
|
||||||
export PATH=${bin_dir}:${PATH}
|
export PATH=${bin_dir}:${PATH}
|
||||||
cd "$temp_dir" || return 1
|
cd "$temp_dir" || return 1
|
||||||
rm -rf ~/.gnupg
|
rm -rf ~/.gnupg
|
||||||
|
|
Loading…
Reference in New Issue