commit 7ea4c34c68e07b6b7031ef4c6afcb085e66d93fc
parent b2b89b3e1ec123f050e1417fe46a79966b0410bd
Author: Natasha Kerensikova <natgh@instinctive.eu>
Date: Sat, 21 Sep 2024 15:32:37 +0000
pass-like behavior is fully tested
Diffstat:
2 files changed, 729 insertions(+), 32 deletions(-)
diff --git a/spec/pass_spec.sh b/spec/pass_spec.sh
@@ -25,10 +25,10 @@
# to check the store behavior.
# So it only works when using shellspec with bash and calling the `pass`
# script directly (e.g. on FreeBSD `/usr/local/libexec/password-store/pass`
-# instead of `/usr/local/bin/pass`.
+# instead of `/usr/local/bin/pass`).
Parameters # script/path scriptname encryption
- /usr/bin/pass pass gpg
+# /usr/bin/pass pass gpg
./src/run.sh pashage age
End
@@ -52,6 +52,8 @@ Describe 'Pass-like command'
#|Initial setup
#|
#| .gpg-id | 1 +
+ #| extra/subdir/file.age | 2 ++
+ #| extra/subdir/file.gpg | 2 ++
#| fluff/.age-recipients | 2 ++
#| fluff/.gpg-id | 2 ++
#| fluff/one.age | 3 +++
@@ -62,9 +64,11 @@ Describe 'Pass-like command'
#| fluff/two.gpg | 4 ++++
#| shared/.age-recipients | 2 ++
#| shared/.gpg-id | 2 ++
+ #| stale.age | 3 +++
+ #| stale.gpg | 3 +++
#| subdir/file.age | 2 ++
#| subdir/file.gpg | 2 ++
- #| 13 files changed, 37 insertions(+)
+ #| 17 files changed, 47 insertions(+)
}
setup_id() {
@@ -74,7 +78,7 @@ Describe 'Pass-like command'
}
setup_secret() {
- @mkdir -p "${PREFIX}/${1%/*}"
+ [ "$1" = "${1%/*}" ] || @mkdir -p "${PREFIX}/${1%/*}"
@sed 's/^/age/' >"${PREFIX}/$1.age"
@sed 's/^age/gpg/' "${PREFIX}/$1.age" >"${PREFIX}/$1.gpg"
}
@@ -88,6 +92,9 @@ Describe 'Pass-like command'
%text | setup_secret 'subdir/file'
#|Recipient:myself
#|:p4ssw0rd
+ %text | setup_secret 'extra/subdir/file'
+ #|Recipient:myself
+ #|:Pa55worD
%text | setup_id 'shared'
#|myself
#|friend
@@ -109,6 +116,10 @@ Describe 'Pass-like command'
#|:3-password
#|:Username: 3Jane
#|:URL: https://example.com/login
+ %text | setup_secret 'stale'
+ #|Recipient:master
+ #|Recipient:myself
+ #|:0-password
@git -C "${PREFIX}" add .
@git -C "${PREFIX}" commit -m 'Initial setup' >/dev/null
@@ -142,15 +153,37 @@ Describe 'Pass-like command'
@cat "$@"
End
+ Mock cp
+ @cp "$@"
+ End
+
Mock cut
. "${SHELLSPEC_SUPPORT_BIN}"
invoke cut "$@"
End
+ Mock dd
+ . "${SHELLSPEC_SUPPORT_BIN}"
+ invoke dd "$@"
+ End
+
+ Mock diff
+ @diff "$@"
+ End
+
Mock dirname
@dirname "$@"
End
+ Mock ed
+ . "${SHELLSPEC_SUPPORT_BIN}"
+ if [ "${1-}" = '-c' ]; then
+ shift
+ invoke touch "$@"
+ fi
+ invoke ed "$@"
+ End
+
Mock feh
printf '$ feh %s\n' "$*" >&2
@cat >&2
@@ -195,6 +228,11 @@ Describe 'Pass-like command'
invoke od -v -t x1 | sed 's/ */ /g;s/ *$//' >&2
End
+ Mock mktemp
+ . "${SHELLSPEC_SUPPORT_BIN}"
+ invoke mktemp "$@"
+ End
+
Mock rm
@rm "$@"
End
@@ -248,7 +286,137 @@ Describe 'Pass-like command'
fi
End
- #TODO: init
+ Describe 'init'
+ It 're-encrypts the whole store using a new recipient id'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 init 'new-id'
+ The output should include 'Password store'
+ expected_log() {
+ if [ "$2" = pashage ]; then
+ %text
+ #|Set age recipients at store root
+ #|
+ #| .age-recipients | 1 +
+ #| extra/subdir/file.age | 2 +-
+ #| stale.age | 3 +--
+ #| subdir/file.age | 2 +-
+ #| 4 files changed, 4 insertions(+), 4 deletions(-)
+ else
+ %text:expand
+ #|Reencrypt password store using new GPG id new-id.
+ #|
+ #| extra/subdir/file.$1 | 2 +-
+ #| stale.$1 | 3 +--
+ #| subdir/file.$1 | 2 +-
+ #| 3 files changed, 3 insertions(+), 4 deletions(-)
+ #|Set GPG id to new-id.
+ #|
+ #| .gpg-id | 2 +-
+ #| 1 file changed, 1 insertion(+), 1 deletion(-)
+ fi
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3 $2)"
+ End
+
+ It 're-encrypts a subdirectory using a new recipient id'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 init -p subdir 'new-id'
+ The output should start with 'Password store'
+ The output should include 'subdir'
+ expected_log() {
+ if [ "$2" = pashage ]; then
+ %text
+ #|Set age recipients at subdir
+ #|
+ #| subdir/.age-recipients | 1 +
+ #| subdir/file.age | 2 +-
+ #| 2 files changed, 2 insertions(+), 1 deletion(-)
+ else
+ %text:expand
+ #|Reencrypt password store using new GPG id new-id (subdir).
+ #|
+ #| subdir/file.$1 | 2 +-
+ #| 1 file changed, 1 insertion(+), 1 deletion(-)
+ #|Set GPG id to new-id (subdir).
+ #|
+ #| subdir/.gpg-id | 1 +
+ #| 1 file changed, 1 insertion(+)
+ fi
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3 $2)"
+ End
+
+ It 're-encrypts a subdirectory after replacing recipient ids'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 init -p fluff 'new-id' 'new-master'
+ The output should start with 'Password store'
+ The output should include 'fluff'
+ expected_log() {
+ if [ "$2" = pashage ]; then
+ %text
+ #|Set age recipients at fluff
+ #|
+ #| fluff/.age-recipients | 4 ++--
+ #| fluff/one.age | 4 ++--
+ #| fluff/three.age | 4 ++--
+ #| fluff/two.age | 4 ++--
+ #| 4 files changed, 8 insertions(+), 8 deletions(-)
+ else
+ %text:expand
+ #|Reencrypt password store using new GPG id new-id, new-master (fluff).
+ #|
+ #| fluff/one.$1 | 4 ++--
+ #| fluff/three.$1 | 4 ++--
+ #| fluff/two.$1 | 4 ++--
+ #| 3 files changed, 6 insertions(+), 6 deletions(-)
+ #|Set GPG id to new-id, new-master (fluff).
+ #|
+ #| fluff/.gpg-id | 4 ++--
+ #| 1 file changed, 2 insertions(+), 2 deletions(-)
+ fi
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3 $2)"
+ End
+
+ It 're-encrypts a subdirectory after removing dedicated recipient ids'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 init -p fluff ''
+ The status should be successful
+ expected_log() {
+ if [ "$2" = pashage ]; then
+ %text
+ #|Deinitialize fluff
+ #|
+ #| fluff/.age-recipients | 2 --
+ #| fluff/one.age | 1 -
+ #| fluff/three.age | 1 -
+ #| fluff/two.age | 1 -
+ #| 4 files changed, 5 deletions(-)
+ else
+ %text:expand
+ #|Reencrypt password store using new GPG id (fluff).
+ #|
+ #| fluff/one.$1 | 1 -
+ #| fluff/three.$1 | 1 -
+ #| fluff/two.$1 | 1 -
+ #| 3 files changed, 3 deletions(-)
+ #|Deinitialize ${PREFIX}/fluff/.gpg-id (fluff).
+ #|
+ #| fluff/.gpg-id | 2 --
+ #| 1 file changed, 2 deletions(-)
+ fi
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3 $2)"
+ End
+ End
Describe 'ls'
It 'lists a directory'
@@ -276,17 +444,23 @@ Describe 'Pass-like command'
Skip if 'pass needs bash' check_skip $1
When run script $1
The line 1 of output should equal 'Password Store'
- The line 2 of output should include 'fluff'
- The line 3 of output should include 'one'
- The line 4 of output should include 'one'
- The line 5 of output should include 'three'
- The line 6 of output should include 'three'
- The line 7 of output should include 'two'
- The line 8 of output should include 'two'
- The line 9 of output should include 'shared'
- The line 10 of output should include 'subdir'
- The line 11 of output should include 'file'
- The line 12 of output should include 'file'
+ The line 2 of output should include 'extra'
+ The line 3 of output should include 'subdir'
+ The line 4 of output should include 'file'
+ The line 5 of output should include 'file'
+ The line 6 of output should include 'fluff'
+ The line 7 of output should include 'one'
+ The line 8 of output should include 'one'
+ The line 9 of output should include 'three'
+ The line 10 of output should include 'three'
+ The line 11 of output should include 'two'
+ The line 12 of output should include 'two'
+ The line 13 of output should include 'shared'
+ The line 14 of output should include 'stale'
+ The line 15 of output should include 'stale'
+ The line 16 of output should include 'subdir'
+ The line 17 of output should include 'file'
+ The line 18 of output should include 'file'
End
It 'does not list a file masquerading as a directory'
@@ -518,8 +692,247 @@ Describe 'Pass-like command'
End
End
- #TODO: edit
- #TODO: generate
+ Describe 'edit'
+ EDITOR=ed
+ TERM=dumb
+
+ It 'creates a file using EDITOR'
+ EDITOR='ed -c'
+ Skip if 'pass needs bash' check_skip $1
+ Data
+ #|a
+ #|New password
+ #|New annotation
+ #|.
+ #|wq
+ End
+ When run script $1 edit subdir/new
+ The file "${PREFIX}/subdir/new.$3" should be exist
+ expected_file() { %text:expand
+ #|$1Recipient:myself
+ #|$1:New password
+ #|$1:New annotation
+ }
+ The contents of file "${PREFIX}/subdir/new.$3" should \
+ equal "$(expected_file "$3")"
+ expected_log() { %text:expand
+ #|Add password for subdir/new using ed -c.
+ #|
+ #| subdir/new.$1 | 3 +++
+ #| 1 file changed, 3 insertions(+)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3)"
+ End
+
+ It 'updates a file using EDITOR'
+ Skip if 'pass needs bash' check_skip $1
+ Data
+ #|2i
+ #|New line
+ #|.
+ #|wq
+ End
+ When run script $1 edit fluff/two
+ expected_file() { %text:expand
+ #|$1Recipient:master
+ #|$1Recipient:myself
+ #|$1:2-password
+ #|$1:New line
+ #|$1:URL: https://example.com/login
+ }
+ The contents of file "${PREFIX}/fluff/two.$3" should \
+ equal "$(expected_file "$3")"
+ expected_log() { %text:expand
+ #|Edit password for fluff/two using ed.
+ #|
+ #| fluff/two.$1 | 1 +
+ #| 1 file changed, 1 insertion(+)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3)"
+ End
+
+ It 'reencrypts an updated file using EDITOR'
+ Skip if 'pass needs bash' check_skip $1
+ Data
+ #|a
+ #|New option
+ #|.
+ #|wq
+ End
+ When run script $1 edit stale
+ expected_file() { %text:expand
+ #|$1Recipient:myself
+ #|$1:0-password
+ #|$1:New option
+ }
+ The contents of file "${PREFIX}/stale.$3" should \
+ equal "$(expected_file "$3")"
+ expected_log() { %text:expand
+ #|Edit password for stale using ed.
+ #|
+ #| stale.$1 | 2 +-
+ #| 1 file changed, 1 insertion(+), 1 deletion(-)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3)"
+ End
+
+ It 'does not reencrypt an unchanged file using EDITOR'
+ Skip if 'pass needs bash' check_skip $1
+ Data 'q'
+ When run script $1 edit stale
+ expected_file() { %text:expand
+ #|$1Recipient:master
+ #|$1Recipient:myself
+ #|$1:0-password
+ }
+ The contents of file "${PREFIX}/stale.$3" should \
+ equal "$(expected_file "$3")"
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(setup_log)"
+ End
+
+ It 'allows cancelling file creation'
+ Skip if 'pass needs bash' check_skip $1
+ Data 'q'
+ When run script $1 edit subdir/new
+ The status should be successful
+ The file "${PREFIX}/subdir/new.age" should not be exist
+ The file "${PREFIX}/subdir/new.gpg" should not be exist
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(setup_log)"
+ End
+ End
+
+ Describe 'generate'
+ It 'generates a new file'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 generate newdir/newfile
+ The output should include 'The generated password for'
+ The file "${PREFIX}/newdir/newfile.$3" should be exist
+ The lines of contents of file "${PREFIX}/newdir/newfile.$3" should \
+ equal 2
+ The line 1 of contents of file "${PREFIX}/newdir/newfile.$3" should \
+ equal "$3Recipient:myself"
+ The output should \
+ include "$(@sed -n "2s/$3://p" "${PREFIX}/newdir/newfile.$3")"
+ expected_log() { %text:expand
+ #|Add generated password for newdir/newfile.
+ #|
+ #| newdir/newfile.$1 | 2 ++
+ #| 1 file changed, 2 insertions(+)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3)"
+ End
+
+ It 'generates a new file without symbols'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 generate -n newfile 4
+ The output should include 'The generated password for'
+ The file "${PREFIX}/newfile.$3" should be exist
+ The lines of contents of file "${PREFIX}/newfile.$3" should \
+ equal 2
+ The line 1 of contents of file "${PREFIX}/newfile.$3" should \
+ equal "$3Recipient:myself"
+ The line 2 of contents of file "${PREFIX}/newfile.$3" should \
+ match pattern "$3:[0-9a-zA-z][0-9a-zA-z][0-9a-zA-z][0-9a-zA-z]"
+ The output should \
+ include "$(@sed -n "2s/$3://p" "${PREFIX}/newfile.$3")"
+ expected_log() { %text:expand
+ #|Add generated password for newfile.
+ #|
+ #| newfile.$1 | 2 ++
+ #| 1 file changed, 2 insertions(+)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3)"
+ End
+
+ It 'replaces an existing file when forced'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 generate -f fluff/three 20
+ The output should include 'The generated password for'
+ The lines of contents of file "${PREFIX}/fluff/three.$3" should equal 3
+ The output should \
+ include "$(@sed -n "3s/$3://p" "${PREFIX}/fluff/three.$3")"
+ expected_log() { %text:expand
+ #|Add generated password for fluff/three.
+ #|
+ #| fluff/three.$1 | 4 +---
+ #| 1 file changed, 1 insertion(+), 3 deletions(-)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3)"
+ End
+
+ It 'replaces the first line of an existing file'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 generate -ni fluff/three 4
+ The output should include 'The generated password for'
+ The lines of contents of file "${PREFIX}/fluff/three.$3" should equal 5
+ The line 3 of contents of file "${PREFIX}/fluff/three.$3" should \
+ match pattern "$3:[0-9a-zA-z][0-9a-zA-z][0-9a-zA-z][0-9a-zA-z]"
+ The output should \
+ include "$(@sed -n "3s/$3://p" "${PREFIX}/fluff/three.$3")"
+ expected_log() { %text:expand
+ #|Replace generated password for fluff/three.
+ #|
+ #| fluff/three.$1 | 2 +-
+ #| 1 file changed, 1 insertion(+), 1 deletion(-)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3)"
+ End
+
+ It 'pastes the generated password into the clipboard'
+ DISPLAY=mock
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 generate -nc subdir/new
+ The output should not include 'The generated password for'
+ The output should not \
+ include "$(@sed -n "2s/$3://p" "${PREFIX}/subdir/new.$3")"
+ The output should include \
+ 'Copied subdir/new to clipboard. Will clear in 45 seconds.'
+ The error should start with '$ xclip -selection clipboard'
+ expected_log() { %text:expand
+ #|Add generated password for subdir/new.
+ #|
+ #| subdir/new.$1 | 2 ++
+ #| 1 file changed, 2 insertions(+)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3)"
+ End
+
+ It 'displays the generated password as a QR-code'
+ DISPLAY=mock
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 generate -qn new
+ The output should not include 'The generated password for'
+ The output should not include "$(@sed -n "2s/$3://p" "${PREFIX}/new.$3")"
+ The error should start with "$ feh -x --title $2: new -g +200+200 -"
+ expected_log() { %text:expand
+ #|Add generated password for new.
+ #|
+ #| new.$1 | 2 ++
+ #| 1 file changed, 2 insertions(+)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3)"
+ End
+ End
Describe 'rm'
It 'removes a file without confirmation when forced'
@@ -539,7 +952,38 @@ Describe 'Pass-like command'
The contents of file "${GITLOG}" should equal "$(expected_log $3)"
End
- #TODO: rm -rf
+ It 'does not remove a directory without `-r` even when forced'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 rm -f fluff
+ The error should include 'fluff/'
+ The error should include 's a directory'
+ The directory "${PREFIX}/fluff" should be exist
+ The file "${PREFIX}/fluff/one.$3" should be exist
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(setup_log)"
+ End
+
+ It 'removes a directory when forced and recursive'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 rm -rf fluff/
+ The directory "${PREFIX}/fluff" should not be exist
+ expected_log() { %text:expand
+ #|Remove fluff/ from store.
+ #|
+ #| fluff/.age-recipients | 2 --
+ #| fluff/.gpg-id | 2 --
+ #| fluff/one.age | 3 ---
+ #| fluff/one.gpg | 3 ---
+ #| fluff/three.age | 5 -----
+ #| fluff/three.gpg | 5 -----
+ #| fluff/two.age | 4 ----
+ #| fluff/two.gpg | 4 ----
+ #| 8 files changed, 28 deletions(-)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3)"
+ End
End
Describe 'mv'
@@ -721,11 +1165,241 @@ Describe 'Pass-like command'
The contents of file "${GITLOG}" should equal "$(expected_log $3 $2)"
End
- #TODO: recursive mv -f
+ It 'does not merge directories recursively'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 mv -f subdir/ extra/
+ The error should include 'subdir'
+ The error should include 'extra/'
+ The directory "${PREFIX}/subdir" should be exist
+ The file "${PREFIX}/subdir/file.$3" should be exist
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(setup_log)"
+ End
+ End
+
+ Describe 'cp'
+ It 'copies a file without reencrypting'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 cp subdir/file subdir/copy
+ The error should be blank
+ file_contents() { %text:expand
+ #|${1}Recipient:myself
+ #|${1}:p4ssw0rd
+ }
+ The contents of file "${PREFIX}/subdir/copy.$3" \
+ should equal "$(file_contents "$3")"
+ expected_log() {
+ if [ "$2" = pashage ]; then
+ %putsn 'Copy subdir/file.age to subdir/copy.age'
+ else
+ %putsn 'Copy subdir/file to subdir/copy.'
+ fi
+ %text:expand
+ #|
+ #| subdir/copy.$1 | 2 ++
+ #| 1 file changed, 2 insertions(+)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3 $2)"
+ End
+
+ It 'reencrypts a copied file'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 cp subdir/file shared/copy
+ The error should be blank
+ file_contents() { %text:expand
+ #|${1}Recipient:myself
+ #|${1}Recipient:friend
+ #|${1}:p4ssw0rd
+ }
+ The contents of file "${PREFIX}/shared/copy.$3" \
+ should equal "$(file_contents "$3")"
+ expected_log() {
+ if [ "$2" = pashage ]; then
+ %putsn 'Copy subdir/file.age to shared/copy.age'
+ else
+ %putsn 'Copy subdir/file to shared/copy.'
+ fi
+ %text:expand
+ #|
+ #| shared/copy.$1 | 3 +++
+ #| 1 file changed, 3 insertions(+)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3 $2)"
+ End
+
+ It 'reencrypts relevant files in a copied directory'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 cp subdir shared/
+ The error should be blank
+ file_contents() { %text:expand
+ #|${1}Recipient:myself
+ #|${1}Recipient:friend
+ #|${1}:p4ssw0rd
+ }
+ The contents of file "${PREFIX}/shared/subdir/file.$3" \
+ should equal "$(file_contents "$3")"
+ expected_log() {
+ if [ "$2" = pashage ]; then
+ %putsn 'Copy subdir/ to shared/subdir/'
+ else
+ %putsn 'Copy subdir to shared/.'
+ fi
+ if [ "$1" = age ]; then
+ %text:expand
+ #|
+ #| shared/subdir/file.age | 3 +++
+ #| shared/subdir/file.gpg | 2 ++
+ #| 2 files changed, 5 insertions(+)
+ else
+ %text:expand
+ #|
+ #| shared/subdir/file.age | 2 ++
+ #| shared/subdir/file.gpg | 3 +++
+ #| 2 files changed, 5 insertions(+)
+ fi
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3 $2)"
+ End
+
+ It 'copies a directory with recipients'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 cp fluff filler
+ The error should be blank
+ The directory "${PREFIX}/filler" should be exist
+ expected_log() {
+ if [ "$2" = pashage ]; then
+ %putsn 'Copy fluff/ to filler/'
+ else
+ %putsn 'Copy fluff to filler.'
+ fi
+ %text:expand
+ #|
+ #| filler/.age-recipients | 2 ++
+ #| filler/.gpg-id | 2 ++
+ #| filler/one.age | 3 +++
+ #| filler/one.gpg | 3 +++
+ #| filler/three.age | 5 +++++
+ #| filler/three.gpg | 5 +++++
+ #| filler/two.age | 4 ++++
+ #| filler/two.gpg | 4 ++++
+ #| 8 files changed, 28 insertions(+)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3 $2)"
+ End
+
+ It 'copies a directory without recipients'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 cp subdir newdir
+ The error should be blank
+ file_contents() { %text:expand
+ #|${1}Recipient:myself
+ #|${1}:p4ssw0rd
+ }
+ The contents of file "${PREFIX}/newdir/file.$3" \
+ should equal "$(file_contents "$3")"
+ expected_log() {
+ if [ "$2" = pashage ]; then
+ %putsn 'Copy subdir/ to newdir/'
+ else
+ %putsn 'Copy subdir to newdir.'
+ fi
+ %text:expand
+ #|
+ #| newdir/file.age | 2 ++
+ #| newdir/file.gpg | 2 ++
+ #| 2 files changed, 4 insertions(+)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3 $2)"
+ End
+
+ It 'overwrites an existing file when forced'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 cp -f fluff/two fluff/one
+ file_contents() { %text:expand
+ #|${1}Recipient:master
+ #|${1}Recipient:myself
+ #|${1}:2-password
+ #|${1}:URL: https://example.com/login
+ }
+ The contents of file "${PREFIX}/fluff/one.$3" \
+ should equal "$(file_contents "$3")"
+ expected_log() {
+ if [ "$2" = pashage ]; then
+ %putsn 'Copy fluff/two.age to fluff/one.age'
+ else
+ %putsn 'Copy fluff/two to fluff/one.'
+ fi
+ %text:expand
+ #|
+ #| fluff/one.$1 | 3 ++-
+ #| 1 file changed, 2 insertions(+), 1 deletion(-)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3 $2)"
+ End
+
+ It 'overwrites collisions when copying recursively and forcefully'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 cp -f subdir/ extra/
+ expected_log() {
+ if [ "$2" = pashage ]; then
+ %putsn 'Copy subdir/ to extra/subdir/'
+ else
+ %putsn 'Copy subdir/ to extra/.'
+ fi
+ %text:expand
+ #|
+ #| extra/subdir/file.age | 2 +-
+ #| extra/subdir/file.gpg | 2 +-
+ #| 2 files changed, 2 insertions(+), 2 deletions(-)
+ setup_log
+ }
+ The result of function git_log should be successful
+ The contents of file "${GITLOG}" should equal "$(expected_log $3 $2)"
+ End
End
- #TODO: cp
- #TODO: git
+ Describe 'git'
+ It 'transmits arguments to git'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 git log --format='%s' --stat
+ The output should equal "$(setup_log)"
+ End
+
+ remove_git() { rm -rf "${PREFIX}/.git"; }
+ BeforeEach remove_git
+
+ It 'fails without a git repository'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 git log
+ The status should equal 1
+ The output should be blank
+ The error should match pattern \
+ 'Error: the password store is not a git repository. Try "* git init".'
+ End
+
+ It 're-initializes the git repository'
+ Skip if 'pass needs bash' check_skip $1
+ When run script $1 git init -b trunk
+ The status should be successful
+ The output should start with \
+ "Initialized empty Git repository in ${PREFIX}/.git"
+ The error should be blank
+ The directory "${PREFIX}/.git" should be exist
+ The file "${PREFIX}/.gitattributes" should be exist
+ End
+ End
Describe 'help'
It 'displays a help text with supported commands'
diff --git a/spec/support/bin/mock-gpg b/spec/support/bin/mock-gpg
@@ -17,34 +17,57 @@ case "$1" in
-e)
shift
MOCK_AGE_OUTPUT="$(@mktemp "$(dirname "$2")/mock-gpg-encrypt.XXXXXXX")"
+ DEST='-'
while [ $# -gt 0 ]; do
case "$1" in
-r)
printf 'gpgRecipient:%s\n' "$2" >>"${MOCK_AGE_OUTPUT}"
shift 2 ;;
-o)
- @sed 's/^/gpg:/' >>"${MOCK_AGE_OUTPUT}"
- @mv -f "${MOCK_AGE_OUTPUT}" "$2"
+ DEST="$2"
shift 2
break ;;
*)
- die "Unexpected arguments togpg -e [...] $*\n"
+ die "Unexpected arguments to gpg -e [...] $*\n"
;;
esac
done
- [ $# -eq 4 ] || die "Unexpected arguments to gpg -e [...] $*\n"
+ if [ $# -lt 4 ] || [ $# -gt 5 ]; then
+ die "Unexpected arguments to gpg -e [...] $*\n"
+ fi
check_eq "$1" '--quiet' "Unexpected gpg -e \$1: \"$1\""
check_eq "$2" '--yes' "Unexpected gpg -e \$2: \"$2\""
check_eq "$3" '--compress-algo=none' "Unexpected gpg -e \$3: \"$3\""
check_eq "$4" '--no-encrypt-to' "Unexpected gpg -e \$4: \"$4\""
+ if [ $# -eq 5 ]; then
+ @sed 's/^/gpg:/' "$5" >>"${MOCK_AGE_OUTPUT}"
+ else
+ @sed 's/^/gpg:/' >>"${MOCK_AGE_OUTPUT}"
+ fi
+ if [ "${DEST}" = '-' ]; then
+ @cat "${MOCK_AGE_OUTPUT}"
+ @rm -f "${MOCK_AGE_OUTPUT}"
+ else
+ @mv -f "${MOCK_AGE_OUTPUT}" "${DEST}"
+ fi
;;
-d)
- check_eq "$2" '--quiet' "Unexpected gpg -d \$2: \"$2\""
- check_eq "$3" '--yes' "Unexpected gpg -d \$3: \"$3\""
- check_eq "$4" '--compress-algo=none' "Unexpected gpg -d \$4: \"$4\""
- check_eq "$5" '--no-encrypt-to' "Unexpected gpg -d \$5: \"$5\""
- @grep -v '^gpg' "$6" >&2 && die "Bad encrypted file \"$6\""
- @sed -n 's/^gpg://p' "$6"
+ shift
+ OUTPUT='-'
+ if [ "$1" = '-o' ]; then
+ OUTPUT="$2"
+ shift 2
+ fi
+ check_eq "$1" '--quiet' "Unexpected gpg -d \$1: \"$1\""
+ check_eq "$2" '--yes' "Unexpected gpg -d \$2: \"$2\""
+ check_eq "$3" '--compress-algo=none' "Unexpected gpg -d \$3: \"$3\""
+ check_eq "$4" '--no-encrypt-to' "Unexpected gpg -d \$4: \"$4\""
+ @grep -v '^gpg' "$5" >&2 && die "Bad encrypted file \"$5\""
+ if [ "${OUTPUT}" = '-' ]; then
+ @sed -n 's/^gpg://p' "$5"
+ else
+ @sed -n 's/^gpg://p' "$5" >|"${OUTPUT}"
+ fi
;;
--list-config)
[ $# -eq 2 ] || die "Unexpected arguments to gpg $*\n"