Merge pull request #82691 from Ma27/pass-exts

pass: don't rebuild when adding extensions, pass-audit: 0.1 -> 1.0.1
This commit is contained in:
Robin Gloster 2020-03-28 09:51:28 +00:00 committed by GitHub
commit 16c8590aa1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 409 additions and 160 deletions

View file

@ -1,6 +1,6 @@
{ stdenv, lib, pkgs, fetchurl, buildEnv
, coreutils, gnused, getopt, git, tree, gnupg, openssl, which, procps
, qrencode , makeWrapper
, qrencode , makeWrapper, pass, symlinkJoin
, xclip ? null, xdotool ? null, dmenu ? null
, x11Support ? !stdenv.isDarwin
@ -23,131 +23,136 @@ let
env = extensions:
let
selected = extensions passExtensions
selected = [ pass ] ++ extensions passExtensions
++ stdenv.lib.optional tombPluginSupport passExtensions.tomb;
in buildEnv {
name = "pass-extensions-env";
paths = selected;
buildInputs = concatMap (x: x.buildInputs) selected;
};
buildInputs = [ makeWrapper ] ++ concatMap (x: x.buildInputs) selected;
generic = extensionsEnv: extraPassthru: stdenv.mkDerivation rec {
version = "1.7.3";
pname = "password-store";
postBuild = ''
files=$(find $out/bin/ -type f -exec readlink -f {} \;)
rm $out/bin
mkdir $out/bin
src = fetchurl {
url = "https://git.zx2c4.com/password-store/snapshot/${pname}-${version}.tar.xz";
sha256 = "1x53k5dn3cdmvy8m4fqdld4hji5n676ksl0ql4armkmsds26av1b";
};
for i in $files; do
ln -sf $i $out/bin/$(basename $i)
done
patches = [ ./set-correct-program-name-for-sleep.patch ]
++ stdenv.lib.optional stdenv.isDarwin ./no-darwin-getopt.patch
# TODO (@Ma27) this patch adds support for wl-clipboard and can be removed during the next
# version bump.
++ stdenv.lib.optional waylandSupport ./clip-wayland-support.patch;
nativeBuildInputs = [ makeWrapper ];
buildInputs = [ extensionsEnv ];
installFlags = [ "PREFIX=$(out)" "WITH_ALLCOMP=yes" ];
postInstall = ''
# Install Emacs Mode. NOTE: We can't install the necessary
# dependencies (s.el and f.el) here. The user has to do this
# himself.
mkdir -p "$out/share/emacs/site-lisp"
cp "contrib/emacs/password-store.el" "$out/share/emacs/site-lisp/"
'' + optionalString x11Support ''
cp "contrib/dmenu/passmenu" "$out/bin/"
'';
wrapperPath = with stdenv.lib; makeBinPath ([
coreutils
getopt
git
gnupg
gnused
tree
which
qrencode
procps
] ++ optional stdenv.isDarwin openssl
++ ifEnable x11Support [ dmenu xclip xdotool ]
++ optional waylandSupport wl-clipboard);
postFixup = ''
# Link extensions env
rmdir $out/lib/password-store/extensions
ln -s ${extensionsEnv}/lib/password-store/extensions $out/lib/password-store/.
for f in ${extensionsEnv}/share/man/man1/*.1.gz; do
ln -s $f $out/share/man/man1/
done
# Fix program name in --help
substituteInPlace $out/bin/pass \
--replace 'PROGRAM="''${0##*/}"' "PROGRAM=pass"
# Ensure all dependencies are in PATH
wrapProgram $out/bin/pass \
--prefix PATH : "${wrapperPath}"
'' + stdenv.lib.optionalString x11Support ''
# We just wrap passmenu with the same PATH as pass. It doesn't
# need all the tools in there but it doesn't hurt either.
wrapProgram $out/bin/passmenu \
--prefix PATH : "$out/bin:${wrapperPath}"
'';
# Turn "check" into "installcheck", since we want to test our pass,
# not the one before the fixup.
postPatch = ''
patchShebangs tests
# the turning
sed -i -e 's@^PASS=.*''$@PASS=$out/bin/pass@' \
-e 's@^GPGS=.*''$@GPG=${gnupg}/bin/gpg2@' \
-e '/which gpg/ d' \
tests/setup.sh
'' + stdenv.lib.optionalString stdenv.isDarwin ''
# 'pass edit' uses hdid, which is not available from the sandbox.
rm -f tests/t0200-edit-tests.sh
rm -f tests/t0010-generate-tests.sh
rm -f tests/t0020-show-tests.sh
rm -f tests/t0050-mv-tests.sh
rm -f tests/t0100-insert-tests.sh
rm -f tests/t0300-reencryption.sh
rm -f tests/t0400-grep.sh
'';
doCheck = false;
doInstallCheck = true;
installCheckInputs = [ git ];
installCheckTarget = "test";
passthru = {
extensions = passExtensions;
} // extraPassthru;
meta = with stdenv.lib; {
description = "Stores, retrieves, generates, and synchronizes passwords securely";
homepage = https://www.passwordstore.org/;
license = licenses.gpl2Plus;
maintainers = with maintainers; [ lovek323 the-kenny fpletz tadfisher globin ];
platforms = platforms.unix;
longDescription = ''
pass is a very simple password store that keeps passwords inside gpg2
encrypted files inside a simple directory tree residing at
~/.password-store. The pass utility provides a series of commands for
manipulating the password store, allowing the user to add, remove, edit,
synchronize, generate, and manipulate passwords.
wrapProgram $out/bin/pass \
--set SYSTEM_EXTENSION_DIR "$out/lib/password-store/extensions"
'';
};
};
in
generic (env (_: [])) {
withExtensions = extensions: generic (env extensions) {};
stdenv.mkDerivation rec {
version = "1.7.3";
pname = "password-store";
src = fetchurl {
url = "https://git.zx2c4.com/password-store/snapshot/${pname}-${version}.tar.xz";
sha256 = "1x53k5dn3cdmvy8m4fqdld4hji5n676ksl0ql4armkmsds26av1b";
};
patches = [
./set-correct-program-name-for-sleep.patch
./extension-dir.patch
] ++ stdenv.lib.optional stdenv.isDarwin ./no-darwin-getopt.patch
# TODO (@Ma27) this patch adds support for wl-clipboard and can be removed during the next
# version bump.
++ stdenv.lib.optional waylandSupport ./clip-wayland-support.patch;
nativeBuildInputs = [ makeWrapper ];
installFlags = [ "PREFIX=$(out)" "WITH_ALLCOMP=yes" ];
postInstall = ''
# Install Emacs Mode. NOTE: We can't install the necessary
# dependencies (s.el and f.el) here. The user has to do this
# himself.
mkdir -p "$out/share/emacs/site-lisp"
cp "contrib/emacs/password-store.el" "$out/share/emacs/site-lisp/"
'' + optionalString x11Support ''
cp "contrib/dmenu/passmenu" "$out/bin/"
'';
wrapperPath = with stdenv.lib; makeBinPath ([
coreutils
getopt
git
gnupg
gnused
tree
which
qrencode
procps
] ++ optional stdenv.isDarwin openssl
++ ifEnable x11Support [ dmenu xclip xdotool ]
++ optional waylandSupport wl-clipboard);
postFixup = ''
# Fix program name in --help
substituteInPlace $out/bin/pass \
--replace 'PROGRAM="''${0##*/}"' "PROGRAM=pass"
# Ensure all dependencies are in PATH
wrapProgram $out/bin/pass \
--prefix PATH : "${wrapperPath}"
'' + stdenv.lib.optionalString x11Support ''
# We just wrap passmenu with the same PATH as pass. It doesn't
# need all the tools in there but it doesn't hurt either.
wrapProgram $out/bin/passmenu \
--prefix PATH : "$out/bin:${wrapperPath}"
'';
# Turn "check" into "installcheck", since we want to test our pass,
# not the one before the fixup.
postPatch = ''
patchShebangs tests
substituteInPlace src/password-store.sh \
--replace "@out@" "$out"
# the turning
sed -i -e 's@^PASS=.*''$@PASS=$out/bin/pass@' \
-e 's@^GPGS=.*''$@GPG=${gnupg}/bin/gpg2@' \
-e '/which gpg/ d' \
tests/setup.sh
'' + stdenv.lib.optionalString stdenv.isDarwin ''
# 'pass edit' uses hdid, which is not available from the sandbox.
rm -f tests/t0200-edit-tests.sh
rm -f tests/t0010-generate-tests.sh
rm -f tests/t0020-show-tests.sh
rm -f tests/t0050-mv-tests.sh
rm -f tests/t0100-insert-tests.sh
rm -f tests/t0300-reencryption.sh
rm -f tests/t0400-grep.sh
'';
doCheck = false;
doInstallCheck = true;
installCheckInputs = [ git ];
installCheckTarget = "test";
passthru = {
extensions = passExtensions;
withExtensions = env;
};
meta = with stdenv.lib; {
description = "Stores, retrieves, generates, and synchronizes passwords securely";
homepage = https://www.passwordstore.org/;
license = licenses.gpl2Plus;
maintainers = with maintainers; [ lovek323 the-kenny fpletz tadfisher globin ma27 ];
platforms = platforms.unix;
longDescription = ''
pass is a very simple password store that keeps passwords inside gpg2
encrypted files inside a simple directory tree residing at
~/.password-store. The pass utility provides a series of commands for
manipulating the password store, allowing the user to add, remove, edit,
synchronize, generate, and manipulate passwords.
'';
};
}

View file

@ -0,0 +1,32 @@
diff --git a/Makefile b/Makefile
index eac2291..1b1df0a 100644
--- a/Makefile
+++ b/Makefile
@@ -46,12 +46,12 @@ install: install-common
@install -v -d "$(DESTDIR)$(LIBDIR)/password-store" && install -m 0644 -v "$(PLATFORMFILE)" "$(DESTDIR)$(LIBDIR)/password-store/platform.sh"
@install -v -d "$(DESTDIR)$(LIBDIR)/password-store/extensions"
@install -v -d "$(DESTDIR)$(BINDIR)/"
- @trap 'rm -f src/.pass' EXIT; sed 's:.*PLATFORM_FUNCTION_FILE.*:source "$(LIBDIR)/password-store/platform.sh":;s:^SYSTEM_EXTENSION_DIR=.*:SYSTEM_EXTENSION_DIR="$(LIBDIR)/password-store/extensions":' src/password-store.sh > src/.pass && \
+ @trap 'rm -f src/.pass' EXIT; sed 's:.*PLATFORM_FUNCTION_FILE.*:source "$(LIBDIR)/password-store/platform.sh":;' src/password-store.sh > src/.pass && \
install -v -d "$(DESTDIR)$(BINDIR)/" && install -m 0755 -v src/.pass "$(DESTDIR)$(BINDIR)/pass"
else
install: install-common
@install -v -d "$(DESTDIR)$(LIBDIR)/password-store/extensions"
- @trap 'rm -f src/.pass' EXIT; sed '/PLATFORM_FUNCTION_FILE/d;s:^SYSTEM_EXTENSION_DIR=.*:SYSTEM_EXTENSION_DIR="$(LIBDIR)/password-store/extensions":' src/password-store.sh > src/.pass && \
+ @trap 'rm -f src/.pass' EXIT; sed '/PLATFORM_FUNCTION_FILE/d;' src/password-store.sh > src/.pass && \
install -v -d "$(DESTDIR)$(BINDIR)/" && install -m 0755 -v src/.pass "$(DESTDIR)$(BINDIR)/pass"
endif
diff --git a/src/password-store.sh b/src/password-store.sh
index 68551a4..2f3b5b7 100755
--- a/src/password-store.sh
+++ b/src/password-store.sh
@@ -656,7 +656,7 @@ cmd_extension_or_show() {
fi
}
-SYSTEM_EXTENSION_DIR=""
+SYSTEM_EXTENSION_DIR="${SYSTEM_EXTENSION_DIR:-@out@/lib/password-store/extensions}"
cmd_extension() {
check_sneaky_paths "$1"
local user_extension system_extension extension

View file

@ -1,42 +0,0 @@
{ stdenv, pass, fetchFromGitHub, pythonPackages, makeWrapper }:
let
pythonEnv = pythonPackages.python.withPackages (p: [ p.requests ]);
in stdenv.mkDerivation rec {
pname = "pass-audit";
version = "0.1";
src = fetchFromGitHub {
owner = "roddhjav";
repo = "pass-audit";
rev = "v${version}";
sha256 = "0v0db8bzpcaa7zqz17syn3c78mgvw4mpg8qg1gh5rmbjsjfxw6sm";
};
nativeBuildInputs = [ makeWrapper ];
buildInputs = [ pythonEnv ];
patchPhase = ''
sed -i -e "s|/usr/lib|$out/lib|" audit.bash
sed -i -e 's|$0|${pass}/bin/pass|' audit.bash
'';
dontBuild = true;
installFlags = [ "PREFIX=$(out)" ];
postFixup = ''
wrapProgram $out/lib/password-store/extensions/audit.bash \
--prefix PATH : "${pythonEnv}/bin" \
--run "export PREFIX"
'';
meta = with stdenv.lib; {
description = "Pass extension for auditing your password repository.";
homepage = https://github.com/roddhjav/pass-audit;
license = licenses.gpl3Plus;
platforms = platforms.unix;
};
}

View file

@ -0,0 +1,175 @@
From 37c2b4d2940476555aeec20fe1e5e3fa0492a94e Mon Sep 17 00:00:00 2001
From: Maximilian Bosch <maximilian@mbosch.me>
Date: Sun, 15 Mar 2020 19:58:53 +0100
Subject: [PATCH] Make it possible to run the tests offline
Helpful when developing without network access, also makes sure that
the test actually depend on the API's data like number of breaches
(which will change in time).
---
tests/commons.py | 25 +++++++++++++++++++++++++
tests/test_audit.py | 8 +++++---
tests/test_pass_audit.py | 10 +++++++++-
tests/test_pwned.py | 8 +++++---
4 files changed, 44 insertions(+), 7 deletions(-)
diff --git a/tests/commons.py b/tests/commons.py
index 13c4cb1..4f1ecd8 100644
--- a/tests/commons.py
+++ b/tests/commons.py
@@ -56,3 +56,28 @@ class TestPass(TestBase):
for path in self.store.list(root):
data[path] = self.store.show(path)
return data
+
+
+def mock_request(*args, **kwargs):
+ class MockResponse:
+ def __init__(self):
+ data = [
+ "D5EE0CB1A41071812CCED2F1930E6E1A5D2:2",
+ "2DC183F740EE76F27B78EB39C8AD972A757:52579",
+ "CF164D7A51A1FD864B1BF9E1CE8A3EC171B:4",
+ "D0B910E7A3028703C0B30039795E908CEB2:7",
+ "AD6438836DBE526AA231ABDE2D0EEF74D42:3",
+ "EBAB0A7CE978E0194608B572E4F9404AA21:3",
+ "17727EAB0E800E62A776C76381DEFBC4145:120",
+ "5370372AC65308F03F6ED75EC6068C8E1BE:1386",
+ "1E4C9B93F3F0682250B6CF8331B7EE68FD8:3730471",
+ "437FAA5A7FCE15D1DDCB9EAEAEA377667B8:123422",
+ "944C22589AC652B0F47918D58CA0CDCCB63:411"
+ ]
+
+ self.text = "\r\n".join(data)
+
+ def raise_for_status(self):
+ pass
+
+ return MockResponse()
diff --git a/tests/test_audit.py b/tests/test_audit.py
index d8c7a9a..5e0a9cf 100644
--- a/tests/test_audit.py
+++ b/tests/test_audit.py
@@ -17,12 +17,13 @@
#
from .. import pass_audit
-from tests.commons import TestPass
-
+from tests.commons import TestPass, mock_request
+from unittest import mock
class TestPassAudit(TestPass):
passwords_nb = 7
+ @mock.patch('requests.get', mock_request)
def test_password_notpwned(self):
"""Testing: pass audit for password not breached with K-anonymity method."""
data = self._getdata("Password/notpwned")
@@ -30,9 +31,10 @@ class TestPassAudit(TestPass):
breached = audit.password()
self.assertTrue(len(breached) == 0)
+ @mock.patch('requests.get', mock_request)
def test_password_pwned(self):
"""Testing: pass audit for password breached with K-anonymity method."""
- ref_counts = [51259, 3, 114, 1352, 3645804, 78773, 396]
+ ref_counts = [52579, 3, 120, 1386, 3730471, 123422, 411]
data = self._getdata("Password/pwned")
audit = pass_audit.PassAudit(data)
breached = audit.password()
diff --git a/tests/test_pass_audit.py b/tests/test_pass_audit.py
index 4c10f87..2c949f7 100644
--- a/tests/test_pass_audit.py
+++ b/tests/test_pass_audit.py
@@ -19,7 +19,8 @@
import os
from .. import pass_audit
-from tests.commons import TestPass
+from tests.commons import TestPass, mock_request
+from unittest import mock
class TestPassAuditCMD(TestPass):
@@ -47,6 +48,7 @@ class TestPassAuditCMD(TestPass):
cmd = ['--not-an-option', '-q']
self._passaudit(cmd, 2)
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_StoreNotInitialized(self):
"""Testing: store not initialized."""
cmd = ['Password/', '-v']
@@ -56,6 +58,7 @@ class TestPassAuditCMD(TestPass):
os.rename(os.path.join(self.store.prefix, 'backup.gpg-id'),
os.path.join(self.store.prefix, '.gpg-id'))
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_InvalidID(self):
"""Testing: invalid user ID."""
os.rename(os.path.join(self.store.prefix, '.gpg-id'),
@@ -66,26 +69,31 @@ class TestPassAuditCMD(TestPass):
os.rename(os.path.join(self.store.prefix, 'backup.gpg-id'),
os.path.join(self.store.prefix, '.gpg-id'))
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_NotAFile(self):
"""Testing: pass audit not_a_file."""
cmd = ['not_a_file']
self._passaudit(cmd, 1)
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_passwords_notpwned(self):
"""Testing: pass audit Password/notpwned."""
cmd = ['Password/notpwned']
self._passaudit(cmd)
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_passwords_pwned(self):
"""Testing: pass audit Password/pwned."""
cmd = ['Password/pwned']
self._passaudit(cmd)
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_passwords_good(self):
"""Testing: pass audit Password/good."""
cmd = ['Password/good']
self._passaudit(cmd)
+ @mock.patch('requests.get', mock_request)
def test_pass_audit_passwords_all(self):
"""Testing: pass audit ."""
cmd = ['']
diff --git a/tests/test_pwned.py b/tests/test_pwned.py
index 5ce6bc6..c28939a 100644
--- a/tests/test_pwned.py
+++ b/tests/test_pwned.py
@@ -17,7 +17,8 @@
#
from .. import pass_audit
-from tests.commons import TestPass
+from tests.commons import TestPass, mock_request
+from unittest import mock
class TestPwnedAPI(TestPass):
@@ -25,12 +26,13 @@ class TestPwnedAPI(TestPass):
def setUp(self):
self.api = pass_audit.PwnedAPI()
+ @mock.patch('requests.get', mock_request)
def test_password_range(self):
"""Testing: https://api.haveibeenpwned.com/range API."""
prefix = '21BD1'
Hash = '21BD12DC183F740EE76F27B78EB39C8AD972A757'
hashes, counts = self.api.password_range(prefix)
self.assertIn(Hash, hashes)
- self.assertTrue(counts[hashes.index(Hash)] == 51259)
+ self.assertTrue(counts[hashes.index(Hash)] == 52579)
self.assertTrue(len(hashes) == len(counts))
- self.assertTrue(len(hashes) == 527)
+ self.assertTrue(len(hashes) == 11)
--
2.25.0

View file

@ -0,0 +1,28 @@
From 8f76b32946430737f97f2702afd828b09536afd2 Mon Sep 17 00:00:00 2001
From: Maximilian Bosch <maximilian@mbosch.me>
Date: Sun, 15 Mar 2020 20:10:11 +0100
Subject: [PATCH 2/2] Fix audit.bash setup
This sets PASSWORD_STORE_DIR (needed by the python-code) to
PASSWORD_STORE_DIR and properly falls back to `~/.password-store` if
it's not set.
---
audit.bash | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/audit.bash b/audit.bash
index 7a973dc..c40ff76 100755
--- a/audit.bash
+++ b/audit.bash
@@ -17,7 +17,7 @@
#
cmd_audit() {
- export PASSWORD_STORE_DIR=$PREFIX GIT_DIR PASSWORD_STORE_GPG_OPTS
+ export PASSWORD_STORE_DIR=${PASSWORD_STORE_DIR:-$HOME/.password-store} GIT_DIR PASSWORD_STORE_GPG_OPTS
export X_SELECTION CLIP_TIME PASSWORD_STORE_UMASK GENERATED_LENGTH
export CHARACTER_SET CHARACTER_SET_NO_SYMBOLS EXTENSIONS PASSWORD_STORE_KEY
export PASSWORD_STORE_ENABLE_EXTENSIONS PASSWORD_STORE_SIGNING_KEY
--
2.25.0

View file

@ -0,0 +1,51 @@
{ stdenv, pass, fetchFromGitHub, pythonPackages, makeWrapper, gnupg }:
let
pythonEnv = pythonPackages.python.withPackages (p: [ p.requests p.setuptools p.zxcvbn ]);
in stdenv.mkDerivation rec {
pname = "pass-audit";
version = "1.0.1";
src = fetchFromGitHub {
owner = "roddhjav";
repo = "pass-audit";
rev = "v${version}";
sha256 = "1mdckw0dwcnv8smp1za96y0zmdnykbkw2606v7mzfnzbz4zjdlwl";
};
patches = [
./0001-Make-it-possible-to-run-the-tests-offline.patch
./0002-Fix-audit.bash-setup.patch
];
postPatch = ''
substituteInPlace audit.bash \
--replace '/usr/bin/env python3' "${pythonEnv}/bin/python3"
'';
outputs = [ "out" "man" ];
buildInputs = [ pythonEnv ];
nativeBuildInputs = [ makeWrapper ];
doCheck = true;
checkInputs = [ pythonPackages.green pass gnupg ];
checkPhase = ''
${pythonEnv}/bin/python3 setup.py green -q
'';
installFlags = [ "DESTDIR=${placeholder "out"}" "PREFIX=" ];
postInstall = ''
wrapProgram $out/lib/password-store/extensions/audit.bash \
--prefix PYTHONPATH : "$out/lib/${pythonEnv.libPrefix}/site-packages"
'';
meta = with stdenv.lib; {
description = "Pass extension for auditing your password repository.";
homepage = https://github.com/roddhjav/pass-audit;
license = licenses.gpl3Plus;
platforms = platforms.unix;
maintainers = with maintainers; [ ma27 ];
};
}

View file

@ -3,7 +3,7 @@
with pkgs;
{
pass-audit = callPackage ./audit.nix {
pass-audit = callPackage ./audit {
pythonPackages = python3Packages;
};
pass-checkup = callPackage ./checkup.nix {};